130 lines
4.7 KiB
JavaScript
130 lines
4.7 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
||
import { useStore } from '../stores/store';
|
||
|
||
export default function Login() {
|
||
const { login, loading, error, groupes, loadGroupes, setPage } = useStore();
|
||
const [courriel, setCourriel] = useState(localStorage.getItem('gm_courriel') || '');
|
||
const [pin, setPin] = useState('');
|
||
const [groupeId, setGroupeId] = useState(localStorage.getItem('gm_groupe_id') || '');
|
||
const [seSouvenir, setSeSouvenir] = useState(!!localStorage.getItem('gm_courriel'));
|
||
|
||
useEffect(() => {
|
||
if (groupes.length === 0) loadGroupes();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (groupes.length === 1 && !groupeId) setGroupeId(groupes[0].id);
|
||
}, [groupes]);
|
||
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
if (!courriel || !pin || !groupeId) return;
|
||
try {
|
||
await login(courriel, pin, groupeId, seSouvenir);
|
||
} catch {}
|
||
};
|
||
|
||
const groupeActif = groupes.find((g) => g.id === groupeId);
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gradient-to-b from-aa-blue to-blue-900 flex flex-col items-center justify-center p-6">
|
||
<div className="text-center mb-6">
|
||
<div className="text-5xl mb-3">☮️</div>
|
||
<h1 className="text-2xl font-bold text-white">Groupe Méditation</h1>
|
||
<p className="text-blue-200 text-sm mt-1">District 87-16 · Région 87</p>
|
||
</div>
|
||
|
||
{/* Infos du groupe */}
|
||
{groupeActif && (
|
||
<div className="w-full max-w-sm bg-white/10 rounded-2xl p-4 mb-4 text-blue-100 text-sm space-y-1">
|
||
{groupeActif.adresse_local && (
|
||
<p className="flex items-start gap-2">
|
||
<span>📍</span>
|
||
<span>{groupeActif.adresse_local}</span>
|
||
</p>
|
||
)}
|
||
{groupeActif.jour_reunion && (
|
||
<p className="flex items-center gap-2">
|
||
<span>📅</span>
|
||
<span>
|
||
{groupeActif.jour_reunion.charAt(0).toUpperCase() + groupeActif.jour_reunion.slice(1)}
|
||
{groupeActif.heure_reunion && ` à ${groupeActif.heure_reunion}`}
|
||
</span>
|
||
</p>
|
||
)}
|
||
{groupeActif.format_reunion && (
|
||
<p className="flex items-center gap-2">
|
||
<span>📖</span>
|
||
<span>{groupeActif.format_reunion}</span>
|
||
</p>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
<form onSubmit={handleSubmit} className="w-full max-w-sm bg-white rounded-2xl shadow-xl p-6 space-y-4">
|
||
{groupes.length > 1 && (
|
||
<select
|
||
value={groupeId}
|
||
onChange={(e) => setGroupeId(e.target.value)}
|
||
className="w-full p-4 bg-gray-50 rounded-xl text-lg border-0 focus:ring-2 focus:ring-aa-blue"
|
||
>
|
||
<option value="">Choisir le groupe</option>
|
||
{groupes.map((g) => (
|
||
<option key={g.id} value={g.id}>{g.nom}</option>
|
||
))}
|
||
</select>
|
||
)}
|
||
|
||
<input
|
||
type="email"
|
||
placeholder="Adresse courriel"
|
||
value={courriel}
|
||
onChange={(e) => setCourriel(e.target.value)}
|
||
className="w-full p-4 bg-gray-50 rounded-xl text-lg border-0 focus:ring-2 focus:ring-aa-blue"
|
||
autoComplete="email"
|
||
inputMode="email"
|
||
/>
|
||
|
||
<input
|
||
type="password"
|
||
inputMode="numeric"
|
||
pattern="[0-9]*"
|
||
maxLength={4}
|
||
placeholder="PIN (4 chiffres)"
|
||
value={pin}
|
||
onChange={(e) => setPin(e.target.value.replace(/\D/g, '').slice(0, 4))}
|
||
className="w-full p-4 bg-gray-50 rounded-xl text-lg text-center tracking-[1em] border-0 focus:ring-2 focus:ring-aa-blue"
|
||
/>
|
||
|
||
<label className="flex items-center gap-2 text-sm text-gray-500 cursor-pointer">
|
||
<input type="checkbox" checked={seSouvenir}
|
||
onChange={(e) => setSeSouvenir(e.target.checked)}
|
||
className="rounded border-gray-300 text-aa-blue focus:ring-aa-blue" />
|
||
Se souvenir de moi
|
||
</label>
|
||
|
||
{error && (
|
||
<p className="text-red-500 text-sm text-center bg-red-50 p-3 rounded-lg">{error}</p>
|
||
)}
|
||
|
||
<button
|
||
type="submit"
|
||
disabled={loading || !courriel || pin.length !== 4 || !groupeId}
|
||
className="w-full p-4 bg-aa-blue text-white rounded-xl text-lg font-bold disabled:opacity-40 active:scale-[0.97] transition"
|
||
>
|
||
{loading ? '...' : 'Connexion'}
|
||
</button>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={() => setPage('inscription')}
|
||
className="w-full p-3 text-aa-blue text-sm font-medium"
|
||
>
|
||
J'ai un code d'invitation →
|
||
</button>
|
||
</form>
|
||
|
||
<p className="text-blue-300 text-xs mt-6">100% logiciel libre · Hébergé au Québec</p>
|
||
</div>
|
||
);
|
||
}
|