Files
links/frontend/linktree-frontend/src/app/auth/login/page.tsx
Andrey K. Choi 2b217ded53
Some checks failed
continuous-integration/drone/push Build is failing
Fix auth URLs to use relative paths instead of absolute NEXT_PUBLIC_API_URL
- Change login page to use /api/auth/login/ instead of absolute URL
- Change register page to use /api/auth/register/ instead of absolute URL
- This fixes the 404 error with /auth/undefined/api/auth/login/ path
- Now uses Next.js rewrites from next.config.js correctly
2025-11-08 19:40:33 +09:00

131 lines
4.7 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.

// src/app/auth/login/page.tsx
'use client'
import { useState, useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
type FormData = { username: string; password: string }
export default function LoginPage() {
const router = useRouter()
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<FormData>()
const [apiError, setApiError] = useState<string | null>(null)
useEffect(() => {
if (typeof window !== 'undefined' && localStorage.getItem('token')) {
router.push('/dashboard')
}
}, [router])
async function onSubmit(data: FormData) {
setApiError(null)
try {
const res = await fetch(
`/api/auth/login/`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
}
)
if (!res.ok) {
const json = await res.json()
setApiError(json.detail || 'Ошибка входа')
return
}
const { access } = await res.json()
localStorage.setItem('token', access)
router.push('/dashboard')
} catch {
setApiError('Сетевая ошибка')
}
}
return (
<div className="min-vh-100 d-flex align-items-center justify-content-center bg-light">
<div className="container">
<div className="row justify-content-center">
<div className="col-md-6 col-lg-5">
<div className="card shadow-lg border-0 rounded-4">
<div className="card-body p-5">
<div className="text-center mb-4">
<img
src="/assets/img/CAT.png"
alt="CatLink"
width="80"
height="80"
className="mb-3"
/>
<h2 className="fw-bold text-primary">Добро пожаловать!</h2>
<p className="text-muted">Войдите в свой аккаунт CatLink</p>
</div>
{apiError && (
<div className="alert alert-danger" role="alert">
{apiError}
</div>
)}
<form onSubmit={handleSubmit(onSubmit)}>
<div className="mb-3">
<label htmlFor="username" className="form-label">Имя пользователя</label>
<input
id="username"
type="text"
placeholder="Введите имя пользователя"
className={`form-control form-control-lg ${errors.username ? 'is-invalid' : ''}`}
{...register('username', { required: 'Введите имя пользователя' })}
/>
{errors.username && (
<div className="invalid-feedback">{errors.username.message}</div>
)}
</div>
<div className="mb-4">
<label htmlFor="password" className="form-label">Пароль</label>
<input
id="password"
type="password"
placeholder="Введите пароль"
className={`form-control form-control-lg ${errors.password ? 'is-invalid' : ''}`}
{...register('password', { required: 'Введите пароль' })}
/>
{errors.password && (
<div className="invalid-feedback">{errors.password.message}</div>
)}
</div>
<button
type="submit"
disabled={isSubmitting}
className="btn btn-primary btn-lg w-100 mb-3"
>
{isSubmitting ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
Входим...
</>
) : (
'Войти'
)}
</button>
</form>
<div className="text-center">
<p className="text-muted mb-0">
Нет аккаунта?{' '}
<Link href="/auth/register" className="text-primary text-decoration-none fw-bold">
Зарегистрироваться
</Link>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}