the-tip-top-frontend/app/mes-lots/page.tsx
2025-11-17 23:38:02 +01:00

280 lines
10 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { useAuth } from "@/contexts/AuthContext";
import { useGame } from "@/hooks/useGame";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/Card";
import { Badge } from "@/components/ui/Badge";
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from "@/components/ui/Table";
import { Loading } from "@/components/ui/Loading";
import { PRIZE_CONFIG, TICKET_STATUS_LABELS, TICKET_STATUS_COLORS } from "@/utils/constants";
import { formatDateTime } from "@/utils/helpers";
import { Ticket } from "@/types";
import { useRouter } from "next/navigation";
import { ROUTES } from "@/utils/constants";
import Button from "@/components/Button";
export default function HistoriquePage() {
const { user, isAuthenticated } = useAuth();
const { getMyTickets, isLoadingTickets } = useGame();
const router = useRouter();
const [tickets, setTickets] = useState<Ticket[]>([]);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (isAuthenticated && user?.role?.toLowerCase() === "client") {
loadTickets();
}
}, [isAuthenticated, user, currentPage]);
const loadTickets = async () => {
try {
setError(null);
console.log('🎫 Chargement des tickets, page:', currentPage);
const result = await getMyTickets(currentPage, 10);
console.log('📦 Résultat API:', result);
if (result) {
console.log('✅ Tickets reçus:', result.data);
setTickets(result.data || []);
setTotalPages(result.totalPages || 1);
} else {
console.log('❌ Aucun résultat reçu');
setTickets([]);
setError('Impossible de charger vos tickets. Veuillez réessayer.');
}
} catch (err) {
console.error('❌ Erreur lors du chargement:', err);
setError('Erreur lors du chargement de vos tickets.');
setTickets([]);
}
};
if (!isAuthenticated || user?.role?.toLowerCase() !== "client") {
return (
<div className="min-h-[calc(100vh-8rem)] flex items-center justify-center">
<Card className="max-w-md text-center">
<CardContent className="py-8">
<h2 className="text-2xl font-bold text-gray-900 mb-4">
Accès non autorisé
</h2>
<p className="text-gray-600 mb-6">
Cette page est réservée aux clients
</p>
<p className="text-sm text-gray-500 mb-4">
Votre rôle actuel : {user?.role || 'Non défini'}
</p>
<Button onClick={() => router.push(ROUTES.HOME)}>
Retour à l'accueil
</Button>
</CardContent>
</Card>
</div>
);
}
const getStatusBadge = (status: string) => {
const statusLower = status.toLowerCase();
const variant =
statusLower === "claimed"
? "success"
: statusLower === "pending"
? "warning"
: "danger";
return (
<Badge variant={variant}>
{TICKET_STATUS_LABELS[statusLower as keyof typeof TICKET_STATUS_LABELS] || status}
</Badge>
);
};
return (
<div className="py-8">
<div className="max-w-6xl mx-auto">
<div className="flex items-center justify-between mb-8">
<h1 className="text-3xl font-bold text-gray-900">
Historique de mes gains
</h1>
<Button onClick={() => router.push(ROUTES.GAME)}>
Jouer à nouveau
</Button>
</div>
{error && (
<Card className="mb-6">
<CardContent className="py-6">
<div className="flex items-center gap-3 text-red-600">
<span className="text-2xl">⚠️</span>
<div>
<p className="font-semibold">Erreur de chargement</p>
<p className="text-sm text-red-500">{error}</p>
<Button
variant="outline"
size="sm"
onClick={loadTickets}
className="mt-3"
>
Réessayer
</Button>
</div>
</div>
</CardContent>
</Card>
)}
{isLoadingTickets ? (
<Loading text="Chargement de l'historique..." />
) : tickets.length === 0 && !error ? (
<Card>
<CardContent className="py-16 text-center">
<div className="text-6xl mb-4">🎲</div>
<h2 className="text-2xl font-semibold text-gray-900 mb-2">
Aucun ticket pour le moment
</h2>
<p className="text-gray-600 mb-6">
Commencez à jouer pour voir vos gains apparaître ici
</p>
<Button onClick={() => router.push(ROUTES.GAME)} size="lg" className="bg-white text-black hover:bg-gray-50 border-2 border-black">
Jouer maintenant
</Button>
</CardContent>
</Card>
) : tickets.length > 0 ? (
<>
{/* Stats Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-500">
Total de tickets
</p>
<p className="text-3xl font-bold text-gray-900">
{tickets.length}
</p>
</div>
<div className="text-4xl">🎫</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-500">
Gains réclamés
</p>
<p className="text-3xl font-bold text-green-600">
{tickets.filter((t) => t.status.toLowerCase() === "claimed").length}
</p>
</div>
<div className="text-4xl">✅</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-500">
En attente
</p>
<p className="text-3xl font-bold text-yellow-600">
{tickets.filter((t) => t.status.toLowerCase() === "pending").length}
</p>
</div>
<div className="text-4xl">⏳</div>
</div>
</CardContent>
</Card>
</div>
{/* Tickets Table */}
<Card>
<CardHeader>
<CardTitle>Mes tickets</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Code</TableHead>
<TableHead>Lot gagné</TableHead>
<TableHead>Statut</TableHead>
<TableHead>Date</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{tickets.map((ticket) => (
<TableRow key={ticket.id}>
<TableCell className="font-mono font-semibold">
{ticket.code}
</TableCell>
<TableCell>
{ticket.prize && (
<div className="flex items-center gap-2">
<span className="text-2xl">
{PRIZE_CONFIG[ticket.prize.type as keyof typeof PRIZE_CONFIG]?.icon || '🎁'}
</span>
<span>
{ticket.prize.name || PRIZE_CONFIG[ticket.prize.type as keyof typeof PRIZE_CONFIG]?.name}
</span>
</div>
)}
</TableCell>
<TableCell>{getStatusBadge(ticket.status)}</TableCell>
<TableCell className="text-gray-600">
{ticket.playedAt ? formatDateTime(ticket.playedAt) : ticket.createdAt ? formatDateTime(ticket.createdAt) : '-'}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{/* Pagination */}
{totalPages > 1 && (
<div className="flex items-center justify-between mt-6 pt-6 border-t">
<p className="text-sm text-gray-600">
Page {currentPage} sur {totalPages}
</p>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
disabled={currentPage === 1}
>
Précédent
</Button>
<Button
variant="outline"
size="sm"
onClick={() =>
setCurrentPage((p) => Math.min(totalPages, p + 1))
}
disabled={currentPage === totalPages}
>
Suivant
</Button>
</div>
</div>
)}
</CardContent>
</Card>
</>
) : null}
</div>
</div>
);
}