Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 44 additions & 16 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import TaskDetails from './pages/TaskDetails';
import CalendarPage from './pages/CalendarPage';
import { supabase } from './lib/supabase';
import ProtectedRoute from './components/ProtectedRoute';
import {useEffect, useState} from "react";
function Navigation() {
const location = useLocation();

const location = useLocation();

const navigate = useNavigate();

const [fullName, setFullName] = useState('');

const handleLogout = async () => {
const { error } = await supabase.auth.signOut();

Expand All @@ -23,6 +27,25 @@ function Navigation() {
navigate('/');
};

useEffect(() => {
const loadUser = async () => {
const { data, error } = await supabase.auth.getUser();

if (error) {
console.error('Ошибка получения пользователя:', error.message);
return;
}

const firstName = data.user?.user_metadata?.first_name ?? '';
const lastName = data.user?.user_metadata?.last_name ?? '';

const name = `${firstName} ${lastName}`.trim();
setFullName(name);
console.log(name);
};

loadUser();
}, []);
// Если мы на странице авторизации, шапку не показываем
if (location.pathname === '/') return null;

Expand All @@ -31,21 +54,26 @@ function Navigation() {
<div className="container" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h1 style={{ color: 'var(--color-primary)', fontSize: '24px' }}>UniFlow</h1>
<nav style={{ display: 'flex', gap: '20px' }}>
<Link to="/courses" style={{ textDecoration: 'none', color: 'var(--color-text-main)' }}>Курсы</Link>
<button
type="button"
onClick={handleLogout}
style={{
background: 'none',
border: 'none',
padding: 0,
cursor: 'pointer',
color: 'var(--color-text-main)',
font: 'inherit'
}}
>
Выход
</button>
{fullName && (
<span style={{ color: 'var(--color-text-main)' }}>
{fullName}
</span>
)}
<Link to="/courses" style={{ textDecoration: 'none', color: 'var(--color-text-main)' }}>Курсы</Link>
<button
type="button"
onClick={handleLogout}
style={{
background: 'none',
border: 'none',
padding: 0,
cursor: 'pointer',
color: 'var(--color-text-main)',
font: 'inherit'
}}
>
Выход
</button>
</nav>
</div>
</header>
Expand Down
84 changes: 76 additions & 8 deletions frontend/src/pages/AuthPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import { supabase } from '../lib/supabase';

export default function AuthPage() {
const [isLogin, setIsLogin] = useState(true);

const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');

const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');

const [error, setError] = useState('');
const [loading, setLoading] = useState(false);

Expand All @@ -29,6 +34,14 @@ export default function AuthPage() {
checkSession();
}, [navigate]);

const resetForm = () => {
setFirstName('');
setLastName('');
setEmail('');
setPassword('');
setConfirmPassword('');
};

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

Expand All @@ -45,6 +58,21 @@ export default function AuthPage() {
return;
}

if (!firstName.trim()) {
setError('Введите имя');
return;
}

if (!lastName.trim()) {
setError('Введите фамилию');
return;
}

if (!confirmPassword.trim()) {
setError('Повторите пароль');
return;
}

if (password !== confirmPassword) {
setError('Пароли не совпадают');
return;
Expand All @@ -56,19 +84,31 @@ export default function AuthPage() {
const { data, error } = await supabase.auth.signUp({
email: email.trim(),
password,
options: {
data: {
first_name: firstName.trim(),
last_name: lastName.trim(),
},
},
});

if (error) {
setError(error.message);
return;
}

if (data.user) {
setEmail('');
setPassword('');
setConfirmPassword('');
if (data.session) {
resetForm();
navigate('/courses');
return;
}

if (data.user) {
resetForm();
setError('Если аккаунт новый, подтвердите регистрацию через почту. Если такой email уже зарегистрирован, просто войдите.');
return;
}

} catch (err) {
setError(err instanceof Error ? err.message : 'Ошибка регистрации');
} finally {
Expand Down Expand Up @@ -102,9 +142,7 @@ export default function AuthPage() {
}

if (data.session) {
setEmail('');
setPassword('');
setConfirmPassword('');
resetForm();
navigate('/courses');
}
} catch (err) {
Expand All @@ -123,13 +161,41 @@ export default function AuthPage() {
</p>

<form onSubmit={handleSubmit} className="auth-form">
{!isLogin && (
<>
<div className="input-group">
<label>Имя</label>
<input
type="text"
placeholder="Имя"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
autoComplete="given-name"
required
/>
</div>

<div className="input-group">
<label>Фамилия</label>
<input
type="text"
placeholder="Фамилия"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
autoComplete="family-name"
required
/>
</div>
</>
)}
<div className="input-group">
<label>Email</label>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
autoComplete="email"
required
/>
</div>
Expand All @@ -141,6 +207,7 @@ export default function AuthPage() {
placeholder="Пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete={isLogin ? 'current-password' : 'new-password'}
required
/>
</div>
Expand All @@ -154,6 +221,7 @@ export default function AuthPage() {
placeholder="Повторите пароль"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
autoComplete="new-password"
required
/>
</div>
Expand All @@ -174,7 +242,7 @@ export default function AuthPage() {
onClick={() => {
setIsLogin(!isLogin);
setError('');
setConfirmPassword('');
resetForm();
}}
>
{isLogin ? 'Создать' : 'Войти'}
Expand Down
Loading