diff options
Diffstat (limited to 'src/components/header')
| -rw-r--r-- | src/components/header/authdialog/LoginForm.tsx | 117 | ||||
| -rw-r--r-- | src/components/header/authdialog/RegisterForm.tsx | 1 | ||||
| -rw-r--r-- | src/components/header/authdialog/register.ts | 76 |
3 files changed, 156 insertions, 38 deletions
diff --git a/src/components/header/authdialog/LoginForm.tsx b/src/components/header/authdialog/LoginForm.tsx index 0a72f67..ceadbcd 100644 --- a/src/components/header/authdialog/LoginForm.tsx +++ b/src/components/header/authdialog/LoginForm.tsx @@ -1,23 +1,112 @@ +'use client'; +import { useState } from 'react'; import { Button } from '@/components/ui/button'; import GoogleIcon from '../../../../public/icons/google.svg'; import { InputField } from '@/components/ui/inputfield'; -import { Input } from '@/components/ui/input'; +import { useAuthContext } from '@/lib/contexts/Auth.context'; + export default function LoginForm() { + const [errors, setErrors] = useState<any>({}); + const [loading, setLoading] = useState(false); + const { setUser } = useAuthContext(); + + const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { + e.preventDefault(); + setLoading(true); + setErrors({}); + + const formData = new FormData(e.currentTarget); + const emailOrUsername = + formData.get('emailOrUsername')?.toString() || ''; + const password = formData.get('password')?.toString() || ''; + + const newErrors: any = {}; + if (!emailOrUsername) + newErrors.emailOrUsername = 'Введите никнейм или email'; + if (!password) newErrors.password = 'Введите пароль'; + + if (Object.keys(newErrors).length > 0) { + setErrors(newErrors); + setLoading(false); + return; + } + + const body = new URLSearchParams(); + body.append('username', emailOrUsername); + body.append('password', password); + + try { + const res = await fetch('http://localhost:8000/api/auth/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: body.toString(), + }); + + const data = await res.json(); + + if (!res.ok) { + setErrors({ general: 'Неверный логин или пароль' }); + } else if (data.access_token) { + localStorage.setItem('token', data.access_token); + + const meRes = await fetch('http://localhost:8000/api/me', { + headers: { Authorization: `Bearer ${data.access_token}` }, + }); + const meData = await meRes.json(); + setUser(meData); + } + } finally { + setLoading(false); + } + }; + return ( - <> - <div className="gap-5 flex flex-col h-[148px] w-[310px]"> - <Button className="w-full bg-white hover:bg-white hover:text-black"> - <GoogleIcon /> - <span className="text-black text-sm"> - Войти через Google - </span> - </Button> - <div className="gap-[10px] flex-col flex h-[88px]"> - <InputField placeholder="Никнейм или почта" /> - <InputField isPassword placeholder="Пароль" /> + <form + onSubmit={handleSubmit} + className="flex flex-col gap-5 min-w-[310px] w-fit" + > + <Button className="w-full bg-white hover:bg-white hover:text-black"> + <GoogleIcon /> + <span className="text-black text-sm">Войти через Google</span> + </Button> + + <div className="flex flex-col gap-2.5"> + <div className="flex flex-col"> + <InputField + placeholder="Никнейм или почта" + name="emailOrUsername" + /> + {errors.emailOrUsername && ( + <p className="text-red pl-5 text-[12px] leading-[16px] mt-[5px]"> + {errors.emailOrUsername} + </p> + )} + </div> + + <div className="flex flex-col"> + <InputField + isPassword + placeholder="Пароль" + name="password" + /> + {errors.password && ( + <p className="text-red pl-5 text-[12px] leading-[16px] mt-[5px]"> + {errors.password} + </p> + )} + {!errors.password && errors.general && ( + <p className="text-red pl-5 text-[12px] leading-[16px] mt-[5px]"> + {errors.general} + </p> + )} </div> </div> - <Button className="w-full gap-[10px]">Войти</Button> - </> + + <Button type="submit" className="w-full" disabled={loading}> + {loading ? 'Вход...' : 'Войти'} + </Button> + </form> ); } diff --git a/src/components/header/authdialog/RegisterForm.tsx b/src/components/header/authdialog/RegisterForm.tsx index 3c2c164..c8ddb55 100644 --- a/src/components/header/authdialog/RegisterForm.tsx +++ b/src/components/header/authdialog/RegisterForm.tsx @@ -5,6 +5,7 @@ import GoogleIcon from '../../../../public/icons/google.svg'; import { InputField } from '@/components/ui/inputfield'; import { validate, registerUser } from './register'; import { useAuthContext } from '@/lib/contexts/Auth.context'; +import Image from 'next/image'; export default function RegisterForm() { const [errors, setErrors] = useState<any>({}); diff --git a/src/components/header/authdialog/register.ts b/src/components/header/authdialog/register.ts index bcbc21b..ba8bceb 100644 --- a/src/components/header/authdialog/register.ts +++ b/src/components/header/authdialog/register.ts @@ -1,44 +1,37 @@ +// register.ts export const validate = ( username: string, email: string, password: string, passwordConfirm: string, ) => { - const newErrors: any = {}; + const newErrors: Record<string, string> = {}; - if (!username) { - newErrors.username = 'Введите никнейм'; - } else if (username.length < 3) { - newErrors.username = 'Минимум 3 символа.'; - } else if (username.length > 32) { - newErrors.username = 'Максимум 32 символа'; - } + if (!username) newErrors.username = 'Введите никнейм'; + else if (username.length < 3) newErrors.username = 'Минимум 3 символа.'; + else if (username.length > 32) newErrors.username = 'Максимум 32 символа'; - if (!email) { - newErrors.email = 'Введите email.'; - } else { + if (!email) newErrors.email = 'Введите email.'; + else { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) newErrors.email = 'Некорректный email'; if (email.length > 254) newErrors.email = 'Слишком длинный email.'; } - if (!password) { - newErrors.password = 'Введите пароль.'; - } else if (password.length < 8) { + if (!password) newErrors.password = 'Введите пароль.'; + else if (password.length < 8) newErrors.password = 'Необходимо минимум 8 символов.'; - } else { + else { const hasLetter = /[A-Za-z]/.test(password); const hasNumber = /\d/.test(password); const hasSymbol = /[^\w\s]/.test(password); - if (!(hasLetter && hasNumber && hasSymbol)) { newErrors.password = 'Попробуйте сочетание букв, цифр и символов.'; } } - if (password !== passwordConfirm) { - newErrors.passwordConfirm = 'пароли не совпадают.'; - } + if (password !== passwordConfirm) + newErrors.passwordConfirm = 'Пароли не совпадают.'; return newErrors; }; @@ -54,16 +47,51 @@ export const registerUser = async ( headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, email, password }), }); - const data = await res.json(); if (!res.ok) { - const { field, message } = data.detail; - return { error: { [field]: message } }; + const { field, message } = data.detail || {}; + return { + data: null, + error: field + ? { [field]: message } + : { general: 'Ошибка регистрации' }, + }; } - return { data }; + const body = new URLSearchParams(); + body.append('username', username); + body.append('password', password); + + const loginRes = await fetch('http://localhost:8000/api/auth/login', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: body.toString(), + }); + + const loginData = await loginRes.json(); + + if (!loginRes.ok) { + return { + data: null, + error: { + general: + loginData.detail || 'Ошибка входа после регистрации', + }, + }; + } + + localStorage.setItem('token', loginData.access_token); + localStorage.setItem('refresh_token', loginData.refresh_token); + + const meRes = await fetch('http://localhost:8000/api/me', { + headers: { Authorization: `Bearer ${loginData.access_token}` }, + }); + + const meData = await meRes.json(); + + return { data: meData, error: null }; } catch (err: any) { - return { error: { general: err.message } }; + return { data: null, error: { general: err.message } }; } }; |
