/* Console partenaire — accès (design dev-auth.jsx) : connexion (mot de passe puis code ou code de secours),
   activation de la double authentification (QR réel + codes de secours), inscription en 3 étapes, email à
   confirmer, lien de vérification, mot de passe oublié, réinitialisation, invitation d'équipe. */
const CONSOLE_API = 'https://api.jokkkotechgroup.com/api:lms-console';
const API_V1_BASE = 'https://api.jokkkotechgroup.com/api:v1';
const {api, lireJeton, ecrireJeton} = creerApi(CONSOLE_API, 'lms_jeton');
const ROLES_M = {proprietaire:'Propriétaire', developpeur:'Développeur', finance:'Finance', lecteur:'Lecteur'};

// Liens reçus par email : /verifier-email?jeton=…, /reinitialiser?jeton=…, /invitation?jeton=… (ou #/verifier-email?jeton=…)
const ROUTES_ACCES = ['verifier-email', 'reinitialiser', 'invitation', 'connexion', 'inscription', 'oubli'];
function lireAcces(){
  const seg = location.pathname.replace(/\/+$/, '').split('/').pop();
  const h = location.hash.replace(/^#\/?/, ''); const [hp, hq] = h.split('?');
  const jeton = new URLSearchParams(location.search).get('jeton') || new URLSearchParams(hq || '').get('jeton');
  const page = ROUTES_ACCES.includes(seg) ? seg : ROUTES_ACCES.includes(hp) ? hp : null;
  return {page:page || (jeton ? 'reinitialiser' : 'connexion'), jeton};
}
function nettoyerUrl(){ const p = location.pathname.replace(/\/+$/, '').split('/'); if(ROUTES_ACCES.includes(p[p.length-1])) p.pop(); history.replaceState(null, '', (p.join('/') || '') + '/'); }

function ReglesMdp({pw}){
  const regles = [['8 caractères minimum', pw.length>=8],['Une majuscule', /[A-Z]/.test(pw)],['Un chiffre', /\d/.test(pw)],['Un caractère spécial', /[^A-Za-z0-9]/.test(pw)]];
  return {ok:regles.every(r=>r[1]), vue:<div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:8}}>{regles.map(r=><span key={r[0]} style={{display:'flex', alignItems:'center', gap:6, fontSize:12.5, fontWeight:600, color:r[1]?V.accD:V.ink3}}><I n={r[1]?'check-circle':'circle'} s={15} fill={r[1]}/>{r[0]}</span>)}</div>};
}
function ChampMdp({value, onChange, placeholder='••••••••', autoComplete='new-password'}){ const [voir, setVoir] = React.useState(false);
  return <div style={{position:'relative'}}><Inp type={voir?'text':'password'} value={value} onChange={onChange} placeholder={placeholder} lead={<I n="lock-simple" s={18}/>} autoComplete={autoComplete}/>
    <button type="button" aria-label={voir?'Masquer le mot de passe':'Afficher le mot de passe'} onClick={()=>setVoir(!voir)} style={{position:'absolute', right:10, top:10, border:0, background:'none', cursor:'pointer', color:V.ink3, padding:4}}><I n={voir?'eye-slash':'eye'} s={18}/></button></div>; }

function Connexion({onConnecte, go}){
  const [email, setEmail] = React.useState(''), [mdp, setMdp] = React.useState('');
  const [etape, setEtape] = React.useState(null), [code, setCode] = React.useState(''), [secours, setSecours] = React.useState(false), [cs, setCs] = React.useState('');
  const [err, setErr] = React.useState(null), [load, setLoad] = React.useState(false), [renvoye, setRenvoye] = React.useState(false);
  const [ini, setIni] = React.useState(null), [scanne, setScanne] = React.useState(false), [codes, setCodes] = React.useState(null), [garde, setGarde] = React.useState(false), [jetonFinal, setJetonFinal] = React.useState(null);
  const envoyer = async (e) => { e && e.preventDefault(); setErr(null); setLoad(true);
    try { const r = await api('POST', 'auth/connexion', {email, mot_de_passe:mdp}); setEtape(r); setCode('');
      if(r.etape === 'activation_2fa') setIni(await api('POST', 'auth/2fa/initier', {jeton:r.jeton}));
    } catch(x){ setErr(x); } setLoad(false); };
  const verifier = async () => { setErr(null); setLoad(true);
    try { const r = await api('POST', 'auth/2fa/verifier', secours ? {jeton:etape.jeton, code_secours:cs} : {jeton:etape.jeton, code}); ecrireJeton(r.jeton); onConnecte(); }
    catch(x){ setErr(x); setCode(''); } setLoad(false); };
  const activer = async () => { setErr(null); setLoad(true);
    try { const r = await api('POST', 'auth/2fa/activer', {jeton:etape.jeton, code}); setCodes(r.codes_secours || []); setJetonFinal(r.jeton); }
    catch(x){ setErr(x); setCode(''); } setLoad(false); };
  const telecharger = () => { const a = document.createElement('a'); a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(`Codes de secours LeMultiservice Developers\n${email}\n\n${codes.join('\n')}\n`); a.download = 'codes-secours-lemultiservice.txt'; a.click(); };

  if(codes) return <AuthFrame w={440}>
    <Progress steps={['Scanner','Vérifier','Codes de secours']} i={2}/>
    <H s={26}>Gardez vos codes de secours</H><Muted>Chaque code s'utilise une seule fois si vous perdez votre téléphone. Ils ne seront plus affichés.</Muted>
    <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:8, padding:16, borderRadius:18, background:V.sub, border:`1px solid ${V.line}`}}>{codes.map(c=><Mono key={c} s={14} c={V.ink}>{c}</Mono>)}</div>
    <div style={{display:'flex', gap:8}}><CopyBtn text={codes.join('\n')} sm={false}/><Btn kind="secondary" icon="download-simple" onClick={telecharger}>Télécharger</Btn></div>
    <Check on={garde} set={setGarde}>J'ai enregistré mes codes de secours en lieu sûr.</Check>
    <Btn full disabled={!garde} onClick={()=>{ ecrireJeton(jetonFinal); onConnecte(); }}>Accéder à mon espace</Btn>
  </AuthFrame>;

  if(etape?.etape === 'activation_2fa') return <AuthFrame w={440}>
    <Progress steps={['Scanner','Vérifier','Codes de secours']} i={scanne ? 1 : 0}/>
    {!scanne ? <><H s={26}>Activez la double authentification</H><Muted>Obligatoire pour tous les membres. Scannez ce QR code avec Google Authenticator, Microsoft Authenticator ou 1Password.</Muted>
      {ini ? <div style={{display:'flex', gap:18, alignItems:'center', flexWrap:'wrap'}}><QR texte={ini.otpauth_uri} s={144}/>
        <div style={{minWidth:0}}><Lbl>Ou saisissez la clé</Lbl><div style={{marginTop:8, display:'flex', alignItems:'center', gap:8, flexWrap:'wrap'}}><Mono s={13} c={V.ink}>{ini.secret.replace(/(.{4})/g,'$1 ').trim()}</Mono><CopyBtn text={ini.secret}/></div></div></div> : <Skel h={170} r={18}/>}
      {err && <Notice tone="bad">{err.message}</Notice>}
      <Btn full disabled={!ini} onClick={()=>setScanne(true)}>J'ai scanné le code</Btn>
      <Link2 onClick={()=>{setEtape(null); setIni(null);}}>← Retour</Link2></>
    : <><H s={26}>Saisissez le code</H><Muted>Entrez le code à 6 chiffres affiché dans l'application.</Muted>
      <OTP value={code} set={v=>{setCode(v); setErr(null);}} err={!!err}/>
      {err && <Notice tone="bad" title="Code incorrect">{err.message}</Notice>}
      <Btn full disabled={code.length<6||load} onClick={activer}>{load?'Vérification…':'Vérifier'}</Btn>
      <Link2 onClick={()=>{setScanne(false); setCode(''); setErr(null);}}>← Revoir le QR code</Link2></>}
  </AuthFrame>;

  if(etape?.etape === 'code_2fa') return <AuthFrame>
    <Tile icon="device-mobile" s={52}/><H s={26}>Vérification en deux étapes</H>
    {secours ? <><Muted>Saisissez un de vos codes de secours (format XXXX-XXXX). Il ne servira qu'une fois.</Muted><Field label="Code de secours"><Inp value={cs} onChange={e=>{setCs(e.target.value.toUpperCase()); setErr(null);}} placeholder="XXXX-XXXX" mono autoFocus/></Field></>
      : <><Muted>Saisissez le code à 6 chiffres affiché dans votre application d'authentification.</Muted><OTP value={code} set={v=>{setCode(v); setErr(null);}} err={!!err}/></>}
    {err && <Notice tone="bad" title="Code incorrect">{err.message} Vérifiez l'heure de votre téléphone. Après 5 essais, le compte est bloqué 15 minutes.</Notice>}
    <Btn full disabled={(secours ? cs.length<9 : code.length<6)||load} onClick={verifier}>{load?'Vérification…':'Vérifier'}</Btn>
    <div style={{display:'flex', justifyContent:'space-between', gap:10, flexWrap:'wrap'}}><Link2 onClick={()=>{setEtape(null); setCode(''); setErr(null);}}>← Retour</Link2><Link2 onClick={()=>{setSecours(!secours); setErr(null);}}>{secours?'Utiliser l\'application':'Utiliser un code de secours'}</Link2></div>
  </AuthFrame>;

  return <AuthFrame>
    <form onSubmit={envoyer} style={{display:'flex', flexDirection:'column', gap:18}}>
      <H s={28}>Connexion</H><Muted>Accédez à votre espace partenaire.</Muted>
      <Field label="Email professionnel"><Inp type="email" value={email} onChange={e=>setEmail(e.target.value)} lead={<I n="envelope-simple" s={18}/>} autoComplete="username" placeholder="prenom.nom@entreprise.sn"/></Field>
      <Field label="Mot de passe"><ChampMdp value={mdp} onChange={e=>setMdp(e.target.value)} autoComplete="current-password" placeholder=""/></Field>
      <div style={{display:'flex', justifyContent:'flex-end', marginTop:-8}}><Link2 onClick={()=>go('oubli')}>Mot de passe oublié ?</Link2></div>
      {err && (err.code === 'email_non_verifie'
        ? <Notice tone="warn" title="Email à confirmer" action={!renvoye && <Btn kind="secondary" sm onClick={async()=>{ try { await api('POST', 'auth/email/renvoyer', {email}); } catch(e){} setRenvoye(true); }}>Renvoyer</Btn>}>{renvoye ? 'Si un compte attend une confirmation pour cette adresse, un nouveau lien vient d\'être envoyé.' : err.message}</Notice>
        : <Notice tone="bad">{err.message}</Notice>)}
      <Btn full type="submit" disabled={!email||!mdp||load}>{load?'Connexion…':'Se connecter'}</Btn>
      <span style={{textAlign:'center', fontSize:13.5, color:V.ink3, fontWeight:500}}>Pas encore partenaire ? <Link2 onClick={()=>go('inscription')}>Demander un accès</Link2></span>
      <div style={{display:'flex', justifyContent:'center', gap:16, paddingTop:14, borderTop:`1px solid ${V.line}`}}><Link2 onClick={()=>go('docs')}>Lire la documentation</Link2></div>
    </form>
  </AuthFrame>;
}

const PAYS = ['Sénégal','Côte d\'Ivoire','Mali','Burkina Faso','Guinée'];
const SECTEURS = [['banque','Banque'],['fintech','Fintech'],['agregateur','Agrégateur'],['assurance','Assurance'],['telecom','Télécom'],['autre','Autre']];
function Inscription({go}){
  const [s, setS] = React.useState(0), [f, setF] = React.useState({raison_sociale:'', pays:'Sénégal', secteur:'banque', prenom:'', nom:'', email:'', telephone:'+221 ', mot_de_passe:''});
  const [cgu, setCgu] = React.useState(false), [err, setErr] = React.useState(null), [load, setLoad] = React.useState(false), [fait, setFait] = React.useState(null), [renvoye, setRenvoye] = React.useState(false);
  const maj = k => e => setF({...f, [k]:e.target ? e.target.value : e});
  const r = ReglesMdp({pw:f.mot_de_passe});
  const pret = [f.raison_sociale.trim().length>1, f.prenom.trim() && f.nom.trim() && /@/.test(f.email) && f.telephone.replace(/\D/g,'').length>=8, r.ok && cgu];
  const envoyer = async () => { setErr(null); setLoad(true);
    try { setFait(await api('POST', 'auth/inscription', {...f, cgu:true})); }
    catch(x){ setErr(x); if(['donnees_incompletes','pays_invalide','secteur_invalide'].includes(x.code)) setS(0); else if(/email|telephone/.test(x.code||'')) setS(1); }
    setLoad(false); };
  if(fait) return <AuthFrame>
    <Tile icon="envelope-simple-open" s={56}/><H s={26}>Vérifiez votre email</H>
    <Muted>Nous avons envoyé un lien de confirmation à <b style={{color:V.ink}}>{fait.email}</b>. Il est valable 24 heures.</Muted>
    <Notice tone="info" icon="flask">Dès la confirmation, votre sandbox est prête : vous pourrez créer une clé de test et faire votre premier appel.</Notice>
    <Btn full onClick={()=>go('connexion')}>J'ai confirmé mon email</Btn>
    <span style={{textAlign:'center', fontSize:13.5, color:V.ink3}}>{renvoye ? 'Un nouveau lien vient d\'être envoyé.' : <>Rien reçu ? <Link2 onClick={async()=>{ try { await api('POST', 'auth/email/renvoyer', {email:fait.email}); } catch(e){} setRenvoye(true); }}>Renvoyer l'email</Link2></>}</span>
  </AuthFrame>;
  return <AuthFrame w={440}>
    <span style={{display:'flex', justifyContent:'space-between', alignItems:'center', gap:10, flexWrap:'wrap'}}><Lbl>Étape {s+1} sur 3</Lbl><Link2 onClick={()=>go('connexion')}>Déjà inscrit ? Se connecter</Link2></span>
    <Progress steps={['Entreprise','Responsable','Mot de passe']} i={s}/>
    <H s={26}>{['Votre entreprise','Le responsable du compte','Choisissez un mot de passe'][s]}</H>
    {s===0 && <><Field label="Raison sociale"><Inp value={f.raison_sociale} onChange={maj('raison_sociale')} autoFocus/></Field>
      <Grid cols="1fr 1fr" mcols="1fr 1fr"><Field label="Pays"><Sel opts={PAYS} value={f.pays} onChange={maj('pays')} label="Pays"/></Field><Field label="Secteur"><Sel opts={SECTEURS} value={f.secteur} onChange={maj('secteur')} label="Secteur"/></Field></Grid></>}
    {s===1 && <><Grid cols="1fr 1fr" mcols="1fr 1fr"><Field label="Prénom"><Inp value={f.prenom} onChange={maj('prenom')} autoComplete="given-name"/></Field><Field label="Nom"><Inp value={f.nom} onChange={maj('nom')} autoComplete="family-name"/></Field></Grid>
      <Field label="Email professionnel" hint="Les adresses Gmail, Yahoo ou Outlook ne sont pas acceptées."><Inp type="email" value={f.email} onChange={maj('email')} autoComplete="email" placeholder="prenom.nom@entreprise.sn"/></Field>
      <Field label="Téléphone"><Inp value={f.telephone} onChange={maj('telephone')} autoComplete="tel" lead={<I n="phone" s={17}/>}/></Field></>}
    {s===2 && <><Field label="Mot de passe"><ChampMdp value={f.mot_de_passe} onChange={maj('mot_de_passe')}/></Field>{r.vue}
      <Check on={cgu} set={setCgu}>J'accepte les conditions d'utilisation et la politique de confidentialité de LeMultiservice.</Check></>}
    {err && <Notice tone="bad">{err.message}</Notice>}
    <div style={{display:'flex', gap:8}}>{s>0 && <Btn kind="secondary" onClick={()=>{setS(s-1); setErr(null);}}>Retour</Btn>}<Btn full disabled={!pret[s] || load} onClick={()=>{ if(s<2){ setS(s+1); setErr(null); } else envoyer(); }}>{s===2?(load?'Création…':'Créer mon compte'):'Continuer'}</Btn></div>
  </AuthFrame>;
}

function VerifierEmail({jeton, go}){
  const [etat, setEtat] = React.useState({load:true}), [email, setEmail] = React.useState(''), [renvoye, setRenvoye] = React.useState(false);
  React.useEffect(()=>{ api('POST', 'auth/email/verifier', {jeton}).then(r=>setEtat({ok:r}), e=>setEtat({err:e})); }, []);
  if(etat.load) return <AuthFrame><span className="kspin" style={{width:40, height:40, borderRadius:99, border:`4px solid ${V.mint}`, borderTopColor:V.acc}}></span><H s={24}>Confirmation de votre email…</H></AuthFrame>;
  if(etat.ok) return <AuthFrame><Tile icon="check-circle" s={56} fill/><H s={26}>Email confirmé</H><Muted>L'adresse <b style={{color:V.ink}}>{etat.ok.email}</b> est vérifiée. Connectez-vous : la double authentification sera activée à la première connexion, puis votre sandbox est prête.</Muted>
    <Btn full onClick={()=>{ nettoyerUrl(); go('connexion'); }}>Se connecter</Btn></AuthFrame>;
  return <AuthFrame><Tile icon="link-break" s={52} c={V.bad} bg={V.badBg}/><H s={26}>Lien invalide ou expiré</H><Notice tone="bad">{etat.err.message}</Notice>
    {renvoye ? <Notice tone="ok">Si un compte attend une confirmation pour cette adresse, un nouveau lien vient d'être envoyé.</Notice>
    : <><Field label="Email professionnel"><Inp type="email" value={email} onChange={e=>setEmail(e.target.value)} lead={<I n="envelope-simple" s={18}/>}/></Field>
      <Btn full disabled={!/@/.test(email)} onClick={async()=>{ try { await api('POST', 'auth/email/renvoyer', {email}); } catch(e){} setRenvoye(true); }}>Recevoir un nouveau lien</Btn></>}
    <Link2 onClick={()=>{ nettoyerUrl(); go('connexion'); }}>← Retour à la connexion</Link2></AuthFrame>;
}

function Oubli({go}){ const [email, setEmail] = React.useState(''), [envoye, setEnvoye] = React.useState(false), [load, setLoad] = React.useState(false);
  return <AuthFrame>
    <Tile icon={envoye?'envelope-simple-open':'key'} s={52}/><H s={26}>{envoye?'Email envoyé':'Mot de passe oublié'}</H>
    {envoye ? <Muted>Si un compte existe pour cette adresse, vous recevrez un lien de réinitialisation valable 1 heure.</Muted>
    : <form onSubmit={async e=>{ e.preventDefault(); setLoad(true); try { await api('POST', 'auth/mdp/oublie', {email}); } catch(x){} setEnvoye(true); setLoad(false); }} style={{display:'flex', flexDirection:'column', gap:18}}>
      <Muted>Indiquez votre email professionnel. Nous vous enverrons un lien pour choisir un nouveau mot de passe.</Muted>
      <Field label="Email professionnel"><Inp type="email" value={email} onChange={e=>setEmail(e.target.value)} placeholder="prenom.nom@entreprise.sn" lead={<I n="envelope-simple" s={18}/>} autoFocus/></Field>
      <Btn full type="submit" disabled={!/@/.test(email)||load}>{load?'Envoi…':'Envoyer le lien'}</Btn></form>}
    <Link2 onClick={()=>go('connexion')}>← Retour à la connexion</Link2></AuthFrame>; }

function Reinitialiser({jeton, go}){
  const [pw, setPw] = React.useState(''), [pw2, setPw2] = React.useState(''), [err, setErr] = React.useState(null), [fait, setFait] = React.useState(false), [load, setLoad] = React.useState(false);
  const r = ReglesMdp({pw});
  if(!jeton) return <AuthFrame><Tile icon="link-break" s={52} c={V.bad} bg={V.badBg}/><H s={26}>Lien incomplet</H><Muted>Ouvrez le lien reçu par email, ou demandez-en un nouveau.</Muted><Btn full onClick={()=>go('oubli')}>Demander un lien</Btn></AuthFrame>;
  if(fait) return <AuthFrame><Tile icon="check-circle" s={56} fill/><H s={26}>Mot de passe modifié</H><Muted>Toutes vos autres sessions ont été déconnectées.</Muted><Btn full onClick={()=>{ nettoyerUrl(); go('connexion'); }}>Se connecter</Btn></AuthFrame>;
  return <AuthFrame>
    <H s={26}>Nouveau mot de passe</H>
    <Field label="Nouveau mot de passe"><ChampMdp value={pw} onChange={e=>setPw(e.target.value)}/></Field>{r.vue}
    <Field label="Confirmer le mot de passe" err={pw2 && pw2!==pw ? 'Les deux mots de passe diffèrent.' : null}><Inp type="password" value={pw2} onChange={e=>setPw2(e.target.value)} placeholder="••••••••" lead={<I n="lock-simple" s={18}/>} autoComplete="new-password"/></Field>
    {err && <Notice tone="bad">{err.message}</Notice>}
    <Btn full disabled={!r.ok || pw!==pw2 || load} onClick={async()=>{ setLoad(true); setErr(null); try { await api('POST', 'auth/mdp/reinitialiser', {jeton, mot_de_passe:pw}); setFait(true); } catch(e){ setErr(e); } setLoad(false); }}>{load?'Enregistrement…':'Enregistrer'}</Btn>
    <Link2 onClick={()=>{ nettoyerUrl(); go('connexion'); }}>← Retour à la connexion</Link2>
  </AuthFrame>;
}

function InvitationAcces({jeton, go}){
  const [inv, , etat] = useDonnees(() => api('GET', `auth/invitation/${encodeURIComponent(jeton||'')}`), []);
  const [f, setF] = React.useState({prenom:'', nom:'', telephone:''}), [pw, setPw] = React.useState(''), [pw2, setPw2] = React.useState(''), [err, setErr] = React.useState(null), [fait, setFait] = React.useState(false), [load, setLoad] = React.useState(false);
  const r = ReglesMdp({pw});
  if(fait) return <AuthFrame><Tile icon="check-circle" s={56} fill/><H s={26}>Bienvenue dans l'équipe</H><Muted>Votre accès est prêt. Connectez-vous : la double authentification sera activée à la première connexion.</Muted><Btn full onClick={()=>{ nettoyerUrl(); go('connexion'); }}>Se connecter</Btn></AuthFrame>;
  if(etat.chargement) return <AuthFrame><Skel h={70} r={18}/><Skel h={30} w="60%"/><Skel h={46} r={16}/><Skel h={46} r={16}/></AuthFrame>;
  if(etat.erreur) return <AuthFrame><Tile icon="link-break" s={52} c={V.bad} bg={V.badBg}/><H s={26}>Invitation invalide</H><Notice tone="bad">{etat.erreur.message}</Notice><Muted>Demandez au propriétaire du compte de vous renvoyer l'invitation.</Muted><Link2 onClick={()=>{ nettoyerUrl(); go('connexion'); }}>← Retour à la connexion</Link2></AuthFrame>;
  return <AuthFrame>
    <Card pad={16} style={{display:'flex', alignItems:'center', gap:12, background:V.sub}}><Av n={inv.invite_par || inv.entreprise || '?'} s={40}/><span style={{minWidth:0}}><span style={{display:'block', fontWeight:700, fontSize:13.5, color:V.ink}}>{inv.invite_par ? `${inv.invite_par} vous invite` : 'Vous êtes invité'}</span><span style={{display:'block', fontSize:12.5, color:V.ink3}}>à rejoindre {inv.entreprise} · rôle <b>{ROLES_M[inv.role] || inv.role}</b></span></span></Card>
    <H s={26}>Définissez votre mot de passe</H>
    <Field label="Email"><Inp value={inv.email} disabled style={{background:V.sub, color:V.ink3}}/></Field>
    <Grid cols="1fr 1fr" mcols="1fr 1fr"><Field label="Prénom"><Inp value={f.prenom} onChange={e=>setF({...f, prenom:e.target.value})} autoComplete="given-name"/></Field><Field label="Nom"><Inp value={f.nom} onChange={e=>setF({...f, nom:e.target.value})} autoComplete="family-name"/></Field></Grid>
    <Field label="Téléphone" opt><Inp value={f.telephone} onChange={e=>setF({...f, telephone:e.target.value})} placeholder="+221 …" autoComplete="tel"/></Field>
    <Field label="Nouveau mot de passe"><ChampMdp value={pw} onChange={e=>setPw(e.target.value)}/></Field>{r.vue}
    <Field label="Confirmer le mot de passe" err={pw2 && pw2!==pw ? 'Les deux mots de passe diffèrent.' : null}><Inp type="password" value={pw2} onChange={e=>setPw2(e.target.value)} placeholder="••••••••" lead={<I n="lock-simple" s={18}/>}/></Field>
    {err && <Notice tone="bad">{err.message}</Notice>}
    <Btn full disabled={!f.prenom.trim() || !f.nom.trim() || !r.ok || pw!==pw2 || load} onClick={async()=>{ setLoad(true); setErr(null); try { await api('POST', 'auth/invitation/accepter', {jeton, prenom:f.prenom, nom:f.nom, telephone:f.telephone, mot_de_passe:pw}); setFait(true); } catch(e){ setErr(e); } setLoad(false); }}>{load?'Enregistrement…':'Rejoindre l\'équipe'}</Btn>
  </AuthFrame>;
}

Object.assign(window, {CONSOLE_API, API_V1_BASE, api, lireJeton, ecrireJeton, ROLES_M, lireAcces, nettoyerUrl, Connexion, Inscription, VerifierEmail, Oubli, Reinitialiser, InvitationAcces});
