|
@@ -1,78 +1,44 @@
|
|
|
-import { useState, useEffect } from 'react'
|
|
|
|
|
-import { Link, useNavigate } from 'react-router-dom'
|
|
|
|
|
-import { useAuth } from '../context/AuthContext'
|
|
|
|
|
|
|
+import { useEffect, useState } from 'react'
|
|
|
import api from '../api'
|
|
import api from '../api'
|
|
|
-import toast from 'react-hot-toast'
|
|
|
|
|
|
|
|
|
|
export default function Login() {
|
|
export default function Login() {
|
|
|
- const [form, setForm] = useState({ email: '', password: '' })
|
|
|
|
|
- const [loading, setLoading] = useState(false)
|
|
|
|
|
const [oidcConfig, setOidcConfig] = useState({ enabled: false, label: 'Se connecter via SSO' })
|
|
const [oidcConfig, setOidcConfig] = useState({ enabled: false, label: 'Se connecter via SSO' })
|
|
|
- const { login } = useAuth()
|
|
|
|
|
- const navigate = useNavigate()
|
|
|
|
|
|
|
+ const [loading, setLoading] = useState(true)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- api.get('/auth/oidc/config').then(res => setOidcConfig(res.data)).catch(() => {})
|
|
|
|
|
|
|
+ api.get('/auth/oidc/config')
|
|
|
|
|
+ .then(res => setOidcConfig(res.data))
|
|
|
|
|
+ .catch(() => {})
|
|
|
|
|
+ .finally(() => setLoading(false))
|
|
|
}, [])
|
|
}, [])
|
|
|
|
|
|
|
|
- const handleSubmit = async e => {
|
|
|
|
|
- e.preventDefault()
|
|
|
|
|
- setLoading(true)
|
|
|
|
|
- try {
|
|
|
|
|
- await login(form.email, form.password)
|
|
|
|
|
- navigate('/')
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- toast.error(err.response?.data?.error || 'Erreur de connexion')
|
|
|
|
|
- } finally {
|
|
|
|
|
- setLoading(false)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
const handleSso = () => {
|
|
const handleSso = () => {
|
|
|
window.location.href = '/api/auth/oidc/login'
|
|
window.location.href = '/api/auth/oidc/login'
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-blue-100 flex items-center justify-center p-4">
|
|
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-blue-100 flex items-center justify-center p-4">
|
|
|
- <div className="bg-white rounded-2xl shadow-lg p-8 w-full max-w-md">
|
|
|
|
|
- <div className="text-center mb-8">
|
|
|
|
|
- <div className="text-5xl mb-3">🏠</div>
|
|
|
|
|
- <h1 className="text-2xl font-bold text-gray-900">Gestion Locative</h1>
|
|
|
|
|
- <p className="text-gray-500 mt-1">Connectez-vous à votre espace</p>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- {oidcConfig.enabled && (
|
|
|
|
|
- <>
|
|
|
|
|
- <button type="button" onClick={handleSso}
|
|
|
|
|
- className="w-full flex items-center justify-center gap-2 py-3 px-4 border-2 border-blue-600 text-blue-600 rounded-xl font-medium hover:bg-blue-50 transition-colors mb-4">
|
|
|
|
|
- 🔑 {oidcConfig.label}
|
|
|
|
|
- </button>
|
|
|
|
|
- <div className="relative mb-4">
|
|
|
|
|
- <div className="absolute inset-0 flex items-center"><div className="w-full border-t border-gray-200" /></div>
|
|
|
|
|
- <div className="relative text-center text-sm text-gray-400"><span className="bg-white px-3">ou</span></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <div className="bg-white rounded-2xl shadow-lg p-8 w-full max-w-sm text-center">
|
|
|
|
|
+ <div className="text-5xl mb-3">🏠</div>
|
|
|
|
|
+ <h1 className="text-2xl font-bold text-gray-900">Gestion Locative</h1>
|
|
|
|
|
+ <p className="text-gray-500 mt-1 mb-8">Connectez-vous à votre espace</p>
|
|
|
|
|
|
|
|
- <form onSubmit={handleSubmit} className="space-y-4">
|
|
|
|
|
- <div>
|
|
|
|
|
- <label className="label">Email</label>
|
|
|
|
|
- <input className="input" type="email" required value={form.email}
|
|
|
|
|
- onChange={e => setForm(f => ({ ...f, email: e.target.value }))} placeholder="votre@email.com" />
|
|
|
|
|
|
|
+ {loading ? (
|
|
|
|
|
+ <div className="flex justify-center py-4">
|
|
|
|
|
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div>
|
|
|
|
|
- <label className="label">Mot de passe</label>
|
|
|
|
|
- <input className="input" type="password" required value={form.password}
|
|
|
|
|
- onChange={e => setForm(f => ({ ...f, password: e.target.value }))} placeholder="••••••••" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <button type="submit" disabled={loading} className="btn-primary w-full py-3">
|
|
|
|
|
- {loading ? 'Connexion...' : 'Se connecter'}
|
|
|
|
|
|
|
+ ) : oidcConfig.enabled ? (
|
|
|
|
|
+ <button type="button" onClick={handleSso}
|
|
|
|
|
+ className="w-full flex items-center justify-center gap-2 py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-semibold text-base transition-colors shadow">
|
|
|
|
|
+ 🔑 {oidcConfig.label}
|
|
|
</button>
|
|
</button>
|
|
|
- </form>
|
|
|
|
|
- <p className="text-center text-sm text-gray-500 mt-6">
|
|
|
|
|
- Pas encore de compte ? <Link to="/register" className="text-blue-600 hover:underline font-medium">Créer un compte</Link>
|
|
|
|
|
- </p>
|
|
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <div className="bg-orange-50 border border-orange-200 rounded-xl p-4 text-sm text-orange-700">
|
|
|
|
|
+ ⚠️ Le SSO n'est pas configuré.<br />Contactez l'administrateur.
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
+
|