From 646c1168349643eb01db53b5e06bf986a16b86d7 Mon Sep 17 00:00:00 2001 From: l3wdfut4pwr Date: Tue, 17 Mar 2026 14:06:58 +0200 Subject: simple registration prototype --- src/components/header/authdialog/LoginForm.tsx | 23 +++++ src/components/header/authdialog/RegisterForm.tsx | 115 ++++++++++++++++++++++ src/components/header/authdialog/ResetForm.tsx | 23 +++++ src/components/header/authdialog/register.ts | 69 +++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 src/components/header/authdialog/LoginForm.tsx create mode 100644 src/components/header/authdialog/RegisterForm.tsx create mode 100644 src/components/header/authdialog/ResetForm.tsx create mode 100644 src/components/header/authdialog/register.ts (limited to 'src/components/header/authdialog') diff --git a/src/components/header/authdialog/LoginForm.tsx b/src/components/header/authdialog/LoginForm.tsx new file mode 100644 index 0000000..c5b606c --- /dev/null +++ b/src/components/header/authdialog/LoginForm.tsx @@ -0,0 +1,23 @@ +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'; +export default function LoginForm() { + return ( + <> +
+ +
+ + +
+
+ + + ); +} diff --git a/src/components/header/authdialog/RegisterForm.tsx b/src/components/header/authdialog/RegisterForm.tsx new file mode 100644 index 0000000..20a7c14 --- /dev/null +++ b/src/components/header/authdialog/RegisterForm.tsx @@ -0,0 +1,115 @@ +'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 { validate, registerUser } from './register'; +import { useAuthContext } from '@/lib/contexts/Auth.context'; + +export default function RegisterForm() { + const [errors, setErrors] = useState({}); + const [loading, setLoading] = useState(false); + const { setUser } = useAuthContext(); + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + setErrors({}); + + const formData = new FormData(e.currentTarget); + const username = formData.get('username')?.toString() || ''; + const email = formData.get('email')?.toString() || ''; + const password = formData.get('password')?.toString() || ''; + const passwordConfirm = + formData.get('passwordConfirm')?.toString() || ''; + + const validationErrors = validate( + username, + email, + password, + passwordConfirm, + ); + + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + setLoading(false); + return; + } + + const { data, error } = await registerUser(username, email, password); + + if (error) { + setErrors(error); + } else if (data) { + setUser({ + id: data.id, + username: data.username, + }); + } + + setLoading(false); + }; + + return ( +
+ + +
+
+ + {errors.username && ( +

+ {errors.username} +

+ )} +
+ +
+ + {errors.email && ( +

+ {errors.email} +

+ )} +
+ +
+ + {errors.password && ( +

+ {errors.password} +

+ )} +
+ +
+ + {errors.passwordConfirm && ( +

+ {errors.passwordConfirm} +

+ )} +
+
+ + {errors.general &&

{errors.general}

} + + +
+ ); +} diff --git a/src/components/header/authdialog/ResetForm.tsx b/src/components/header/authdialog/ResetForm.tsx new file mode 100644 index 0000000..42ca1b2 --- /dev/null +++ b/src/components/header/authdialog/ResetForm.tsx @@ -0,0 +1,23 @@ +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'; +export default function ResetForm() { + return ( + <> +
+
+ ВОССТАНОВЛЕНИЕ ПАРОЛЯ +
+ + Введите никнейм или почту, с помощью которых входите + в аккаунт. + + +
+
+ +
+ + ); +} diff --git a/src/components/header/authdialog/register.ts b/src/components/header/authdialog/register.ts new file mode 100644 index 0000000..bcbc21b --- /dev/null +++ b/src/components/header/authdialog/register.ts @@ -0,0 +1,69 @@ +export const validate = ( + username: string, + email: string, + password: string, + passwordConfirm: string, +) => { + const newErrors: any = {}; + + 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 { + 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) { + newErrors.password = 'Необходимо минимум 8 символов.'; + } 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 = 'пароли не совпадают.'; + } + + return newErrors; +}; + +export const registerUser = async ( + username: string, + email: string, + password: string, +) => { + try { + const res = await fetch('http://localhost:8000/api/auth/register', { + method: 'POST', + 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 } }; + } + + return { data }; + } catch (err: any) { + return { error: { general: err.message } }; + } +}; -- cgit v1.3-3-g829e