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 */}
@@ -112,7 +137,7 @@ export default function ForgotPasswordPage() { disabled={isSubmitting} className="w-full bg-[#1a4d2e] hover:bg-[#2d5a3d] disabled:bg-gray-400 text-white font-bold px-8 py-4 rounded-lg transition-all" > - {isSubmitting ? "Envoi en cours..." : "Envoyer le lien de réinitialisation"} + {isSubmitting ? "Envoi en cours..." : "Envoyer le lien de r\u00e9initialisation"} {/* Back to Login */} diff --git a/app/lots/page.tsx b/app/lots/page.tsx index b6a201d..4770e93 100644 --- a/app/lots/page.tsx +++ b/app/lots/page.tsx @@ -60,7 +60,7 @@ export default function LotsPage() { 1 an de thé offert

- Le grand prix du tirage final : une année complète de thé premium livré chez vous + Le grand prix du tirage final : une année complète de thé premium

Tirage sous contrôle d'huissier diff --git a/app/page.tsx b/app/page.tsx index 12f8c3e..1d2a0d5 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -69,8 +69,7 @@ export default function HomePage() { {/* Grand Prize Banner */}
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 */} + + + {/* New Password */} +
+ +
+ setPassword(e.target.value)} + placeholder="Minimum 8 caractères" + className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#1a4d2e] focus:border-transparent pr-12" + disabled={!token} + /> + +
+
+ + {/* Confirm Password */} +
+ + setConfirmPassword(e.target.value)} + placeholder="Répétez le mot de passe" + className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#1a4d2e] focus:border-transparent" + disabled={!token} + /> +
+ + {/* Password Requirements */} +
+

Le mot de passe doit contenir :

+
    +
  • = 8 ? 'text-green-600' : ''}`}> + {password.length >= 8 ? ( + + + + ) : ( + + + + )} + Au moins 8 caractères +
  • +
  • 0 ? 'text-green-600' : ''}`}> + {password === confirmPassword && password.length > 0 ? ( + + + + ) : ( + + + + )} + Les mots de passe correspondent +
  • +
+
+ + {/* Submit Button */} + + + {/* Back to Login */} +
+ + Retour à la connexion + +
+ + +
+
+
+
+ ); +} + +export default function ResetPasswordPage() { + return ( + +
+
+

Chargement...

+
+ + }> + +
+ ); +} 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).

Modalités de remise :