"use client" import { useCallback, useEffect, useMemo, useState } from "react" import Link from "next/link" import { Loader2 } from "lucide-react" import { AuthCard } from "@/components/auth/auth-card" import { FlowChallengeForm } from "@/components/auth/flow-challenge-form" import { AUTH_FLOW_SLUGS, flowComponent, flowRedirectUrl, flowTitle, flowValidationErrors, isRecoveryEmailSent, respondAuthFlow, startAuthFlow, type AuthFlowSlug, type FlowChallenge, } from "@/lib/auth/flow-api" type AuthFlowPageProps = { slug: AuthFlowSlug defaultTitle: string defaultDescription: string successTitle: string successDescription: string successActionLabel: string successHref: string /** Full document navigation required (OIDC login routes). */ successExternal?: boolean footer: React.ReactNode onSuccess?: () => void } export function AuthFlowPage({ slug, defaultTitle, defaultDescription, successTitle, successDescription, successActionLabel, successHref, successExternal = false, footer, onSuccess, }: AuthFlowPageProps) { const [sessionId, setSessionId] = useState(null) const [challenge, setChallenge] = useState(null) const [loading, setLoading] = useState(true) const [submitting, setSubmitting] = useState(false) const [error, setError] = useState(null) const [done, setDone] = useState(false) const [denied, setDenied] = useState(false) const bootstrap = useCallback(async () => { setLoading(true) setError(null) try { const step = await startAuthFlow(slug) setSessionId(step.sessionId) setChallenge(step.challenge) setDone(step.done) setDenied(step.denied) if (step.done && !step.denied) { onSuccess?.() } } catch (err) { setError(err instanceof Error ? err.message : "Impossible de démarrer le parcours") } finally { setLoading(false) } }, [onSuccess, slug]) useEffect(() => { void bootstrap() }, [bootstrap]) const validationErrors = useMemo(() => flowValidationErrors(challenge), [challenge]) const formError = error ?? validationErrors._form ?? null const title = useMemo(() => { if ((done && !denied) || isRecoveryEmailSent(slug, challenge)) return successTitle if (denied) return "Accès refusé" return flowTitle(challenge) || defaultTitle }, [challenge, defaultTitle, denied, done, slug, successTitle]) const description = useMemo(() => { if ((done && !denied) || isRecoveryEmailSent(slug, challenge)) return successDescription if (denied) { return "Ce parcours a été refusé. Vérifiez vos informations ou contactez le support." } return defaultDescription }, [challenge, defaultDescription, denied, done, slug, successDescription]) async function handleSubmit(payload: Record) { if (!sessionId) return setSubmitting(true) setError(null) try { const step = await respondAuthFlow(slug, payload) setSessionId(step.sessionId) setChallenge(step.challenge) setDone(step.done) setDenied(step.denied) if (step.done && !step.denied) { onSuccess?.() } } catch (err) { setError(err instanceof Error ? err.message : "Échec de l'étape") } finally { setSubmitting(false) } } const component = flowComponent(challenge) const redirectUrl = flowRedirectUrl(challenge) const recoveryEmailSent = isRecoveryEmailSent(slug, challenge) const showSuccess = (done && !denied) || recoveryEmailSent return ( {loading ? (
Chargement…
) : showSuccess ? (
{redirectUrl ? (

Redirection en cours…

) : null}
{successExternal ? ( {successActionLabel} ) : ( {successActionLabel} )}
) : ( )}
) } export { AUTH_FLOW_SLUGS }