import csv propositions et participants fonctionnel

This commit is contained in:
Yannick Le Duc
2025-08-25 17:00:24 +02:00
parent 63db9983bc
commit 1f3d607e87
4 changed files with 387 additions and 8 deletions

View File

@@ -7,6 +7,7 @@ import { campaignService, participantService, voteService } from '@/lib/services
import AddParticipantModal from '@/components/AddParticipantModal';
import EditParticipantModal from '@/components/EditParticipantModal';
import DeleteParticipantModal from '@/components/DeleteParticipantModal';
import ImportCSVModal from '@/components/ImportCSVModal';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
@@ -14,7 +15,7 @@ import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { Input } from '@/components/ui/input';
import Navigation from '@/components/Navigation';
import AuthGuard from '@/components/AuthGuard';
import { Users, User, Calendar, Mail, Vote, Copy, Check } from 'lucide-react';
import { Users, User, Calendar, Mail, Vote, Copy, Check, Upload } from 'lucide-react';
export const dynamic = 'force-dynamic';
@@ -27,6 +28,7 @@ function CampaignParticipantsPageContent() {
const [showAddModal, setShowAddModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [showImportModal, setShowImportModal] = useState(false);
const [selectedParticipant, setSelectedParticipant] = useState<Participant | null>(null);
const [copiedParticipantId, setCopiedParticipantId] = useState<string | null>(null);
@@ -67,6 +69,26 @@ function CampaignParticipantsPageContent() {
loadData();
};
const handleImportParticipants = async (data: any[]) => {
try {
const participantsToCreate = data.map(row => ({
campaign_id: campaignId,
first_name: row.first_name || '',
last_name: row.last_name || '',
email: row.email || ''
}));
// Créer les participants un par un
for (const participant of participantsToCreate) {
await participantService.create(participant);
}
loadData();
} catch (error) {
console.error('Erreur lors de l\'import des participants:', error);
}
};
const getInitials = (firstName: string, lastName: string) => {
return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
};
@@ -139,9 +161,15 @@ function CampaignParticipantsPageContent() {
{campaign.title}
</p>
</div>
<Button onClick={() => setShowAddModal(true)} size="lg">
Nouveau participant
</Button>
<div className="flex gap-2">
<Button variant="outline" onClick={() => setShowImportModal(true)}>
<Upload className="w-4 h-4 mr-2" />
Importer CSV
</Button>
<Button onClick={() => setShowAddModal(true)} size="lg">
Nouveau participant
</Button>
</div>
</div>
</div>
@@ -366,6 +394,14 @@ function CampaignParticipantsPageContent() {
participant={selectedParticipant}
/>
)}
<ImportCSVModal
isOpen={showImportModal}
onClose={() => setShowImportModal(false)}
onImport={handleImportParticipants}
type="participants"
campaignTitle={campaign?.title}
/>
</div>
</div>
);

View File

@@ -7,13 +7,14 @@ import { campaignService, propositionService } from '@/lib/services';
import AddPropositionModal from '@/components/AddPropositionModal';
import EditPropositionModal from '@/components/EditPropositionModal';
import DeletePropositionModal from '@/components/DeletePropositionModal';
import ImportCSVModal from '@/components/ImportCSVModal';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import Navigation from '@/components/Navigation';
import AuthGuard from '@/components/AuthGuard';
import { FileText, User, Calendar, Mail } from 'lucide-react';
import { FileText, User, Calendar, Mail, Upload } from 'lucide-react';
export const dynamic = 'force-dynamic';
@@ -26,6 +27,7 @@ function CampaignPropositionsPageContent() {
const [showAddModal, setShowAddModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [showImportModal, setShowImportModal] = useState(false);
const [selectedProposition, setSelectedProposition] = useState<Proposition | null>(null);
useEffect(() => {
@@ -65,6 +67,28 @@ function CampaignPropositionsPageContent() {
loadData();
};
const handleImportPropositions = async (data: any[]) => {
try {
const propositionsToCreate = data.map(row => ({
campaign_id: campaignId,
title: row.title || '',
description: row.description || '',
author_first_name: row.author_first_name || 'admin',
author_last_name: row.author_last_name || 'admin',
author_email: row.author_email || 'admin@example.com'
}));
// Créer les propositions une par une
for (const proposition of propositionsToCreate) {
await propositionService.create(proposition);
}
loadData();
} catch (error) {
console.error('Erreur lors de l\'import des propositions:', error);
}
};
const getInitials = (firstName: string, lastName: string) => {
return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
};
@@ -127,9 +151,15 @@ function CampaignPropositionsPageContent() {
{campaign.title}
</p>
</div>
<Button onClick={() => setShowAddModal(true)} size="lg">
Nouvelle proposition
</Button>
<div className="flex gap-2">
<Button variant="outline" onClick={() => setShowImportModal(true)}>
<Upload className="w-4 h-4 mr-2" />
Importer CSV
</Button>
<Button onClick={() => setShowAddModal(true)} size="lg">
Nouvelle proposition
</Button>
</div>
</div>
</div>
@@ -292,6 +322,14 @@ function CampaignPropositionsPageContent() {
proposition={selectedProposition}
/>
)}
<ImportCSVModal
isOpen={showImportModal}
onClose={() => setShowImportModal(false)}
onImport={handleImportPropositions}
type="propositions"
campaignTitle={campaign?.title}
/>
</div>
</div>
);