146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useEffect } from 'react';
|
||
import { useRouter } from 'next/navigation';
|
||
import { requestPasswordReset } from '@/api/auth';
|
||
import { getErrorMessage } from '@/lib/error-utils';
|
||
|
||
const loadMaterialComponents = async () => {
|
||
await Promise.all([
|
||
import('@material/web/textfield/filled-text-field.js'),
|
||
import('@material/web/button/filled-button.js'),
|
||
import('@material/web/button/text-button.js'),
|
||
]);
|
||
};
|
||
|
||
export default function ForgotPasswordPage() {
|
||
const router = useRouter();
|
||
const [email, setEmail] = useState('');
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState('');
|
||
const [success, setSuccess] = useState(false);
|
||
const [componentsLoaded, setComponentsLoaded] = useState(false);
|
||
|
||
useEffect(() => {
|
||
loadMaterialComponents()
|
||
.then(() => setComponentsLoaded(true))
|
||
.catch((err) => {
|
||
console.error('Error loading components:', err);
|
||
setComponentsLoaded(true);
|
||
});
|
||
}, []);
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
setLoading(true);
|
||
setError('');
|
||
setSuccess(false);
|
||
|
||
try {
|
||
await requestPasswordReset({ email });
|
||
setSuccess(true);
|
||
} catch (err: any) {
|
||
setError(getErrorMessage(err, 'Ошибка при отправке запроса. Проверьте email.'));
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
if (!componentsLoaded) {
|
||
return (
|
||
<div style={{ display: 'flex', justifyContent: 'center', padding: '48px' }}>
|
||
<div
|
||
style={{
|
||
width: '40px',
|
||
height: '40px',
|
||
border: '3px solid #e0e0e0',
|
||
borderTopColor: 'var(--md-sys-color-primary, #6750a4)',
|
||
borderRadius: '50%',
|
||
animation: 'spin 0.8s linear infinite',
|
||
}}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div style={{ width: '100%', maxWidth: '400px' }}>
|
||
|
||
<p style={{ fontSize: '14px', color: '#666', marginBottom: '28px' }}>
|
||
Восстановление пароля
|
||
</p>
|
||
|
||
{success ? (
|
||
<>
|
||
<div
|
||
style={{
|
||
padding: '16px',
|
||
marginBottom: '24px',
|
||
background: '#e8f5e9',
|
||
color: '#2e7d32',
|
||
borderRadius: '12px',
|
||
fontSize: '14px',
|
||
lineHeight: '1.5',
|
||
}}
|
||
>
|
||
Инструкции по восстановлению пароля отправлены на ваш email.
|
||
</div>
|
||
<md-filled-button
|
||
onClick={() => router.push('/login')}
|
||
style={{ width: '100%', height: '48px' }}
|
||
>
|
||
Вернуться к входу
|
||
</md-filled-button>
|
||
</>
|
||
) : (
|
||
<>
|
||
<p style={{ fontSize: '14px', color: '#666', marginBottom: '20px' }}>
|
||
Введите ваш email для восстановления пароля
|
||
</p>
|
||
<form onSubmit={handleSubmit}>
|
||
<div style={{ marginBottom: '20px' }}>
|
||
<md-filled-text-field
|
||
label="Email"
|
||
type="email"
|
||
value={email}
|
||
onInput={(e: any) => setEmail(e.target.value || '')}
|
||
required
|
||
style={{ width: '100%' }}
|
||
/>
|
||
</div>
|
||
|
||
{error && (
|
||
<div
|
||
style={{
|
||
padding: '12px 16px',
|
||
marginBottom: '20px',
|
||
background: '#ffebee',
|
||
color: '#c62828',
|
||
borderRadius: '12px',
|
||
fontSize: '14px',
|
||
}}
|
||
>
|
||
{error}
|
||
</div>
|
||
)}
|
||
|
||
<md-filled-button
|
||
type="submit"
|
||
disabled={loading}
|
||
style={{ width: '100%', height: '48px', marginBottom: '16px' }}
|
||
>
|
||
{loading ? 'Отправка...' : 'Отправить'}
|
||
</md-filled-button>
|
||
|
||
<div style={{ textAlign: 'center', marginTop: '20px' }}>
|
||
<md-text-button onClick={() => router.push('/login')} style={{ fontSize: '14px' }}>
|
||
Вернуться к входу
|
||
</md-text-button>
|
||
</div>
|
||
</form>
|
||
</>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|