| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- "use client";
- import React from "react";
- import { RefreshCw } from "lucide-react";
- import { usePathname, useRouter } from "next/navigation";
- import { useAuth } from "@/components/auth/authContext";
- import {
- shouldRedirectToProfileForPasswordChange,
- buildMustChangePasswordRedirectUrl,
- resolveMustChangePasswordResumePath,
- } from "@/lib/frontend/auth/mustChangePasswordGate";
- import { Button } from "@/components/ui/button";
- import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
- import {
- Card,
- CardHeader,
- CardTitle,
- CardDescription,
- CardContent,
- CardFooter,
- } from "@/components/ui/card";
- export default function AuthGate({ children }) {
- const router = useRouter();
- const pathname = usePathname() || "/";
- const { status, user, error, retry } = useAuth();
- const canRetry = typeof retry === "function";
- const isAuthenticated = status === "authenticated" && user;
- const mustChangePassword = isAuthenticated && user.mustChangePassword === true;
- const currentSearch =
- typeof window !== "undefined" ? window.location.search || "" : "";
- const currentPathWithSearch = `${pathname}${currentSearch}`;
- const mustChangePasswordRedirectUrl = buildMustChangePasswordRedirectUrl(
- currentPathWithSearch,
- );
- const shouldForceProfileRedirect = isAuthenticated
- ? shouldRedirectToProfileForPasswordChange({
- pathname,
- mustChangePassword,
- })
- : false;
- const resumePathAfterPasswordChange = isAuthenticated
- ? resolveMustChangePasswordResumePath({
- pathname,
- searchParams:
- typeof window !== "undefined"
- ? new URLSearchParams(window.location.search || "")
- : null,
- mustChangePassword,
- })
- : null;
- React.useEffect(() => {
- if (!shouldForceProfileRedirect) return;
- router.replace(mustChangePasswordRedirectUrl);
- }, [shouldForceProfileRedirect, mustChangePasswordRedirectUrl, router]);
- React.useEffect(() => {
- if (!resumePathAfterPasswordChange) return;
- router.replace(resumePathAfterPasswordChange);
- }, [resumePathAfterPasswordChange, router]);
- if (status === "authenticated") {
- if (shouldForceProfileRedirect) return null;
- if (resumePathAfterPasswordChange) return null;
- return children;
- }
- if (status === "error") {
- return (
- <Card>
- <CardHeader>
- <CardTitle>Sitzungsprüfung fehlgeschlagen</CardTitle>
- <CardDescription>
- Die Sitzung konnte nicht geprüft werden.
- </CardDescription>
- </CardHeader>
- <CardContent className="space-y-3">
- <Alert variant="destructive">
- <AlertTitle>Fehler</AlertTitle>
- <AlertDescription>
- {error ||
- "Bitte prüfen Sie Ihre Verbindung und versuchen Sie es erneut."}
- </AlertDescription>
- </Alert>
- </CardContent>
- <CardFooter className="flex flex-col gap-2 sm:flex-row sm:justify-end">
- <Button
- type="button"
- variant="outline"
- onClick={() => {
- if (canRetry) retry();
- else window.location.reload();
- }}
- >
- <RefreshCw className="h-4 w-4" />
- Erneut versuchen
- </Button>
- </CardFooter>
- </Card>
- );
- }
- // "unauthenticated" -> redirect happens in AuthProvider.
- // Keeping this message is fine because TopNav indicator is not shown in this state.
- if (status === "unauthenticated") {
- return (
- <Card>
- <CardHeader>
- <CardTitle>Weiterleitung</CardTitle>
- <CardDescription>
- Sie werden zum Login weitergeleitet.
- </CardDescription>
- </CardHeader>
- <CardContent>
- <p className="text-sm text-muted-foreground">Bitte warten…</p>
- </CardContent>
- </Card>
- );
- }
- // Default: loading (or unknown)
- // RHL-032:
- // Do not render a second "session checking" UI here.
- // The TopNav SessionIndicator is the single source of feedback.
- return null;
- }
|