Przeglądaj źródła

feat: login modal instead of separate page

neyrogovnarik 1 miesiąc temu
rodzic
commit
5d274b5757

+ 7 - 8
frontend/src/components/Header.tsx

@@ -1,15 +1,13 @@
 'use client'
 
+import { useState } from 'react'
 import Link from 'next/link'
 import { useAuth } from '@/hooks/useAuth'
+import LoginModal from './LoginModal'
 
-/**
- * Шапка приложения. Отображает логотип PhotoPlaces и навигацию.
- * Для авторизованных пользователей показывает email и кнопку выхода.
- * Для гостей — ссылки на вход и регистрацию.
- */
 export default function Header() {
   const { user, isLoading, logout } = useAuth()
+  const [showLogin, setShowLogin] = useState(false)
 
   return (
     <header className="absolute left-0 right-0 top-0 z-30 flex items-center justify-between px-4 py-3">
@@ -30,12 +28,13 @@ export default function Header() {
           </>
         ) : (
           <>
-            <Link
-              href="/auth/login"
+            {showLogin && <LoginModal onClose={() => setShowLogin(false)} />}
+            <button
+              onClick={() => setShowLogin(true)}
               className="rounded-lg bg-white/10 backdrop-blur-md px-4 py-2 text-sm text-white hover:bg-white/20 transition"
             >
               Войти
-            </Link>
+            </button>
             <Link
               href="/auth/register"
               className="rounded-lg bg-green-600 px-4 py-2 text-sm text-white hover:bg-green-500 transition"

+ 62 - 0
frontend/src/components/LoginModal.tsx

@@ -0,0 +1,62 @@
+'use client'
+
+import { useState } from 'react'
+import { useAuth } from '@/hooks/useAuth'
+import { useRouter } from 'next/navigation'
+
+export default function LoginModal({ onClose }: { onClose: () => void }) {
+  const router = useRouter()
+  const { login } = useAuth()
+  const [email, setEmail] = useState('')
+  const [password, setPassword] = useState('')
+  const [error, setError] = useState('')
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault()
+    try {
+      await login(email, password)
+      onClose()
+    } catch (err: any) {
+      setError(err.message || 'Login failed')
+    }
+  }
+
+  return (
+    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={onClose}>
+      <form
+        onSubmit={handleSubmit}
+        onClick={(e) => e.stopPropagation()}
+        className="w-full max-w-sm space-y-4 rounded-2xl bg-white/10 p-8 backdrop-blur-md"
+      >
+        <h1 className="text-center text-2xl font-bold text-white">Вход</h1>
+
+        {error && <p className="text-sm text-red-400">{error}</p>}
+
+        <input
+          type="email"
+          placeholder="Email"
+          value={email}
+          onChange={(e) => setEmail(e.target.value)}
+          className="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-3 text-white placeholder-white/40 outline-none focus:border-green-500"
+          required
+        />
+
+        <input
+          type="password"
+          placeholder="Пароль"
+          value={password}
+          onChange={(e) => setPassword(e.target.value)}
+          className="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-3 text-white placeholder-white/40 outline-none focus:border-green-500"
+          required
+        />
+
+        <button
+          type="submit"
+          className="w-full rounded-lg bg-green-600 px-4 py-3 font-medium text-white hover:bg-green-500 transition"
+        >
+          Войти
+        </button>
+      </form>
+    </div>
+  )
+}