210 lines
8.0 KiB
TypeScript
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>
|
|
);
|
|
}
|