ajout de l'export des votes dans un fichier ODS avec toutes les données (anonymisées par défaut - réglable dans les paramètres)

This commit is contained in:
Yannick Le Duc
2025-08-27 18:38:20 +02:00
parent c94c8038f3
commit b7ce1145e3
10 changed files with 979 additions and 23 deletions

View File

@@ -28,6 +28,7 @@ import {
Target as TargetIcon,
Hash
} from 'lucide-react';
import { ExportStatsButton } from '@/components/ExportStatsButton';
export const dynamic = 'force-dynamic';
@@ -264,6 +265,18 @@ function CampaignStatsPageContent() {
{campaign.description}
</p>
</div>
<div className="flex gap-2">
<ExportStatsButton
campaignTitle={campaign.title}
propositions={propositions}
participants={participants}
votes={votes}
budgetPerUser={campaign.budget_per_user}
propositionStats={propositionStats}
disabled={loading}
/>
</div>
</div>
</div>

View File

@@ -9,7 +9,8 @@ import { Label } from '@/components/ui/label';
import Navigation from '@/components/Navigation';
import AuthGuard from '@/components/AuthGuard';
import SmtpSettingsForm from '@/components/SmtpSettingsForm';
import { Settings, Monitor, Save, CheckCircle, Mail, FileText } from 'lucide-react';
import { Settings, Monitor, Save, CheckCircle, Mail, FileText, Download } from 'lucide-react';
import { ExportAnonymizationSelect, AnonymizationLevel } from '@/components/ExportAnonymizationSelect';
export const dynamic = 'force-dynamic';
@@ -21,6 +22,7 @@ function SettingsPageContent() {
const [randomizePropositions, setRandomizePropositions] = useState(false);
const [proposePageMessage, setProposePageMessage] = useState('');
const [footerMessage, setFooterMessage] = useState('');
const [exportAnonymization, setExportAnonymization] = useState<AnonymizationLevel>('full');
useEffect(() => {
loadSettings();
@@ -43,6 +45,10 @@ function SettingsPageContent() {
// Charger le message du bas de page
const footerValue = await settingsService.getStringValue('footer_message', 'Développé avec ❤️ pour faciliter la démocratie participative - [Logiciel libre et open source](GITURL) et transparent pour tous');
setFooterMessage(footerValue);
// Charger le niveau d'anonymisation des exports
const anonymizationValue = await settingsService.getStringValue('export_anonymization', 'full') as AnonymizationLevel;
setExportAnonymization(anonymizationValue);
} catch (error) {
console.error('Erreur lors du chargement des paramètres:', error);
} finally {
@@ -60,6 +66,7 @@ function SettingsPageContent() {
await settingsService.setBooleanValue('randomize_propositions', randomizePropositions);
await settingsService.setStringValue('propose_page_message', proposePageMessage);
await settingsService.setStringValue('footer_message', footerMessage);
await settingsService.setStringValue('export_anonymization', exportAnonymization);
setSaved(true);
setTimeout(() => setSaved(false), 2000);
} catch (error) {
@@ -216,24 +223,36 @@ function SettingsPageContent() {
</CardContent>
</Card>
{/* Exports Category */}
<Card>
<CardHeader>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-purple-100 dark:bg-purple-900 rounded-lg flex items-center justify-center">
<Download className="w-5 h-5 text-purple-600 dark:text-purple-300" />
</div>
<div>
<CardTitle className="text-xl">Exports</CardTitle>
<CardDescription>
Paramètres de confidentialité pour les exports de données
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className="space-y-6">
<div className="p-4 bg-slate-50 dark:bg-slate-800 rounded-lg">
<ExportAnonymizationSelect
value={exportAnonymization}
onValueChange={setExportAnonymization}
/>
</div>
</CardContent>
</Card>
{/* Email Category */}
<SmtpSettingsForm onSave={() => {
setSaved(true);
setTimeout(() => setSaved(false), 2000);
}} />
{/* Future Categories Placeholder */}
<Card className="border-dashed">
<CardContent className="p-8 text-center">
<Settings className="w-12 h-12 text-slate-400 mx-auto mb-4" />
<h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100 mb-2">
Plus de catégories à venir
</h3>
<p className="text-slate-600 dark:text-slate-300">
D'autres catégories de paramètres seront ajoutées prochainement.
</p>
</CardContent>
</Card>
</div>
</div>
</div>