import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { api } from '@/api/client'; import { humanMessage, useAuth } from '@/auth/AuthProvider'; const MIN_PASSWORD_LENGTH = 12; /** * Acceptation d'une invitation — la première page qu'un traducteur voit. * * Elle annonce à quoi il est invité AVANT de lui demander quoi que ce soit : * quel projet, quel rôle, quelles langues. Demander un mot de passe sans dire * pour quoi est la façon la plus sûre de faire abandonner quelqu'un, ou pire, de * lui faire croire à une tentative d'hameçonnage. */ export function InvitationPage() { const { token = '' } = useParams(); const navigate = useNavigate(); const { login } = useAuth(); const [name, setName] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const [pending, setPending] = useState(false); const invitation = useQuery({ queryKey: ['invitation', token], queryFn: () => api.invitationPreview(token), retry: false, }); async function submit(event: React.FormEvent) { event.preventDefault(); setError(null); setPending(true); try { await api.acceptInvitation(token, { name, password }); // Connexion immédiate : demander de ressaisir des identifiants qu'on // vient de définir est une étape gratuite, juste après l'effort. await login(invitation.data?.email ?? '', password); navigate('/projects', { replace: true }); } catch (caught) { setError(humanMessage(caught)); } finally { setPending(false); } } if (invitation.isLoading) { return Vérification de l'invitation…; } if (invitation.isError) { return (

Invitation non valable

{humanMessage(invitation.error)}

Aller à la page de connexion
); } const data = invitation.data; const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH; return (

Rejoindre {data?.project}

Invitation pour {data?.email}

{/* Ce que l'invitation donne, énoncé avant toute saisie. */}
Rôle
{data?.role}
Langues
{data?.locales.length === 0 ? 'toutes les langues du projet' : data?.locales.join(', ')}
{data?.isExternal && (

Vous rejoignez ce projet comme prestataire externe. Votre accès est limité aux langues ci-dessus et vos connexions sont journalisées.

)} {error !== null && (

{error}

)}

Ce lien ne fonctionne qu'une fois. Si vous n'attendiez pas cette invitation, fermez simplement cette page : aucun compte ne sera créé.

); } function Centered({ children }: { children: React.ReactNode }) { return
{children}
; }