Yocapp commited on
Commit
e4e7c58
·
verified ·
1 Parent(s): 4f714a5

génère moi le visuel à partir de ce code suivant : <!DOCTYPE html><html lang="fr"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.

Browse files
Files changed (4) hide show
  1. README.md +8 -5
  2. index.html +788 -19
  3. script.js +767 -0
  4. style.css +64 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Tie Espace Client Priv Wguy6
3
- emoji: 🐨
4
- colorFrom: blue
5
  colorTo: green
6
  sdk: static
7
- pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: TIE Espace Client Privé 🚙
3
+ colorFrom: pink
 
4
  colorTo: green
5
  sdk: static
6
+ emoji: 🧠
7
+ tags:
8
+ - deepsite-v4
9
  ---
10
 
11
+ # TIE Espace Client Privé 🚙
12
+
13
+ This project has been created with [DeepSite](https://deepsite.hf.co) AI Vibe Coding.
index.html CHANGED
@@ -1,19 +1,788 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+ <title>TIE Espace Client Privé</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
11
+ <script src="https://unpkg.com/lucide@latest"></script>
12
+ <link rel="stylesheet" href="style.css">
13
+ </head>
14
+ <body class="antialiased select-none touch-manipulation min-h-screen bg-[#0b0b0f]">
15
+ <div id="app" class="min-h-screen bg-[#0b0b0f] text-white">
16
+
17
+ <!-- HOME -->
18
+ <main id="view-home" class="view-section max-w-3xl mx-auto px-5 pt-6 pb-28 space-y-5">
19
+ <!-- Header -->
20
+ <div class="flex items-center justify-between">
21
+ <div class="flex items-center gap-3">
22
+ <div class="relative shrink-0">
23
+ <img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop&crop=face" class="w-11 h-11 rounded-full object-cover border border-white/10" alt="Marie">
24
+ </div>
25
+ <div>
26
+ <h1 class="text-2xl font-semibold tracking-tight text-white">Bonjour Marie</h1>
27
+ <p class="text-sm text-white/45 mt-1">Votre chauffeur privé est prêt.</p>
28
+ </div>
29
+ </div>
30
+ <button onclick="openAvailableDriversSheet()" class="press shrink-0 flex items-center gap-1.5 bg-[#151821] border border-white/10 rounded-full px-3 py-1.5">
31
+ <span class="w-2 h-2 rounded-full bg-emerald-400 shadow-[0_0_8px_rgba(16,185,129,0.5)]"></span>
32
+ <span class="text-xs font-medium text-white/80">2 disponibles</span>
33
+ </button>
34
+ </div>
35
+
36
+ <!-- Pastilles rapides -->
37
+ <div class="flex gap-2 overflow-x-auto no-scrollbar">
38
+ <button onclick="openModal('modal-status-confirmed')" class="press shrink-0 bg-[#151821] border border-white/10 rounded-full px-3 py-1.5 text-xs text-white/65 flex items-center gap-1.5">
39
+ <span class="w-1.5 h-1.5 rounded-full bg-emerald-400"></span>
40
+ 1 confirmée
41
+ </button>
42
+ <button onclick="openModal('modal-status-pending')" class="press shrink-0 bg-[#151821] border border-white/10 rounded-full px-3 py-1.5 text-xs text-white/65 flex items-center gap-1.5">
43
+ <span class="w-1.5 h-1.5 rounded-full bg-amber-400"></span>
44
+ 1 en attente
45
+ </button>
46
+ </div>
47
+
48
+ <!-- Planifier une course -->
49
+ <section class="bg-gradient-to-b from-[#1a1f2b] to-[#151821] border border-white/10 rounded-[1.5rem] p-5 shadow-xl shadow-black/20 space-y-5">
50
+ <div class="flex items-start justify-between gap-3">
51
+ <div>
52
+ <h2 class="text-lg font-semibold text-white">Planifier une course</h2>
53
+ <p class="text-xs text-white/45 mt-0.5">Envoyez une demande à votre chauffeur favori ou à votre réseau.</p>
54
+ </div>
55
+ <div id="return-badge" class="hidden shrink-0 mt-0.5">
56
+ <span class="inline-flex items-center bg-orange-500/10 text-orange-300 border border-orange-500/20 rounded-full text-[10px] px-2 py-1 font-medium tracking-wide uppercase">Trajet retour</span>
57
+ </div>
58
+ </div>
59
+
60
+ <div class="space-y-3">
61
+ <div class="flex items-center gap-3 bg-[#0b0b0f] border border-white/10 rounded-xl px-3 py-3">
62
+ <div class="w-2 h-2 rounded-full bg-emerald-400 shrink-0 shadow-[0_0_8px_rgba(16,185,129,0.5)]"></div>
63
+ <input type="text" id="input-depart" placeholder="Adresse de départ" class="w-full bg-transparent text-sm text-white placeholder-white/30 focus:outline-none" />
64
+ </div>
65
+ <div id="favorite-depart-pills" class="flex gap-2 overflow-x-auto no-scrollbar"></div>
66
+ <div id="extra-stops" class="space-y-2"></div>
67
+ <button onclick="addStop()" class="flex items-center gap-2 text-xs text-white/45 hover:text-emerald-400 transition-colors press">
68
+ <i data-lucide="plus" class="w-4 h-4"></i>
69
+ Ajouter un arrêt
70
+ </button>
71
+ <div class="flex items-center gap-3 bg-[#0b0b0f] border border-white/10 rounded-xl px-3 py-3">
72
+ <div class="w-2 h-2 rounded-full bg-red-400 shrink-0"></div>
73
+ <input type="text" id="input-arrivee" placeholder="Adresse d'arrivée" class="w-full bg-transparent text-sm text-white placeholder-white/30 focus:outline-none" />
74
+ </div>
75
+ <div id="favorite-arrivee-pills" class="flex gap-2 overflow-x-auto no-scrollbar"></div>
76
+ </div>
77
+
78
+ <!-- Mini-map premium -->
79
+ <div id="route-preview" class="hidden h-[140px] bg-[#0b0b0f] border border-white/10 rounded-2xl relative overflow-hidden">
80
+ <svg class="absolute inset-0 w-full h-full" preserveAspectRatio="none">
81
+ <defs>
82
+ <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
83
+ <path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(255,255,255,0.03)" stroke-width="1"/>
84
+ </pattern>
85
+ </defs>
86
+ <rect width="100%" height="100%" fill="url(#grid)" />
87
+ <line x1="20%" y1="75%" x2="75%" y2="25%" stroke="#10b981" stroke-width="2" stroke-dasharray="5 3" opacity="0.7" />
88
+ <circle cx="20%" cy="75%" r="5" fill="#10b981" />
89
+ <circle cx="75%" cy="25%" r="5" fill="#ef4444" />
90
+ </svg>
91
+ <div class="absolute bottom-2 left-0 right-0 text-center">
92
+ <span class="text-[10px] text-white/40">12 km estimés • environ 25 min</span>
93
+ </div>
94
+ <div class="absolute top-3 left-3 flex items-center gap-1.5 bg-[#151821]/80 px-2 py-1 rounded-md border border-white/5">
95
+ <div class="w-1.5 h-1.5 rounded-full bg-emerald-400"></div>
96
+ <span class="text-[10px] text-white/70 font-medium">Départ</span>
97
+ </div>
98
+ <div class="absolute top-3 right-3 flex items-center gap-1.5 bg-[#151821]/80 px-2 py-1 rounded-md border border-white/5">
99
+ <div class="w-1.5 h-1.5 rounded-full bg-red-400"></div>
100
+ <span class="text-[10px] text-white/70 font-medium">Arrivée</span>
101
+ </div>
102
+ </div>
103
+
104
+ <!-- Bloc prix premium -->
105
+ <div id="estimate-block" class="hidden bg-[#0b0b0f] border border-white/10 rounded-2xl p-5 space-y-3">
106
+ <p class="text-xs text-white/45 uppercase tracking-wider">Estimation de votre trajet</p>
107
+ <div class="flex items-end justify-between gap-4">
108
+ <div>
109
+ <p class="text-xs text-white/45 mb-0.5">Distance</p>
110
+ <p class="text-sm text-white font-medium">12 km estimés</p>
111
+ </div>
112
+ <div class="text-right">
113
+ <p id="estimate-price" class="text-3xl font-semibold text-white tracking-tight">24 €</p>
114
+ </div>
115
+ </div>
116
+ <p class="text-[10px] text-white/40 leading-relaxed">Prix indicatif, confirmé avec votre chauffeur avant départ.</p>
117
+ </div>
118
+
119
+ <div>
120
+ <p class="text-xs font-medium text-white/45 mb-2 uppercase tracking-wider">Quand ?</p>
121
+ <div class="flex gap-3">
122
+ <button id="btn-now" onclick="setWhen('now')" class="press flex-1 py-2.5 rounded-xl border text-sm font-medium transition-all bg-emerald-500/10 border-emerald-500/30 text-emerald-400">
123
+ Dès que possible
124
+ </button>
125
+ <button id="btn-later" onclick="setWhen('later')" class="press flex-1 py-2.5 rounded-xl border text-sm font-medium transition-all bg-transparent border-white/10 text-white/45">
126
+ Plus tard
127
+ </button>
128
+ </div>
129
+ </div>
130
+
131
+ <div class="flex bg-[#0b0b0f] border border-white/10 rounded-xl p-1">
132
+ <button id="seg-fav" onclick="setSegment('fav')" class="press flex-1 py-2 rounded-lg text-xs font-medium transition-all bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">Chauffeur favori</button>
133
+ <button id="seg-group" onclick="setSegment('group')" class="press flex-1 py-2 rounded-lg text-xs font-medium transition-all text-white/45 hover:text-white/70">Tous mes chauffeurs</button>
134
+ </div>
135
+
136
+ <div id="driver-block" onclick="openSelectDriverSheet()" class="cursor-pointer flex items-center justify-between bg-[#0b0b0f] border border-white/10 rounded-xl px-3 py-3">
137
+ <div class="flex items-center gap-3 pointer-events-none">
138
+ <div class="relative">
139
+ <img src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face" class="w-8 h-8 rounded-full object-cover border border-white/10">
140
+ <span class="absolute bottom-0 right-0 w-2.5 h-2.5 bg-emerald-400 rounded-full border-2 border-[#0b0b0f]"></span>
141
+ </div>
142
+ <div>
143
+ <p class="text-sm font-medium text-white">Karim</p>
144
+ <p class="text-[10px] text-emerald-400">Disponible</p>
145
+ </div>
146
+ </div>
147
+ <div class="flex items-center gap-2 pointer-events-auto">
148
+ <a href="tel:+33612345678" onclick="event.stopPropagation()" class="press h-7 w-7 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-emerald-400"><i data-lucide="phone" class="w-3.5 h-3.5"></i></a>
149
+ <i data-lucide="chevron-right" class="w-4 h-4 text-white/30 pointer-events-none"></i>
150
+ </div>
151
+ </div>
152
+
153
+ <button onclick="openModal('modal-details')" class="press w-full py-3 rounded-xl bg-[#1a1f2b] border border-white/10 text-sm font-medium text-white/80">
154
+ Détails & options
155
+ </button>
156
+ <button onclick="sendRequest()" class="press w-full py-4 rounded-2xl bg-emerald-500 text-[#0b0b0f] font-semibold text-sm shadow-lg shadow-emerald-500/20 hover:bg-emerald-400 transition-colors">
157
+ Envoyer la demande
158
+ </button>
159
+ </section>
160
+ </main>
161
+
162
+ <!-- DRIVERS -->
163
+ <section id="view-drivers" class="view-section hidden max-w-3xl mx-auto px-5 pt-6 pb-28 space-y-4">
164
+ <div class="flex items-center gap-3 mb-2">
165
+ <button onclick="showView('home')" class="press w-8 h-8 rounded-full bg-[#151821] border border-white/10 flex items-center justify-center text-white/60">
166
+ <i data-lucide="arrow-left" class="w-4 h-4"></i>
167
+ </button>
168
+ <h2 class="text-xl font-semibold text-white">Mes chauffeurs</h2>
169
+ </div>
170
+ <div id="drivers-list" class="space-y-3"></div>
171
+ <button onclick="openModal('modal-qr')" class="press mt-4 flex items-center justify-center gap-2 text-xs text-white/45 hover:text-emerald-400 transition-colors w-full py-3 rounded-xl border border-white/10 border-dashed">
172
+ <i data-lucide="scan-line" class="w-4 h-4"></i>
173
+ Ajouter via QR code
174
+ </button>
175
+ </section>
176
+
177
+ <!-- RIDES -->
178
+ <section id="view-rides" class="view-section hidden max-w-3xl mx-auto px-5 pt-6 pb-28 space-y-4">
179
+ <h2 class="text-xl font-semibold text-white mb-2">Mes courses</h2>
180
+ <div class="flex gap-2 overflow-x-auto no-scrollbar pb-1">
181
+ <button onclick="renderRides('today')" id="filter-today" class="press px-3 py-1.5 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">Aujourd'hui</button>
182
+ <button onclick="renderRides('upcoming')" id="filter-upcoming" class="press px-3 py-1.5 rounded-full text-xs font-medium bg-[#151821] text-white/60 border border-white/10">À venir</button>
183
+ <button onclick="renderRides('cancelled')" id="filter-cancelled" class="press px-3 py-1.5 rounded-full text-xs font-medium bg-[#151821] text-white/60 border border-white/10">Annulées</button>
184
+ <button onclick="renderRides('past')" id="filter-past" class="press px-3 py-1.5 rounded-full text-xs font-medium bg-[#151821] text-white/60 border border-white/10">Passées</button>
185
+ </div>
186
+ <div id="rides-list" class="space-y-3"></div>
187
+ </section>
188
+
189
+ <!-- PROFILE -->
190
+ <section id="view-profile" class="view-section hidden max-w-3xl mx-auto px-5 pt-6 pb-28 space-y-6">
191
+ <h2 class="text-xl font-semibold text-white mb-2">Profil</h2>
192
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-4 space-y-3">
193
+ <div class="flex items-center gap-3">
194
+ <img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop&crop=face" class="w-10 h-10 rounded-full object-cover border border-white/10">
195
+ <div class="flex-1 min-w-0">
196
+ <p id="profile-name-display" class="text-sm font-medium text-white">Marie Dupont</p>
197
+ <p id="profile-contact-display" class="text-xs text-white/45">06 12 34 56 78 • marie@email.com</p>
198
+ <p id="profile-type-display" class="text-[10px] text-white/30 mt-0.5">Particulier</p>
199
+ </div>
200
+ </div>
201
+ <button onclick="openModal('modal-edit-profile')" class="press w-full py-2.5 rounded-xl bg-[#1a1f2b] border border-white/10 text-xs font-medium text-white/80">Modifier mon profil</button>
202
+ </div>
203
+
204
+ <div>
205
+ <div class="flex items-center justify-between mb-3">
206
+ <h3 class="text-sm font-semibold text-white">Mes proches</h3>
207
+ <button onclick="openModal('modal-add-relative')" class="press w-8 h-8 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-white/60">
208
+ <i data-lucide="plus" class="w-4 h-4"></i>
209
+ </button>
210
+ </div>
211
+ <div id="relatives-list" class="space-y-2"></div>
212
+ </div>
213
+
214
+ <div>
215
+ <div class="flex items-center justify-between mb-3">
216
+ <h3 class="text-sm font-semibold text-white">Mes adresses favorites</h3>
217
+ <button onclick="openModal('modal-add-address')" class="press w-8 h-8 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-white/60">
218
+ <i data-lucide="plus" class="w-4 h-4"></i>
219
+ </button>
220
+ </div>
221
+ <div id="profile-favorite-addresses" class="space-y-2"></div>
222
+ </div>
223
+
224
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-4 space-y-3">
225
+ <h3 class="text-sm font-semibold text-white mb-1">Moyens de paiement</h3>
226
+ <div class="flex items-center gap-3">
227
+ <div class="w-10 h-10 rounded-lg bg-[#1a1f2b] border border-white/10 flex items-center justify-center">
228
+ <i data-lucide="credit-card" class="w-5 h-5 text-white/60"></i>
229
+ </div>
230
+ <div class="flex-1">
231
+ <p class="text-sm font-medium text-white">Carte bancaire</p>
232
+ <p class="text-xs text-white/45">**** **** **** 4242</p>
233
+ </div>
234
+ </div>
235
+ <button class="press w-full py-2.5 rounded-xl bg-[#1a1f2b] border border-white/10 text-xs font-medium text-white/80">Modifier / Ajouter</button>
236
+ </div>
237
+
238
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-4 space-y-2">
239
+ <h3 class="text-sm font-semibold text-white mb-2">FAQ</h3>
240
+ <div class="space-y-2">
241
+ <button onclick="toggleFaq(this)" class="press w-full text-left flex items-center justify-between py-2 border-b border-white/10">
242
+ <span class="text-sm text-white/80">Comment ajouter un chauffeur de confiance ?</span>
243
+ <i data-lucide="chevron-down" class="w-4 h-4 text-white/40 faq-icon transition-transform"></i>
244
+ </button>
245
+ <div class="hidden text-xs text-white/55 leading-relaxed pb-2">Scannez le QR code TIE de votre chauffeur ou saisissez manuellement son code depuis l’espace Chauffeurs.</div>
246
+
247
+ <button onclick="toggleFaq(this)" class="press w-full text-left flex items-center justify-between py-2 border-b border-white/10">
248
+ <span class="text-sm text-white/80">Le prix est-il définitif ?</span>
249
+ <i data-lucide="chevron-down" class="w-4 h-4 text-white/40 faq-icon transition-transform"></i>
250
+ </button>
251
+ <div class="hidden text-xs text-white/55 leading-relaxed pb-2">Le prix affiché est indicatif. Le montant final est confirmé par votre chauffeur avant la course.</div>
252
+
253
+ <button onclick="toggleFaq(this)" class="press w-full text-left flex items-center justify-between py-2 border-b border-white/10">
254
+ <span class="text-sm text-white/80">Qui confirme la course ?</span>
255
+ <i data-lucide="chevron-down" class="w-4 h-4 text-white/40 faq-icon transition-transform"></i>
256
+ </button>
257
+ <div class="hidden text-xs text-white/55 leading-relaxed pb-2">Votre chauffeur de confiance reçoit la demande et la confirme directement.</div>
258
+
259
+ <button onclick="toggleFaq(this)" class="press w-full text-left flex items-center justify-between py-2">
260
+ <span class="text-sm text-white/80">Comment obtenir ma facture ?</span>
261
+ <i data-lucide="chevron-down" class="w-4 h-4 text-white/40 faq-icon transition-transform"></i>
262
+ </button>
263
+ <div class="hidden text-xs text-white/55 leading-relaxed pb-2">Retrouvez vos factures dans le détail de chaque course passée, rubrique Documents.</div>
264
+ </div>
265
+ </div>
266
+
267
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-4 space-y-3">
268
+ <h3 class="text-sm font-semibold text-white mb-1">Assistance</h3>
269
+ <a href="https://wa.me/" target="_blank" class="press flex items-center gap-3 py-2 border-b border-white/10">
270
+ <i data-lucide="message-circle" class="w-5 h-5 text-emerald-400"></i>
271
+ <span class="text-sm text-white/80">WhatsApp</span>
272
+ </a>
273
+ <a href="mailto:support@tie.fr" class="press flex items-center gap-3 py-2">
274
+ <i data-lucide="mail" class="w-5 h-5 text-white/60"></i>
275
+ <span class="text-sm text-white/80">Email</span>
276
+ </a>
277
+ <p class="text-[10px] text-white/40 pt-1">Réponse sous 48h ouvrées.</p>
278
+ </div>
279
+ </section>
280
+
281
+ <!-- NAVBAR -->
282
+ <nav class="fixed bottom-0 left-0 right-0 z-40" style="padding-bottom: env(safe-area-inset-bottom);">
283
+ <div class="max-w-3xl mx-auto h-16 bg-[#0b0b0f]/80 backdrop-blur-2xl border-t border-white/[0.08] flex items-center justify-around px-2">
284
+ <button onclick="showView('home')" class="nav-btn w-12 h-12 flex items-center justify-center rounded-full text-emerald-400 transition-colors" data-view="home">
285
+ <i data-lucide="home" class="w-6 h-6"></i>
286
+ </button>
287
+ <button onclick="showView('drivers')" class="nav-btn w-12 h-12 flex items-center justify-center rounded-full text-white/40 hover:text-white/70 transition-colors" data-view="drivers">
288
+ <i data-lucide="users" class="w-6 h-6"></i>
289
+ </button>
290
+
291
+ <button onclick="openModal('modal-qr')" class="press -mt-5 w-12 h-12 rounded-full bg-emerald-500 flex items-center justify-center shadow-lg shadow-emerald-500/30 ring-4 ring-[#0b0b0f]">
292
+ <i data-lucide="scan-line" class="w-6 h-6 text-[#0b0b0f]"></i>
293
+ </button>
294
+
295
+ <button onclick="showView('rides')" class="nav-btn w-12 h-12 flex items-center justify-center rounded-full text-white/40 hover:text-white/70 transition-colors" data-view="rides">
296
+ <i data-lucide="route" class="w-6 h-6"></i>
297
+ </button>
298
+ <button onclick="showView('profile')" class="nav-btn w-12 h-12 flex items-center justify-center rounded-full text-white/40 hover:text-white/70 transition-colors" data-view="profile">
299
+ <i data-lucide="user" class="w-6 h-6"></i>
300
+ </button>
301
+ </div>
302
+ </nav>
303
+
304
+ <!-- MODALS -->
305
+ <!-- Modal: Confirmed trip -->
306
+ <div id="modal-status-confirmed" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-status-confirmed')">
307
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
308
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
309
+ <div class="flex items-center gap-3 mb-4">
310
+ <div class="w-10 h-10 rounded-full bg-emerald-500/10 flex items-center justify-center text-emerald-400">
311
+ <i data-lucide="check-circle-2" class="w-5 h-5"></i>
312
+ </div>
313
+ <div>
314
+ <h3 class="text-lg font-semibold text-white">Course confirmée</h3>
315
+ <p class="text-xs text-white/45">Aujourd'hui à 14:30</p>
316
+ </div>
317
+ </div>
318
+ <div class="space-y-3 text-sm text-white/65">
319
+ <div class="flex justify-between py-2 border-b border-white/10">
320
+ <span>Départ</span>
321
+ <span class="text-white text-right">12 Rue de la Paix, Paris</span>
322
+ </div>
323
+ <div class="flex justify-between py-2 border-b border-white/10">
324
+ <span>Arrivée</span>
325
+ <span class="text-white text-right">Aéroport CDG, Terminal 2</span>
326
+ </div>
327
+ <div class="flex justify-between py-2 border-b border-white/10">
328
+ <span>Chauffeur</span>
329
+ <span class="text-white">Karim</span>
330
+ </div>
331
+ <div class="flex justify-between py-2">
332
+ <span>Prix estimé</span>
333
+ <span class="text-white font-medium">52 €</span>
334
+ </div>
335
+ </div>
336
+ <button onclick="closeModal('modal-status-confirmed')" class="mt-6 w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Fermer</button>
337
+ </div>
338
+ </div>
339
+
340
+ <!-- Modal: Pending trip -->
341
+ <div id="modal-status-pending" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-status-pending')">
342
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
343
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
344
+ <div class="flex items-center gap-3 mb-4">
345
+ <div class="w-10 h-10 rounded-full bg-amber-500/10 flex items-center justify-center text-amber-400">
346
+ <i data-lucide="clock" class="w-5 h-5"></i>
347
+ </div>
348
+ <div>
349
+ <h3 class="text-lg font-semibold text-white">Attente de confirmation</h3>
350
+ <p class="text-xs text-white/45">Envoyée il y a 5 min</p>
351
+ </div>
352
+ </div>
353
+ <div class="space-y-3 text-sm text-white/65">
354
+ <div class="flex justify-between py-2 border-b border-white/10">
355
+ <span>Départ</span>
356
+ <span class="text-white text-right">Domicile</span>
357
+ </div>
358
+ <div class="flex justify-between py-2 border-b border-white/10">
359
+ <span>Arrivée</span>
360
+ <span class="text-white text-right">Gare de Lyon, Paris</span>
361
+ </div>
362
+ <div class="flex justify-between py-2">
363
+ <span>Chauffeur</span>
364
+ <span class="text-white">Demande groupée</span>
365
+ </div>
366
+ </div>
367
+ <button onclick="closeModal('modal-status-pending')" class="mt-6 w-full h-12 rounded-xl bg-[#1a1f2b] border border-white/10 text-white font-medium press">Fermer</button>
368
+ </div>
369
+ </div>
370
+
371
+ <!-- Modal: Date + Time -->
372
+ <div id="modal-datetime" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-datetime')">
373
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
374
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
375
+ <h3 class="text-lg font-semibold text-white mb-5">Quand souhaitez-vous partir ?</h3>
376
+ <div class="space-y-4">
377
+ <div>
378
+ <label class="text-xs text-white/45 uppercase tracking-wider mb-2 block">Date</label>
379
+ <input type="date" id="date-picker" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white focus:outline-none focus:border-emerald-500/50" />
380
+ </div>
381
+ <div>
382
+ <label class="text-xs text-white/45 uppercase tracking-wider mb-2 block">Heure</label>
383
+ <input type="time" id="time-picker" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white focus:outline-none focus:border-emerald-500/50" />
384
+ </div>
385
+ </div>
386
+ <button onclick="confirmDateTime()" class="mt-6 w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Confirmer</button>
387
+ </div>
388
+ </div>
389
+
390
+ <!-- Modal: Details & options -->
391
+ <div id="modal-details" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-details')">
392
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
393
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
394
+ <h3 class="text-lg font-semibold text-white mb-5">Détails & options</h3>
395
+ <div class="space-y-5">
396
+ <div class="flex items-center justify-between">
397
+ <div class="flex items-center gap-3">
398
+ <i data-lucide="users" class="w-5 h-5 text-white/45"></i>
399
+ <span class="text-sm text-white/80">Passagers</span>
400
+ </div>
401
+ <div class="flex items-center gap-3">
402
+ <button onclick="adjust('passengers', -1)" class="press w-8 h-8 rounded-lg bg-[#0b0b0f] border border-white/10 text-white flex items-center justify-center">-</button>
403
+ <span id="val-passengers" class="text-sm font-semibold w-4 text-center text-white">1</span>
404
+ <button onclick="adjust('passengers', 1)" class="press w-8 h-8 rounded-lg bg-[#0b0b0f] border border-white/10 text-white flex items-center justify-center">+</button>
405
+ </div>
406
+ </div>
407
+ <div class="flex items-center justify-between">
408
+ <div class="flex items-center gap-3">
409
+ <i data-lucide="briefcase" class="w-5 h-5 text-white/45"></i>
410
+ <span class="text-sm text-white/80">Valises</span>
411
+ </div>
412
+ <div class="flex items-center gap-3">
413
+ <button onclick="adjust('luggage', -1)" class="press w-8 h-8 rounded-lg bg-[#0b0b0f] border border-white/10 text-white flex items-center justify-center">-</button>
414
+ <span id="val-luggage" class="text-sm font-semibold w-4 text-center text-white">1</span>
415
+ <button onclick="adjust('luggage', 1)" class="press w-8 h-8 rounded-lg bg-[#0b0b0f] border border-white/10 text-white flex items-center justify-center">+</button>
416
+ </div>
417
+ </div>
418
+ <div class="flex items-center justify-between py-2 border-t border-white/10">
419
+ <div class="flex items-center gap-3">
420
+ <i data-lucide="dog" class="w-5 h-5 text-white/45"></i>
421
+ <span class="text-sm text-white/80">Animal de compagnie</span>
422
+ </div>
423
+ <button id="btn-animal" onclick="toggleAnimal()" class="press px-3 py-1.5 rounded-lg border border-white/10 text-xs font-medium text-white/45 transition-all">Non</button>
424
+ </div>
425
+ <div class="flex items-center justify-between py-2 border-t border-white/10">
426
+ <div class="flex items-center gap-3">
427
+ <i data-lucide="user-plus" class="w-5 h-5 text-white/45"></i>
428
+ <span class="text-sm text-white/80">Course pour un proche</span>
429
+ </div>
430
+ <button id="btn-for-other" onclick="toggleForOther()" class="press px-3 py-1.5 rounded-lg border border-white/10 text-xs font-medium text-white/45 transition-all">Non</button>
431
+ </div>
432
+ <div id="fields-for-other" class="hidden space-y-3">
433
+ <input type="text" id="other-name" placeholder="Nom" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
434
+ <input type="text" id="other-firstname" placeholder="Prénom" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
435
+ <input type="tel" id="other-phone" placeholder="Téléphone (optionnel)" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
436
+ </div>
437
+ <div>
438
+ <label class="text-xs text-white/45 uppercase tracking-wider mb-2 block">Précisions pour le chauffeur</label>
439
+ <textarea id="notes" rows="3" placeholder="Ex : porte d'entrée B, interphone 42..." class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50 resize-none"></textarea>
440
+ </div>
441
+ </div>
442
+ <button onclick="closeModal('modal-details')" class="mt-6 w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Enregistrer</button>
443
+ </div>
444
+ </div>
445
+
446
+ <!-- Modal: Sending / Loading -->
447
+ <div id="modal-loading" class="modal-enter fixed inset-0 z-50 flex flex-col items-center justify-center bg-[#0b0b0f] text-center px-6 hidden">
448
+ <div class="relative w-20 h-20 mb-10 flex items-center justify-center">
449
+ <div class="absolute inset-0 rounded-full border border-emerald-500/20"></div>
450
+ <div class="absolute inset-0 rounded-full pulse-ring"></div>
451
+ <i data-lucide="hourglass" class="w-8 h-8 text-emerald-400 animate-pulse relative z-10"></i>
452
+ </div>
453
+ <h2 id="loading-title" class="text-xl font-semibold text-white mb-2">Demande envoyée</h2>
454
+ <p id="loading-sub" class="text-sm text-white/55 max-w-[260px] mb-2">Karim consulte votre demande…</p>
455
+ <p class="text-xs text-emerald-500/80 font-medium tracking-wide uppercase">Réponse garantie : 5 min max</p>
456
+ </div>
457
+
458
+ <!-- Modal: Return trip -->
459
+ <div id="modal-return" class="modal-enter fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-return')">
460
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-6 max-w-[320px] w-full mx-4 shadow-2xl text-center" onclick="event.stopPropagation()">
461
+ <div class="w-12 h-12 rounded-full bg-emerald-500/10 flex items-center justify-center text-emerald-400 mx-auto mb-4">
462
+ <i data-lucide="repeat" class="w-6 h-6"></i>
463
+ </div>
464
+ <h3 class="text-lg font-semibold text-white mb-2">Souhaitez-vous aussi prévoir le trajet retour ?</h3>
465
+ <div class="flex gap-3 mt-6">
466
+ <button onclick="handleReturn(true)" class="press flex-1 h-11 rounded-xl bg-emerald-500 text-[#0b0b0f] text-sm font-semibold">Oui, planifier le retour</button>
467
+ <button onclick="handleReturn(false)" class="press flex-1 h-11 rounded-xl bg-[#1a1f2b] border border-white/10 text-white text-sm font-medium">Non, plus tard</button>
468
+ </div>
469
+ </div>
470
+ </div>
471
+
472
+ <!-- Modal: QR Scan -->
473
+ <div id="modal-qr" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/80 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-qr')">
474
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
475
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
476
+ <h3 class="text-lg font-semibold text-white mb-4 text-center">Scanner un QR code TIE</h3>
477
+ <div class="relative w-full h-64 bg-black rounded-xl border border-white/10 overflow-hidden mb-4">
478
+ <div class="scan-line"></div>
479
+ <div class="absolute inset-0 flex items-center justify-center">
480
+ <div class="w-32 h-32 border-2 border-dashed border-white/20 rounded-xl flex items-center justify-center">
481
+ <i data-lucide="qr-code" class="w-10 h-10 text-white/20"></i>
482
+ </div>
483
+ </div>
484
+ <div class="absolute top-3 left-3 text-[10px] text-white/40 font-mono">CAMERA SIMULATION</div>
485
+ </div>
486
+ <p class="text-xs text-white/45 text-center mb-5">Scannez le QR code TIE d'un chauffeur pour l'ajouter à vos chauffeurs de confiance.</p>
487
+ <button onclick="showManualCode()" class="w-full h-12 rounded-xl bg-[#1a1f2b] border border-white/10 text-sm font-medium text-white press mb-3">Entrer un code manuellement</button>
488
+ <div id="manual-code-area" class="hidden space-y-3">
489
+ <input type="text" id="manual-code" placeholder="Code chauffeur TIE" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50 uppercase tracking-wider" />
490
+ <button onclick="addManualCode()" class="w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Ajouter</button>
491
+ </div>
492
+ <button onclick="closeModal('modal-qr')" class="w-full h-12 rounded-xl text-sm font-medium text-white/55 hover:text-white transition-colors">Annuler</button>
493
+ </div>
494
+ </div>
495
+
496
+ <!-- Modal: Ride Detail -->
497
+ <div id="modal-ride-detail" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-ride-detail')">
498
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full max-h-[85vh] overflow-y-auto no-scrollbar" onclick="event.stopPropagation()">
499
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
500
+ <div class="flex items-center justify-between mb-4">
501
+ <h3 class="text-lg font-semibold text-white">Détail de la course</h3>
502
+ <button onclick="closeModal('modal-ride-detail')" class="press w-8 h-8 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-white/60">
503
+ <i data-lucide="x" class="w-4 h-4"></i>
504
+ </button>
505
+ </div>
506
+ <div id="ride-detail-content" class="space-y-4 text-sm"></div>
507
+ </div>
508
+ </div>
509
+
510
+ <!-- Modal: Bon de commande -->
511
+ <div id="modal-bdc" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-bdc')">
512
+ <div class="modal-sheet bg-gray-50 text-gray-900 border-t border-gray-200 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full max-h-[85vh] overflow-y-auto no-scrollbar" onclick="event.stopPropagation()">
513
+ <div class="w-10 h-1 bg-gray-300 rounded-full mx-auto mb-5"></div>
514
+ <div class="flex items-center justify-between mb-4">
515
+ <h3 class="text-lg font-bold text-gray-900">BON DE COMMANDE</h3>
516
+ <button onclick="closeModal('modal-bdc')" class="press w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center text-gray-600">
517
+ <i data-lucide="x" class="w-4 h-4"></i>
518
+ </button>
519
+ </div>
520
+ <div class="space-y-4 text-sm">
521
+ <div class="space-y-1">
522
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Référence</p>
523
+ <p class="font-semibold">BDC-2026-0001</p>
524
+ </div>
525
+ <div class="space-y-1">
526
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Date d'émission</p>
527
+ <p id="bdc-date">—</p>
528
+ </div>
529
+ <div class="space-y-1">
530
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Date & heure prévues</p>
531
+ <p id="bdc-datetime">—</p>
532
+ </div>
533
+ <div class="border-t border-gray-200 pt-3 space-y-1">
534
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Client</p>
535
+ <p class="font-medium">Marie Dupont</p>
536
+ <p class="text-xs text-gray-500">Tél. : 06 12 ** ** **</p>
537
+ </div>
538
+ <div class="border-t border-gray-200 pt-3 space-y-1">
539
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Prestataire</p>
540
+ <p class="font-medium">Karim B.</p>
541
+ <p class="text-xs text-gray-600">SAS TIE Prestige</p>
542
+ <p class="text-xs text-gray-600">SIRET : 123 456 789 00010</p>
543
+ <p class="text-xs text-gray-600">Carte VTC n° CVTC-75-2024-001</p>
544
+ <p class="text-xs text-gray-600">Immatriculation : AA-123-AA</p>
545
+ <p class="text-xs text-gray-600">contact@tie-prestige.fr</p>
546
+ </div>
547
+ <div class="border-t border-gray-200 pt-3 space-y-1">
548
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Détail de la course</p>
549
+ <p id="bdc-trajet" class="font-medium">—</p>
550
+ <p id="bdc-distance" class="text-xs text-gray-600">—</p>
551
+ <p id="bdc-duration" class="text-xs text-gray-600">Durée estimée : 35 min</p>
552
+ </div>
553
+ <div class="border-t border-gray-200 pt-3 space-y-1">
554
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Tarification</p>
555
+ <p id="bdc-rate" class="text-xs text-gray-600">—</p>
556
+ <p id="bdc-price" class="font-semibold text-gray-900">—</p>
557
+ </div>
558
+ <div class="bg-yellow-50 border border-yellow-100 rounded-lg p-3 text-xs text-yellow-800 space-y-1 mt-2">
559
+ <p>Montant indicatif sous réserve de confirmation du chauffeur.</p>
560
+ <p>Prestation de transport réalisée sur réservation préalable.</p>
561
+ <p class="font-medium">Document généré à titre d’illustration, sans valeur contractuelle.</p>
562
+ </div>
563
+ <button class="w-full h-12 rounded-xl bg-gray-900 text-white font-medium press mt-2">Télécharger PDF — démo</button>
564
+ </div>
565
+ </div>
566
+ </div>
567
+
568
+ <!-- Modal: Facture -->
569
+ <div id="modal-invoice" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-invoice')">
570
+ <div class="modal-sheet bg-gray-50 text-gray-900 border-t border-gray-200 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full max-h-[85vh] overflow-y-auto no-scrollbar" onclick="event.stopPropagation()">
571
+ <div class="w-10 h-1 bg-gray-300 rounded-full mx-auto mb-5"></div>
572
+ <div class="flex items-center justify-between mb-4">
573
+ <div>
574
+ <h3 class="text-lg font-bold text-gray-900">FACTURE</h3>
575
+ <span class="inline-block mt-1 px-2 py-0.5 rounded-full bg-emerald-100 text-emerald-700 text-[10px] font-semibold">Payée</span>
576
+ </div>
577
+ <button onclick="closeModal('modal-invoice')" class="press w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center text-gray-600">
578
+ <i data-lucide="x" class="w-4 h-4"></i>
579
+ </button>
580
+ </div>
581
+ <div class="space-y-4 text-sm">
582
+ <div class="space-y-1">
583
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Référence</p>
584
+ <p class="font-semibold">FAC-2026-0001</p>
585
+ </div>
586
+ <div class="space-y-1">
587
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Réf. bon de commande</p>
588
+ <p>BDC-2026-0001</p>
589
+ </div>
590
+ <div class="space-y-1">
591
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Date d'émission</p>
592
+ <p id="invoice-date">—</p>
593
+ </div>
594
+ <div class="space-y-1">
595
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Date de prestation</p>
596
+ <p id="invoice-prestation">—</p>
597
+ </div>
598
+ <div class="space-y-1">
599
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Heure de prise en charge</p>
600
+ <p id="invoice-time">—</p>
601
+ </div>
602
+ <div class="border-t border-gray-200 pt-3 space-y-1">
603
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Prestataire</p>
604
+ <p class="font-medium">Karim B.</p>
605
+ <p class="text-xs text-gray-600">SAS TIE Prestige</p>
606
+ <p class="text-xs text-gray-600">SIRET : 123 456 789 00010</p>
607
+ <p class="text-xs text-gray-600">Carte VTC n° CVTC-75-2024-001</p>
608
+ <p class="text-xs text-gray-600">Immatriculation : AA-123-AA</p>
609
+ <p class="text-xs text-gray-600">contact@tie-prestige.fr</p>
610
+ </div>
611
+ <div class="border-t border-gray-200 pt-3 space-y-1">
612
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Client</p>
613
+ <p class="font-medium">Marie Dupont</p>
614
+ <p class="text-xs text-gray-500">Tél. : 06 12 ** ** **</p>
615
+ </div>
616
+ <div class="border-t border-gray-200 pt-3">
617
+ <p class="text-xs text-gray-500 uppercase tracking-wider mb-2">Détail prestation</p>
618
+ <div class="bg-white border border-gray-200 rounded-lg p-3 space-y-2">
619
+ <div class="flex justify-between">
620
+ <span class="text-sm text-gray-700">Prestation VTC – trajet</span>
621
+ <span class="text-sm text-gray-900 font-medium">1</span>
622
+ </div>
623
+ <div class="flex justify-between text-xs text-gray-500">
624
+ <span>Départ → Arrivée</span>
625
+ </div>
626
+ <div class="flex justify-between pt-2 border-t border-gray-100">
627
+ <span class="text-sm text-gray-700">Prix HT</span>
628
+ <span class="text-sm text-gray-900">31,82 €</span>
629
+ </div>
630
+ <div class="flex justify-between text-xs text-gray-500">
631
+ <span>TVA 10 %</span>
632
+ <span>3,18 €</span>
633
+ </div>
634
+ <div class="flex justify-between text-sm font-semibold text-gray-900 pt-1 border-t border-gray-100">
635
+ <span>Total TTC</span>
636
+ <span>35,00 €</span>
637
+ </div>
638
+ </div>
639
+ </div>
640
+ <div class="border-t border-gray-200 pt-3 space-y-1 text-xs text-gray-600">
641
+ <p>Distance estimée : 12 km</p>
642
+ <p>Durée estimée : 35 min</p>
643
+ </div>
644
+ <div class="border-t border-gray-200 pt-3 space-y-1">
645
+ <div class="flex justify-between text-sm"><span class="text-gray-600">Total HT</span><span class="text-gray-900 font-medium">31,82 €</span></div>
646
+ <div class="flex justify-between text-sm"><span class="text-gray-600">TVA 10 %</span><span class="text-gray-900 font-medium">3,18 €</span></div>
647
+ <div class="flex justify-between text-base font-bold text-gray-900 pt-1"><span>Total TTC</span><span>35,00 €</span></div>
648
+ <div class="flex justify-between text-sm pt-1"><span class="text-emerald-600">Montant payé</span><span class="text-emerald-700 font-medium">35,00 €</span></div>
649
+ <div class="flex justify-between text-sm"><span class="text-gray-600">Reste à payer</span><span class="text-gray-900 font-medium">0,00 €</span></div>
650
+ </div>
651
+ <div class="border-t border-gray-200 pt-3 space-y-1">
652
+ <p class="text-xs text-gray-500 uppercase tracking-wider">Paiement</p>
653
+ <p class="text-sm text-gray-700">Carte bancaire **** 4242</p>
654
+ <p class="text-xs text-gray-500">Payé le 15/01/2026</p>
655
+ </div>
656
+ <div class="bg-gray-100 rounded-lg p-3 text-xs text-gray-600 space-y-1 mt-2">
657
+ <p>Prestation de transport réalisée sur réservation préalable.</p>
658
+ <p>TVA applicable selon la nature de la prestation.</p>
659
+ <p>Document à conserver comme justificatif.</p>
660
+ <p class="font-medium text-gray-500">Démo POC : document généré à titre d’illustration, sans valeur contractuelle.</p>
661
+ </div>
662
+ <button class="w-full h-12 rounded-xl bg-gray-900 text-white font-medium press mt-2">Télécharger PDF — démo</button>
663
+ </div>
664
+ </div>
665
+ </div>
666
+
667
+ <!-- Modal: Add Relative -->
668
+ <div id="modal-add-relative" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-add-relative')">
669
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
670
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
671
+ <h3 class="text-lg font-semibold text-white mb-5">Ajouter un proche</h3>
672
+ <div class="space-y-3">
673
+ <input type="text" id="rel-firstname" placeholder="Prénom" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
674
+ <input type="text" id="rel-lastname" placeholder="Nom" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
675
+ <input type="tel" id="rel-phone" placeholder="Téléphone" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
676
+ </div>
677
+ <button onclick="addRelative()" class="mt-6 w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Ajouter</button>
678
+ </div>
679
+ </div>
680
+
681
+ <!-- Modal: Select Driver (tous les chauffeurs) -->
682
+ <div id="modal-select-driver" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-select-driver')">
683
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full max-h-[80vh] overflow-y-auto no-scrollbar" onclick="event.stopPropagation()">
684
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
685
+ <h3 class="text-lg font-semibold text-white mb-5">Choisir un chauffeur</h3>
686
+ <div id="select-driver-list" class="space-y-3"></div>
687
+ <button onclick="closeModal('modal-select-driver')" class="mt-6 w-full h-12 rounded-xl bg-[#1a1f2b] border border-white/10 text-white font-medium press">Annuler</button>
688
+ </div>
689
+ </div>
690
+
691
+ <!-- Modal: Available Drivers (disponibles) -->
692
+ <div id="modal-available-drivers" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-available-drivers')">
693
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
694
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
695
+ <h3 class="text-lg font-semibold text-white mb-5">Chauffeurs disponibles</h3>
696
+ <div id="available-drivers-list" class="space-y-3"></div>
697
+ <button onclick="closeModal('modal-available-drivers')" class="mt-6 w-full h-12 rounded-xl bg-[#1a1f2b] border border-white/10 text-white font-medium press">Fermer</button>
698
+ </div>
699
+ </div>
700
+
701
+ <!-- Modal: Edit Profile -->
702
+ <div id="modal-edit-profile" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-edit-profile')">
703
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
704
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
705
+ <h3 class="text-lg font-semibold text-white mb-5">Modifier mon profil</h3>
706
+ <div class="space-y-4">
707
+ <div class="flex justify-center">
708
+ <div class="relative">
709
+ <img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop&crop=face" class="w-16 h-16 rounded-full object-cover border border-white/10">
710
+ <button onclick="document.getElementById('profile-photo-input').click()" class="absolute -bottom-1 -right-1 w-6 h-6 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-white/70 press">
711
+ <i data-lucide="camera" class="w-3.5 h-3.5"></i>
712
+ </button>
713
+ <input type="file" id="profile-photo-input" class="hidden" accept="image/*">
714
+ </div>
715
+ </div>
716
+ <div class="flex bg-[#0b0b0f] border border-white/10 rounded-xl p-1">
717
+ <button id="seg-type-particulier" onclick="setCustomerType('particulier')" class="press flex-1 py-2 rounded-lg text-xs font-medium transition-all bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">Particulier</button>
718
+ <button id="seg-type-professionnel" onclick="setCustomerType('professionnel')" class="press flex-1 py-2 rounded-lg text-xs font-medium transition-all text-white/45 hover:text-white/70">Professionnel</button>
719
+ </div>
720
+ <div class="space-y-3">
721
+ <input type="text" id="profile-firstname" placeholder="Prénom" value="Marie" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
722
+ <input type="text" id="profile-lastname" placeholder="Nom" value="Dupont" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
723
+ <input type="tel" id="profile-phone" placeholder="Téléphone" value="06 12 34 56 78" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
724
+ <input type="email" id="profile-email" placeholder="Email" value="marie@email.com" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
725
+ <input type="text" id="profile-address" placeholder="Adresse postale" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
726
+ </div>
727
+ <div id="company-fields" class="hidden space-y-3">
728
+ <input type="text" id="company-name" placeholder="Nom de l'entreprise" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
729
+ <input type="text" id="company-siret" placeholder="SIRET" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
730
+ <input type="text" id="company-vat" placeholder="Numéro de TVA" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
731
+ <input type="email" id="company-billing-email" placeholder="Email de facturation" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
732
+ </div>
733
+ </div>
734
+ <button onclick="saveProfile()" class="mt-6 w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Enregistrer</button>
735
+ </div>
736
+ </div>
737
+
738
+ <!-- Modal: Add Favorite Address -->
739
+ <div id="modal-add-address" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-add-address')">
740
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
741
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
742
+ <h3 class="text-lg font-semibold text-white mb-5">Ajouter une adresse favorite</h3>
743
+ <div class="space-y-3">
744
+ <input type="text" id="addr-label" placeholder="Label (ex: Maison)" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
745
+ <input type="text" id="addr-address" placeholder="Adresse complète" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
746
+ <input type="text" id="addr-tag" placeholder="Tag (ex: maison, travail...)" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
747
+ <select id="addr-icon" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white focus:outline-none focus:border-emerald-500/50 appearance-none">
748
+ <option value="map-pin">Icône par défaut</option>
749
+ <option value="home">Maison</option>
750
+ <option value="briefcase">Travail</option>
751
+ <option value="plane">Avion</option>
752
+ <option value="train">Train</option>
753
+ </select>
754
+ </div>
755
+ <button onclick="addFavoriteAddress()" class="mt-6 w-full h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] font-semibold press">Ajouter</button>
756
+ </div>
757
+ </div>
758
+
759
+ <!-- Modal: Edit Favorite Address -->
760
+ <div id="modal-edit-address" class="modal-enter fixed inset-0 z-50 flex flex-col justify-end bg-black/60 backdrop-blur-sm hidden" onclick="if(event.target===this)closeModal('modal-edit-address')">
761
+ <div class="modal-sheet bg-[#151821] border-t border-white/10 rounded-t-2xl p-6 max-w-[430px] mx-auto w-full" onclick="event.stopPropagation()">
762
+ <div class="w-10 h-1 bg-white/20 rounded-full mx-auto mb-5"></div>
763
+ <h3 class="text-lg font-semibold text-white mb-5">Modifier l'adresse</h3>
764
+ <input type="hidden" id="edit-addr-id" />
765
+ <div class="space-y-3">
766
+ <input type="text" id="edit-addr-label" placeholder="Label" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
767
+ <input type="text" id="edit-addr-address" placeholder="Adresse complète" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
768
+ <input type="text" id="edit-addr-tag" placeholder="Tag" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 focus:outline-none focus:border-emerald-500/50" />
769
+ <select id="edit-addr-icon" class="w-full bg-[#0b0b0f] border border-white/10 rounded-xl px-4 py-3 text-sm text-white focus:outline-none focus:border-emerald-500/50 appearance-none">
770
+ <option value="map-pin">Icône par défaut</option>
771
+ <option value="home">Maison</option>
772
+ <option value="briefcase">Travail</option>
773
+ <option value="plane">Avion</option>
774
+ <option value="train">Train</option>
775
+ </select>
776
+ </div>
777
+ <div class="flex gap-3 mt-6">
778
+ <button onclick="deleteFavoriteAddress()" class="flex-1 h-12 rounded-xl bg-red-500/10 border border-red-500/20 text-red-400 text-sm font-semibold press">Supprimer</button>
779
+ <button onclick="saveEditedAddress()" class="flex-1 h-12 rounded-xl bg-emerald-500 text-[#0b0b0f] text-sm font-semibold press">Enregistrer</button>
780
+ </div>
781
+ </div>
782
+ </div>
783
+
784
+ </div>
785
+ <script src="script.js"></script>
786
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
787
+ </body>
788
+ </html>
script.js ADDED
@@ -0,0 +1,767 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ window.onerror = function(msg, url, line) {
2
+ console.error('ERREUR JS :', msg, line);
3
+ };
4
+
5
+ const state = {
6
+ isReturnTrip: false,
7
+ profile: { firstName: 'Marie', lastName: 'Dupont', phone: '06 12 34 56 78', email: 'marie@email.com', address: '' },
8
+ customerType: 'particulier',
9
+ billingAddress: '',
10
+ company: {
11
+ name: '',
12
+ siret: '',
13
+ vat: '',
14
+ billingEmail: ''
15
+ },
16
+ drivers: [
17
+ { id: 'karim', name: 'Karim', photo: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face', status: 'Disponible', vehicle: 'Mercedes Classe E', rate: 2, rides: 18, favorite: true, available: true, phone: '+33612345678' },
18
+ { id: 'sofiane', name: 'Sofiane', photo: 'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=100&h=100&fit=crop&crop=face', status: 'Disponible', vehicle: 'Tesla Model 3', rate: 2.2, rides: 11, favorite: false, available: true, phone: '+33623456789' },
19
+ { id: 'nadia', name: 'Nadia', photo: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop&crop=face', status: 'Occupé', vehicle: 'Peugeot 508', rate: 1.9, rides: 7, favorite: false, available: false, phone: '+33634567890' },
20
+ { id: 'rachid', name: 'Rachid', photo: 'https://images.unsplash.com/photo-1531123897727-8f129e1688ce?w=100&h=100&fit=crop&crop=face', status: 'Hors ligne', vehicle: 'Toyota Corolla', rate: 2, rides: 5, favorite: false, available: false, phone: '+33645678901' }
21
+ ],
22
+ favoriteAddresses: [
23
+ { id:'home', label:'Maison', tag:'maison', icon:'home', address:'12 Rue de la Paix, Paris' },
24
+ { id:'work', label:'Travail', tag:'travail', icon:'briefcase', address:'Bureau, Paris' },
25
+ { id:'airport', label:'Aéroport', tag:'aéroport', icon:'plane', address:'Aéroport CDG, Terminal 2' },
26
+ { id:'station', label:'Gare', tag:'gare', icon:'train', address:'Gare de Lyon, Paris' }
27
+ ],
28
+ rides: [
29
+ { id: 1, date: "Aujourd'hui à 14:30", from: '12 Rue de la Paix', to: 'Aéroport CDG', driver: 'Karim', status: 'Confirmée', amount: '52 €', filter: 'today', vehicle: 'Mercedes Classe E', distance: '24 km', rate: 2, passengers: 1, luggage: 1, animal: false },
30
+ { id: 2, date: 'Envoyée il y a 5 min', from: 'Domicile', to: 'Gare de Lyon', driver: 'Demande groupée', status: 'En attente', amount: null, filter: 'today', vehicle: '-', distance: '-', rate: null, passengers: 1, luggage: 1, animal: false },
31
+ { id: 3, date: 'Demain à 09:00', from: 'Orly', to: 'La Défense', driver: 'Sofiane', status: 'Confirmée', amount: '45 €', filter: 'upcoming', vehicle: 'Tesla Model 3', distance: '22 km', rate: 2.2, passengers: 2, luggage: 2, animal: false },
32
+ { id: 4, date: 'Hier à 18:15', from: 'Bureau', to: 'Domicile', driver: 'Karim', status: 'Terminée', amount: '28 €', filter: 'past', vehicle: 'Mercedes Classe E', distance: '14 km', rate: 2, passengers: 1, luggage: 0, animal: false },
33
+ { id: 5, date: '12/01/2026', from: 'Domicile', to: 'Gare du Nord', driver: 'Nadia', status: 'Annulée', amount: '-', filter: 'cancelled', vehicle: 'Peugeot 508', distance: '-', rate: 1.9, passengers: 1, luggage: 1, animal: false }
34
+ ],
35
+ relatives: [
36
+ { firstName: 'Lucas', lastName: 'Dupont', phone: '06 23 45 67 89' }
37
+ ],
38
+ segment: 'fav',
39
+ when: 'now',
40
+ passengers: 1,
41
+ luggage: 1,
42
+ animal: false,
43
+ forOther: false,
44
+ currentRide: null
45
+ };
46
+
47
+ const views = ['home', 'drivers', 'rides', 'profile'];
48
+
49
+ function showView(name) {
50
+ views.forEach(v => {
51
+ const el = document.getElementById('view-' + v);
52
+ if (el) {
53
+ el.classList.add('hidden');
54
+ el.classList.remove('flex');
55
+ el.classList.remove('block');
56
+ }
57
+ });
58
+ const target = document.getElementById('view-' + name);
59
+ if (target) {
60
+ target.classList.remove('hidden');
61
+ if (target.tagName.toLowerCase() === 'main') {
62
+ target.classList.add('block');
63
+ } else {
64
+ target.classList.add('block');
65
+ }
66
+ target.scrollTop = 0;
67
+ }
68
+ document.querySelectorAll('.nav-btn').forEach(btn => {
69
+ if (btn.dataset.view === name) {
70
+ btn.classList.remove('text-white/40');
71
+ btn.classList.add('text-emerald-400');
72
+ } else {
73
+ btn.classList.remove('text-emerald-400');
74
+ btn.classList.add('text-white/40');
75
+ }
76
+ });
77
+ }
78
+
79
+ function openModal(id) {
80
+ const el = document.getElementById(id);
81
+ if (!el) return;
82
+ el.classList.remove('hidden');
83
+ void el.offsetWidth;
84
+ el.classList.add('active');
85
+ lucide.createIcons();
86
+ }
87
+
88
+ function closeModal(id) {
89
+ const el = document.getElementById(id);
90
+ if (!el) return;
91
+ el.classList.remove('active');
92
+ setTimeout(() => el.classList.add('hidden'), 300);
93
+ }
94
+
95
+ function renderDrivers() {
96
+ const container = document.getElementById('drivers-list');
97
+ if (!container) return;
98
+ if (state.drivers.length === 0) {
99
+ container.innerHTML = '<p class="text-sm text-white/45 text-center py-8">Aucun chauffeur dans votre réseau.</p>';
100
+ lucide.createIcons();
101
+ return;
102
+ }
103
+ container.innerHTML = state.drivers.map(d => {
104
+ const statusColor = d.status === 'Disponible' ? 'text-emerald-400' : d.status === 'Occupé' ? 'text-amber-400' : 'text-white/40';
105
+ return `
106
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-4 shadow-sm flex items-center gap-4">
107
+ <div class="relative shrink-0">
108
+ <img src="${d.photo}" class="w-12 h-12 rounded-full object-cover opacity-90 border border-white/10">
109
+ <span class="absolute bottom-0 right-0 w-3 h-3 ${d.status === 'Disponible' ? 'bg-emerald-400' : d.status === 'Occupé' ? 'bg-amber-400' : 'bg-gray-500'} rounded-full border-[2.5px] border-[#151821]"></span>
110
+ </div>
111
+ <div class="flex-1 min-w-0">
112
+ <div class="flex items-center gap-2">
113
+ <p class="text-sm font-semibold text-white">${d.name}</p>
114
+ <button onclick="setFavoriteDriver('${d.id}')" class="press">
115
+ <i data-lucide="star" class="w-4 h-4 ${d.favorite ? 'text-yellow-400 fill-yellow-400' : 'text-white/30'}"></i>
116
+ </button>
117
+ </div>
118
+ <p class="text-xs ${statusColor}">${d.status}</p>
119
+ <p class="text-xs text-white/45 mt-0.5">${d.vehicle} • ${d.rate.toFixed(1).replace('.0','')} €/km • ${d.rides} courses</p>
120
+ </div>
121
+ <div class="flex gap-2 items-center">
122
+ ${d.phone ? `<a href="tel:${d.phone}" class="press h-8 w-8 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-emerald-400"><i data-lucide="phone" class="w-4 h-4"></i></a>` : ''}
123
+ <button onclick="selectDriver('${d.id}')" class="press h-8 px-3 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs font-semibold text-emerald-400 hover:bg-emerald-500/20 transition-colors">Choisir</button>
124
+ <button onclick="removeDriver('${d.id}')" class="press h-8 w-8 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-red-400">
125
+ <i data-lucide="trash-2" class="w-4 h-4"></i>
126
+ </button>
127
+ </div>
128
+ </div>
129
+ `;
130
+ }).join('');
131
+ lucide.createIcons();
132
+ }
133
+
134
+ function setFavoriteDriver(id) {
135
+ state.drivers.forEach(d => d.favorite = (d.id === id));
136
+ renderDrivers();
137
+ renderSelectedDriver();
138
+ renderEstimate();
139
+ }
140
+
141
+ function removeDriver(id) {
142
+ const wasFav = state.drivers.find(d => d.id === id)?.favorite;
143
+ state.drivers = state.drivers.filter(d => d.id !== id);
144
+ if (wasFav && state.drivers.length > 0) {
145
+ state.drivers[0].favorite = true;
146
+ }
147
+ renderDrivers();
148
+ renderSelectedDriver();
149
+ renderEstimate();
150
+ }
151
+
152
+ function selectDriver(id) {
153
+ setFavoriteDriver(id);
154
+ setSegment('fav');
155
+ showView('home');
156
+ }
157
+
158
+ function selectDriverFromModal(id) {
159
+ setFavoriteDriver(id);
160
+ setSegment('fav');
161
+ renderSelectedDriver();
162
+ renderEstimate();
163
+ closeModal('modal-select-driver');
164
+ closeModal('modal-available-drivers');
165
+ }
166
+
167
+ function renderSelectedDriver() {
168
+ const block = document.getElementById('driver-block');
169
+ if (!block) return;
170
+ if (state.segment === 'group') {
171
+ block.innerHTML = `
172
+ <div class="flex items-center gap-3 pointer-events-none">
173
+ <div class="w-8 h-8 rounded-full bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-400">
174
+ <i data-lucide="users" class="w-4 h-4"></i>
175
+ </div>
176
+ <div>
177
+ <p class="text-sm font-medium text-white">Tous mes chauffeurs</p>
178
+ <p class="text-[10px] text-emerald-400">Demande groupée</p>
179
+ </div>
180
+ </div>
181
+ <div class="flex items-center gap-2 pointer-events-none">
182
+ <i data-lucide="chevron-right" class="w-4 h-4 text-white/30"></i>
183
+ </div>
184
+ `;
185
+ } else {
186
+ const fav = state.drivers.find(d => d.favorite) || state.drivers[0];
187
+ if (!fav) {
188
+ block.innerHTML = '<p class="text-sm text-white/45">Aucun chauffeur favori</p>';
189
+ lucide.createIcons();
190
+ return;
191
+ }
192
+ block.innerHTML = `
193
+ <div class="flex items-center gap-3 pointer-events-none">
194
+ <div class="relative">
195
+ <img src="${fav.photo}" class="w-8 h-8 rounded-full object-cover border border-white/10">
196
+ <span class="absolute bottom-0 right-0 w-2.5 h-2.5 ${fav.status === 'Disponible' ? 'bg-emerald-400' : fav.status === 'Occupé' ? 'bg-amber-400' : 'bg-gray-500'} rounded-full border-2 border-[#0b0b0f]"></span>
197
+ </div>
198
+ <div>
199
+ <p class="text-sm font-medium text-white">${fav.name}</p>
200
+ <p class="text-[10px] ${fav.status === 'Disponible' ? 'text-emerald-400' : fav.status === 'Occupé' ? 'text-amber-400' : 'text-white/40'}">${fav.status}</p>
201
+ </div>
202
+ </div>
203
+ <div class="flex items-center gap-2 pointer-events-auto">
204
+ ${fav.phone ? `<a href="tel:${fav.phone}" onclick="event.stopPropagation()" class="press h-7 w-7 rounded-full bg-[#1a1f2b] border border-white/10 flex items-center justify-center text-emerald-400"><i data-lucide="phone" class="w-3.5 h-3.5"></i></a>` : ''}
205
+ <i data-lucide="chevron-right" class="w-4 h-4 text-white/30 pointer-events-none"></i>
206
+ </div>
207
+ `;
208
+ }
209
+ block.classList.add('cursor-pointer');
210
+ block.onclick = openSelectDriverSheet;
211
+ lucide.createIcons();
212
+ }
213
+
214
+ function renderEstimate() {
215
+ const dep = document.getElementById('input-depart')?.value?.trim();
216
+ const arr = document.getElementById('input-arrivee')?.value?.trim();
217
+ const block = document.getElementById('estimate-block');
218
+ const priceEl = document.getElementById('estimate-price');
219
+ const preview = document.getElementById('route-preview');
220
+ if (!dep || !arr) {
221
+ block?.classList.add('hidden');
222
+ preview?.classList.add('hidden');
223
+ return;
224
+ }
225
+ block?.classList.remove('hidden');
226
+ preview?.classList.remove('hidden');
227
+ const distance = 12;
228
+ let price = 0;
229
+ if (state.segment === 'fav') {
230
+ const fav = state.drivers.find(d => d.favorite) || state.drivers[0];
231
+ if (fav) price = distance * fav.rate;
232
+ } else {
233
+ const availableRates = state.drivers.filter(d => d.available).map(d => d.rate);
234
+ const minRate = availableRates.length > 0 ? Math.min(...availableRates) : 0;
235
+ price = distance * minRate;
236
+ }
237
+ if (priceEl) priceEl.textContent = price.toFixed(2).replace('.00','') + ' €';
238
+ }
239
+
240
+ function setSegment(type) {
241
+ state.segment = type;
242
+ const favBtn = document.getElementById('seg-fav');
243
+ const groupBtn = document.getElementById('seg-group');
244
+ if (type === 'fav') {
245
+ favBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all bg-emerald-500/10 text-emerald-400 border border-emerald-500/20';
246
+ groupBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all text-white/45 hover:text-white/70';
247
+ } else {
248
+ groupBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all bg-emerald-500/10 text-emerald-400 border border-emerald-500/20';
249
+ favBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all text-white/45 hover:text-white/70';
250
+ }
251
+ renderSelectedDriver();
252
+ renderEstimate();
253
+ }
254
+
255
+ function addStop() {
256
+ const container = document.getElementById('extra-stops');
257
+ const div = document.createElement('div');
258
+ div.className = 'flex items-center gap-3 bg-[#0b0b0f] border border-white/10 rounded-xl px-3 py-3 animate-fade-in';
259
+ div.innerHTML = `
260
+ <div class="w-2 h-2 rounded-full bg-amber-400 shrink-0"></div>
261
+ <input type="text" placeholder="Adresse de l'arrêt" class="w-full bg-transparent text-sm text-white placeholder-white/30 focus:outline-none" />
262
+ <button onclick="this.parentElement.remove()" class="text-white/30 hover:text-red-400 transition-colors press"><i data-lucide="x" class="w-4 h-4"></i></button>
263
+ `;
264
+ container.appendChild(div);
265
+ lucide.createIcons();
266
+ }
267
+
268
+ function setWhen(type) {
269
+ state.when = type;
270
+ const btnNow = document.getElementById('btn-now');
271
+ const btnLater = document.getElementById('btn-later');
272
+ if (type === 'now') {
273
+ btnNow.className = 'press flex-1 py-2.5 rounded-xl border text-sm font-medium transition-all bg-emerald-500/10 border-emerald-500/30 text-emerald-400';
274
+ btnLater.className = 'press flex-1 py-2.5 rounded-xl border text-sm font-medium transition-all bg-transparent border-white/10 text-white/45';
275
+ } else {
276
+ btnNow.className = 'press flex-1 py-2.5 rounded-xl border text-sm font-medium transition-all bg-transparent border-white/10 text-white/45';
277
+ btnLater.className = 'press flex-1 py-2.5 rounded-xl border text-sm font-medium transition-all bg-emerald-500/10 border-emerald-500/30 text-emerald-400';
278
+ openModal('modal-datetime');
279
+ }
280
+ }
281
+
282
+ function confirmDateTime() {
283
+ closeModal('modal-datetime');
284
+ }
285
+
286
+ function adjust(key, delta) {
287
+ state[key] = Math.max(0, state[key] + delta);
288
+ if (key === 'passengers' && state[key] < 1) state[key] = 1;
289
+ const el = document.getElementById('val-' + key);
290
+ if (el) el.textContent = state[key];
291
+ }
292
+
293
+ function toggleAnimal() {
294
+ state.animal = !state.animal;
295
+ const btn = document.getElementById('btn-animal');
296
+ if (state.animal) {
297
+ btn.textContent = 'Oui';
298
+ btn.classList.remove('border-white/10','text-white/45');
299
+ btn.classList.add('border-emerald-500/30','bg-emerald-500/10','text-emerald-400');
300
+ } else {
301
+ btn.textContent = 'Non';
302
+ btn.classList.add('border-white/10','text-white/45');
303
+ btn.classList.remove('border-emerald-500/30','bg-emerald-500/10','text-emerald-400');
304
+ }
305
+ }
306
+
307
+ function toggleForOther() {
308
+ state.forOther = !state.forOther;
309
+ const btn = document.getElementById('btn-for-other');
310
+ const fields = document.getElementById('fields-for-other');
311
+ if (state.forOther) {
312
+ btn.textContent = 'Oui';
313
+ btn.classList.remove('border-white/10','text-white/45');
314
+ btn.classList.add('border-emerald-500/30','bg-emerald-500/10','text-emerald-400');
315
+ fields.classList.remove('hidden');
316
+ } else {
317
+ btn.textContent = 'Non';
318
+ btn.classList.add('border-white/10','text-white/45');
319
+ btn.classList.remove('border-emerald-500/30','bg-emerald-500/10','text-emerald-400');
320
+ fields.classList.add('hidden');
321
+ }
322
+ }
323
+
324
+ function sendRequest() {
325
+ state.isReturnTrip = false;
326
+ renderReturnBadge();
327
+ openModal('modal-loading');
328
+ const title = document.getElementById('loading-title');
329
+ const sub = document.getElementById('loading-sub');
330
+ title.textContent = 'Demande envoyée';
331
+ if (state.segment === 'group') {
332
+ sub.textContent = 'Vos chauffeurs de confiance reçoivent la demande…';
333
+ setTimeout(() => { sub.textContent = 'Karim consulte…'; }, 1800);
334
+ setTimeout(() => { sub.textContent = 'Sofiane consulte…'; }, 2800);
335
+ setTimeout(() => { sub.textContent = 'Sofiane confirme votre trajet'; title.textContent = 'Course confirmée'; }, 3800);
336
+ setTimeout(() => { closeModal('modal-loading'); openModal('modal-return'); }, 4800);
337
+ } else {
338
+ const fav = state.drivers.find(d => d.favorite) || { name: 'Karim' };
339
+ sub.textContent = fav.name + ' consulte votre demande…';
340
+ setTimeout(() => { sub.textContent = 'Votre chauffeur vérifie sa disponibilité'; }, 1800);
341
+ setTimeout(() => { sub.textContent = fav.name + ' confirme votre trajet'; title.textContent = 'Course confirmée'; }, 3200);
342
+ setTimeout(() => { closeModal('modal-loading'); openModal('modal-return'); }, 4200);
343
+ }
344
+ }
345
+
346
+ function renderReturnBadge() {
347
+ const badge = document.getElementById('return-badge');
348
+ if (!badge) return;
349
+ if (state.isReturnTrip) {
350
+ badge.classList.remove('hidden');
351
+ } else {
352
+ badge.classList.add('hidden');
353
+ }
354
+ }
355
+
356
+ function handleReturn(yes) {
357
+ closeModal('modal-return');
358
+ if (yes) {
359
+ const dep = document.getElementById('input-depart').value;
360
+ const arr = document.getElementById('input-arrivee').value;
361
+ document.getElementById('input-depart').value = arr;
362
+ document.getElementById('input-arrivee').value = dep;
363
+ document.getElementById('extra-stops').innerHTML = '';
364
+ state.isReturnTrip = true;
365
+ renderReturnBadge();
366
+ renderEstimate();
367
+ window.scrollTo({top:0, behavior:'smooth'});
368
+ } else {
369
+ document.getElementById('input-depart').value = '';
370
+ document.getElementById('input-arrivee').value = '';
371
+ document.getElementById('extra-stops').innerHTML = '';
372
+ state.isReturnTrip = false;
373
+ renderReturnBadge();
374
+ renderEstimate();
375
+ }
376
+ }
377
+
378
+ function showManualCode() {
379
+ document.getElementById('manual-code-area').classList.remove('hidden');
380
+ }
381
+
382
+ function addManualCode() {
383
+ const val = document.getElementById('manual-code').value;
384
+ if (val.trim()) {
385
+ closeModal('modal-qr');
386
+ }
387
+ }
388
+
389
+ function renderRides(filter) {
390
+ const filters = ['today','upcoming','cancelled','past'];
391
+ filters.forEach(f => {
392
+ const btn = document.getElementById('filter-' + f);
393
+ if (!btn) return;
394
+ if (f === filter) {
395
+ btn.className = 'press px-3 py-1.5 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20';
396
+ } else {
397
+ btn.className = 'press px-3 py-1.5 rounded-full text-xs font-medium bg-[#151821] text-white/60 border border-white/10';
398
+ }
399
+ });
400
+ const list = document.getElementById('rides-list');
401
+ const filtered = state.rides.filter(r => r.filter === filter);
402
+ if (filtered.length === 0) {
403
+ list.innerHTML = '<p class="text-sm text-white/45 text-center py-8">Aucune course dans cette catégorie.</p>';
404
+ return;
405
+ }
406
+ list.innerHTML = filtered.map(r => {
407
+ const statusColor = r.status === 'Confirmée' ? 'bg-emerald-500/10 text-emerald-400' : r.status === 'En attente' ? 'bg-amber-500/10 text-amber-400' : r.status === 'Annulée' ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400';
408
+ return `
409
+ <div class="bg-[#151821] border border-white/10 rounded-2xl p-4">
410
+ <div class="flex items-center justify-between mb-3">
411
+ <span class="text-xs text-white/45">${r.date}</span>
412
+ <span class="px-2 py-0.5 rounded-full ${statusColor} text-[10px] font-medium">${r.status}</span>
413
+ </div>
414
+ <p class="text-sm text-white">${r.from} → ${r.to}</p>
415
+ <div class="flex items-center justify-between mt-3">
416
+ <p class="text-xs text-white/45">Chauffeur : ${r.driver}</p>
417
+ ${r.amount ? `<p class="text-xs font-medium text-white">${r.amount}</p>` : ''}
418
+ </div>
419
+ <button onclick="openRideDetail(${r.id})" class="press mt-3 w-full py-2 rounded-xl bg-[#1a1f2b] border border-white/10 text-xs font-medium text-white/80">Détail</button>
420
+ </div>
421
+ `;
422
+ }).join('');
423
+ }
424
+
425
+ function openRideDetail(id) {
426
+ const ride = state.rides.find(r => r.id === id);
427
+ if (!ride) return;
428
+ state.currentRide = ride;
429
+ const content = document.getElementById('ride-detail-content');
430
+ const statusColor = ride.status === 'Confirmée' ? 'text-emerald-400' : ride.status === 'En attente' ? 'text-amber-400' : ride.status === 'Annulée' ? 'text-red-400' : 'text-blue-400';
431
+ let docButton = '';
432
+ if (ride.status === 'Annulée') {
433
+ docButton = '<p class="text-xs text-white/40 mt-2">Aucun document disponible pour une course annulée.</p>';
434
+ } else if (ride.filter === 'today' || ride.filter === 'upcoming') {
435
+ docButton = `<button onclick="openDocument('bdc')" class="press mt-3 w-full py-3 rounded-xl bg-emerald-500 text-[#0b0b0f] text-sm font-semibold">Voir le bon de commande</button>`;
436
+ } else if (ride.filter === 'past') {
437
+ docButton = `<button onclick="openDocument('invoice')" class="press mt-3 w-full py-3 rounded-xl bg-emerald-500 text-[#0b0b0f] text-sm font-semibold">Voir la facture</button>`;
438
+ }
439
+ content.innerHTML = `
440
+ <div class="space-y-3">
441
+ <div class="flex justify-between items-center">
442
+ <span class="text-xs text-white/45">Date / Heure</span>
443
+ <span class="text-sm text-white">${ride.date}</span>
444
+ </div>
445
+ <div class="flex justify-between items-center">
446
+ <span class="text-xs text-white/45">Trajet</span>
447
+ <span class="text-sm text-white text-right">${ride.from} → ${ride.to}</span>
448
+ </div>
449
+ <div class="flex justify-between items-center">
450
+ <span class="text-xs text-white/45">Chauffeur</span>
451
+ <span class="text-sm text-white">${ride.driver}</span>
452
+ </div>
453
+ <div class="flex justify-between items-center">
454
+ <span class="text-xs text-white/45">Véhicule</span>
455
+ <span class="text-sm text-white">${ride.vehicle}</span>
456
+ </div>
457
+ <div class="flex justify-between items-center">
458
+ <span class="text-xs text-white/45">Distance</span>
459
+ <span class="text-sm text-white">${ride.distance}</span>
460
+ </div>
461
+ ${ride.rate ? `<div class="flex justify-between items-center"><span class="text-xs text-white/45">Tarif/km</span><span class="text-sm text-white">${ride.rate} €/km</span></div>` : ''}
462
+ ${ride.amount && ride.amount !== '-' ? `<div class="flex justify-between items-center pt-2 border-t border-white/10"><span class="text-xs text-white/45">Montant</span><span class="text-sm font-semibold text-white">${ride.amount}</span></div>` : ''}
463
+ <div class="flex justify-between items-center">
464
+ <span class="text-xs text-white/45">Statut</span>
465
+ <span class="text-sm font-medium ${statusColor}">${ride.status}</span>
466
+ </div>
467
+ <div class="flex justify-between items-center">
468
+ <span class="text-xs text-white/45">Passagers</span>
469
+ <span class="text-sm text-white">${ride.passengers}</span>
470
+ </div>
471
+ <div class="flex justify-between items-center">
472
+ <span class="text-xs text-white/45">Bagages</span>
473
+ <span class="text-sm text-white">${ride.luggage}</span>
474
+ </div>
475
+ ${docButton}
476
+ </div>
477
+ `;
478
+ openModal('modal-ride-detail');
479
+ }
480
+
481
+ function openDocument(type) {
482
+ const ride = state.currentRide;
483
+ if (!ride) return;
484
+ if (type === 'bdc') {
485
+ document.getElementById('bdc-date').textContent = new Date().toLocaleDateString('fr-FR');
486
+ document.getElementById('bdc-datetime').textContent = ride.date;
487
+ document.getElementById('bdc-trajet').textContent = ride.from + ' → ' + ride.to;
488
+ document.getElementById('bdc-distance').textContent = 'Distance estimée : ' + (ride.distance || '12 km');
489
+ document.getElementById('bdc-rate').textContent = 'Tarif kilométrique : ' + (ride.rate ? ride.rate + ' €/km' : 'sur devis');
490
+ document.getElementById('bdc-price').textContent = 'Prix indicatif TTC : ' + (ride.amount || '24 €');
491
+ openModal('modal-bdc');
492
+ } else if (type === 'invoice') {
493
+ document.getElementById('invoice-date').textContent = new Date().toLocaleDateString('fr-FR');
494
+ document.getElementById('invoice-prestation').textContent = ride.date;
495
+ document.getElementById('invoice-time').textContent = ride.date.split('à')[1]?.trim() || '14:30';
496
+ openModal('modal-invoice');
497
+ }
498
+ }
499
+
500
+ function renderProfile() {
501
+ const container = document.getElementById('relatives-list');
502
+ if (!container) return;
503
+ container.innerHTML = state.relatives.map(r => `
504
+ <div class="bg-[#1a1f2b] border border-white/10 rounded-xl p-3 flex items-center justify-between">
505
+ <div>
506
+ <p class="text-sm font-medium text-white">${r.firstName} ${r.lastName}</p>
507
+ <p class="text-xs text-white/45">${r.phone}</p>
508
+ </div>
509
+ </div>
510
+ `).join('');
511
+ }
512
+
513
+ function addRelative() {
514
+ const first = document.getElementById('rel-firstname').value.trim();
515
+ const last = document.getElementById('rel-lastname').value.trim();
516
+ const phone = document.getElementById('rel-phone').value.trim();
517
+ if (!first || !last) return;
518
+ state.relatives.push({ firstName: first, lastName: last, phone: phone || '—' });
519
+ document.getElementById('rel-firstname').value = '';
520
+ document.getElementById('rel-lastname').value = '';
521
+ document.getElementById('rel-phone').value = '';
522
+ renderProfile();
523
+ closeModal('modal-add-relative');
524
+ }
525
+
526
+ function toggleFaq(btn) {
527
+ const answer = btn.nextElementSibling;
528
+ const icon = btn.querySelector('.faq-icon');
529
+ if (answer.classList.contains('hidden')) {
530
+ answer.classList.remove('hidden');
531
+ icon.style.transform = 'rotate(180deg)';
532
+ } else {
533
+ answer.classList.add('hidden');
534
+ icon.style.transform = 'rotate(0deg)';
535
+ }
536
+ }
537
+
538
+ function openSelectDriverSheet() {
539
+ const container = document.getElementById('select-driver-list');
540
+ if (!container) return;
541
+ if (state.drivers.length === 0) {
542
+ container.innerHTML = '<p class="text-sm text-white/45 text-center py-4">Aucun chauffeur.</p>';
543
+ } else {
544
+ container.innerHTML = state.drivers.map(d => {
545
+ const statusColor = d.status === 'Disponible' ? 'text-emerald-400' : d.status === 'Occupé' ? 'text-amber-400' : 'text-white/40';
546
+ return `
547
+ <div class="bg-[#1a1f2b] border border-white/10 rounded-xl p-3 flex items-center gap-3">
548
+ <div class="relative shrink-0">
549
+ <img src="${d.photo}" class="w-10 h-10 rounded-full object-cover border border-white/10">
550
+ <span class="absolute bottom-0 right-0 w-2.5 h-2.5 ${d.status === 'Disponible' ? 'bg-emerald-400' : d.status === 'Occupé' ? 'bg-amber-400' : 'bg-gray-500'} rounded-full border-2 border-[#1a1f2b]"></span>
551
+ </div>
552
+ <div class="flex-1 min-w-0">
553
+ <p class="text-sm font-medium text-white">${d.name}</p>
554
+ <p class="text-xs ${statusColor}">${d.status}</p>
555
+ <p class="text-xs text-white/45">${d.vehicle} • ${d.rate.toFixed(1).replace('.0','')} €/km</p>
556
+ </div>
557
+ <div class="flex gap-2 items-center">
558
+ ${d.phone ? `<a href="tel:${d.phone}" class="press h-8 w-8 rounded-full bg-[#151821] border border-white/10 flex items-center justify-center text-emerald-400"><i data-lucide="phone" class="w-4 h-4"></i></a>` : ''}
559
+ <button onclick="selectDriverFromModal('${d.id}')" class="press h-8 px-3 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs font-semibold text-emerald-400">Choisir</button>
560
+ </div>
561
+ </div>
562
+ `;
563
+ }).join('');
564
+ }
565
+ openModal('modal-select-driver');
566
+ }
567
+
568
+ function openAvailableDriversSheet() {
569
+ const container = document.getElementById('available-drivers-list');
570
+ if (!container) return;
571
+ const available = state.drivers.filter(d => d.available);
572
+ if (available.length === 0) {
573
+ container.innerHTML = '<p class="text-sm text-white/45 text-center py-4">Aucun chauffeur disponible.</p>';
574
+ } else {
575
+ container.innerHTML = available.map(d => `
576
+ <div class="bg-[#1a1f2b] border border-white/10 rounded-xl p-3 flex items-center gap-3">
577
+ <div class="relative shrink-0">
578
+ <img src="${d.photo}" class="w-10 h-10 rounded-full object-cover border border-white/10">
579
+ <span class="absolute bottom-0 right-0 w-2.5 h-2.5 bg-emerald-400 rounded-full border-2 border-[#1a1f2b]"></span>
580
+ </div>
581
+ <div class="flex-1 min-w-0">
582
+ <p class="text-sm font-medium text-white">${d.name}</p>
583
+ <p class="text-xs text-emerald-400">Disponible</p>
584
+ <p class="text-xs text-white/45">${d.vehicle}</p>
585
+ </div>
586
+ <div class="flex gap-2 items-center">
587
+ ${d.phone ? `<a href="tel:${d.phone}" class="press h-8 w-8 rounded-full bg-[#151821] border border-white/10 flex items-center justify-center text-emerald-400"><i data-lucide="phone" class="w-4 h-4"></i></a>` : ''}
588
+ <button onclick="selectDriverFromModal('${d.id}')" class="press h-8 px-3 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs font-semibold text-emerald-400">Choisir</button>
589
+ </div>
590
+ </div>
591
+ `).join('');
592
+ }
593
+ openModal('modal-available-drivers');
594
+ }
595
+
596
+ function renderFavoriteAddressPills() {
597
+ const departContainer = document.getElementById('favorite-depart-pills');
598
+ const arriveeContainer = document.getElementById('favorite-arrivee-pills');
599
+ if (!departContainer || !arriveeContainer) return;
600
+ const pills = (target) => state.favoriteAddresses.map(a => `
601
+ <button onclick="setFavoriteAddress('${target}', '${a.id}')" class="press shrink-0 bg-[#151821] border border-white/10 rounded-full px-3 py-1.5 text-xs text-white/55 flex items-center gap-1.5 hover:border-emerald-500/30 hover:text-emerald-400 transition-colors">
602
+ <i data-lucide="${a.icon || 'map-pin'}" class="w-3 h-3"></i>
603
+ ${a.label}
604
+ </button>
605
+ `).join('');
606
+ departContainer.innerHTML = pills('depart');
607
+ arriveeContainer.innerHTML = pills('arrivee');
608
+ lucide.createIcons();
609
+ }
610
+
611
+ function setFavoriteAddress(target, id) {
612
+ const addr = state.favoriteAddresses.find(a => a.id === id);
613
+ if (!addr) return;
614
+ if (target === 'depart') {
615
+ const input = document.getElementById('input-depart');
616
+ if (input) input.value = addr.address;
617
+ } else if (target === 'arrivee') {
618
+ const input = document.getElementById('input-arrivee');
619
+ if (input) input.value = addr.address;
620
+ }
621
+ renderEstimate();
622
+ }
623
+
624
+ function renderFavoriteAddressesProfile() {
625
+ const container = document.getElementById('profile-favorite-addresses');
626
+ if (!container) return;
627
+ if (state.favoriteAddresses.length === 0) {
628
+ container.innerHTML = '<p class="text-xs text-white/45">Aucune adresse favorite.</p>';
629
+ return;
630
+ }
631
+ container.innerHTML = state.favoriteAddresses.map(a => `
632
+ <div onclick="openEditAddress('${a.id}')" class="cursor-pointer bg-[#1a1f2b] border border-white/10 rounded-xl p-3 flex items-center justify-between press">
633
+ <div class="min-w-0">
634
+ <div class="flex items-center gap-2">
635
+ <i data-lucide="${a.icon || 'map-pin'}" class="w-4 h-4 text-white/45"></i>
636
+ <p class="text-sm font-medium text-white">${a.label}</p>
637
+ </div>
638
+ <p class="text-xs text-white/45 mt-0.5 truncate">${a.address}</p>
639
+ </div>
640
+ <span class="text-[10px] text-white/30 uppercase tracking-wider border border-white/10 px-2 py-0.5 rounded-full shrink-0">${a.tag}</span>
641
+ </div>
642
+ `).join('');
643
+ lucide.createIcons();
644
+ }
645
+
646
+ function addFavoriteAddress() {
647
+ const label = document.getElementById('addr-label').value.trim();
648
+ const address = document.getElementById('addr-address').value.trim();
649
+ const tag = document.getElementById('addr-tag').value.trim() || label.toLowerCase();
650
+ const icon = document.getElementById('addr-icon')?.value || 'map-pin';
651
+ if (!label || !address) return;
652
+ const id = 'addr_' + Date.now();
653
+ state.favoriteAddresses.push({ id, label, tag, icon, address });
654
+ document.getElementById('addr-label').value = '';
655
+ document.getElementById('addr-address').value = '';
656
+ document.getElementById('addr-tag').value = '';
657
+ if (document.getElementById('addr-icon')) document.getElementById('addr-icon').value = 'map-pin';
658
+ closeModal('modal-add-address');
659
+ renderFavoriteAddressesProfile();
660
+ renderFavoriteAddressPills();
661
+ }
662
+
663
+ let editingAddressId = null;
664
+
665
+ function openEditAddress(id) {
666
+ const addr = state.favoriteAddresses.find(a => a.id === id);
667
+ if (!addr) return;
668
+ editingAddressId = id;
669
+ document.getElementById('edit-addr-id').value = id;
670
+ document.getElementById('edit-addr-label').value = addr.label;
671
+ document.getElementById('edit-addr-address').value = addr.address;
672
+ document.getElementById('edit-addr-tag').value = addr.tag;
673
+ const iconSelect = document.getElementById('edit-addr-icon');
674
+ if (iconSelect) iconSelect.value = addr.icon || 'map-pin';
675
+ openModal('modal-edit-address');
676
+ }
677
+
678
+ function saveEditedAddress() {
679
+ if (!editingAddressId) return;
680
+ const addr = state.favoriteAddresses.find(a => a.id === editingAddressId);
681
+ if (!addr) return;
682
+ addr.label = document.getElementById('edit-addr-label').value.trim();
683
+ addr.address = document.getElementById('edit-addr-address').value.trim();
684
+ addr.tag = document.getElementById('edit-addr-tag').value.trim();
685
+ const iconSelect = document.getElementById('edit-addr-icon');
686
+ if (iconSelect) addr.icon = iconSelect.value;
687
+ editingAddressId = null;
688
+ closeModal('modal-edit-address');
689
+ renderFavoriteAddressesProfile();
690
+ renderFavoriteAddressPills();
691
+ }
692
+
693
+ function deleteFavoriteAddress(id) {
694
+ if (!id && editingAddressId) id = editingAddressId;
695
+ if (!id) return;
696
+ state.favoriteAddresses = state.favoriteAddresses.filter(a => a.id !== id);
697
+ editingAddressId = null;
698
+ closeModal('modal-edit-address');
699
+ renderFavoriteAddressesProfile();
700
+ renderFavoriteAddressPills();
701
+ }
702
+
703
+ function setCustomerType(type) {
704
+ state.customerType = type;
705
+ const partBtn = document.getElementById('seg-type-particulier');
706
+ const proBtn = document.getElementById('seg-type-professionnel');
707
+ const companyFields = document.getElementById('company-fields');
708
+ if (type === 'particulier') {
709
+ partBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all bg-emerald-500/10 text-emerald-400 border border-emerald-500/20';
710
+ proBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all text-white/45 hover:text-white/70';
711
+ if (companyFields) companyFields.classList.add('hidden');
712
+ } else {
713
+ proBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all bg-emerald-500/10 text-emerald-400 border border-emerald-500/20';
714
+ partBtn.className = 'press flex-1 py-2 rounded-lg text-xs font-medium transition-all text-white/45 hover:text-white/70';
715
+ if (companyFields) companyFields.classList.remove('hidden');
716
+ }
717
+ }
718
+
719
+ function saveProfile() {
720
+ const first = document.getElementById('profile-firstname').value.trim();
721
+ const last = document.getElementById('profile-lastname').value.trim();
722
+ const phone = document.getElementById('profile-phone').value.trim();
723
+ const email = document.getElementById('profile-email').value.trim();
724
+ const address = document.getElementById('profile-address').value.trim();
725
+ if (!first || !last) return;
726
+ state.profile = { firstName: first, lastName: last, phone, email, address };
727
+ state.billingAddress = address;
728
+ const nameDisplay = document.getElementById('profile-name-display');
729
+ const contactDisplay = document.getElementById('profile-contact-display');
730
+ const typeDisplay = document.getElementById('profile-type-display');
731
+ if (nameDisplay) nameDisplay.textContent = first + ' ' + last;
732
+ if (contactDisplay) contactDisplay.textContent = (phone ? phone + ' • ' : '') + (email || '');
733
+ if (typeDisplay) {
734
+ if (state.customerType === 'professionnel' && state.company.name) {
735
+ typeDisplay.textContent = 'Professionnel • ' + state.company.name;
736
+ } else {
737
+ typeDisplay.textContent = state.customerType === 'particulier' ? 'Particulier' : 'Professionnel';
738
+ }
739
+ }
740
+ if (state.customerType === 'professionnel') {
741
+ state.company.name = document.getElementById('company-name').value.trim();
742
+ state.company.siret = document.getElementById('company-siret').value.trim();
743
+ state.company.vat = document.getElementById('company-vat').value.trim();
744
+ state.company.billingEmail = document.getElementById('company-billing-email').value.trim();
745
+ }
746
+ closeModal('modal-edit-profile');
747
+ }
748
+
749
+ window.addEventListener('DOMContentLoaded', () => {
750
+ lucide.createIcons();
751
+ showView('home');
752
+ renderDrivers();
753
+ renderSelectedDriver();
754
+ renderRides('today');
755
+ renderProfile();
756
+ renderFavoriteAddressPills();
757
+ renderFavoriteAddressesProfile();
758
+ const today = new Date().toISOString().split('T')[0];
759
+ const dp = document.getElementById('date-picker');
760
+ if (dp) dp.value = today;
761
+ const tp = document.getElementById('time-picker');
762
+ if (tp) tp.value = '14:30';
763
+ const depInput = document.getElementById('input-depart');
764
+ const arrInput = document.getElementById('input-arrivee');
765
+ if (depInput) depInput.addEventListener('input', renderEstimate);
766
+ if (arrInput) arrInput.addEventListener('input', renderEstimate);
767
+ });
style.css CHANGED
@@ -1,28 +1,74 @@
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
28
  }
 
 
 
 
1
  body {
2
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
3
+ background: #0b0b0f;
4
+ color: #fff;
5
+ -webkit-tap-highlight-color: transparent;
6
  }
7
 
8
+ .no-scrollbar::-webkit-scrollbar { display: none; }
9
+ .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
10
+
11
+ .modal-enter {
12
+ opacity: 0;
13
+ pointer-events: none;
14
+ transition: opacity 0.3s ease;
15
+ }
16
+ .modal-enter.active {
17
+ opacity: 1;
18
+ pointer-events: auto;
19
+ }
20
+ .modal-sheet {
21
+ transform: translateY(100%);
22
+ transition: transform 0.35s cubic-bezier(0.32,0.72,0,1);
23
+ }
24
+ .modal-enter.active .modal-sheet {
25
+ transform: translateY(0);
26
+ }
27
+
28
+ input[type="date"]::-webkit-calendar-picker-indicator,
29
+ input[type="time"]::-webkit-calendar-picker-indicator {
30
+ filter: invert(1);
31
+ opacity: 0.4;
32
+ cursor: pointer;
33
  }
34
 
35
+ .press:active {
36
+ transform: scale(0.97);
37
+ transition: transform 0.08s;
 
 
38
  }
39
 
40
+ @keyframes scan {
41
+ 0% { top: 0%; opacity: 0; }
42
+ 10% { opacity: 1; }
43
+ 90% { opacity: 1; }
44
+ 100% { top: 100%; opacity: 0; }
45
+ }
46
+ .scan-line {
47
+ position: absolute;
48
+ left: 0; right: 0;
49
+ height: 2px;
50
+ background: linear-gradient(90deg, transparent, #10b981, transparent);
51
+ animation: scan 2.5s linear infinite;
52
+ box-shadow: 0 0 12px rgba(16,185,129,0.6);
53
+ }
54
+
55
+ @keyframes ping-ring {
56
+ 0% { transform: scale(0.8); opacity: 0.5; }
57
+ 100% { transform: scale(2); opacity: 0; }
58
+ }
59
+ .pulse-ring::before {
60
+ content: '';
61
+ position: absolute;
62
+ inset: 0;
63
+ border-radius: 50%;
64
+ border: 1px solid #10b981;
65
+ animation: ping-ring 2s cubic-bezier(0,0,0.2,1) infinite;
66
  }
67
 
68
+ @keyframes fadeIn {
69
+ from { opacity: 0; transform: translateY(-4px); }
70
+ to { opacity: 1; transform: translateY(0); }
71
  }
72
+ .animate-fade-in {
73
+ animation: fadeIn 0.2s ease-out both;
74
+ }