153 lines
5.6 KiB
JavaScript
153 lines
5.6 KiB
JavaScript
import { useState } from 'react'
|
|
import { Link, useNavigate, useLocation } from 'react-router-dom'
|
|
import { loginApi } from '../services/auth'
|
|
import { useAuth } from '../context/AuthContext'
|
|
|
|
export default function Connexion() {
|
|
const navigate = useNavigate()
|
|
const location = useLocation()
|
|
const { login } = useAuth()
|
|
const justRegistered = location.state?.registered === true
|
|
const [form, setForm] = useState({ email: '', password: '' })
|
|
const [showPassword, setShowPassword] = useState(false)
|
|
const [error, setError] = useState('')
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
const handleChange = (e) => setForm({ ...form, [e.target.name]: e.target.value })
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault()
|
|
setError('')
|
|
setLoading(true)
|
|
try {
|
|
const { token, user } = await loginApi(form)
|
|
login(user, token)
|
|
if (user.role === 'ADMIN') navigate('/admin')
|
|
else if (user.role === 'EMPLOYEE') navigate('/employe')
|
|
else navigate('/mes-gains')
|
|
} catch (err) {
|
|
setError(err.message)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white flex flex-col justify-center px-8 py-12 max-w-sm mx-auto">
|
|
|
|
<div className="mb-8">
|
|
<h1 className="text-4xl font-bold italic font-serif text-[#006B6B]">Se connecter</h1>
|
|
<p className="text-gray-500 mt-1 text-sm">Connexion à votre espace</p>
|
|
</div>
|
|
|
|
{justRegistered && (
|
|
<div className="mb-4 px-4 py-3 rounded-lg bg-green-50 border border-green-200 text-green-700 text-sm">
|
|
Compte créé avec succès ! Connectez-vous.
|
|
</div>
|
|
)}
|
|
|
|
{error && (
|
|
<div className="mb-4 px-4 py-3 rounded-lg bg-red-50 border border-red-200 text-red-600 text-sm">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-5">
|
|
|
|
<div>
|
|
<label htmlFor="email" className="block text-sm font-medium text-gray-800 mb-1">
|
|
Adresse email <span className="text-gray-800">*</span>
|
|
</label>
|
|
<input
|
|
type="email"
|
|
id="email"
|
|
name="email"
|
|
value={form.email}
|
|
onChange={handleChange}
|
|
required
|
|
placeholder="Votre email"
|
|
className="w-full border border-gray-200 rounded-lg px-4 py-3 text-sm text-gray-700 placeholder-gray-300 focus:outline-none focus:ring-1 focus:ring-[#006B6B] focus:border-[#006B6B]"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="password" className="block text-sm font-medium text-gray-800 mb-1">
|
|
Mot de passe <span className="text-gray-800">*</span>
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
type={showPassword ? 'text' : 'password'}
|
|
id="password"
|
|
name="password"
|
|
value={form.password}
|
|
onChange={handleChange}
|
|
required
|
|
placeholder="Votre mot de passe"
|
|
className="w-full border border-gray-200 rounded-lg px-4 py-3 pr-12 text-sm text-gray-700 placeholder-gray-300 focus:outline-none focus:ring-1 focus:ring-[#006B6B] focus:border-[#006B6B]"
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowPassword(!showPassword)}
|
|
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
|
aria-label="Afficher/masquer le mot de passe"
|
|
>
|
|
<div className="w-6 h-6 rounded-full border-2 border-gray-400 flex items-center justify-center">
|
|
{showPassword && (
|
|
<div className="w-1.5 h-1.5 rounded-full bg-gray-400" />
|
|
)}
|
|
</div>
|
|
</button>
|
|
</div>
|
|
<div className="text-right mt-1">
|
|
<button type="button" className="text-xs text-gray-400 hover:text-[#006B6B] hover:underline">
|
|
Mot de passe oublié ?
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={loading}
|
|
className="w-full bg-[#006B6B] hover:bg-[#005959] disabled:opacity-60 text-white font-medium py-3 rounded-lg transition-colors"
|
|
>
|
|
{loading ? 'Connexion...' : 'Se connecter'}
|
|
</button>
|
|
</form>
|
|
|
|
<div className="flex items-center gap-3 my-6">
|
|
<div className="flex-1 h-px bg-gray-200" />
|
|
<span className="text-sm text-gray-500">Ou</span>
|
|
<div className="flex-1 h-px bg-gray-200" />
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-3">
|
|
<button
|
|
type="button"
|
|
className="flex items-center justify-center gap-2 border border-gray-200 rounded-lg py-3 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
|
|
>
|
|
<div className="w-5 h-5 rounded-full border border-gray-400 flex items-center justify-center text-[10px] font-bold text-gray-500">
|
|
G
|
|
</div>
|
|
Google
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="flex items-center justify-center gap-2 border border-gray-200 rounded-lg py-3 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
|
|
>
|
|
<div className="w-5 h-5 rounded-full border border-gray-400 flex items-center justify-center text-[10px] font-bold text-gray-500">
|
|
f
|
|
</div>
|
|
Facebook
|
|
</button>
|
|
</div>
|
|
|
|
<p className="text-center text-sm text-gray-500 mt-8">
|
|
Pas encore de compte ?{' '}
|
|
<Link to="/inscription" className="text-gray-700 font-medium hover:underline">
|
|
S'inscrire
|
|
</Link>
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|