From e0330d4f28af2b1661dfd62514e59551d241a7eb Mon Sep 17 00:00:00 2001
From: soufiane
Date: Tue, 2 Dec 2025 16:15:30 +0100
Subject: [PATCH] feat: add reset-password page and update contest dates
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Add reset-password page to handle password reset flow
- Fix forgot-password to call real API
- Update contest dates (validation: Dec 1-31, recovery: Dec 1 - Jan 31)
- Update draw date to Feb 1, 2026
- Improve GamePeriod and GrandPrize components design
- Remove "livré chez vous" text
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude
---
app/forgot-password/page.tsx | 55 ++++++--
app/lots/page.tsx | 2 +-
app/page.tsx | 3 +-
app/reset-password/page.tsx | 258 +++++++++++++++++++++++++++++++++++
app/rules/page.tsx | 8 +-
components/GamePeriod.tsx | 50 ++++---
components/GrandPrize.tsx | 91 ++++++------
7 files changed, 374 insertions(+), 93 deletions(-)
create mode 100644 app/reset-password/page.tsx
diff --git a/app/forgot-password/page.tsx b/app/forgot-password/page.tsx
index 5c1026a..edec73e 100644
--- a/app/forgot-password/page.tsx
+++ b/app/forgot-password/page.tsx
@@ -1,23 +1,41 @@
"use client";
import { useState } from "react";
import Link from "next/link";
-import { ROUTES } from "@/utils/constants";
+import { ROUTES, API_BASE_URL } from "@/utils/constants";
export default function ForgotPasswordPage() {
const [email, setEmail] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
+ const [error, setError] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
+ setError("");
- // Simulation d'envoi
- await new Promise(resolve => setTimeout(resolve, 1500));
+ try {
+ const response = await fetch(`${API_BASE_URL}/auth/forgot-password`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ email }),
+ });
- console.log('Password reset email sent to:', email);
- setIsSuccess(true);
- setIsSubmitting(false);
+ const data = await response.json();
+
+ if (data.success) {
+ setIsSuccess(true);
+ } else {
+ setError(data.message || 'Une erreur est survenue');
+ }
+ } catch (err) {
+ setError('Erreur de connexion au serveur');
+ console.error('Forgot password error:', err);
+ } finally {
+ setIsSubmitting(false);
+ }
};
if (isSuccess) {
@@ -27,9 +45,9 @@ export default function ForgotPasswordPage() {
{/* Title */}
-
Email envoyé !
+
Email envoyé !
- Vérifiez votre boîte de réception
+ Vérifiez votre boîte de réception
@@ -43,16 +61,16 @@ export default function ForgotPasswordPage() {
- Lien de réinitialisation envoyé
+ Lien de réinitialisation envoyé
- Nous avons envoyé un lien de réinitialisation à {email}
+ Si cet email existe dans notre base, vous recevrez un lien de réinitialisation à {email}
- 💡 Conseil : Si vous ne recevez pas l'email dans quelques minutes, vérifiez votre dossier spam.
+ Conseil : Si vous ne recevez pas l'email dans quelques minutes, vérifiez votre dossier spam.
@@ -60,7 +78,7 @@ export default function ForgotPasswordPage() {
href={ROUTES.LOGIN}
className="inline-flex items-center justify-center w-full bg-[#1a4d2e] hover:bg-[#2d5a3d] text-white font-bold px-8 py-4 rounded-lg transition-all"
>
- Retour Ă la connexion
+ Retour à la connexion
@@ -75,9 +93,9 @@ export default function ForgotPasswordPage() {
{/* Title */}
-
Mot de passe oublié
+
Mot de passe oublié
- Entrez votre email pour recevoir un lien de réinitialisation
+ Entrez votre email pour recevoir un lien de réinitialisation
@@ -87,6 +105,13 @@ export default function ForgotPasswordPage() {
{/* Form Container */}
+ {/* Error Message */}
+ {error && (
+
+ {error}
+
+ )}
+
{/* Form */}
diff --git a/app/reset-password/page.tsx b/app/reset-password/page.tsx
new file mode 100644
index 0000000..4fc8492
--- /dev/null
+++ b/app/reset-password/page.tsx
@@ -0,0 +1,258 @@
+"use client";
+import { useState, useEffect, Suspense } from "react";
+import { useSearchParams, useRouter } from "next/navigation";
+import Link from "next/link";
+import { ROUTES, API_BASE_URL } from "@/utils/constants";
+
+function ResetPasswordForm() {
+ const searchParams = useSearchParams();
+ const router = useRouter();
+ const token = searchParams.get("token");
+
+ const [password, setPassword] = useState("");
+ const [confirmPassword, setConfirmPassword] = useState("");
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [error, setError] = useState("");
+ const [showPassword, setShowPassword] = useState(false);
+
+ useEffect(() => {
+ if (!token) {
+ setError("Token de réinitialisation manquant. Veuillez demander un nouveau lien.");
+ }
+ }, [token]);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setError("");
+
+ // Validation
+ if (password.length < 8) {
+ setError("Le mot de passe doit contenir au moins 8 caractères");
+ return;
+ }
+
+ if (password !== confirmPassword) {
+ setError("Les mots de passe ne correspondent pas");
+ return;
+ }
+
+ setIsSubmitting(true);
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/auth/reset-password`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ token, password }),
+ });
+
+ const data = await response.json();
+
+ if (data.success) {
+ setIsSuccess(true);
+ // Redirection après 3 secondes
+ setTimeout(() => {
+ router.push(ROUTES.LOGIN);
+ }, 3000);
+ } else {
+ setError(data.message || 'Une erreur est survenue');
+ }
+ } catch (err) {
+ setError('Erreur de connexion au serveur');
+ console.error('Reset password error:', err);
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ if (isSuccess) {
+ return (
+
+
+
+
Mot de passe modifié !
+
+
+
+
+
+
+
+ Votre mot de passe a été réinitialisé
+
+
+
+ Vous allez être redirigé vers la page de connexion...
+
+
+
+ Se connecter maintenant
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ {/* Title */}
+
+
Nouveau mot de passe
+
+ Choisissez un nouveau mot de passe sécurisé
+
+
+
+ {/* Main Card */}
+
+
+
+ {/* Error Message */}
+ {error && (
+
+ {error}
+
+ )}
+
+ {/* Form */}
+
+
+
+
+
+
+ );
+}
+
+export default function ResetPasswordPage() {
+ return (
+
+
+
+ }>
+
+
+ );
+}
diff --git a/app/rules/page.tsx b/app/rules/page.tsx
index e9713e9..0896c12 100644
--- a/app/rules/page.tsx
+++ b/app/rules/page.tsx
@@ -47,12 +47,12 @@ export default function RulesPage() {
- {/* 30 + 30 jours */}
+ {/* 30 + 60 jours */}
🔄
-
30 + 30 jours
+
30 + 60 jours
- Période de jeu + délai de réclamation
+ Validation tickets (30j) + récupération lots (60j)
@@ -240,7 +240,7 @@ export default function RulesPage() {
{openSection === 5 && (
-
Les lots doivent être réclamés dans un délai de 30 jours à compter de la date de participation.
+
Les lots doivent être réclamés dans un délai de 60 jours (du 1er décembre 2025 au 31 janvier 2026).