Ajouter selection de groupe avant connexion
This commit is contained in:
parent
393f9243cb
commit
1ffce6e92c
1 changed files with 116 additions and 96 deletions
|
|
@ -1,11 +1,17 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useStore } from '../stores/store';
|
import { useStore } from '../stores/store';
|
||||||
|
|
||||||
|
const jourLabel = (jour) => {
|
||||||
|
if (!jour) return 'Jour à préciser';
|
||||||
|
return jour.charAt(0).toUpperCase() + jour.slice(1);
|
||||||
|
};
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const { login, loading, error, groupes, loadGroupes, setPage } = useStore();
|
const { login, loading, error, groupes, loadGroupes, setPage } = useStore();
|
||||||
const [courriel, setCourriel] = useState(localStorage.getItem('gm_courriel') || '');
|
const [courriel, setCourriel] = useState(localStorage.getItem('gm_courriel') || '');
|
||||||
const [pin, setPin] = useState('');
|
const [pin, setPin] = useState('');
|
||||||
const [groupeId, setGroupeId] = useState(localStorage.getItem('gm_groupe_id') || '');
|
const [groupeId, setGroupeId] = useState(localStorage.getItem('gm_groupe_id') || '');
|
||||||
|
const [groupeOuvert, setGroupeOuvert] = useState(localStorage.getItem('gm_groupe_id') || '');
|
||||||
const [seSouvenir, setSeSouvenir] = useState(!!localStorage.getItem('gm_courriel'));
|
const [seSouvenir, setSeSouvenir] = useState(!!localStorage.getItem('gm_courriel'));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -18,6 +24,7 @@ export default function Login() {
|
||||||
if (groupeId && groupeExiste) return;
|
if (groupeId && groupeExiste) return;
|
||||||
const prochainGroupeId = groupes.length === 1 ? groupes[0].id : '';
|
const prochainGroupeId = groupes.length === 1 ? groupes[0].id : '';
|
||||||
setGroupeId(prochainGroupeId);
|
setGroupeId(prochainGroupeId);
|
||||||
|
setGroupeOuvert(prochainGroupeId);
|
||||||
if (prochainGroupeId) {
|
if (prochainGroupeId) {
|
||||||
localStorage.setItem('gm_groupe_id', prochainGroupeId);
|
localStorage.setItem('gm_groupe_id', prochainGroupeId);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -25,6 +32,13 @@ export default function Login() {
|
||||||
}
|
}
|
||||||
}, [groupes, groupeId]);
|
}, [groupes, groupeId]);
|
||||||
|
|
||||||
|
const ouvrirGroupe = (id) => {
|
||||||
|
const prochain = groupeOuvert === id ? '' : id;
|
||||||
|
setGroupeOuvert(prochain);
|
||||||
|
setGroupeId(id);
|
||||||
|
localStorage.setItem('gm_groupe_id', id);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!courriel || !pin || !groupeId) return;
|
if (!courriel || !pin || !groupeId) return;
|
||||||
|
|
@ -33,63 +47,66 @@ export default function Login() {
|
||||||
} catch {}
|
} catch {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupeActif = groupes.find((g) => g.id === groupeId);
|
|
||||||
|
|
||||||
return (
|
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="min-h-screen bg-gradient-to-b from-aa-blue to-blue-900 p-4">
|
||||||
<div className="text-center mb-6">
|
<div className="mx-auto flex min-h-screen w-full max-w-md flex-col py-6">
|
||||||
|
<div className="text-center mb-5">
|
||||||
<div className="text-5xl mb-3">☮️</div>
|
<div className="text-5xl mb-3">☮️</div>
|
||||||
<h1 className="text-2xl font-bold text-white">Groupe Méditation</h1>
|
<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>
|
<p className="text-blue-200 text-sm mt-1">Choisir un groupe</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Infos du groupe */}
|
<a
|
||||||
{groupeActif && (
|
href="/presentation.html"
|
||||||
<div className="w-full max-w-sm bg-white/10 rounded-2xl p-4 mb-4 text-blue-100 text-sm space-y-1">
|
className="mb-4 block w-full rounded-xl bg-white/95 p-4 text-center text-sm font-bold text-aa-blue shadow-lg active:scale-[0.98]"
|
||||||
{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>
|
Découvrir l'application
|
||||||
{groupes.map((g) => (
|
</a>
|
||||||
<option key={g.id} value={g.id}>{g.nom}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
<div className="flex-1 space-y-3 pb-6">
|
||||||
|
{groupes.length === 0 ? (
|
||||||
|
<div className="rounded-2xl bg-white/10 p-5 text-center text-blue-100">
|
||||||
|
Chargement des groupes...
|
||||||
|
</div>
|
||||||
|
) : groupes.map((groupe) => {
|
||||||
|
const ouvert = groupeOuvert === groupe.id;
|
||||||
|
const horaire = `${jourLabel(groupe.jour_reunion)}${groupe.heure_reunion ? ` · ${groupe.heure_reunion}` : ''}`;
|
||||||
|
return (
|
||||||
|
<section key={groupe.id} className="overflow-hidden rounded-2xl bg-white shadow-xl">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => ouvrirGroupe(groupe.id)}
|
||||||
|
className="flex w-full items-center justify-between gap-3 p-4 text-left active:bg-blue-50"
|
||||||
|
aria-expanded={ouvert}
|
||||||
|
>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span className="block truncate text-lg font-bold text-gray-900">{groupe.nom}</span>
|
||||||
|
<span className="mt-1 block text-sm font-semibold text-aa-blue">{horaire}</span>
|
||||||
|
</span>
|
||||||
|
<span className={`shrink-0 text-2xl text-aa-blue transition ${ouvert ? 'rotate-180' : ''}`}>⌄</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{ouvert && (
|
||||||
|
<div className="border-t border-gray-100 p-4 pt-3">
|
||||||
|
<div className="mb-4 space-y-2 rounded-xl bg-gray-50 p-3 text-sm text-gray-700">
|
||||||
|
{groupe.adresse_local && (
|
||||||
|
<p><span className="font-semibold text-gray-900">Lieu : </span>{groupe.adresse_local}</p>
|
||||||
|
)}
|
||||||
|
{groupe.format_reunion && (
|
||||||
|
<p><span className="font-semibold text-gray-900">Format : </span>{groupe.format_reunion}</p>
|
||||||
|
)}
|
||||||
|
{groupe.district && (
|
||||||
|
<p><span className="font-semibold text-gray-900">District : </span>{groupe.district}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Adresse courriel ou identifiant"
|
placeholder="Adresse courriel ou identifiant"
|
||||||
value={courriel}
|
value={courriel}
|
||||||
onChange={(e) => setCourriel(e.target.value)}
|
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"
|
className="w-full rounded-xl border-0 bg-gray-50 p-4 text-lg focus:ring-2 focus:ring-aa-blue"
|
||||||
autoComplete="username"
|
autoComplete="username"
|
||||||
inputMode="email"
|
inputMode="email"
|
||||||
/>
|
/>
|
||||||
|
|
@ -99,48 +116,51 @@ export default function Login() {
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
maxLength={4}
|
maxLength={4}
|
||||||
placeholder="PIN (4 chiffres)"
|
placeholder="PIN"
|
||||||
value={pin}
|
value={pin}
|
||||||
onChange={(e) => setPin(e.target.value.replace(/\D/g, '').slice(0, 4))}
|
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"
|
className="w-full rounded-xl border-0 bg-gray-50 p-4 text-center text-lg tracking-[0.8em] focus:ring-2 focus:ring-aa-blue"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label className="flex items-center gap-2 text-sm text-gray-500 cursor-pointer">
|
<label className="flex cursor-pointer items-center gap-2 text-sm text-gray-500">
|
||||||
<input type="checkbox" checked={seSouvenir}
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={seSouvenir}
|
||||||
onChange={(e) => setSeSouvenir(e.target.checked)}
|
onChange={(e) => setSeSouvenir(e.target.checked)}
|
||||||
className="rounded border-gray-300 text-aa-blue focus:ring-aa-blue" />
|
className="rounded border-gray-300 text-aa-blue focus:ring-aa-blue"
|
||||||
|
/>
|
||||||
Se souvenir de moi
|
Se souvenir de moi
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<p className="text-red-500 text-sm text-center bg-red-50 p-3 rounded-lg">{error}</p>
|
<p className="rounded-lg bg-red-50 p-3 text-center text-sm text-red-500">{error}</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={loading || !courriel || pin.length !== 4 || !groupeId}
|
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"
|
className="w-full rounded-xl bg-aa-blue p-4 text-lg font-bold text-white transition active:scale-[0.97] disabled:opacity-40"
|
||||||
>
|
>
|
||||||
{loading ? '...' : 'Connexion'}
|
{loading ? '...' : 'Connexion'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<a
|
|
||||||
href="/presentation.html"
|
|
||||||
className="block w-full p-3 bg-blue-50 text-aa-blue rounded-xl text-center text-sm font-bold"
|
|
||||||
>
|
|
||||||
Découvrir l'application
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setPage('inscription')}
|
onClick={() => setPage('inscription')}
|
||||||
className="w-full p-3 text-aa-blue text-sm font-medium"
|
className="w-full p-3 text-sm font-medium text-aa-blue"
|
||||||
>
|
>
|
||||||
J'ai un code d'invitation →
|
J'ai un code d'invitation →
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
<p className="text-blue-300 text-xs mt-6">100% logiciel libre · Hébergé au Québec</p>
|
<p className="text-center text-xs text-blue-300">100% logiciel libre · Hébergé au Québec</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue