groupe-meditation/frontend/src/pages/Login.jsx
2026-04-17 04:04:04 -04:00

130 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
}