mitai-jinkendo/frontend/src/pages/PasswordRecovery.jsx
Lars Stommer 89b6c0b072
Some checks are pending
Deploy to Raspberry Pi / deploy (push) Waiting to run
Build Test / build-frontend (push) Waiting to run
Build Test / lint-backend (push) Waiting to run
feat: initial commit – Mitai Jinkendo v9a
2026-03-16 13:35:11 +01:00

127 lines
5.1 KiB
JavaScript

import { useState } from 'react'
import { Check, ArrowLeft } from 'lucide-react'
export function ForgotPassword({ onBack }) {
const [email, setEmail] = useState('')
const [sent, setSent] = useState(false)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const handleSubmit = async () => {
if (!email.trim()) return setError('E-Mail eingeben')
setLoading(true); setError(null)
try {
const r = await fetch('/api/auth/forgot-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email.trim() })
})
if (!r.ok) throw new Error(await r.text())
setSent(true)
} catch(e) {
setError(e.message)
} finally { setLoading(false) }
}
if (sent) return (
<div style={{textAlign:'center',padding:'20px 0'}}>
<div style={{fontSize:48,marginBottom:12}}>📧</div>
<div style={{fontSize:16,fontWeight:700,marginBottom:8}}>E-Mail gesendet</div>
<div style={{fontSize:13,color:'var(--text2)',lineHeight:1.6,marginBottom:20}}>
Falls ein Konto mit dieser E-Mail existiert, hast du einen Link zum Zurücksetzen erhalten.
Bitte prüfe auch deinen Spam-Ordner.
</div>
<button className="btn btn-secondary btn-full" onClick={onBack}>
<ArrowLeft size={14}/> Zurück zum Login
</button>
</div>
)
return (
<div>
<div style={{display:'flex',alignItems:'center',gap:10,marginBottom:20}}>
<button onClick={onBack}
style={{background:'none',border:'none',cursor:'pointer',color:'var(--text3)',fontSize:20,padding:4}}></button>
<div>
<div style={{fontWeight:600,fontSize:16}}>Passwort vergessen</div>
<div style={{fontSize:12,color:'var(--text3)'}}>Recovery-Link per E-Mail</div>
</div>
</div>
<div style={{fontSize:13,color:'var(--text2)',marginBottom:16,lineHeight:1.6}}>
Gib deine E-Mail-Adresse ein. Du erhältst einen Link zum Zurücksetzen deines Passworts.
</div>
<input type="email" className="form-input" placeholder="deine@email.de"
value={email} onChange={e=>setEmail(e.target.value)}
onKeyDown={e=>e.key==='Enter'&&handleSubmit()}
style={{width:'100%',marginBottom:12,boxSizing:'border-box'}} autoFocus/>
{error && <div style={{color:'#D85A30',fontSize:12,marginBottom:10}}>{error}</div>}
<button className="btn btn-primary btn-full" onClick={handleSubmit} disabled={loading}>
{loading
? <><div className="spinner" style={{width:14,height:14}}/> Senden</>
: <>Recovery-Link senden</>}
</button>
</div>
)
}
export function ResetPassword({ token, onDone }) {
const [pin, setPin] = useState('')
const [pin2, setPin2] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [done, setDone] = useState(false)
const handleReset = async () => {
if (pin.length < 4) return setError('Mind. 4 Zeichen')
if (pin !== pin2) return setError('Eingaben stimmen nicht überein')
setLoading(true); setError(null)
try {
const r = await fetch('/api/auth/reset-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, pin })
})
if (!r.ok) {
const err = await r.json()
throw new Error(err.detail || 'Fehler')
}
setDone(true)
} catch(e) {
setError(e.message)
} finally { setLoading(false) }
}
if (done) return (
<div style={{textAlign:'center',padding:'20px 0'}}>
<div style={{fontSize:48,marginBottom:12}}></div>
<div style={{fontSize:16,fontWeight:700,marginBottom:8}}>Passwort geändert</div>
<div style={{fontSize:13,color:'var(--text2)',marginBottom:20}}>
Du kannst dich jetzt mit deinem neuen Passwort einloggen.
</div>
<button className="btn btn-primary btn-full" onClick={onDone}>
Zum Login
</button>
</div>
)
return (
<div>
<div style={{fontSize:16,fontWeight:700,marginBottom:6}}>Neues Passwort setzen</div>
<div style={{fontSize:13,color:'var(--text2)',marginBottom:16}}>
Wähle ein neues Passwort oder eine neue PIN (mind. 4 Zeichen).
</div>
<input type="password" className="form-input" placeholder="Neues Passwort"
value={pin} onChange={e=>setPin(e.target.value)}
style={{width:'100%',marginBottom:10,boxSizing:'border-box'}} autoFocus/>
<input type="password" className="form-input" placeholder="Wiederholen"
value={pin2} onChange={e=>setPin2(e.target.value)}
onKeyDown={e=>e.key==='Enter'&&handleReset()}
style={{width:'100%',marginBottom:12,boxSizing:'border-box'}}/>
{error && <div style={{color:'#D85A30',fontSize:12,marginBottom:10}}>{error}</div>}
<button className="btn btn-primary btn-full" onClick={handleReset} disabled={loading}>
{loading ? <><div className="spinner" style={{width:14,height:14}}/> Speichern</> : 'Passwort setzen'}
</button>
</div>
)
}