uchill/front_material/app/(auth)/login/page.tsx

177 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import { login } from '@/api/auth';
import { useAuth } from '@/contexts/AuthContext';
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 LoginPage() {
const router = useRouter();
const { login: authLogin } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [componentsLoaded, setComponentsLoaded] = useState(false);
useEffect(() => {
loadMaterialComponents()
.then(() => setComponentsLoaded(true))
.catch((err) => {
console.error('Error loading Material components:', err);
setComponentsLoaded(true);
});
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
try {
const response = await login({ email, password });
if (response.access) {
localStorage.setItem('access_token', response.access);
if (response.refresh) {
localStorage.setItem('refresh_token', response.refresh);
}
if (response.user) {
authLogin(response.access, response.user).catch(console.error);
} else {
authLogin(response.access).catch(console.error);
}
window.location.href = '/dashboard';
return;
} else {
setError('Ошибка: токен не получен');
setLoading(false);
return;
}
} catch (err: any) {
setError(getErrorMessage(err, 'Ошибка входа. Проверьте данные.'));
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>
<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>
<div style={{ marginBottom: '20px' }}>
<md-filled-text-field
label="Пароль"
type="password"
value={password}
onInput={(e: any) => setPassword(e.target.value || '')}
required
style={{ width: '100%' }}
/>
</div>
{error && (
<div
style={{
padding: '12px 16px',
marginBottom: '20px',
background: '#ffebee',
color: '#c62828',
borderRadius: '12px',
fontSize: '14px',
lineHeight: '1.5',
}}
>
{error}
</div>
)}
<md-filled-button
type="submit"
disabled={loading}
style={{
width: '100%',
height: '48px',
marginBottom: '16px',
fontSize: '16px',
fontWeight: '500',
}}
>
{loading ? 'Вход...' : 'Войти'}
</md-filled-button>
</form>
<div
style={{
textAlign: 'center',
marginTop: '20px',
display: 'flex',
flexDirection: 'column',
gap: '8px',
}}
>
<Link
href="/forgot-password"
style={{
fontSize: '14px',
color: 'var(--md-sys-color-primary, #6750a4)',
textDecoration: 'none',
}}
>
Забыли пароль?
</Link>
<Link
href="/register"
style={{
fontSize: '14px',
color: 'var(--md-sys-color-primary, #6750a4)',
textDecoration: 'none',
}}
>
Нет аккаунта? Зарегистрироваться
</Link>
</div>
</div>
);
}