From 1d20080db8a26e4b7dd4071daac1166142592afa Mon Sep 17 00:00:00 2001 From: l3wdfut4pwr Date: Thu, 2 Apr 2026 08:36:51 +0300 Subject: minor improvements --- src/app/premium/page.tsx | 3 ++ src/components/header/AuthDialog.tsx | 6 +++- src/components/header/authdialog/LoginForm.tsx | 22 ++++++------- src/components/header/authdialog/register.ts | 39 +++++++---------------- src/components/ui/inputfield.tsx | 6 +++- src/components/upload/SourceInput.tsx | 3 +- src/components/upload/TagsInput.tsx | 1 - src/lib/contexts/Auth.context.tsx | 44 ++++++++++++++++---------- src/lib/contexts/Global.context.tsx | 2 -- 9 files changed, 62 insertions(+), 64 deletions(-) create mode 100644 src/app/premium/page.tsx diff --git a/src/app/premium/page.tsx b/src/app/premium/page.tsx new file mode 100644 index 0000000..17cee81 --- /dev/null +++ b/src/app/premium/page.tsx @@ -0,0 +1,3 @@ +export default function Premium() { + return null; +} diff --git a/src/components/header/AuthDialog.tsx b/src/components/header/AuthDialog.tsx index 0b4bc74..8c00b81 100644 --- a/src/components/header/AuthDialog.tsx +++ b/src/components/header/AuthDialog.tsx @@ -1,5 +1,5 @@ import { Button } from '@/components/ui/button'; -import { DialogContent } from '@/components/ui/dialog'; +import { DialogContent, DialogTitle } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import GoogleIcon from '../../../public/icons/google.svg'; @@ -7,10 +7,14 @@ import { InputField } from '../ui/inputfield'; import LoginForm from './authdialog/LoginForm'; import RegisterForm from './authdialog/RegisterForm'; import ResetForm from './authdialog/ResetForm'; +import { VisuallyHidden } from '@radix-ui/react-visually-hidden'; export function AuthDialog() { return (
+ + Authentication +
diff --git a/src/components/header/authdialog/LoginForm.tsx b/src/components/header/authdialog/LoginForm.tsx index ceadbcd..c6cdbcd 100644 --- a/src/components/header/authdialog/LoginForm.tsx +++ b/src/components/header/authdialog/LoginForm.tsx @@ -6,6 +6,7 @@ import { InputField } from '@/components/ui/inputfield'; import { useAuthContext } from '@/lib/contexts/Auth.context'; export default function LoginForm() { + const API_URL = process.env.NEXT_PUBLIC_API_URL; const [errors, setErrors] = useState({}); const [loading, setLoading] = useState(false); const { setUser } = useAuthContext(); @@ -36,27 +37,27 @@ export default function LoginForm() { body.append('password', password); try { - const res = await fetch('http://localhost:8000/api/auth/login', { + const res = await fetch(`${API_URL}/api/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: body.toString(), + credentials: 'include', }); - 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}` }, + } else { + const meRes = await fetch(`${API_URL}/api/me`, { + credentials: 'include', }); + if (!meRes.ok) throw new Error('Failed to fetch user'); const meData = await meRes.json(); setUser(meData); } + } catch (err) { + setErrors({ general: 'Ошибка при авторизации' }); } finally { setLoading(false); } @@ -91,11 +92,6 @@ export default function LoginForm() { placeholder="Пароль" name="password" /> - {errors.password && ( -

- {errors.password} -

- )} {!errors.password && errors.general && (

{errors.general} diff --git a/src/components/header/authdialog/register.ts b/src/components/header/authdialog/register.ts index ba8bceb..46a59f2 100644 --- a/src/components/header/authdialog/register.ts +++ b/src/components/header/authdialog/register.ts @@ -1,4 +1,3 @@ -// register.ts export const validate = ( username: string, email: string, @@ -36,20 +35,23 @@ export const validate = ( return newErrors; }; +const API_URL = process.env.NEXT_PUBLIC_API_URL; + export const registerUser = async ( username: string, email: string, password: string, ) => { try { - const res = await fetch('http://localhost:8000/api/auth/register', { + const res = await fetch(`${API_URL}/api/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, email, password }), + credentials: 'include', }); - const data = await res.json(); if (!res.ok) { + const data = await res.json(); const { field, message } = data.detail || {}; return { data: null, @@ -59,35 +61,16 @@ export const registerUser = async ( }; } - 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 meRes = await fetch(`${API_URL}/api/me`, { + credentials: 'include', }); - const loginData = await loginRes.json(); - - if (!loginRes.ok) { - return { - data: null, - error: { - general: - loginData.detail || 'Ошибка входа после регистрации', - }, - }; + if (!meRes.ok) { + throw new Error( + 'Не удалось получить данные пользователя после регистрации', + ); } - 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 }; diff --git a/src/components/ui/inputfield.tsx b/src/components/ui/inputfield.tsx index 6b585a9..991aca0 100644 --- a/src/components/ui/inputfield.tsx +++ b/src/components/ui/inputfield.tsx @@ -1,7 +1,11 @@ import { Input } from '@/components/ui/input'; import React from 'react'; -export function InputField(props: React.InputHTMLAttributes) { +type InputFieldProps = React.InputHTMLAttributes & { + isPassword?: boolean; +}; + +export function InputField(props: InputFieldProps) { return (

ИСТОЧНИК { + onKeyDown={(e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); } diff --git a/src/components/upload/TagsInput.tsx b/src/components/upload/TagsInput.tsx index 1b88fa2..cdff794 100644 --- a/src/components/upload/TagsInput.tsx +++ b/src/components/upload/TagsInput.tsx @@ -72,7 +72,6 @@ class RemoveTag extends React.Component { onClick={onRemove} className={className} onFocus={(e) => { - // Это говно здесь из-за того, что без него после удаления бэкспейсом, фокусится крестик document.getElementById('tags-input')?.focus(); }} > diff --git a/src/lib/contexts/Auth.context.tsx b/src/lib/contexts/Auth.context.tsx index 29e2005..fbf2e24 100644 --- a/src/lib/contexts/Auth.context.tsx +++ b/src/lib/contexts/Auth.context.tsx @@ -1,39 +1,49 @@ 'use client'; import React, { createContext, useState, useContext, useEffect } from 'react'; -type User = { +export type User = { id: number; username: string; + avatar?: string; + banner_file?: string; + premium?: boolean; + is_banned?: boolean; + is_moderator?: boolean; }; - interface AuthContextType { user: User | null; setUser: (user: User | null) => void; logout: () => void; } - const AuthContext = createContext(null); +const API_URL = process.env.NEXT_PUBLIC_API_URL; export const AuthContextProvider = ({ children }: React.PropsWithChildren) => { const [user, setUser] = useState(null); useEffect(() => { - const token = localStorage.getItem('token'); - if (!token) return; - - fetch('http://localhost:8000/api/me', { - headers: { Authorization: `Bearer ${token}` }, - }) - .then((res) => { - if (!res.ok) throw new Error('Not authenticated'); - return res.json(); - }) - .then((userData) => setUser(userData)) - .catch(() => setUser(null)); + const fetchUser = async () => { + const hasCookies = document.cookie.includes('access_token'); + if (!hasCookies) return; + + try { + const res = await fetch(`${API_URL}/api/me`, { + credentials: 'include', + }); + if (!res.ok) return; + const userData = await res.json(); + setUser(userData); + } catch {} + }; + + fetchUser(); }, []); - const logout = () => { - localStorage.removeItem('token'); + const logout = async () => { + await fetch(`${API_URL}/api/auth/logout`, { + method: 'POST', + credentials: 'include', + }); setUser(null); }; diff --git a/src/lib/contexts/Global.context.tsx b/src/lib/contexts/Global.context.tsx index c903456..3f8b61b 100644 --- a/src/lib/contexts/Global.context.tsx +++ b/src/lib/contexts/Global.context.tsx @@ -1,5 +1,3 @@ -import react from 'react'; -import { authcontextprovider } from './auth.context'; import React from 'react'; import { AuthContextProvider } from './Auth.context'; -- cgit v1.3-3-g829e