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

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:
soroush.asadi
2026-06-04 05:56:11 +03:30
parent 7c35984096
commit cc0933c514
@@ -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>
);