source: chapterx-frontend/src/pages/auth/LoginPage.tsx@ 3ae4bab

main
Last change on this file since 3ae4bab was 3ae4bab, checked in by kikisrbinoska <srbinoskakristina07@…>, 3 days ago

Changes for log in

  • Property mode set to 100644
File size: 4.5 KB
Line 
1import React, { useState } from 'react'
2import { useNavigate, Link } from 'react-router-dom'
3import { Eye, EyeOff } from 'lucide-react'
4import logo from '../../assets/chapterX-removebg-preview.png'
5import { useAuthStore } from '../../store/authStore'
6import { useUIStore } from '../../store/uiStore'
7import { Button } from '../../components/ui/Button'
8
9export const LoginPage: React.FC = () => {
10 const navigate = useNavigate()
11 const { login } = useAuthStore()
12 const { addToast } = useUIStore()
13 const [email, setEmail] = useState('')
14 const [password, setPassword] = useState('')
15 const [showPw, setShowPw] = useState(false)
16 const [loading, setLoading] = useState(false)
17 const [errors, setErrors] = useState<{ email?: string; password?: string }>({})
18 const [noAccount, setNoAccount] = useState(false)
19
20 const validate = () => {
21 const e: typeof errors = {}
22 if (!email.trim()) e.email = 'Email is required'
23 if (!password.trim()) e.password = 'Password is required'
24 setErrors(e)
25 return Object.keys(e).length === 0
26 }
27
28 const handleSubmit = async (ev: React.FormEvent) => {
29 ev.preventDefault()
30 if (!validate()) return
31 setNoAccount(false)
32 setLoading(true)
33 try {
34 await login(email, password)
35 addToast('Welcome back!')
36 navigate('/')
37 } catch (err: any) {
38 const message = err?.message || 'Incorrect email or password. Please try again.'
39 if (/no account found/i.test(message)) {
40 setNoAccount(true)
41 setErrors(p => ({ ...p, email: message }))
42 } else {
43 setErrors(p => ({ ...p, password: message }))
44 }
45 addToast(message, 'error')
46 } finally {
47 setLoading(false)
48 }
49 }
50
51 return (
52 <div className="min-h-[80vh] flex items-center justify-center px-4 py-12">
53 <div className="w-full max-w-md">
54 {/* Logo */}
55 <div className="text-center mb-8">
56 <Link to="/" className="inline-flex items-center gap-2 mb-6">
57 <img src={logo} alt="ChapterX" className="h-20 w-20 object-contain" />
58 </Link>
59 <h1 className="font-serif text-2xl font-bold text-white">Welcome back</h1>
60 <p className="text-slate-400 text-sm mt-2">Sign in to your account</p>
61 </div>
62
63 {/* Form */}
64 <form onSubmit={handleSubmit} className="space-y-4">
65 <div>
66 <label className="block text-sm text-slate-400 mb-1.5">Login with Email</label>
67 <input
68 type="text"
69 value={email}
70 onChange={e => { setEmail(e.target.value); setErrors(p => ({ ...p, email: '' })); setNoAccount(false) }}
71 placeholder="you@example.com"
72 className={`w-full px-4 py-3 bg-slate-800 border rounded-xl text-white placeholder-slate-500 focus:outline-none focus:border-indigo-500 transition-colors ${
73 errors.email ? 'border-rose-500' : 'border-slate-700'
74 }`}
75 />
76 {errors.email && <p className="text-rose-400 text-xs mt-1">{errors.email}</p>}
77 </div>
78 <div>
79 <label className="block text-sm text-slate-400 mb-1.5">Password</label>
80 <div className="relative">
81 <input
82 type={showPw ? 'text' : 'password'}
83 value={password}
84 onChange={e => { setPassword(e.target.value); setErrors(p => ({ ...p, password: '' })) }}
85 placeholder="••••••••"
86 className={`w-full px-4 py-3 pr-12 bg-slate-800 border rounded-xl text-white placeholder-slate-500 focus:outline-none focus:border-indigo-500 transition-colors ${
87 errors.password ? 'border-rose-500' : 'border-slate-700'
88 }`}
89 />
90 <button
91 type="button"
92 onClick={() => setShowPw(!showPw)}
93 className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-500 hover:text-slate-300"
94 >
95 {showPw ? <EyeOff size={16} /> : <Eye size={16} />}
96 </button>
97 </div>
98 {errors.password && <p className="text-rose-400 text-xs mt-1">{errors.password}</p>}
99 </div>
100
101 <Button type="submit" className="w-full" size="lg" loading={loading}>
102 Sign In
103 </Button>
104 </form>
105
106 <p className={`text-center text-sm mt-6 ${noAccount ? 'text-rose-400' : 'text-slate-500'}`}>
107 Don't have an account?{' '}
108 <Link to="/register" className="text-indigo-400 hover:text-indigo-300 font-medium">
109 Create one
110 </Link>
111 </p>
112 </div>
113 </div>
114 )
115}
Note: See TracBrowser for help on using the repository browser.