implemented improved account verification flow with recovery and resend

This commit is contained in:
nvrl committed 2026-02-19 15:26:21 +01:00
1 parent 0c00552905
commit 83f46e6619
3 files changed
+99 -13

No files matched your search

+28
View File
@@ -118,6 +118,20 @@ const resources = {
"save": "Save",
"cancel": "Cancel"
},
"auth": {
"loginTitle": "Login",
"signupTitle": "Signup",
"verifyTitle": "Verify Account",
"verifyDesc": "Enter the code sent to your email for <strong>{{username}}</strong>.",
"resendButton": "Resend Verification Code",
"resendSuccess": "A new verification code has been sent to your email.",
"verifySuccess": "Account verified! You can now login.",
"unverifiedError": "Account not verified. Please verify your account to login.",
"loginFailed": "Login failed. Please check your credentials.",
"signupSuccess": "Signup successful! Please enter the verification code sent to your email.",
"forgotPassword": "Forgot Password?",
"backToAuth": "Back to Signup/Login"
},
"community": {
"title": "Community Activity",
"subtitle": "Stay updated with your circle's latest ratings and discussions.",
@@ -344,6 +358,20 @@ const resources = {
"save": "Speichern",
"cancel": "Abbrechen"
},
"auth": {
"loginTitle": "Anmelden",
"signupTitle": "Registrieren",
"verifyTitle": "Konto verifizieren",
"verifyDesc": "Gib den Code ein, der an deine E-Mail für <strong>{{username}}</strong> gesendet wurde.",
"resendButton": "Verifizierungscode erneut senden",
"resendSuccess": "Ein neuer Verifizierungscode wurde an deine E-Mail gesendet.",
"verifySuccess": "Konto verifiziert! Du kannst dich jetzt anmelden.",
"unverifiedError": "Konto nicht verifiziert. Bitte verifiziere dein Konto, um dich anzumelden.",
"loginFailed": "Anmeldung fehlgeschlagen. Bitte überprüfe deine Zugangsdaten.",
"signupSuccess": "Registrierung erfolgreich! Bitte gib den Verifizierungscode ein, der an deine E-Mail gesendet wurde.",
"forgotPassword": "Passwort vergessen?",
"backToAuth": "Zurück zur Anmeldung"
},
"community": {
"title": "Community-Aktivität",
"subtitle": "Bleib auf dem Laufenden mit den neuesten Bewertungen und Diskussionen deines Kreises.",
+37 -12
View File
@@ -16,6 +16,7 @@ const Login: React.FC<LoginProps> = () => {
const [email, setEmail] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [isVerifying, setIsVerifying] = useState(false);
const [showResend, setShowResend] = useState(false);
const [isResetting, setIsResetting] = useState(false);
const [resetStep, setResetStep] = useState(1); // 1: email, 2: code/new pass
const [message, setMessage] = useState<{type: 'success' | 'error', text: string} | null>(null);
@@ -31,7 +32,13 @@ const Login: React.FC<LoginProps> = () => {
localStorage.setItem('token', res.data.token);
window.location.href = '/';
} catch (err: any) {
setMessage({ type: 'error', text: 'Login failed. Please check your credentials or verify your account.' });
const errorMsg = err.response?.data?.non_field_errors?.[0] || t('auth.loginFailed');
if (errorMsg.toLowerCase().includes('inactive') || errorMsg.toLowerCase().includes('verify') || errorMsg.includes('disabled')) {
setMessage({ type: 'error', text: t('auth.unverifiedError') });
setIsVerifying(true);
} else {
setMessage({ type: 'error', text: errorMsg });
}
}
};
@@ -41,7 +48,7 @@ const Login: React.FC<LoginProps> = () => {
try {
await api.post('users/signup/', { username, email, password });
setIsVerifying(true);
setMessage({ type: 'success', text: 'Signup successful! Please enter the verification code sent to your email.' });
setMessage({ type: 'success', text: t('auth.signupSuccess') });
} catch (err: any) {
setMessage({ type: 'error', text: err.response?.data?.error || 'Signup failed' });
}
@@ -52,12 +59,24 @@ const Login: React.FC<LoginProps> = () => {
setMessage(null);
try {
await api.post('users/verify_signup/', { username, code: verificationCode });
setMessage({ type: 'success', text: 'Account verified! You can now login.' });
setMessage({ type: 'success', text: t('auth.verifySuccess') });
setIsVerifying(false);
setTab(0);
setPassword('');
} catch (err: any) {
setMessage({ type: 'error', text: err.response?.data?.error || 'Verification failed' });
setShowResend(true);
}
};
const handleResendCode = async () => {
setMessage(null);
try {
await api.post('users/resend_verification/', { username });
setMessage({ type: 'success', text: t('auth.resendSuccess') });
setShowResend(false);
} catch (err: any) {
setMessage({ type: 'error', text: err.response?.data?.error || 'Failed to resend code' });
}
};
@@ -93,20 +112,26 @@ const Login: React.FC<LoginProps> = () => {
if (isVerifying) {
return (
<form onSubmit={handleVerify}>
<Typography variant="h6" gutterBottom>Verify Account</Typography>
<Typography variant="body2" sx={{ mb: 2 }}>Enter the code sent to {email}</Typography>
<Typography variant="h6" gutterBottom>{t('auth.verifyTitle')}</Typography>
<Typography variant="body2" sx={{ mb: 2 }} dangerouslySetInnerHTML={{ __html: t('auth.verifyDesc', { username }) }} />
<TextField
fullWidth
label="Verification Code"
margin="normal"
value={verificationCode}
onChange={(e) => setVerificationCode(e.target.value)}
autoFocus
/>
<Button fullWidth variant="contained" type="submit" sx={{ mt: 2 }}>
Verify
</Button>
<Button fullWidth onClick={() => setIsVerifying(false)} sx={{ mt: 1 }}>
Back to Signup
<Button fullWidth variant="outlined" onClick={handleResendCode} sx={{ mt: 2, textTransform: 'none' }}>
{t('auth.resendButton')}
</Button>
<Button fullWidth onClick={() => { setIsVerifying(false); setMessage(null); }} sx={{ mt: 1 }}>
{t('auth.backToAuth')}
</Button>
</form>
);
@@ -156,8 +181,8 @@ const Login: React.FC<LoginProps> = () => {
return (
<>
<Tabs value={tab} onChange={(_, v) => { setTab(v); setMessage(null); }} sx={{ mb: 2 }}>
<Tab label="Login" />
<Tab label="Signup" />
<Tab label={t('auth.loginTitle')} />
<Tab label={t('auth.signupTitle')} />
</Tabs>
{tab === 0 ? (
@@ -178,10 +203,10 @@ const Login: React.FC<LoginProps> = () => {
onChange={(e) => setPassword(e.target.value)}
/>
<Button fullWidth variant="contained" type="submit" sx={{ mt: 2 }}>
Login
{t('auth.loginTitle')}
</Button>
<Button fullWidth onClick={() => { setIsResetting(true); setMessage(null); }} sx={{ mt: 1, textTransform: 'none' }} size="small">
Forgot Password?
{t('auth.forgotPassword')}
</Button>
</form>
) : (
@@ -210,7 +235,7 @@ const Login: React.FC<LoginProps> = () => {
onChange={(e) => setPassword(e.target.value)}
/>
<Button fullWidth variant="contained" type="submit" sx={{ mt: 2 }}>
Signup
{t('auth.signupTitle')}
</Button>
</form>
)}