+ const [gains, setGains] = useState([])
+ const [loading, setLoading] = useState(true)
+ const [error, setError] = useState('')
-
- {MOCK_GAINS.map((gain) => (
-
-
-
{gain.lot}
-
{gain.code}
-
-
- {statusLabel[gain.status].label}
-
-
- ))}
+ useEffect(() => {
+ myGainsApi()
+ .then((data) => setGains(data.gains))
+ .catch((err) => setError(err.message))
+ .finally(() => setLoading(false))
+ }, [])
+
+ return (
+
+
+
+
+
+ Saisir un nouveau code
+
+
+ {loading && (
+
Chargement...
+ )}
+
+ {error && (
+
+ {error}
+ )}
+
+ {!loading && !error && gains.length === 0 && (
+
Aucun gain pour le moment.
+ )}
+
+ {/* Timeline */}
+
+ {gains.map((gain, index) => (
+
+ {/* Ligne verticale + cercle */}
+
+
+ {index < gains.length - 1 && (
+
+ )}
+
+
+ {/* Contenu */}
+
+
{gain.lot}
+
{gain.description}
+
Gain obtenu le {formatDate(gain.wonAt)}
+
+
+ ))}
)
diff --git a/frontend/src/pages/Perdu.jsx b/frontend/src/pages/Perdu.jsx
new file mode 100644
index 0000000..ddd4b62
--- /dev/null
+++ b/frontend/src/pages/Perdu.jsx
@@ -0,0 +1,37 @@
+import { useLocation, useNavigate } from 'react-router-dom'
+
+export default function Perdu() {
+ const navigate = useNavigate()
+ const location = useLocation()
+ const message = location.state?.message
+
+ return (
+
+
+
+
+
+ Réessayer la prochaine fois
+
+
+
+ {message || 'Ce code est invalide ou a déjà été utilisé.'}
+
+
+
+ Vérifiez le code présent sur votre ticket et réessayez.
+
+
+
+
+ )
+}
diff --git a/frontend/src/pages/Profile.jsx b/frontend/src/pages/Profile.jsx
index e7fa9c9..e485c39 100644
--- a/frontend/src/pages/Profile.jsx
+++ b/frontend/src/pages/Profile.jsx
@@ -1,94 +1,89 @@
-import { useState } from 'react'
+import { Link } from 'react-router-dom'
+
+function TabNav({ active }) {
+ return (
+
+
+
+ Mes gains
+
+
+
+ Profile
+
+
+ )
+}
export default function Profile() {
- const [form, setForm] = useState({
- firstName: '',
- lastName: '',
- email: '',
- })
+ const user = JSON.parse(localStorage.getItem('user') || '{}')
- const handleChange = (e) => {
- const { name, value } = e.target
- setForm({ ...form, [name]: value })
- }
+ const initials = `${(user.firstname || '?')[0]}${(user.lastname || '?')[0]}`.toUpperCase()
- const handleSubmit = (e) => {
- e.preventDefault()
- // TODO: appeler backend pour update profil
- alert('Profil mis à jour')
- }
+ const handleSubmit = (e) => {
+ e.preventDefault()
+ // TODO: connecter au backend pour update profil
+ alert('Modification du profil à venir')
+ }
- // Initiales pour l'avatar
- const initials = 'MD'
+ return (
+
+
- return (
-
-
-
Mon Profil
- {/* Avatar */}
-
-
- {/* Formulaire */}
-
-
+ {/* Avatar */}
+
+
+ {initials}
- )
-}
\ No newline at end of file
+
+
+
+
+ )
+}
diff --git a/frontend/src/pages/SaisirCodeUnique.jsx b/frontend/src/pages/SaisirCodeUnique.jsx
index ad93d59..999e6c7 100644
--- a/frontend/src/pages/SaisirCodeUnique.jsx
+++ b/frontend/src/pages/SaisirCodeUnique.jsx
@@ -1,65 +1,88 @@
import { useState } from 'react'
+import { useNavigate } from 'react-router-dom'
+import { participateApi } from '../services/game'
export default function SaisirCodeUnique() {
- const [form, setForm] = useState({
- codeUnique: '',
- })
+ const navigate = useNavigate()
+ const [code, setCode] = useState('')
+ const [loading, setLoading] = useState(false)
+ const [gain, setGain] = useState(null)
- const handleChange = (e) => {
- const { name, value } = e.target
- setForm({ ...form, [name]: value.toUpperCase() })
+ const handleSubmit = async (e) => {
+ e.preventDefault()
+ setLoading(true)
+ try {
+ const data = await participateApi(code.trim().toUpperCase())
+ setGain(data.gain)
+ } catch (err) {
+ navigate('/perdu', { state: { message: err.message } })
+ } finally {
+ setLoading(false)
}
+ }
- const handleSubmit = (e) => {
- e.preventDefault()
+ return (
+
- const code = form.codeUnique.trim()
-
- if (!code) {
- alert('Veuillez saisir un code')
- return
- }
- if (code.length !== 10) {
- alert('Le code doit contenir exactement 10 caractères')
- return
- }
-
- // TODO: appeler backend pour valider le code unique
- alert('Code validé')
- }
+
+
Saisir mon code gagnant
+
Saisissez le code présent sur votre ticket
+
- return (
-
-
-
Saisir mon code gagnant
-
Saisissez le code présent sur votre ticket
-
+
- {/* Code unique */}
-
-
-
-
- {/* Bouton de soumission */}
-
-
+ {/* Overlay Félicitation */}
+ {gain && (
+
+
+
Félicitation !
+
Vous avez obtenu une récompense
+
+
+
+ {/* Code saisi */}
+
+ {code}
+
+
+ {/* Icône décorative */}
+
+
+
+
{gain.name}
+
{gain.description}
+
+
- )
-}
\ No newline at end of file
+ )}
+
+ )
+}
diff --git a/frontend/src/services/game.js b/frontend/src/services/game.js
new file mode 100644
index 0000000..c3fe267
--- /dev/null
+++ b/frontend/src/services/game.js
@@ -0,0 +1,24 @@
+export async function myGainsApi() {
+ const token = localStorage.getItem('token')
+ const res = await fetch('/api/game/my-gains', {
+ headers: { Authorization: `Bearer ${token}` },
+ })
+ const data = await res.json()
+ if (!res.ok) throw new Error(data.message || 'Erreur lors de la récupération des gains.')
+ return data
+}
+
+export async function participateApi(code) {
+ const token = localStorage.getItem('token')
+ const res = await fetch('/api/game/participate', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({ code }),
+ })
+ const data = await res.json()
+ if (!res.ok) throw new Error(data.message || 'Erreur lors de la participation.')
+ return data
+}