'use client'; import { useState, useEffect, useCallback } from 'react'; import { Card } from '@/components/ui/Card'; import Button from '@/components/Button'; import toast from 'react-hot-toast'; import { API_BASE_URL } from '@/utils/constants'; import { Trophy, Users, CheckCircle, AlertCircle, Download, Mail, Gift, User, RefreshCw, Trash2, } from 'lucide-react'; interface Participant { id: string; email: string; first_name: string; last_name: string; is_verified: boolean; tickets_played: number; prizes_won: number; } interface DrawResult { draw: { id: string; drawDate: string; status: string; }; winner: { id: string; email: string; name: string; ticketsPlayed: number; }; statistics: { totalParticipants: number; eligibleParticipants: number; criteria: any; }; prize: { name: string; value: string; }; } interface ExistingDraw { id: string; draw_date: string; winner_email: string; winner_name: string; prize_name: string; prize_value: string; total_participants: number; eligible_participants: number; status: string; notified_at: string | null; claimed_at: string | null; } export default function TiragesPage() { const [participants, setParticipants] = useState([]); const [loading, setLoading] = useState(false); const [drawResult, setDrawResult] = useState(null); const [existingDraw, setExistingDraw] = useState(null); const [hasExistingDraw, setHasExistingDraw] = useState(false); // Critères const [minTickets, setMinTickets] = useState(1); const [verifiedOnly, setVerifiedOnly] = useState(true); const [prizeName, setPrizeName] = useState('An de thé'); const [prizeValue, setPrizeValue] = useState('360'); const [allowRedraw, setAllowRedraw] = useState(false); const checkExistingDraw = useCallback(async () => { try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch(`${API_BASE_URL}/draw/check-existing`, { headers: { Authorization: `Bearer ${token}`, }, }); if (response.ok) { const data = await response.json(); setHasExistingDraw(data.data.hasExistingDraw); setExistingDraw(data.data.lastDraw); } } catch (error) { console.error('Erreur:', error); } }, []); const loadParticipants = useCallback(async () => { setLoading(true); try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch( `${API_BASE_URL}/draw/eligible-participants?minTickets=${minTickets}&verified=${verifiedOnly}`, { headers: { Authorization: `Bearer ${token}`, }, } ); if (!response.ok) throw new Error('Erreur lors du chargement'); const data = await response.json(); setParticipants(data.data.participants); toast.success(`${data.data.total} participants éligibles trouvés`); } catch (error: any) { toast.error(error.message || 'Erreur lors du chargement'); setParticipants([]); } finally { setLoading(false); } }, [minTickets, verifiedOnly]); useEffect(() => { checkExistingDraw(); // Charger automatiquement les participants au chargement de la page loadParticipants(); }, [checkExistingDraw, loadParticipants]); const conductDraw = async () => { if (participants.length === 0) { toast.error('Veuillez d\'abord charger les participants éligibles'); return; } const confirmMessage = hasExistingDraw ? `⚠️ ATTENTION: Un tirage a déjà été effectué!\n\nÊtes-vous ABSOLUMENT SÛR de vouloir effectuer un nouveau tirage parmi ${participants.length} participants éligibles?\n\nCeci remplacera le tirage précédent!` : `Êtes-vous sûr de vouloir lancer le tirage au sort parmi ${participants.length} participants éligibles?\n\nCette action est irréversible!`; if (!confirm(confirmMessage)) return; setLoading(true); try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch(`${API_BASE_URL}/draw/conduct`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, body: JSON.stringify({ criteria: { minTickets, verified: verifiedOnly, }, prizeName, prizeValue, allowRedraw: hasExistingDraw, }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'Erreur lors du tirage'); } const data = await response.json(); setDrawResult(data.data); setHasExistingDraw(true); toast.success('🎉 Tirage au sort effectué avec succès!'); await checkExistingDraw(); } catch (error: any) { toast.error(error.message || 'Erreur lors du tirage'); } finally { setLoading(false); } }; const downloadReport = async () => { if (!existingDraw) return; try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch( `${API_BASE_URL}/draw/${existingDraw.id}/report`, { headers: { Authorization: `Bearer ${token}`, }, } ); if (!response.ok) throw new Error('Erreur lors de la génération du rapport'); const data = await response.json(); const report = data.data; // Créer un rapport texte const reportText = ` ================================================= RAPPORT DE TIRAGE AU SORT - THÉ TIP TOP ================================================= 📅 Date du tirage: ${new Date(report.draw.date).toLocaleString('fr-FR')} 👤 Effectué par: ${report.draw.conductedBy.name} (${report.draw.conductedBy.email}) 📊 Statut: ${report.draw.status} ------------------------------------------------- GAGNANT ------------------------------------------------- 🏆 Nom: ${report.winner.firstName} ${report.winner.lastName} 📧 Email: ${report.winner.email} 📱 Téléphone: ${report.winner.phone || 'Non renseigné'} 📍 Ville: ${report.winner.city || 'Non renseignée'} 🎫 Nombre de tickets joués: ${report.winner.totalTickets} ------------------------------------------------- PRIX ------------------------------------------------- 🎁 Nom: ${report.prize.name} 💰 Valeur: ${report.prize.value}€ ------------------------------------------------- STATISTIQUES ------------------------------------------------- 👥 Total de participants: ${report.statistics.totalParticipants} ✅ Participants éligibles: ${report.statistics.eligibleParticipants} 📋 Critères: - Tickets minimum: ${report.statistics.criteria.minTickets} - Email vérifié: ${report.statistics.criteria.verified ? 'Oui' : 'Non'} ------------------------------------------------- TICKETS DU GAGNANT ------------------------------------------------- ${report.winner.tickets.map((t: any, i: number) => `${i + 1}. Code: ${t.code} | Lot: ${t.prize_name} | Statut: ${t.status} | Joué le: ${new Date(t.played_at).toLocaleDateString('fr-FR')}` ).join('\n')} ------------------------------------------------- ${report.draw.notifiedAt ? `📧 Gagnant notifié le: ${new Date(report.draw.notifiedAt).toLocaleString('fr-FR')}\n` : ''}${report.draw.claimedAt ? `✅ Lot récupéré le: ${new Date(report.draw.claimedAt).toLocaleString('fr-FR')}\n` : ''}------------------------------------------------- 📝 Notes: ${report.draw.notes || 'Aucune note'} ================================================= Généré le ${new Date().toLocaleString('fr-FR')} ================================================= `.trim(); // Télécharger le rapport const blob = new Blob([reportText], { type: 'text/plain;charset=utf-8' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `rapport-tirage-${existingDraw.id}.txt`; link.click(); toast.success('Rapport téléchargé!'); } catch (error: any) { toast.error(error.message || 'Erreur lors du téléchargement'); } }; const markAsNotified = async () => { if (!existingDraw) return; try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch( `${API_BASE_URL}/draw/${existingDraw.id}/notify`, { method: 'PUT', headers: { Authorization: `Bearer ${token}`, }, } ); if (!response.ok) throw new Error('Erreur'); toast.success('Gagnant marqué comme notifié'); await checkExistingDraw(); } catch (error: any) { toast.error(error.message || 'Erreur'); } }; const markAsClaimed = async () => { if (!existingDraw) return; const notes = prompt('Notes (optionnel):'); try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch( `${API_BASE_URL}/draw/${existingDraw.id}/claim`, { method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, body: JSON.stringify({ notes }), } ); if (!response.ok) throw new Error('Erreur'); toast.success('Lot marqué comme récupéré'); await checkExistingDraw(); } catch (error: any) { toast.error(error.message || 'Erreur'); } }; const deleteDraw = async () => { if (!existingDraw) return; const confirmMessage = `⚠️ ATTENTION: Cette action est IRRÉVERSIBLE!\n\nVoulez-vous vraiment annuler ce tirage au sort?\n\nGagnant: ${existingDraw.winner_name}\nEmail: ${existingDraw.winner_email}\nPrix: ${existingDraw.prize_name}`; if (!confirm(confirmMessage)) { return; } setLoading(true); try { const token = localStorage.getItem('auth_token') || localStorage.getItem('token'); const response = await fetch( `${API_BASE_URL}/draw/${existingDraw.id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, } ); if (!response.ok) { let errorMessage = 'Erreur lors de l\'annulation'; try { const error = await response.json(); errorMessage = error.message || errorMessage; } catch (e) { // Si le parsing JSON échoue, utiliser le message par défaut errorMessage = `Erreur ${response.status}: ${response.statusText}`; } throw new Error(errorMessage); } toast.success('🗑️ Tirage au sort annulé avec succès!'); setHasExistingDraw(false); setExistingDraw(null); setDrawResult(null); setAllowRedraw(false); await checkExistingDraw(); await loadParticipants(); } catch (error: any) { console.error('Erreur lors de l\'annulation du tirage:', error); toast.error(error.message || 'Erreur lors de l\'annulation'); } finally { setLoading(false); } }; return (
{/* En-tête avec titre du prix */}

Tirage au Sort - {prizeName}

Prix à gagner : {prizeValue}€ • Participants ayant joué au moins {minTickets} ticket{minTickets > 1 ? 's' : ''}

{/* Alerte si un tirage existe déjà */} {hasExistingDraw && existingDraw && (

Un tirage a déjà été effectué!

Date: {new Date(existingDraw.draw_date).toLocaleString('fr-FR')}

Gagnant: {existingDraw.winner_name} ({existingDraw.winner_email})

Prix: {existingDraw.prize_name} - {existingDraw.prize_value}€

Participants éligibles: {existingDraw.eligible_participants} / {existingDraw.total_participants}

Statut:{' '} {existingDraw.status}

{existingDraw.status === 'COMPLETED' && ( )} {existingDraw.status === 'NOTIFIED' && ( )}
)} {/* Liste des participants éligibles */}

Participants Éligibles

{loading ? 'Chargement en cours...' : participants.length > 0 ? `${participants.length} participant${participants.length > 1 ? 's' : ''} éligible${participants.length > 1 ? 's' : ''} au tirage` : 'Aucun participant chargé'}

{loading && (

Chargement des participants éligibles...

)} {!loading && participants.length === 0 && (

Aucun participant éligible

Vérifiez que des participants ont joué au moins {minTickets} ticket{minTickets > 1 ? 's' : ''}

)} {!loading && participants.length > 0 && ( <>
{participants.map((participant, index) => ( ))}
# Nom Complet Email Tickets Joués Lots Gagnés
{index + 1}
{participant.first_name} {participant.last_name}
{participant.email} {participant.tickets_played} {participant.prizes_won}
{/* Bouton de tirage au sort */}

Prêt à lancer le tirage au sort ?

{participants.length} participant{participants.length > 1 ? 's ont' : ' a'} une chance égale de gagner {prizeName} ({prizeValue}€)

)}
{/* Résultat du tirage */} {drawResult && (

Félicitations au gagnant!

{drawResult.winner.name}

{drawResult.winner.email}

{drawResult.winner.ticketsPlayed} ticket(s) joué(s)

{drawResult.prize.name}

{drawResult.prize.value}€

{drawResult.statistics.totalParticipants}

Total participants

{drawResult.statistics.eligibleParticipants}

Éligibles

1

Gagnant

)}
); }