76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
'use client';
|
|
|
|
import { Suspense, useEffect, useState } from 'react';
|
|
import { useSearchParams } from 'next/navigation';
|
|
import { useI18n } from '../../components/I18nProvider';
|
|
|
|
function ResetForm() {
|
|
const { t } = useI18n();
|
|
const searchParams = useSearchParams();
|
|
const [password, setPassword] = useState('');
|
|
const [token, setToken] = useState('');
|
|
const [message, setMessage] = useState<string | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const tok = searchParams.get('token') || '';
|
|
setToken(tok);
|
|
}, [searchParams]);
|
|
|
|
async function onSubmit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
setMessage(null);
|
|
setError(null);
|
|
if (!token) {
|
|
setError(t('resetMissingToken'));
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
try {
|
|
const res = await fetch('/api/auth/reset', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ token, password }),
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok) {
|
|
setError(data.error || t('resetError'));
|
|
} else {
|
|
setMessage(t('resetSuccess'));
|
|
setPassword('');
|
|
}
|
|
} catch (err) {
|
|
setError(t('resetError'));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main className="panel" style={{ maxWidth: 480, margin: '40px auto' }}>
|
|
<h1>{t('resetTitle')}</h1>
|
|
<p style={{ color: '#cbd5e1', marginTop: 6 }}>{t('resetLead')}</p>
|
|
<form onSubmit={onSubmit} style={{ display: 'grid', gap: 12, marginTop: 14 }}>
|
|
<label>
|
|
{t('passwordLabel')}
|
|
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} minLength={8} required />
|
|
</label>
|
|
<button className="button" type="submit" disabled={loading}>
|
|
{loading ? t('saving') : t('resetSubmit')}
|
|
</button>
|
|
</form>
|
|
{message ? <p style={{ marginTop: 12, color: 'green' }}>{message}</p> : null}
|
|
{error ? <p style={{ marginTop: 12, color: 'red' }}>{error}</p> : null}
|
|
{!token ? <p style={{ marginTop: 12, color: '#f59e0b' }}>{t('resetMissingToken')}</p> : null}
|
|
</main>
|
|
);
|
|
}
|
|
|
|
export default function ResetPasswordPage() {
|
|
return (
|
|
<Suspense fallback={<main className="panel" style={{ maxWidth: 480, margin: '40px auto' }}><p>Loading…</p></main>}>
|
|
<ResetForm />
|
|
</Suspense>
|
|
);
|
|
}
|