mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
implemented improved account verification flow with recovery and resend
This commit is contained in:
1 parent
0c00552905
commit
83f46e6619
3 files changed
+99
-13
No files matched your search
@@ -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.",
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user