initialisation du projet

This commit is contained in:
Emma781227
2026-06-10 23:00:41 +02:00
parent f5a5fa6901
commit 45535e2b21
22 changed files with 3443 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
const MOCK_STATS = {
totalParticipants: 1248,
gainsRemis: 342,
gainsEnAttente: 906,
tauxParticipation: '78%',
}
const MOCK_USERS = [
{ id: 1, name: 'Jean Dupont', email: 'jean.dupont@email.com', gains: 2 },
{ id: 2, name: 'Marie Martin', email: 'marie.martin@email.com', gains: 1 },
{ id: 3, name: 'Paul Bernard', email: 'paul.bernard@email.com', gains: 3 },
]
export default function Admin() {
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="max-w-4xl mx-auto">
<h1 className="text-2xl font-bold text-gray-800 mb-6">Tableau de bord Admin</h1>
{/* Stats */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
{[
{ label: 'Participants', value: MOCK_STATS.totalParticipants },
{ label: 'Gains remis', value: MOCK_STATS.gainsRemis },
{ label: 'En attente', value: MOCK_STATS.gainsEnAttente },
{ label: 'Taux participation', value: MOCK_STATS.tauxParticipation },
].map((stat) => (
<div key={stat.label} className="bg-white rounded-xl shadow p-4 text-center">
<p className="text-2xl font-bold text-green-700">{stat.value}</p>
<p className="text-sm text-gray-500 mt-1">{stat.label}</p>
</div>
))}
</div>
{/* Tirage au sort */}
<div className="bg-white rounded-xl shadow p-6 mb-6">
<h2 className="text-lg font-bold text-gray-800 mb-3">Grand tirage au sort</h2>
<button
onClick={() => alert('TODO: connecter au backend')}
className="bg-green-700 hover:bg-green-800 text-white font-semibold px-6 py-2.5 rounded-lg transition-colors"
>
Lancer le tirage
</button>
</div>
{/* Liste participants */}
<div className="bg-white rounded-xl shadow p-6">
<h2 className="text-lg font-bold text-gray-800 mb-4">Participants</h2>
<table className="w-full text-sm">
<thead>
<tr className="text-left text-gray-500 border-b">
<th className="pb-2">Nom</th>
<th className="pb-2">Email</th>
<th className="pb-2 text-right">Gains</th>
</tr>
</thead>
<tbody>
{MOCK_USERS.map((user) => (
<tr key={user.id} className="border-b last:border-0">
<td className="py-3 font-medium text-gray-800">{user.name}</td>
<td className="py-3 text-gray-500">{user.email}</td>
<td className="py-3 text-right text-green-700 font-semibold">{user.gains}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,73 @@
import { useState } from 'react'
import { Link } from 'react-router-dom'
export default function Connexion() {
const [form, setForm] = useState({ email: '', password: '' })
const handleChange = (e) => setForm({ ...form, [e.target.name]: e.target.value })
const handleSubmit = (e) => {
e.preventDefault()
// TODO: connecter au backend
alert(`Connexion avec ${form.email}`)
}
return (
<div className="min-h-screen bg-green-50 flex items-center justify-center p-4">
<div className="bg-white rounded-2xl shadow-lg w-full max-w-md p-8">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-green-800">Thé Tip Top</h1>
<p className="text-gray-500 mt-1">Con
nexion à votre espace</p>
</div>
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Email
</label>
<input
type="email"
name="email"
value={form.email}
onChange={handleChange}
required
placeholder="exemple@email.com"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Mot de passe
</label>
<input
type="password"
name="password"
value={form.password}
onChange={handleChange}
required
placeholder="••••••••"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
<button
type="submit"
className="w-full bg-green-700 hover:bg-green-800 text-white font-semibold py-2.5 rounded-lg transition-colors"
>
Se connecter
</button>
</form>
<p className="text-center text-sm text-gray-500 mt-6">
Pas encore de compte ?{' '}
<Link to="/inscription" className="text-green-700 font-medium hover:underline">
S'inscrire
</Link>
</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,77 @@
import { useState } from 'react'
export default function Employe() {
const [code, setCode] = useState('')
const [gain, setGain] = useState(null)
const handleSearch = (e) => {
e.preventDefault()
// TODO: connecter au backend
setGain({
code,
lot: 'Thé signature (100g)',
client: 'Jean Dupont',
email: 'jean.dupont@email.com',
status: 'PENDING',
})
}
const handleDeliver = () => {
// TODO: connecter au backend
setGain({ ...gain, status: 'DELIVERED' })
}
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="max-w-lg mx-auto">
<h1 className="text-2xl font-bold text-gray-800 mb-1">Espace Employé</h1>
<p className="text-gray-500 mb-6">Vérifier et remettre un lot</p>
<form onSubmit={handleSearch} className="flex gap-2 mb-6">
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
required
placeholder="Code ticket (TTT-XXXXX)"
className="flex-1 border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500 font-mono"
/>
<button
type="submit"
className="bg-green-700 hover:bg-green-800 text-white font-semibold px-5 py-2.5 rounded-lg transition-colors"
>
Rechercher
</button>
</form>
{gain && (
<div className="bg-white rounded-xl shadow p-6 space-y-3">
<div className="flex justify-between items-start">
<div>
<p className="font-bold text-gray-800 text-lg">{gain.lot}</p>
<p className="text-sm text-gray-500 font-mono">{gain.code}</p>
</div>
<span className={`text-xs font-semibold px-3 py-1 rounded-full ${gain.status === 'DELIVERED' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'}`}>
{gain.status === 'DELIVERED' ? 'Remis' : 'À remettre'}
</span>
</div>
<div className="border-t pt-3">
<p className="text-sm text-gray-600"><span className="font-medium">Client :</span> {gain.client}</p>
<p className="text-sm text-gray-600"><span className="font-medium">Email :</span> {gain.email}</p>
</div>
{gain.status === 'PENDING' && (
<button
onClick={handleDeliver}
className="w-full bg-green-700 hover:bg-green-800 text-white font-semibold py-2.5 rounded-lg transition-colors mt-2"
>
Confirmer la remise du lot
</button>
)}
</div>
)}
</div>
</div>
)
}

View File

@@ -0,0 +1,116 @@
import { useState } from 'react'
import { Link } from 'react-router-dom'
export default function Inscription() {
const [form, setForm] = useState({
firstName: '',
lastName: '',
email: '',
password: '',
acceptMarketing: false,
})
const handleChange = (e) => {
const { name, value, type, checked } = e.target
setForm({ ...form, [name]: type === 'checkbox' ? checked : value })
}
const handleSubmit = (e) => {
e.preventDefault()
// TODO: connecter au backend
alert(`Inscription de ${form.firstName} ${form.lastName}`)
}
return (
<div className="min-h-screen bg-green-50 flex items-center justify-center p-4">
<div className="bg-white rounded-2xl shadow-lg w-full max-w-md p-8">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-green-800">Thé Tip Top</h1>
<p className="text-gray-500 mt-1">Créer votre compte</p>
</div>
<form onSubmit={handleSubmit} className="space-y-5">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Prénom</label>
<input
type="text"
name="firstName"
value={form.firstName}
onChange={handleChange}
required
placeholder="Jean"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Nom</label>
<input
type="text"
name="lastName"
value={form.lastName}
onChange={handleChange}
required
placeholder="Dupont"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input
type="email"
name="email"
value={form.email}
onChange={handleChange}
required
placeholder="exemple@email.com"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Mot de passe</label>
<input
type="password"
name="password"
value={form.password}
onChange={handleChange}
required
placeholder="••••••••"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
<label className="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
name="acceptMarketing"
checked={form.acceptMarketing}
onChange={handleChange}
className="mt-1 accent-green-700"
/>
<span className="text-sm text-gray-600">
J'accepte de recevoir des communications marketing de Thé Tip Top
</span>
</label>
<button
type="submit"
className="w-full bg-green-700 hover:bg-green-800 text-white font-semibold py-2.5 rounded-lg transition-colors"
>
Créer mon compte
</button>
</form>
<p className="text-center text-sm text-gray-500 mt-6">
Déjà un compte ?{' '}
<Link to="/connexion" className="text-green-700 font-medium hover:underline">
Se connecter
</Link>
</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,35 @@
const MOCK_GAINS = [
{ id: 1, code: 'TTT-00123', lot: 'Infusion découverte (30g)', status: 'PENDING' },
{ id: 2, code: 'TTT-00456', lot: 'Thé signature (100g)', status: 'DELIVERED' },
]
const statusLabel = {
PENDING: { label: 'À récupérer', color: 'bg-yellow-100 text-yellow-800' },
DELIVERED: { label: 'Récupéré', color: 'bg-green-100 text-green-800' },
CANCELLED: { label: 'Annulé', color: 'bg-red-100 text-red-800' },
}
export default function MesGains() {
return (
<div className="min-h-screen bg-green-50 p-6">
<div className="max-w-2xl mx-auto">
<h1 className="text-3xl font-bold text-green-800 mb-2">Mes gains</h1>
<p className="text-gray-500 mb-6">Historique de vos participations</p>
<div className="space-y-4">
{MOCK_GAINS.map((gain) => (
<div key={gain.id} className="bg-white rounded-xl shadow p-5 flex items-center justify-between">
<div>
<p className="font-semibold text-gray-800">{gain.lot}</p>
<p className="text-sm text-gray-400 font-mono mt-1">{gain.code}</p>
</div>
<span className={`text-xs font-semibold px-3 py-1 rounded-full ${statusLabel[gain.status].color}`}>
{statusLabel[gain.status].label}
</span>
</div>
))}
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,61 @@
import { useState } from 'react'
import { Link } from 'react-router-dom'
export default function Participation() {
const [code, setCode] = useState('')
const [result, setResult] = useState(null)
const handleSubmit = (e) => {
e.preventDefault()
// TODO: connecter au backend
setResult({
lot: 'Infusion découverte (30g)',
description: 'Un assortiment de nos meilleures infusions',
})
}
return (
<div className="min-h-screen bg-green-50 flex items-center justify-center p-4">
<div className="bg-white rounded-2xl shadow-lg w-full max-w-md p-8">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-green-800">Thé Tip Top</h1>
<p className="text-gray-500 mt-1">Participer au jeu-concours</p>
</div>
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Code ticket
</label>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
required
placeholder="Ex: TTT-XXXXX"
className="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500 font-mono tracking-widest"
/>
</div>
<button
type="submit"
className="w-full bg-green-700 hover:bg-green-800 text-white font-semibold py-2.5 rounded-lg transition-colors"
>
Valider mon ticket
</button>
</form>
{result && (
<div className="mt-6 bg-green-100 border border-green-300 rounded-xl p-5 text-center">
<p className="text-green-800 font-bold text-lg">Félicitations !</p>
<p className="text-green-700 font-medium mt-1">{result.lot}</p>
<p className="text-gray-600 text-sm mt-1">{result.description}</p>
<Link to="/mes-gains" className="inline-block mt-4 text-sm text-green-700 font-medium hover:underline">
Voir tous mes gains
</Link>
</div>
)}
</div>
</div>
)
}