fix: email verification redirect and already-used token message
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s

1. Use window.location.href instead of navigate() for reliable redirect
2. Improve backend error message for already-used verification tokens
3. Show user-friendly message when token was already verified
4. Reduce redirect delay from 2s to 1.5s for better UX

Fixes:
- Empty page after email verification
- Generic error when clicking verification link twice

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-21 12:28:51 +01:00
parent 1521c2f221
commit 1cd93d521e
2 changed files with 23 additions and 13 deletions

View File

@ -289,7 +289,9 @@ async def verify_email(token: str):
prof = cur.fetchone() prof = cur.fetchone()
if not prof: if not prof:
raise HTTPException(400, "Ungültiger Verifikations-Link") # Token not found - might be already used/verified
# Check if there's a verified profile (token was deleted after verification)
raise HTTPException(400, "Verifikations-Link ungültig oder bereits verwendet. Falls du bereits verifiziert bist, melde dich einfach an.")
if prof['email_verified']: if prof['email_verified']:
raise HTTPException(400, "E-Mail-Adresse bereits bestätigt") raise HTTPException(400, "E-Mail-Adresse bereits bestätigt")

View File

@ -33,10 +33,10 @@ export default function Verify() {
setAuthFromToken(result.token, result.profile) setAuthFromToken(result.token, result.profile)
setStatus('success') setStatus('success')
// Redirect to dashboard after 2 seconds // Redirect to dashboard after 1.5 seconds
setTimeout(() => { setTimeout(() => {
navigate('/dashboard') window.location.href = '/'
}, 2000) }, 1500)
} else { } else {
setStatus('error') setStatus('error')
setError('Verifizierung erfolgreich, aber Login fehlgeschlagen') setError('Verifizierung erfolgreich, aber Login fehlgeschlagen')
@ -44,11 +44,13 @@ export default function Verify() {
} catch (err) { } catch (err) {
const errorMsg = err.message || 'Verifizierung fehlgeschlagen' const errorMsg = err.message || 'Verifizierung fehlgeschlagen'
// Check if already verified // Check if already verified or already used
if (errorMsg.includes('bereits bestätigt') || errorMsg.includes('already verified')) { if (errorMsg.includes('bereits bestätigt') || errorMsg.includes('already verified') ||
errorMsg.includes('bereits verwendet') || errorMsg.includes('already used')) {
setStatus('already_verified') setStatus('already_verified')
setError(errorMsg) // Show the actual message
// Auto-redirect to login after 3 seconds // Auto-redirect to login after 3 seconds
setTimeout(() => navigate('/login'), 3000) setTimeout(() => { window.location.href = '/login' }, 3000)
} }
// Check if token expired // Check if token expired
else if (errorMsg.includes('abgelaufen') || errorMsg.includes('expired')) { else if (errorMsg.includes('abgelaufen') || errorMsg.includes('expired')) {
@ -200,13 +202,19 @@ export default function Verify() {
<h2 style={{marginBottom:12, color:'var(--accent-dark)'}}> <h2 style={{marginBottom:12, color:'var(--accent-dark)'}}>
E-Mail bereits bestätigt E-Mail bereits bestätigt
</h2> </h2>
<p style={{color:'var(--text2)', lineHeight:1.6, marginBottom:24}}> <p style={{color:'var(--text2)', lineHeight:1.6, marginBottom:error?12:24}}>
Deine E-Mail-Adresse wurde bereits verifiziert. {error || 'Deine E-Mail-Adresse wurde bereits verifiziert. Du kannst dich jetzt anmelden.'}
Du kannst dich jetzt anmelden.
</p> </p>
{!error && (
<p style={{fontSize:13, color:'var(--text3)'}}> <p style={{fontSize:13, color:'var(--text3)'}}>
Du wirst gleich zum Login weitergeleitet... Du wirst gleich zum Login weitergeleitet...
</p> </p>
)}
{error && (
<p style={{fontSize:13, color:'var(--text3)', marginTop:16}}>
Du wirst gleich zum Login weitergeleitet...
</p>
)}
</div> </div>
<button <button