Files
crowdlending-app/frontend/src/pages/Register.jsx
T

232 lines
8.2 KiB
React

import { useState, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext.jsx';
import PasswordStrength from '../components/PasswordStrength.jsx';
import AuthBgCol from '../components/AuthBgCol.jsx';
import PasswordInput from '../components/PasswordInput.jsx';
export default function Register() {
const { register } = useAuth();
const navigate = useNavigate();
const [form, setForm] = useState({ email: '', password: '', displayName: '' });
const [err, setErr] = useState(null);
const [busy, setBusy] = useState(false);
const [appInfo, setAppInfo] = useState({ appName: 'Crowdlending Tracker', iconUrl: null, minPasswordLength: 8 });
useEffect(() => {
fetch('/api/app-info')
.then(r => r.json())
.then(d => setAppInfo(d))
.catch(() => {});
}, []);
const set = (k) => (e) => setForm({ ...form, [k]: e.target.value });
const [verifyEmail, setVerifyEmail] = useState(null); // email à vérifier
const submit = async (e) => {
e.preventDefault();
setErr(null); setBusy(true);
try {
const result = await register(form.email, form.password, form.displayName || undefined);
if (result?.requiresVerification) {
setVerifyEmail(result.email);
} else {
navigate('/');
}
} catch (e) { setErr(e.message); }
finally { setBusy(false); }
};
return (
<div style={{ display: 'flex', minHeight: '100dvh' }}>
<AuthBgCol appInfo={appInfo} />
{/* ── Colonne droite — formulaire ──────────────────────── */}
<div style={{
flex: '1 1 50%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '48px 24px',
background: 'var(--background, #fff)',
minWidth: 0,
}}>
{/* Logo + nom */}
<div style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 10,
marginBottom: 32,
}}>
{appInfo.iconUrl && (
<img src={appInfo.iconUrl} alt={appInfo.appName}
width={52} height={52} style={{ borderRadius: 12 }} />
)}
<span style={{
fontSize: 20, fontWeight: 700,
color: 'var(--text)', letterSpacing: '-0.4px',
}}>
{appInfo.appName}
</span>
</div>
<div style={{ width: '100%', maxWidth: 360 }}>
{/* ── Écran vérification email ── */}
{verifyEmail ? (
<div style={{ textAlign: 'center' }}>
<div style={{
width: 56, height: 56, borderRadius: '50%',
background: 'var(--primary-bg, #eff6ff)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
margin: '0 auto 20px',
}}>
<svg width="26" height="26" viewBox="0 0 24 24" fill="none">
<path d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
stroke="var(--primary, #1e40af)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
<h1 style={{ margin: '0 0 10px', fontSize: 22, fontWeight: 700, color: 'var(--text)' }}>
Vérifiez votre email
</h1>
<p style={{ margin: '0 0 6px', color: 'var(--text-muted)', fontSize: 14, lineHeight: 1.6 }}>
Un email de vérification a été envoyé à
</p>
<p style={{ margin: '0 0 24px', fontWeight: 600, color: 'var(--text)', fontSize: 14 }}>
{verifyEmail}
</p>
<p style={{ margin: '0 0 28px', color: 'var(--text-muted)', fontSize: 13, lineHeight: 1.6 }}>
Cliquez sur le lien dans l'email pour activer votre compte. Vérifiez aussi vos spams.
</p>
<Link to="/login" style={{
display: 'block', width: '100%', padding: '11px 0',
background: 'var(--primary, #1e40af)', color: '#fff',
borderRadius: 8, fontSize: 15, fontWeight: 600,
textDecoration: 'none', textAlign: 'center',
}}>
Retour à la connexion
</Link>
</div>
) : (
<>
{/* En-tête */}
<div style={{ marginBottom: 28 }}>
<h1 style={{
margin: '0 0 6px',
fontSize: 26, fontWeight: 700,
letterSpacing: '-0.5px',
color: 'var(--text)',
}}>
Créer un compte
</h1>
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: 14 }}>
Rejoignez {appInfo.appName}
</p>
</div>
{/* Formulaire */}
<form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
{err && (
<div style={{
padding: '10px 14px', borderRadius: 8, fontSize: 14,
background: 'var(--danger-bg, #fef2f2)',
color: 'var(--danger, #dc2626)',
border: '1px solid var(--danger-light, #fca5a5)',
}}>
{err}
</div>
)}
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<label style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>
Nom d'affichage
</label>
<input
className="form-input"
type="text"
autoComplete="name"
placeholder="Olivier"
value={form.displayName}
onChange={set('displayName')}
style={{ width: '100%' }}
/>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<label style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>
Adresse email
</label>
<input
className="form-input"
type="email" required
autoComplete="email"
placeholder="vous@exemple.com"
value={form.email}
onChange={set('email')}
style={{ width: '100%' }}
/>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<label style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>
Mot de passe
</label>
<PasswordInput
className="form-input"
required
minLength={appInfo.minPasswordLength || 8}
autoComplete="new-password"
placeholder="••••••••"
value={form.password}
onChange={set('password')}
style={{ width: '100%' }}
/>
<PasswordStrength password={form.password} minLength={appInfo.minPasswordLength || 8} />
</div>
<button
type="submit"
disabled={busy}
style={{
marginTop: 4, width: '100%',
padding: '11px 0',
background: busy ? 'var(--text-muted)' : 'var(--primary, #1e40af)',
color: '#fff',
border: 'none', borderRadius: 8,
fontSize: 15, fontWeight: 600,
cursor: busy ? 'not-allowed' : 'pointer',
transition: 'background 0.15s',
}}
>
{busy ? 'Création…' : 'Créer le compte'}
</button>
</form>
<p style={{
marginTop: 24, textAlign: 'center',
fontSize: 13, color: 'var(--text-muted)',
}}>
Déjà inscrit ?{' '}
<Link to="/login" style={{
color: 'var(--text)', fontWeight: 500, textDecoration: 'underline',
}}>
Se connecter
</Link>
</p>
</>)} {/* fin verifyEmail ternaire */}
</div>
</div>
</div>
);
}