groupe-meditation/frontend/src/pages/Calendrier.jsx
2026-03-04 14:01:00 -05:00

133 lines
5.1 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { api } from '../stores/api';
import { useStore } from '../stores/store';
import PageHeader from '../components/PageHeader';
const CATEGORIES = {
executif: { label: 'Exécutif', bg: 'bg-blue-100', text: 'text-blue-700' },
service: { label: 'Service', bg: 'bg-purple-100', text: 'text-purple-700' },
physique: { label: 'Physique', bg: 'bg-green-100', text: 'text-green-700' },
};
export default function Calendrier() {
const { groupeId } = useStore();
const [entries, setEntries] = useState([]);
const [detailGroupe, setDetailGroupe] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
api.get('/calendrier/').then((data) => {
setEntries(data);
setLoading(false);
}).catch(() => setLoading(false));
}, []);
// Grouper par groupe
const parGroupe = {};
entries.forEach((e) => {
if (!parGroupe[e.groupe_nom]) {
parGroupe[e.groupe_nom] = { nom: e.groupe_nom, id: e.groupe_id, jour: e.jour_reunion, serviteurs: [] };
}
parGroupe[e.groupe_nom].serviteurs.push(e);
});
const groupes = Object.values(parGroupe);
const voirDetail = async (gId) => {
try {
const data = await api.get(`/calendrier/groupe/${gId}`);
setDetailGroupe(data);
} catch {}
};
if (detailGroupe) {
return (
<div className="min-h-screen bg-gray-100">
<div className="bg-aa-blue text-white p-4 flex items-center gap-3">
<button onClick={() => setDetailGroupe(null)} className="text-2xl active:opacity-60">←</button>
<div>
<h1 className="text-lg font-bold">{detailGroupe.groupe?.nom}</h1>
<p className="text-blue-200 text-xs">
{detailGroupe.groupe?.jour_reunion ? `Réunion le ${detailGroupe.groupe.jour_reunion}` : 'Calendrier'}
</p>
</div>
</div>
<div className="p-4 space-y-2">
{detailGroupe.groupe?.adresse && (
<div className="bg-white rounded-2xl p-4 shadow-sm">
<p className="text-xs text-gray-400">Adresse</p>
<p className="text-gray-700">{detailGroupe.groupe.adresse}</p>
</div>
)}
{detailGroupe.serviteurs?.map((s, i) => {
const cat = CATEGORIES[s.categorie] || CATEGORIES.physique;
return (
<div key={i} className="bg-white rounded-2xl p-4 shadow-sm flex items-center justify-between">
<div>
<p className="font-bold text-gray-800">{s.poste}</p>
<p className="text-sm text-gray-500">{s.prenom}</p>
</div>
<span className={`text-xs px-2 py-1 rounded-full font-bold ${cat.bg} ${cat.text}`}>
{cat.label}
</span>
</div>
);
})}
{(!detailGroupe.serviteurs || detailGroupe.serviteurs.length === 0) && (
<p className="text-center text-gray-400 py-8">Aucun serviteur assigné</p>
)}
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-100">
<PageHeader titre="Calendrier district" sousTitre="C2 — Serviteurs du district 87-16" />
<div className="p-4 space-y-4">
{loading ? (
<p className="text-center text-gray-400 py-8">Chargement...</p>
) : groupes.length === 0 ? (
<div className="text-center py-12">
<p className="text-4xl mb-2">📅</p>
<p className="text-gray-500">Aucune donnée de calendrier</p>
</div>
) : (
groupes.map((g) => {
const isMon = g.id === groupeId;
return (
<button
key={g.id}
onClick={() => voirDetail(g.id)}
className={`w-full text-left rounded-2xl p-4 shadow-sm active:scale-[0.98] transition ${
isMon ? 'bg-blue-50 border-2 border-blue-300' : 'bg-white border border-gray-100'
}`}
>
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-2">
{isMon && <span className="text-yellow-500">⭐</span>}
<h3 className="font-bold text-gray-800">{g.nom}</h3>
</div>
<span className="text-gray-300 text-lg">→</span>
</div>
{g.jour && (
<p className="text-xs text-gray-400 mb-2">Réunion le {g.jour}</p>
)}
<div className="flex flex-wrap gap-1">
{g.serviteurs.slice(0, 4).map((s, i) => (
<span key={i} className="text-xs bg-gray-100 text-gray-600 px-2 py-1 rounded-full">
{s.poste_nom}: {s.membre_prenom}
</span>
))}
{g.serviteurs.length > 4 && (
<span className="text-xs text-gray-400 px-2 py-1">+{g.serviteurs.length - 4}</span>
)}
</div>
</button>
);
})
)}
</div>
</div>
);
}