"use client" import { Suspense, useEffect, useMemo, useState } from "react" import Link from "next/link" import { useRouter, useSearchParams } from "next/navigation" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { MigrationStepList, appOnlyAuthStepLabel } from "@/components/migration/onboarding-ui" import { ApiRequestError } from "@/lib/api/client" import { useClaimMigration, useMigrationInvite } from "@/lib/api/hooks/use-hosted-mail" import { useAuthReady } from "@/lib/api/use-auth-ready" import { buildOidcLoginUrl } from "@/lib/auth/login-url" export default function OnboardClaimPage() { return (

Chargement…

} >
) } function claimErrorMessage(error: unknown): string { if (error instanceof ApiRequestError) { switch (error.code) { case "email_mismatch": return "L'adresse de connexion ne correspond pas à l'invitation. Utilisez le compte invité ou contactez votre administrateur pour ajouter une adresse SSO alternative." case "invite_already_claimed": return "Cette invitation a déjà été revendiquée." case "invite_not_found": return "Invitation introuvable ou expirée." case "migration_domain_not_active": return "Le domaine mail du projet n'est pas encore actif — contactez votre administrateur." case "migration_domain_mismatch": return "L'adresse invitée ne correspond pas au domaine mail du projet." } return error.message } if (error instanceof Error) { return error.message } return "Échec de la revendication — vérifiez que vous êtes connecté avec la bonne adresse." } function OnboardClaimContent() { const params = useSearchParams() const router = useRouter() const token = params.get("token") const { authenticated } = useAuthReady() const inviteQuery = useMigrationInvite(token) const claimMutation = useClaimMigration() const [password, setPassword] = useState("") const loginHref = useMemo(() => { const returnTo = token ? `/onboard/claim?token=${encodeURIComponent(token)}` : "/onboard/claim" return buildOidcLoginUrl({ returnTo }) }, [token]) const invite = inviteQuery.data?.invite const project = inviteQuery.data?.project const alreadyClaimed = invite?.status === "claimed" useEffect(() => { if (!token || !alreadyClaimed) return router.replace(`/onboard/migration?token=${encodeURIComponent(token)}`) }, [token, alreadyClaimed, router]) if (!token) { return (

Lien d'invitation invalide

Ce lien ne contient pas de jeton de migration.

) } if (!authenticated) { return (

Revendiquer votre compte

Connectez-vous avec le même compte que l'adresse invitée ( {inviteQuery.data?.invite.email ?? "…"}) pour provisionner votre boîte Ultimail.

) } if (alreadyClaimed) { return (

Redirection vers le suivi de migration…

) } const steps = [ { label: "Connexion", done: true, current: false }, { label: "Revendiquer la boîte mail", done: false, current: true }, { label: appOnlyAuthStepLabel(project), done: false, current: false, }, ] return (

Revendiquer votre compte

Projet {project?.name ?? ""} — {invite?.email}

Connectez-vous avec le compte correspondant à l'invitation ({invite?.email}). Les alias SSO reconnus (UPN, adresse alternative) sont acceptés si configurés par l'administrateur.

setPassword(e.target.value)} placeholder="Pour IMAP/SMTP hébergé" />
{claimMutation.isError && (

{claimErrorMessage(claimMutation.error)}

)}
) }