diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx new file mode 100644 index 0000000..e66f59a --- /dev/null +++ b/src/app/admin/layout.tsx @@ -0,0 +1,79 @@ +'use client' + +import { useEffect, useMemo, useState } from 'react' +import { useRouter } from 'next/navigation' +import useAuthStore from '../store/authStore' + +function isUserAdmin(user: any): boolean { + if (!user) return false + const role = user.role ?? user.userType ?? user.user_type + if (role === 'admin' || role === 'super_admin') return true + if (user.isAdmin === true || user.isSuperAdmin === true) return true + if (Array.isArray(user.roles) && (user.roles.includes('admin') || user.roles.includes('super_admin'))) return true + return false +} + +export default function AdminLayout({ children }: { children: React.ReactNode }) { + const router = useRouter() + const user = useAuthStore(s => s.user) + const isAuthReady = useAuthStore(s => s.isAuthReady) + const refreshAuthToken = useAuthStore(s => s.refreshAuthToken) + const [mounted, setMounted] = useState(false) + + const isAdmin = useMemo(() => isUserAdmin(user), [user]) + + useEffect(() => { + setMounted(true) + }, []) + + useEffect(() => { + let cancelled = false + + const guard = async () => { + if (!mounted || !isAuthReady) return + + if (!user) { + try { + await refreshAuthToken?.() + } catch {} + } + + const currentUser = useAuthStore.getState().user + const ok = isUserAdmin(currentUser) + + if (!currentUser) { + router.replace('/login') + return + } + + if (!ok) { + router.replace('/dashboard') + return + } + + if (!cancelled) { + // allowed + } + } + + guard() + return () => { cancelled = true } + }, [mounted, isAuthReady, user, refreshAuthToken, router]) + + if (!mounted || !isAuthReady) { + return ( +
+
+
+

Loading...

+
+
+ ) + } + + if (!isAdmin) { + return null + } + + return <>{children} +}