fix(auth): don't log out fullscreen routes (POS/queue) on refresh
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m4s
CI/CD / CI · Admin Web (tsc) (push) Successful in 36s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 48s
CI/CD / Deploy · all services (push) Successful in 2m35s
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m4s
CI/CD / CI · Admin Web (tsc) (push) Successful in 36s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 48s
CI/CD / Deploy · all services (push) Successful in 2m35s
The (fullscreen) layout redirected to /login whenever user.accessToken was falsy — but on a page refresh that fires before Zustand finishes rehydrating the persisted auth from localStorage, so an authenticated user was bounced to login on every refresh. Gate the redirect on _hasHydrated (and show a loader while rehydrating), matching RouteGuard. Tokens themselves are already long (30d access / 365d refresh), so sessions now survive refreshes as expected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,24 +2,39 @@
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useLocale } from "next-intl";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
import { useAuthStore } from "@/lib/stores/auth.store";
|
||||
import { RouteGuard } from "@/components/auth/route-guard";
|
||||
|
||||
/** Full-viewport routes (queue TV display) — auth only, no dashboard chrome. */
|
||||
/** Full-viewport routes (POS, queue TV display) — auth only, no dashboard chrome. */
|
||||
export default function FullscreenLayout({ children }: { children: React.ReactNode }) {
|
||||
const locale = useLocale();
|
||||
const router = useRouter();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const hasHydrated = useAuthStore((s) => s._hasHydrated);
|
||||
const dir = locale === "en" ? "ltr" : "rtl";
|
||||
|
||||
useEffect(() => {
|
||||
if (!user?.accessToken) {
|
||||
// Only redirect AFTER the persisted auth has rehydrated from localStorage —
|
||||
// otherwise a page refresh sees the empty initial state and bounces an
|
||||
// already-authenticated user to /login before their session loads back in.
|
||||
if (hasHydrated && !user?.accessToken) {
|
||||
router.replace("/login");
|
||||
}
|
||||
}, [user, router]);
|
||||
}, [hasHydrated, user, router]);
|
||||
|
||||
// While rehydrating, show a loader instead of redirecting or flashing content.
|
||||
if (!hasHydrated) {
|
||||
return (
|
||||
<div className="flex min-h-svh items-center justify-center" dir={dir}>
|
||||
<Loader2 className="size-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-svh" dir={locale === "en" ? "ltr" : "rtl"}>
|
||||
<div className="min-h-svh" dir={dir}>
|
||||
<RouteGuard>{children}</RouteGuard>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user