130 lines
5.9 KiB
JavaScript
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>
|
|
);
|
|
}
|