groupe-meditation/frontend/src/pages/Rapports.jsx

104 lines
4.2 KiB
React
Raw Normal View History

2026-03-04 14:01:00 -05:00
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 [loading, setLoading] = useState(true);
const [generating, setGenerating] = useState(null);
useEffect(() => {
api.get('/rapports/disponibles').then((data) => {
setDisponibles(data);
setLoading(false);
}).catch(() => setLoading(false));
}, []);
const telecharger = async (type, annee, mois) => {
const key = `${type}-${annee}-${mois}`;
setGenerating(key);
try {
const token = localStorage.getItem('gm_token');
const url = `/api/rapports/${type}/${annee}/${mois}`;
const res = await fetch(url, {
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 = `rapport_${type}_${annee}_${mois.toString().padStart(2, '0')}.pdf`;
a.click();
URL.revokeObjectURL(a.href);
} catch (e) {
alert(`Erreur: ${e.message}`);
}
setGenerating(null);
};
return (
<div className="min-h-screen bg-gray-100">
<PageHeader titre="Rapports PDF" sousTitre="C1 — Finances, réunions" />
<div className="p-4 space-y-4">
{loading ? (
<p className="text-center text-gray-400 py-8">Chargement...</p>
) : disponibles.length === 0 ? (
<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>
) : (
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)}
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)}
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>
))
)}
</div>
</div>
);
}