From 1757aba3e7008dadca9aaa6baa2427a74cf0cfcc Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 12 Dec 2025 11:10:49 -0500 Subject: [PATCH] fixed authcontext for sign up, added 404 and middleware for prod readiness --- app/(builder)/builder/page.tsx | 14 +- app/admin/products/page.tsx | 411 +++++++++++++++++++++++++++++++++ app/not-found.tsx | 41 ++++ app/register/page.tsx | 2 +- context/AuthContext.tsx | 4 +- middleware.ts | 38 +++ 6 files changed, 504 insertions(+), 6 deletions(-) create mode 100644 app/admin/products/page.tsx create mode 100644 app/not-found.tsx create mode 100644 middleware.ts diff --git a/app/(builder)/builder/page.tsx b/app/(builder)/builder/page.tsx index 952aea4..5118569 100644 --- a/app/(builder)/builder/page.tsx +++ b/app/(builder)/builder/page.tsx @@ -403,9 +403,17 @@ export default function GunbuilderPage() { Platform setPlatform(e.target.value)} + className="rounded-md border border-zinc-700 bg-zinc-900 px-2 py-1 text-xs text-zinc-100 focus:outline-none focus:ring-1 focus:ring-amber-400" + > + {platforms.map((p) => ( + + ))} + + + +
+ + setQuery(e.target.value)} + placeholder="brand, name, part role…" + className="w-64 max-w-full rounded-md border border-zinc-700 bg-zinc-900/70 px-2 py-1 text-xs text-zinc-200 focus:outline-none focus:ring-1 focus:ring-amber-400" + /> +
+ + + + +
+ {loading ? ( + Loading… + ) : error ? ( + {error} + ) : ( + + Showing{" "} + + {filtered.length === 0 ? 0 : pageStart + 1}-{pageEndExclusive} + + {" "}of{" "} + {filtered.length} + {" "}{filtered.length === 1 ? "product" : "products"} + + )} +
+ + + {!loading && !error && filtered.length > 0 && ( +
+
+ Page {clampedPage} of{" "} + {totalPages} +
+ +
+ + +
+
+ )} + +
+ + + + + + + + + + + + + {loading ? ( + + + + ) : error ? ( + + + + ) : paginated.length === 0 ? ( + + + + ) : ( + paginated.map((p) => ( + + + + + + + + + )) + )} + +
ProductBrandPlatformPart RolePriceLink
+ Loading products… +
+ {error} +
+ No products found. +
+
{p.name}
+
ID: {p.id}
+
{p.brand} + {p.platform ?? platformKeyToApiPlatform(platform)} + {p.partRole} + {p.price == null ? "—" : `$${Number(p.price).toFixed(2)}`} + + {p.buyUrl ? ( + + Open + + ) : ( + + )} +
+
+ + {!loading && !error && filtered.length > 0 && ( +
+ + + + Page{" "} + + {clampedPage} + {" "} + of{" "} + + {totalPages} + + + + +
+ )} + +
+ Backend: {API_BASE_URL} · Endpoint: /api/products?platform=... · Page size: {pageSize} +
+ + + + ); +} \ No newline at end of file diff --git a/app/not-found.tsx b/app/not-found.tsx new file mode 100644 index 0000000..d89982d --- /dev/null +++ b/app/not-found.tsx @@ -0,0 +1,41 @@ +import Link from "next/link"; + +export default function NotFound() { + return ( +
+
+

+ Battl Builders +

+ +

+ Page Not Found +

+ +

+ This area of the site isn’t publicly accessible yet. +

+ +
+ + Go Home + + + + Learn More + +
+ +

+ Early access features are launching soon. +

+
+
+ ); +} \ No newline at end of file diff --git a/app/register/page.tsx b/app/register/page.tsx index baf6310..02fda33 100644 --- a/app/register/page.tsx +++ b/app/register/page.tsx @@ -34,7 +34,7 @@ export default function RegisterPage() {

- Join the Shadow Standard beta + Join the Battl Builder Beta

Create an account so we can save your builds, watch price drops, and diff --git a/context/AuthContext.tsx b/context/AuthContext.tsx index 81a7802..48c923a 100644 --- a/context/AuthContext.tsx +++ b/context/AuthContext.tsx @@ -85,7 +85,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { async ({ email, password }: { email: string; password: string }) => { setLoading(true); try { - const res = await fetch(`${API_BASE_URL}/auth/login`, { + const res = await fetch(`${API_BASE_URL}/api/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }), @@ -130,7 +130,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { }) => { setLoading(true); try { - const res = await fetch(`${API_BASE_URL}/auth/register`, { + const res = await fetch(`${API_BASE_URL}/api/auth/register`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password, displayName }), diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..1134aa2 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,38 @@ +// middleware.ts +import { NextResponse } from "next/server"; +import type { NextRequest } from "next/server"; + +const LAUNCH_ONLY_ROOT = process.env.NEXT_PUBLIC_LAUNCH_ONLY_ROOT === "true"; + +// Allow only root + essential static files +const ALLOW = new Set([ + "/", + "/favicon.ico", + "/robots.txt", + "/sitemap.xml", +]); + +export function middleware(req: NextRequest) { + if (!LAUNCH_ONLY_ROOT) return NextResponse.next(); + + const { pathname } = req.nextUrl; + + // Always allow Next internals + static assets + if ( + pathname.startsWith("/_next") || + pathname.startsWith("/assets") || + pathname.startsWith("/images") + ) { + return NextResponse.next(); + } + + // Allow the root + a few public files + if (ALLOW.has(pathname)) return NextResponse.next(); + + // Everything else: hide it + return NextResponse.rewrite(new URL("/404", req.url)); // or redirect to "/" +} + +export const config = { + matcher: ["/:path*"], +}; \ No newline at end of file