'use client'; import { useState, useEffect, useCallback } from 'react'; import { adminService } from '@/services/admin.service'; import { Ticket, PaginatedResponse } from '@/types'; export default function TicketManagement() { const [tickets, setTickets] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [totalTickets, setTotalTickets] = useState(0); const [filterStatus, setFilterStatus] = useState(''); const [filterPrizeType, setFilterPrizeType] = useState(''); const [selectedTicket, setSelectedTicket] = useState(null); const [showDebug, setShowDebug] = useState(false); const loadTickets = useCallback(async () => { try { setLoading(true); setError(null); // Construire les filtres const filters: any = {}; if (filterStatus) filters.status = filterStatus; if (filterPrizeType) filters.prizeType = filterPrizeType; const response = await adminService.getAllTickets( page, 20, Object.keys(filters).length > 0 ? filters : undefined ); // Vérifier si la réponse est directement un tableau ou un objet avec data let ticketsData: Ticket[] = []; let total = 0; let totalPagesCount = 1; if (Array.isArray(response)) { // Si la réponse est directement un tableau console.log('📦 Réponse est un tableau direct'); ticketsData = response; total = response.length; totalPagesCount = 1; } else if (response.data && Array.isArray(response.data)) { // Si la réponse est un objet avec data console.log('📦 Réponse est un objet avec data'); ticketsData = response.data; total = response.total || response.data.length; totalPagesCount = response.totalPages || 1; } else { console.warn('⚠️ Format de réponse inattendu:', response); } console.log('🎯 Tickets à afficher:', ticketsData); setTickets(ticketsData); setTotalPages(totalPagesCount); setTotalTickets(total); } catch (err: any) { console.error('❌ Erreur lors du chargement:', err); // Messages d'erreur personnalisés selon le type d'erreur let errorMessage = 'Erreur lors du chargement des tickets'; if (err.status === 401) { errorMessage = '🔐 Non autorisé (401) - Votre session a expiré ou votre token est invalide. Veuillez vous reconnecter.'; } else if (err.status === 403) { errorMessage = '🚫 Accès refusé (403) - Vous n\'avez pas les permissions administrateur nécessaires.'; } else if (err.status === 0 || err.message.includes('fetch')) { errorMessage = '🔌 Impossible de contacter le serveur. Vérifiez que le backend est démarré sur http://localhost:4000'; } else { errorMessage = err.message || errorMessage; } setError(errorMessage); setTickets([]); setTotalTickets(0); } finally { setLoading(false); } }, [page, filterStatus, filterPrizeType]); useEffect(() => { loadTickets(); }, [loadTickets]); const getStatusBadgeColor = (status: string) => { switch (status) { case 'PENDING': return 'bg-yellow-100 text-yellow-800'; case 'REJECTED': return 'bg-red-100 text-red-800'; case 'CLAIMED': return 'bg-green-100 text-green-800'; default: return 'bg-gray-100 text-gray-800'; } }; const getStatusLabel = (status: string) => { switch (status) { case 'PENDING': return 'En attente'; case 'REJECTED': return 'Rejeté'; case 'CLAIMED': return 'Réclamé'; default: return status; } }; if (loading && tickets.length === 0) { return
Chargement des tickets...
; } return (

Gestion des Tickets

{error && (

Erreur de chargement:

{error}

{error.includes('401') && (

✅ Le header Authorization est bien envoyé

❌ Mais votre token est invalide ou a expiré

)} {error.includes('403') && (

Vous n'avez pas le rôle ADMIN requis.

🩺 Voir le diagnostic complet
)} {!error.includes('401') && !error.includes('403') && (

Vérifiez que le backend est démarré sur http://localhost:4000

🩺 Lancer le diagnostic
)}
)} {/* Info et Filtres */}
{totalTickets > 0 && ( {totalTickets} ticket{totalTickets > 1 ? 's' : ''} au total {(filterStatus || filterPrizeType) && ' (filtré)'} )}
{/* Filtre par type de lot */} {/* Filtre par statut */} {/* Bouton pour réinitialiser les filtres */} {(filterStatus || filterPrizeType) && ( )}
{/* Table des tickets */}
{tickets.length === 0 ? ( ) : ( tickets.map((ticket) => ( {/* CODE TICKET */} {/* LOT GAGNÉ */} {/* STATUT */} {/* DISTRIBUÉ LE */} {/* UTILISÉ PAR */} {/* ACTIONS */} )) )}
Code Ticket Lot Gagné Statut Distribué le Utilisé par Actions
🎫

{!error ? 'Aucun ticket trouvé' : 'Impossible de charger les tickets'}

{filterStatus ? `Aucun ticket avec le statut "${getStatusLabel(filterStatus)}"` : 'Aucun ticket n\'a été créé pour le moment' }

{!error && (

Les tickets apparaîtront ici une fois que des utilisateurs auront joué au jeu

)}
{ticket.code}
{ticket.prize?.name || 'N/A'}
{getStatusLabel(ticket.status)} {ticket.createdAt ? new Date(ticket.createdAt).toLocaleDateString('fr-FR', { year: 'numeric', month: '2-digit', day: '2-digit' }) : 'N/A'}
{ticket.user ? `${ticket.user.firstName} ${ticket.user.lastName}` : '-'}
{ticket.user && (
{ticket.user.email}
)}
{/* Pagination */}
Page {page} sur {totalPages}
{/* Panneau de Debug */}
{showDebug && (

📊 Informations de Debug

État: {loading ? 'Chargement...' : 'Chargé'}
Erreur: {error || 'Aucune'}
Nombre de tickets: {tickets.length}
Total tickets (API): {totalTickets}
Page actuelle: {page} / {totalPages}
Filtre statut: {filterStatus || 'Aucun'}
URL API: {process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000/api'}
Tickets reçus:
                  {JSON.stringify(tickets, null, 2)}
                

💡 Astuce: Ouvrez la console du navigateur (F12) pour voir les logs détaillés

)}
{/* Modal détails ticket */} {selectedTicket && (

Détails du ticket

Code

{selectedTicket.code}

Statut

{getStatusLabel(selectedTicket.status)}

Utilisateur

{selectedTicket.user ? `${selectedTicket.user.firstName} ${selectedTicket.user.lastName}` : 'N/A'}

{selectedTicket.user?.email}

Prix gagné

{selectedTicket.prize?.name}

{selectedTicket.prize?.description}

{selectedTicket.prize?.value}€

Date de jeu

{selectedTicket.playedAt ? new Date(selectedTicket.playedAt).toLocaleString('fr-FR') : 'N/A'}

{selectedTicket.validatedAt && (

Date de validation

{new Date(selectedTicket.validatedAt).toLocaleString('fr-FR')}

)}
{selectedTicket.rejectionReason && (

Raison du rejet

{selectedTicket.rejectionReason}

)}
)}
); }