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

210 lines
8.0 KiB
TypeScript

"use client";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useAuth } from "@/contexts/AuthContext";
import { useGame } from "@/hooks/useGame";
import { ticketCodeSchema, TicketCodeFormData } from "@/lib/validations";
import { Input } from "@/components/ui/Input";
import Button from "@/components/Button";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/Card";
import { Modal } from "@/components/ui/Modal";
import { PRIZE_CONFIG } from "@/utils/constants";
import { PlayGameResponse } from "@/types";
import { useRouter } from "next/navigation";
import { ROUTES } from "@/utils/constants";
import Link from "next/link";
export default function JeuxPage() {
const { user, isAuthenticated } = useAuth();
const { play, isPlaying } = useGame();
const router = useRouter();
const [showResultModal, setShowResultModal] = useState(false);
const [gameResult, setGameResult] = useState<PlayGameResponse | null>(null);
const [errorMessage, setErrorMessage] = useState<string>("");
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<TicketCodeFormData>({
resolver: zodResolver(ticketCodeSchema),
});
const onSubmit = async (data: TicketCodeFormData) => {
// Réinitialiser le message d'erreur
setErrorMessage("");
// Si non connecté, rediriger vers login
if (!isAuthenticated) {
router.push(`${ROUTES.LOGIN}?redirect=/jeux`);
return;
}
const result = await play(data.ticketCode);
if (result) {
setGameResult(result);
setShowResultModal(true);
setErrorMessage("");
reset();
} else {
// En cas d'erreur, afficher un message personnalisé
setErrorMessage("Ce code a déjà été utilisé ou est invalide. Si vous avez déjà utilisé ce code, consultez vos tickets dans 'Mes lots'.");
}
};
const closeModal = () => {
setShowResultModal(false);
setGameResult(null);
};
const prizeConfig = gameResult?.prize
? PRIZE_CONFIG[gameResult.prize.type as keyof typeof PRIZE_CONFIG]
: null;
return (
<div className="py-8">
{/* Formulaire Section */}
<section className="mb-16">
<div className="max-w-2xl mx-auto">
<Card className="shadow-xl">
<CardHeader className="bg-gradient-to-r from-primary-50 to-green-50">
<CardTitle className="text-center text-2xl md:text-3xl text-primary-800">
🎁 Jouez maintenant !
</CardTitle>
</CardHeader>
<CardContent className="pt-8">
<div className="mb-6 text-center">
{isAuthenticated ? (
<p className="text-gray-700">
Bonjour <span className="font-bold text-primary-600">{user?.firstName}</span>,
entrez le code de 10 caractères présent sur votre ticket de caisse
</p>
) : (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-4">
<p className="text-yellow-800 text-sm">
💡 Vous devez être connecté pour valider votre code.
<Link href={ROUTES.LOGIN} className="font-semibold underline ml-1">
Connectez-vous
</Link>
</p>
</div>
)}
</div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div>
<label htmlFor="ticketCode" className="block text-sm font-medium text-gray-700 mb-2">
Code du ticket
</label>
<input
id="ticketCode"
type="text"
placeholder="TTP2025ABC"
{...register("ticketCode")}
className="w-full px-6 py-4 text-center text-2xl font-mono font-bold uppercase border-2 border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent tracking-widest"
maxLength={10}
/>
{errors.ticketCode && (
<p className="mt-2 text-sm text-red-600">{errors.ticketCode.message}</p>
)}
{errorMessage && (
<div className="mt-3 p-4 bg-red-50 border border-red-200 rounded-lg">
<p className="text-sm text-red-800 font-medium mb-2">
{errorMessage}
</p>
<Link
href={ROUTES.MY_LOTS}
className="text-sm text-red-600 hover:text-red-800 underline font-medium"
>
Voir vos tickets déjà utilisés
</Link>
</div>
)}
<p className="mt-2 text-sm text-gray-500 text-center">
Format: TTP2025ABC (10 caractères)
</p>
</div>
<div className="flex justify-center">
<Button
type="submit"
isLoading={isPlaying}
disabled={isPlaying}
size="lg"
className="px-12 py-4 text-lg"
>
{isPlaying ? "Vérification en cours..." : "🎲 Tenter ma chance !"}
</Button>
</div>
</form>
{!isAuthenticated && (
<div className="mt-6 text-center">
<p className="text-sm text-gray-600 mb-3">
Pas encore de compte ?
</p>
<Link href={ROUTES.REGISTER}>
<Button variant="outline" size="sm">
Créer un compte gratuitement
</Button>
</Link>
</div>
)}
{isAuthenticated && (
<div className="mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<p className="text-sm text-blue-800 mb-2">
💡 <strong>Bon à savoir :</strong>
</p>
<ul className="text-sm text-blue-700 space-y-1 list-disc list-inside">
<li>Chaque code ne peut être utilisé qu'une seule fois</li>
<li>Consultez vos tickets sur la page <Link href={ROUTES.MY_LOTS} className="underline font-medium">Mes lots</Link></li>
</ul>
</div>
)}
</CardContent>
</Card>
</div>
</section>
{/* Result Modal */}
<Modal
isOpen={showResultModal}
onClose={closeModal}
title="Résultat"
size="md"
>
{gameResult && prizeConfig && (
<div className="text-center py-6">
<div className="text-6xl mb-4">{prizeConfig.icon}</div>
<h3 className="text-2xl font-bold text-gray-900 mb-2">
Félicitations ! 🎉
</h3>
<p className="text-lg text-gray-700 mb-4">
Vous avez gagné :
</p>
<div
className={`inline-block px-6 py-3 rounded-full text-lg font-semibold mb-6 ${prizeConfig.color}`}
>
{prizeConfig.name}
</div>
<p className="text-gray-600 mb-6">
{gameResult.message || "Présentez-vous en magasin pour récupérer votre lot !"}
</p>
<div className="flex gap-3 justify-center">
<Button onClick={closeModal} variant="outline">
Fermer
</Button>
<Button onClick={() => router.push(ROUTES.MY_LOTS)}>
Voir mes lots
</Button>
</div>
</div>
)}
</Modal>
</div>
);
}