File size: 2,204 Bytes
24cf0c4
 
 
 
 
 
ee111cd
 
24cf0c4
 
 
 
7782325
 
 
 
 
 
 
24cf0c4
 
ee111cd
24cf0c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ee111cd
7782325
24cf0c4
 
 
 
7782325
24cf0c4
ee111cd
24cf0c4
ee111cd
24cf0c4
7782325
 
 
 
 
 
 
24cf0c4
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"use client";

import { useEffect, useState } from "react";
import { usePathname, useRouter } from "next/navigation";
import { DashboardLayout } from "./DashboardLayout";
import { useAuthStore } from "@/lib/stores/authStore";
import { useThemeStore } from "@/lib/stores/themeStore";
import { useLanguageStore } from "@/lib/stores/languageStore";
import { Loader2, Sparkles } from "lucide-react";

const PUBLIC_PATHS = ["/login"];

// Lang codes mapped to BCP-47 HTML lang values
const LANG_MAP: Record<string, string> = {
  en: "en",
  hi: "hi",
  mr: "mr",
};

function FullPageSpinner() {
  return (
    <div className="flex min-h-screen items-center justify-center" style={{ background: "var(--bg, #050505)" }}>
      <div className="flex flex-col items-center gap-4">
        <div className="flex h-14 w-14 items-center justify-center rounded-2xl bg-gradient-to-br from-emerald-400 to-cyan-500 shadow-2xl shadow-emerald-500/30">
          <Sparkles className="h-7 w-7 text-white" />
        </div>
        <Loader2 className="h-5 w-5 animate-spin text-emerald-400" />
        <p className="text-xs text-zinc-500">Loading BankBot AI...</p>
      </div>
    </div>
  );
}

export function AppShell({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();
  const router = useRouter();
  const { isAuthenticated, restoreSession } = useAuthStore();
  const { theme, setTheme } = useThemeStore();
  const { language } = useLanguageStore();
  const [hydrated, setHydrated] = useState(false);

  const isPublic = PUBLIC_PATHS.includes(pathname);

  // Apply persisted theme on mount
  useEffect(() => {
    setTheme(theme);
    restoreSession().finally(() => setHydrated(true));
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // Sync <html lang> whenever language changes
  useEffect(() => {
    if (typeof document !== "undefined") {
      document.documentElement.lang = LANG_MAP[language] ?? language;
    }
  }, [language]);

  if (!hydrated) return <FullPageSpinner />;
  if (isPublic) return <>{children}</>;
  if (!isAuthenticated) {
    router.replace("/login");
    return <FullPageSpinner />;
  }

  return <DashboardLayout>{children}</DashboardLayout>;
}