Add Suspense fallback for loading states in multiple pages and layouts
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
// app/(builder)/builder/page.tsx
|
// app/(builder)/builder/page.tsx
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Battl Builder - Main builder page
|
* Battl Builder - Main builder page
|
||||||
*
|
*
|
||||||
@@ -329,7 +331,7 @@ function buildAssemblyRows(params: {
|
|||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function GunbuilderPage() {
|
function GunbuilderPageContent() {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -1704,3 +1706,19 @@ export default function GunbuilderPage() {
|
|||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function GunbuilderPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={
|
||||||
|
<main className="min-h-screen bg-white text-zinc-900 dark:bg-black dark:text-zinc-50">
|
||||||
|
<div className="mx-auto max-w-6xl px-4 py-6 lg:py-10">
|
||||||
|
<div className="rounded-lg border border-zinc-800 bg-zinc-950/80 p-4">
|
||||||
|
<div className="text-sm text-zinc-400">Loading builder…</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
}>
|
||||||
|
<GunbuilderPageContent />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
// app/(builder)/layout.tsx
|
// app/(builder)/layout.tsx
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
import { BuilderNav } from "@/components/BuilderNav";
|
import { BuilderNav } from "@/components/BuilderNav";
|
||||||
import { TopNav } from "@/components/TopNav";
|
import { TopNav } from "@/components/TopNav";
|
||||||
import { Import } from "lucide-react";
|
|
||||||
import { Footer } from "@/components/Footer";
|
import { Footer } from "@/components/Footer";
|
||||||
|
|
||||||
export default function BuilderLayout({ children }: { children: ReactNode }) {
|
export default function BuilderLayout({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white text-zinc-900 dark:bg-neutral-950 dark:text-zinc-50">
|
<div className="min-h-screen bg-white text-zinc-900 dark:bg-neutral-950 dark:text-zinc-50">
|
||||||
<TopNav />
|
<TopNav />
|
||||||
<BuilderNav />
|
<Suspense fallback={<div className="h-[52px]" />}>
|
||||||
|
<BuilderNav />
|
||||||
|
</Suspense>
|
||||||
<main className="min-h-screen">{children}</main>
|
<main className="min-h-screen">{children}</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// app/beta/confirm/page.tsx
|
// app/beta/confirm/page.tsx
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState, Suspense } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
|
|
||||||
const API_BASE_URL =
|
const API_BASE_URL =
|
||||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
||||||
|
|
||||||
export default function BetaConfirmPage() {
|
function BetaConfirmPageContent() {
|
||||||
const params = useSearchParams();
|
const params = useSearchParams();
|
||||||
const token = params.get("token");
|
const token = params.get("token");
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -88,4 +88,19 @@ export default function BetaConfirmPage() {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BetaConfirmPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={
|
||||||
|
<main className="min-h-screen flex items-center justify-center bg-black text-white px-6">
|
||||||
|
<div className="max-w-md w-full rounded-xl border border-white/10 bg-white/5 p-6 text-center">
|
||||||
|
<h1 className="text-lg font-semibold">Battl Builders</h1>
|
||||||
|
<p className="mt-2 text-sm text-zinc-300">Loading…</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
}>
|
||||||
|
<BetaConfirmPageContent />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
+17
-2
@@ -1,10 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState, Suspense } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
|
|
||||||
export default function BetaMagicPage() {
|
function BetaMagicPageContent() {
|
||||||
const params = useSearchParams();
|
const params = useSearchParams();
|
||||||
const token = params.get("token");
|
const token = params.get("token");
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -75,4 +75,19 @@ export default function BetaMagicPage() {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BetaMagicPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={
|
||||||
|
<main className="min-h-screen bg-black text-zinc-50 flex items-center justify-center px-4">
|
||||||
|
<div className="max-w-md w-full rounded-xl border border-white/10 bg-white/5 p-6">
|
||||||
|
<h1 className="text-lg font-semibold">Battl Builders</h1>
|
||||||
|
<p className="mt-2 text-sm text-zinc-300">Loading…</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
}>
|
||||||
|
<BetaMagicPageContent />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
// app/(builder)/layout.tsx
|
// app/(builder)/layout.tsx
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
import { AuthProvider } from "@/context/AuthContext";
|
import { AuthProvider } from "@/context/AuthContext";
|
||||||
import { BuilderNav } from "@/components/BuilderNav";
|
import { BuilderNav } from "@/components/BuilderNav";
|
||||||
@@ -10,7 +11,9 @@ export default function BuilderLayout({ children }: { children: ReactNode }) {
|
|||||||
<div className="min-h-screen bg-neutral-950 text-zinc-50">
|
<div className="min-h-screen bg-neutral-950 text-zinc-50">
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<TopNav />
|
<TopNav />
|
||||||
<BuilderNav />
|
<Suspense fallback={<div className="h-[52px]" />}>
|
||||||
|
<BuilderNav />
|
||||||
|
</Suspense>
|
||||||
<main className="min-h-screen">{children}</main>
|
<main className="min-h-screen">{children}</main>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+16
-2
@@ -1,7 +1,7 @@
|
|||||||
// app/login/page.tsx
|
// app/login/page.tsx
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FormEvent, useMemo, useState } from "react";
|
import { FormEvent, useMemo, useState, Suspense } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
@@ -10,7 +10,7 @@ import { Button, Field, Input } from "@/components/ui/form";
|
|||||||
const API_BASE_URL =
|
const API_BASE_URL =
|
||||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
||||||
|
|
||||||
export default function LoginPage() {
|
function LoginPageContent() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const { login, loading } = useAuth();
|
const { login, loading } = useAuth();
|
||||||
@@ -186,3 +186,17 @@ export default function LoginPage() {
|
|||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function LoginPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={
|
||||||
|
<main className="min-h-screen bg-black text-zinc-50">
|
||||||
|
<div className="mx-auto flex max-w-md flex-col px-4 py-10">
|
||||||
|
<div className="h-8 w-48 animate-pulse bg-zinc-800 rounded" />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
}>
|
||||||
|
<LoginPageContent />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
+17
-3
@@ -1,7 +1,7 @@
|
|||||||
// app/register/page.tsx
|
// app/register/page.tsx
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FormEvent, useState } from "react";
|
import { FormEvent, useState, Suspense } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
@@ -9,7 +9,7 @@ import { Button, Field, Input } from "@/components/ui/form";
|
|||||||
|
|
||||||
const TOS_VERSION = "2025-12-27";
|
const TOS_VERSION = "2025-12-27";
|
||||||
|
|
||||||
export default function RegisterPage() {
|
function RegisterPageContent() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const { register, loading } = useAuth();
|
const { register, loading } = useAuth();
|
||||||
@@ -125,7 +125,7 @@ export default function RegisterPage() {
|
|||||||
>
|
>
|
||||||
Privacy Policy
|
Privacy Policy
|
||||||
</Link>
|
</Link>
|
||||||
. I understand Battl Builders is informational only and I’m
|
. I understand Battl Builders is informational only and I'm
|
||||||
solely responsible for legality, compatibility, and safe
|
solely responsible for legality, compatibility, and safe
|
||||||
assembly/use of any firearm or components.
|
assembly/use of any firearm or components.
|
||||||
</span>
|
</span>
|
||||||
@@ -147,4 +147,18 @@ export default function RegisterPage() {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RegisterPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={
|
||||||
|
<main className="min-h-screen bg-black text-zinc-50">
|
||||||
|
<div className="mx-auto flex max-w-md flex-col px-4 py-10">
|
||||||
|
<div className="h-8 w-64 animate-pulse bg-zinc-800 rounded" />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
}>
|
||||||
|
<RegisterPageContent />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user