110 lines
3 KiB
TypeScript
110 lines
3 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useSession } from "@/lib/auth-client";
|
||
|
|
import { hasCompletedHealthProfile } from "@/lib/hellth-data";
|
||
|
|
import { trpc } from "@/lib/trpc";
|
||
|
|
import { usePathname, useRouter } from "next/navigation";
|
||
|
|
import { useEffect } from "react";
|
||
|
|
|
||
|
|
const PLATFORM_ALLOWED_PREFIXES = [
|
||
|
|
"/",
|
||
|
|
"/aktivitaeten",
|
||
|
|
"/benutzer",
|
||
|
|
"/einstellungen",
|
||
|
|
"/erinnerungen",
|
||
|
|
"/hellfireclub",
|
||
|
|
"/einkaufsliste",
|
||
|
|
"/lebensmittel",
|
||
|
|
"/maerkte",
|
||
|
|
"/onboarding",
|
||
|
|
"/planung",
|
||
|
|
"/rezepte",
|
||
|
|
"/ziele",
|
||
|
|
"/wochenbudget",
|
||
|
|
"/sicherheit/2fa-setup",
|
||
|
|
];
|
||
|
|
|
||
|
|
export function AuthGuard({ children }: { children: React.ReactNode }) {
|
||
|
|
const { data: session, isPending } = useSession();
|
||
|
|
const router = useRouter();
|
||
|
|
const pathname = usePathname();
|
||
|
|
|
||
|
|
const platformAdminEmails = (
|
||
|
|
process.env.NEXT_PUBLIC_PLATFORM_ADMIN_EMAILS ?? "admin@onl1.eu"
|
||
|
|
)
|
||
|
|
.split(",")
|
||
|
|
.map((email) => email.trim().toLowerCase())
|
||
|
|
.filter(Boolean);
|
||
|
|
const userRole = ((session?.user as { role?: string } | undefined)?.role ?? "").toLowerCase();
|
||
|
|
const userEmail = (session?.user?.email ?? "").toLowerCase();
|
||
|
|
const isPlatformAdmin =
|
||
|
|
userRole === "admin" ||
|
||
|
|
userRole === "platform_admin" ||
|
||
|
|
platformAdminEmails.includes(userEmail);
|
||
|
|
const securityQuery = trpc.security.status.useQuery(undefined, {
|
||
|
|
enabled: !!session && !isPending,
|
||
|
|
retry: false,
|
||
|
|
});
|
||
|
|
const requiresTwoFactorSetup = securityQuery.data?.requiresTwoFactorSetup ?? false;
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!isPending && !session) {
|
||
|
|
router.push("/login");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!isPending && session) {
|
||
|
|
if (securityQuery.isLoading) return;
|
||
|
|
|
||
|
|
if (requiresTwoFactorSetup && !pathname.startsWith("/sicherheit/2fa-setup")) {
|
||
|
|
router.push("/sicherheit/2fa-setup");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isPlatformAdmin) {
|
||
|
|
const isAllowed = PLATFORM_ALLOWED_PREFIXES.some((prefix) =>
|
||
|
|
prefix === "/" ? pathname === "/" : pathname.startsWith(prefix),
|
||
|
|
);
|
||
|
|
if (!isAllowed) {
|
||
|
|
router.push("/");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
const userKey = session.user.id ?? session.user.email ?? null;
|
||
|
|
const onboardingComplete = hasCompletedHealthProfile(userKey);
|
||
|
|
if (!onboardingComplete && !pathname.startsWith("/onboarding")) {
|
||
|
|
router.push("/onboarding");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (pathname.startsWith("/benutzer") || pathname.startsWith("/einstellungen")) {
|
||
|
|
router.push("/");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}, [
|
||
|
|
session,
|
||
|
|
isPending,
|
||
|
|
isPlatformAdmin,
|
||
|
|
pathname,
|
||
|
|
router,
|
||
|
|
requiresTwoFactorSetup,
|
||
|
|
securityQuery.isLoading,
|
||
|
|
]);
|
||
|
|
|
||
|
|
if (isPending || (!!session && securityQuery.isLoading)) {
|
||
|
|
return (
|
||
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||
|
|
<div className="flex flex-col items-center gap-3">
|
||
|
|
<div className="w-8 h-8 border-2 border-[#0F766E] border-t-transparent rounded-full animate-spin" />
|
||
|
|
<p className="text-sm text-gray-400">Laden...</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!session) return null;
|
||
|
|
|
||
|
|
return <>{children}</>;
|
||
|
|
}
|
||
|
|
|