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

130 lines
5.9 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { api } from '../stores/api';
import PageHeader from '../components/PageHeader';
const MOIS_FR = [
'', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre',
];
export default function Rapports() {
const [disponibles, setDisponibles] = useState([]);
const [anneesResolutions, setAnneesResolutions] = useState([]);
const [loading, setLoading] = useState(true);
const [generating, setGenerating] = useState(null);
useEffect(() => {
Promise.all([
api.get('/rapports/disponibles'),
api.get('/rapports/resolutions/annees'),
]).then(([dispo, annees]) => {
setDisponibles(dispo);
setAnneesResolutions(annees);
setLoading(false);
}).catch(() => setLoading(false));
}, []);
const telecharger = async (path, key, filename) => {
setGenerating(key);
try {
const token = localStorage.getItem('gm_token');
const res = await fetch(`/api/rapports/${path}`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error('Erreur de génération');
const blob = await res.blob();
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = filename;
a.click();
URL.revokeObjectURL(a.href);
} catch (e) {
alert(`Erreur: ${e.message}`);
}
setGenerating(null);
};
const vide = disponibles.length === 0 && anneesResolutions.length === 0;
return (
<div className="min-h-screen bg-gray-100">
<PageHeader titre="Rapports PDF" sousTitre="C1 — Finances, réunions, résolutions" />
<div className="p-4 space-y-4">
{loading ? (
<p className="text-center text-gray-400 py-8">Chargement...</p>
) : vide ? (
<div className="text-center py-12">
<p className="text-4xl mb-2">📄</p>
<p className="text-gray-500">Aucun rapport disponible</p>
<p className="text-gray-400 text-sm mt-1">Les rapports apparaîtront après les premières saisies</p>
</div>
) : (
<>
{/* Rapports mensuels */}
{disponibles.map((m) => (
<div key={`${m.annee}-${m.mois}`} className="bg-white rounded-2xl p-4 shadow-sm">
<h3 className="font-bold text-gray-800 mb-3">
{MOIS_FR[m.mois]} {m.annee}
</h3>
<div className="grid gap-2">
{m.finances && (
<button
onClick={() => telecharger(`finances/${m.annee}/${m.mois}`, `finances-${m.annee}-${m.mois}`, `rapport_finances_${m.annee}_${String(m.mois).padStart(2,'0')}.pdf`)}
disabled={generating === `finances-${m.annee}-${m.mois}`}
className="flex items-center gap-3 p-3 bg-green-50 rounded-xl text-left active:scale-[0.98] transition border border-green-200"
>
<span className="text-xl">💰</span>
<div className="flex-1">
<p className="font-bold text-green-800 text-sm">Rapport financier</p>
<p className="text-xs text-green-600">Collectes, dépenses, solde</p>
</div>
<span className="text-green-400">{generating === `finances-${m.annee}-${m.mois}` ? '⏳' : '↓'}</span>
</button>
)}
{m.reunions && (
<button
onClick={() => telecharger(`reunions/${m.annee}/${m.mois}`, `reunions-${m.annee}-${m.mois}`, `rapport_reunions_${m.annee}_${String(m.mois).padStart(2,'0')}.pdf`)}
disabled={generating === `reunions-${m.annee}-${m.mois}`}
className="flex items-center gap-3 p-3 bg-purple-50 rounded-xl text-left active:scale-[0.98] transition border border-purple-200"
>
<span className="text-xl">🎤</span>
<div className="flex-1">
<p className="font-bold text-purple-800 text-sm">Résumé des réunions</p>
<p className="text-xs text-purple-600">Thèmes, annonces, animateurs</p>
</div>
<span className="text-purple-400">{generating === `reunions-${m.annee}-${m.mois}` ? '⏳' : '↓'}</span>
</button>
)}
</div>
</div>
))}
{/* Registre des résolutions */}
{anneesResolutions.length > 0 && (
<div className="bg-white rounded-2xl p-4 shadow-sm">
<h3 className="font-bold text-gray-800 mb-3">📜 Registre des résolutions</h3>
<div className="grid gap-2">
{anneesResolutions.map((a) => (
<button key={a.annee}
onClick={() => telecharger(`resolutions/${a.annee}`, `res-${a.annee}`, `registre_resolutions_${a.annee}.pdf`)}
disabled={generating === `res-${a.annee}`}
className="flex items-center gap-3 p-3 bg-orange-50 rounded-xl text-left active:scale-[0.98] transition border border-orange-200"
>
<span className="text-xl">📜</span>
<div className="flex-1">
<p className="font-bold text-orange-800 text-sm">Résolutions {a.annee}</p>
<p className="text-xs text-orange-600">Propositions adoptées et rejetées</p>
</div>
<span className="text-orange-400">{generating === `res-${a.annee}` ? '⏳' : '↓'}</span>
</button>
))}
</div>
</div>
)}
</>
)}
</div>
</div>
);
}