@hotelcard/ui 0.0.13 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @hotelcard/ui might be problematic. Click here for more details.
- package/README.md +121 -68
- package/dist/index.cjs +1510 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +607 -17
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +857 -79
- package/dist/index.d.ts +857 -79
- package/dist/index.js +1488 -105
- package/dist/index.js.map +1 -1
- package/package.json +22 -11
package/dist/index.js
CHANGED
|
@@ -1,19 +1,556 @@
|
|
|
1
1
|
// src/context/UIContext.tsx
|
|
2
|
-
import { createContext, useContext } from "react";
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
|
+
|
|
4
|
+
// src/locales/de.json
|
|
5
|
+
var de_default = {
|
|
6
|
+
button: {
|
|
7
|
+
order: "Bestellen",
|
|
8
|
+
"order-navigation": "Bestellen",
|
|
9
|
+
"order-hc": "HotelCard bestellen",
|
|
10
|
+
"my-account": "Mein Konto",
|
|
11
|
+
search: "Suchen",
|
|
12
|
+
"back-to-top": "Nach oben"
|
|
13
|
+
},
|
|
14
|
+
link: {
|
|
15
|
+
"member-benefits": "Member Benefits",
|
|
16
|
+
"view-all-hotels": "Alle Hoteldeals ansehen",
|
|
17
|
+
"search-by-map": "Kartenansicht",
|
|
18
|
+
"search-by-region": "Hotels nach Region",
|
|
19
|
+
"search-by-experience": "Hotels nach Erlebnis",
|
|
20
|
+
"travel-inspiration": "Reiseinspiration",
|
|
21
|
+
"booking-tips-and-tricks": "Buchungstipps",
|
|
22
|
+
home: "Startseite",
|
|
23
|
+
"all-hotel-deals": "Alle Hotelangebote",
|
|
24
|
+
"search-results": "Suchergebnisse"
|
|
25
|
+
},
|
|
26
|
+
general: {
|
|
27
|
+
"signed-out": "Anmelden und buchen",
|
|
28
|
+
"room-price": "ab CHF xxx / Zimmer",
|
|
29
|
+
guarantee: "14 Tage Geld-zur\xFCck-Garantie",
|
|
30
|
+
contact: "Weitere Fragen? Kontaktieren Sie uns.",
|
|
31
|
+
"breakfast-included": "Fr\xFChst\xFCck inbegriffen",
|
|
32
|
+
"free-cancellation": "Kostenlose Stornierung",
|
|
33
|
+
"suggested-destinations": "Vorgeschlagene Reiseziele",
|
|
34
|
+
"when-months": "Wann m\xF6chtest du reisen?",
|
|
35
|
+
"hotel-deals-found": "Hotelangebote gefunden",
|
|
36
|
+
"no-results": "Probieren Sie andere Reiseziele, \xE4ndern Sie Ihre Daten oder entfernen Sie einige Filter.",
|
|
37
|
+
"unavailable-for-selected-days": "F\xFCr die ausgew\xE4hlten Daten nicht verf\xFCgbar.",
|
|
38
|
+
"cant-accommodate-all": "Das Hotel kann nicht alle G\xE4ste beherbergen.",
|
|
39
|
+
"reset-destination": "Zielsuche zur\xFCcksetzen, um Regionen zu filtern"
|
|
40
|
+
},
|
|
41
|
+
label: {
|
|
42
|
+
"price-from": "ab ",
|
|
43
|
+
"price-for": "/ Zimmer",
|
|
44
|
+
"per-room-night": "pro Zimmer & Nacht ab",
|
|
45
|
+
new: "Neu",
|
|
46
|
+
anytime: "Jederzeit",
|
|
47
|
+
anywhere: "Alle Reiseziele",
|
|
48
|
+
dates: "Datum",
|
|
49
|
+
flexible: "Flexibel",
|
|
50
|
+
where: "Wohin",
|
|
51
|
+
when: "Wann",
|
|
52
|
+
who: "Wer",
|
|
53
|
+
nearby: "In der N\xE4he",
|
|
54
|
+
hotels: "Hotel",
|
|
55
|
+
filter: "Filter",
|
|
56
|
+
sort: "Sortieren",
|
|
57
|
+
map: "Karte",
|
|
58
|
+
rating: "Bewertung",
|
|
59
|
+
"rating-excellent": "Ausgezeichnet",
|
|
60
|
+
"rating-very-good": "Sehr gut",
|
|
61
|
+
"rating-good": "Gut",
|
|
62
|
+
"rating-fair": "Ansprechend",
|
|
63
|
+
"rating-none": "Keine Bewertung"
|
|
64
|
+
},
|
|
65
|
+
product: {
|
|
66
|
+
"6m": "6-Monatsabo",
|
|
67
|
+
"1y": "1-Jahresabo",
|
|
68
|
+
"2y": "2-Jahresabo",
|
|
69
|
+
"3y": "3-Jahresabo",
|
|
70
|
+
"price-6m": "79.-",
|
|
71
|
+
"price-6m-disc": "59.-",
|
|
72
|
+
"price-1y": "99.-",
|
|
73
|
+
"price-1y-disc": "79.-",
|
|
74
|
+
"price-2y": "198.-",
|
|
75
|
+
"price-2y-disc": "173.-",
|
|
76
|
+
"price-3y": "297.-",
|
|
77
|
+
"price-3y-disc": "247.-",
|
|
78
|
+
"price-gift": "99.-",
|
|
79
|
+
"price-gift-disc": "59.-"
|
|
80
|
+
},
|
|
81
|
+
subheadline: {
|
|
82
|
+
"your-hc": "Ihre HotelCard",
|
|
83
|
+
"popular-hotels": "Beliebte Hotelangebote",
|
|
84
|
+
"no-results": "Probieren Sie andere Reiseziele, \xE4ndern Sie Ihre Daten oder entfernen Sie einige Filter.",
|
|
85
|
+
"sort-by": "Sortieren nach"
|
|
86
|
+
},
|
|
87
|
+
form: {
|
|
88
|
+
guests: "G\xE4ste",
|
|
89
|
+
guest: "Gast",
|
|
90
|
+
adults: "Erwachsene",
|
|
91
|
+
children: "Kinder",
|
|
92
|
+
pet: "Haustier",
|
|
93
|
+
"age-of-child": "Alter des Kindes",
|
|
94
|
+
age: "Alter",
|
|
95
|
+
"age-error": "Bitte w\xE4hlen Sie das Alter aus"
|
|
96
|
+
},
|
|
97
|
+
filter: {
|
|
98
|
+
filters: "Filter",
|
|
99
|
+
destination: "Reiseziel",
|
|
100
|
+
experience: "Erlebnis",
|
|
101
|
+
"show-all": "Alle anzeigen",
|
|
102
|
+
price: "Preis",
|
|
103
|
+
discount: "Rabatt",
|
|
104
|
+
services: "Leistungen",
|
|
105
|
+
meals: "Verpflegung",
|
|
106
|
+
"hotel-category": "Hotelkategorie",
|
|
107
|
+
reviews: "Bewertungen",
|
|
108
|
+
mobility: "Mobilit\xE4t",
|
|
109
|
+
"wellness-spa": "Wellness & Spa",
|
|
110
|
+
"price-high-low": "Preis: absteigend",
|
|
111
|
+
"price-low-high": "Preis: aufsteigend",
|
|
112
|
+
"best-rating": "Beste Bewertung",
|
|
113
|
+
"most-popular": "Beliebt",
|
|
114
|
+
"newest-hotels": "Neueste",
|
|
115
|
+
relevance: "Relevanz",
|
|
116
|
+
selected: "String value",
|
|
117
|
+
"clear-all": "Alles l\xF6schen",
|
|
118
|
+
options: "Leistungen",
|
|
119
|
+
"hotellerie-suisse": "Klassifikation HotellerieSuisse",
|
|
120
|
+
trustyou: "Bewertungen von Reisenden auf Trust You\xAE",
|
|
121
|
+
"select-all": "Alle ausw\xE4hlen",
|
|
122
|
+
reset: "Zur\xFCcksetzen",
|
|
123
|
+
"breakfast-included": "Fr\xFChst\xFCck inbegriffen"
|
|
124
|
+
},
|
|
125
|
+
headline: {
|
|
126
|
+
"no-results": "Zurzeit entsprechen keine Aufenthalte Ihrer Suche"
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// src/locales/en.json
|
|
131
|
+
var en_default = {
|
|
132
|
+
button: {
|
|
133
|
+
order: "Order",
|
|
134
|
+
"order-navigation": "Join",
|
|
135
|
+
"order-hc": "Order HotelCard",
|
|
136
|
+
"my-account": "My account",
|
|
137
|
+
search: "Search",
|
|
138
|
+
"back-to-top": "Back to top"
|
|
139
|
+
},
|
|
140
|
+
link: {
|
|
141
|
+
"member-benefits": "Member Benefits",
|
|
142
|
+
"view-all-hotels": "View all hotel deals",
|
|
143
|
+
"search-by-map": "Map search",
|
|
144
|
+
"search-by-region": "Hotels by region",
|
|
145
|
+
"search-by-experience": "Hotels by experience",
|
|
146
|
+
"travel-inspiration": "Travel inspiration",
|
|
147
|
+
"booking-tips-and-tricks": "Booking tips",
|
|
148
|
+
home: "Home",
|
|
149
|
+
"all-hotel-deals": "All hotel deals",
|
|
150
|
+
"search-results": "Search results"
|
|
151
|
+
},
|
|
152
|
+
general: {
|
|
153
|
+
"signed-out": "Log in and book",
|
|
154
|
+
"room-price": "from CHF xxx / room",
|
|
155
|
+
guarantee: "14-day money-back guarantee",
|
|
156
|
+
contact: "More questions? Contact us.",
|
|
157
|
+
"breakfast-included": "Breakfast included",
|
|
158
|
+
"free-cancellation": "Free cancellation",
|
|
159
|
+
"suggested-destinations": "Not sure where to travel next?",
|
|
160
|
+
"when-months": "When do you want to go?",
|
|
161
|
+
"hotel-deals-found": "hotel deals found",
|
|
162
|
+
"no-results": "Explore different destinations, change your dates, or remove some filters.",
|
|
163
|
+
"unavailable-for-selected-days": "Unavailable for selected dates.",
|
|
164
|
+
"cant-accommodate-all": "Hotel can\u2019t accommodate all guests.",
|
|
165
|
+
"reset-destination": "Reset destination search to use region filters."
|
|
166
|
+
},
|
|
167
|
+
label: {
|
|
168
|
+
"price-from": "from ",
|
|
169
|
+
"price-for": "/ room",
|
|
170
|
+
"per-room-night": "per room & night from",
|
|
171
|
+
new: "New",
|
|
172
|
+
anytime: "Anytime",
|
|
173
|
+
anywhere: "All destinations",
|
|
174
|
+
dates: "Dates",
|
|
175
|
+
flexible: "Flexible",
|
|
176
|
+
where: "Where",
|
|
177
|
+
when: "When",
|
|
178
|
+
who: "Who",
|
|
179
|
+
nearby: "Nearby",
|
|
180
|
+
hotels: "Hotel",
|
|
181
|
+
filter: "Filter",
|
|
182
|
+
sort: "Sort",
|
|
183
|
+
map: "Map",
|
|
184
|
+
rating: "Rating",
|
|
185
|
+
"rating-excellent": "Excellent",
|
|
186
|
+
"rating-very-good": "Very good",
|
|
187
|
+
"rating-good": "Good",
|
|
188
|
+
"rating-fair": "Fair",
|
|
189
|
+
"rating-none": "No rating"
|
|
190
|
+
},
|
|
191
|
+
product: {
|
|
192
|
+
"6m": "6-month subscription",
|
|
193
|
+
"1y": "1-year subscription",
|
|
194
|
+
"2y": "2-year subscription",
|
|
195
|
+
"3y": "3-year subscription",
|
|
196
|
+
"price-6m": "79.-",
|
|
197
|
+
"price-6m-disc": "59.-",
|
|
198
|
+
"price-1y": "99.-",
|
|
199
|
+
"price-1y-disc": "79.-",
|
|
200
|
+
"price-2y": "198.-",
|
|
201
|
+
"price-2y-disc": "173.-",
|
|
202
|
+
"price-3y": "297.-",
|
|
203
|
+
"price-3y-disc": "247.-",
|
|
204
|
+
"price-gift": "99.-",
|
|
205
|
+
"price-gift-disc": "59.-"
|
|
206
|
+
},
|
|
207
|
+
subheadline: {
|
|
208
|
+
"your-hc": "Your HotelCard",
|
|
209
|
+
"popular-hotels": "Popular hotel deals",
|
|
210
|
+
"no-results": "Explore different destinations, change your dates, or remove some filters.",
|
|
211
|
+
"sort-by": "Sort by"
|
|
212
|
+
},
|
|
213
|
+
form: {
|
|
214
|
+
guests: "guests",
|
|
215
|
+
guest: "guest",
|
|
216
|
+
adults: "Adults",
|
|
217
|
+
children: "Children",
|
|
218
|
+
pet: "Pet",
|
|
219
|
+
"age-of-child": "Child\u2019s age",
|
|
220
|
+
age: "Age",
|
|
221
|
+
"age-error": "Please select age"
|
|
222
|
+
},
|
|
223
|
+
filter: {
|
|
224
|
+
filters: "Filters",
|
|
225
|
+
destination: "Destination",
|
|
226
|
+
experience: "Experience",
|
|
227
|
+
"show-all": "Show all",
|
|
228
|
+
price: "Price",
|
|
229
|
+
discount: "Discount",
|
|
230
|
+
services: "Services",
|
|
231
|
+
meals: "Meals",
|
|
232
|
+
"hotel-category": "Hotel category",
|
|
233
|
+
reviews: "Reviews",
|
|
234
|
+
mobility: "Mobility",
|
|
235
|
+
"wellness-spa": "Wellness & Spa",
|
|
236
|
+
"price-high-low": "Price high to low",
|
|
237
|
+
"price-low-high": "Price low to high",
|
|
238
|
+
"best-rating": "Best guest rating",
|
|
239
|
+
"most-popular": "Most popular",
|
|
240
|
+
"newest-hotels": "Newest",
|
|
241
|
+
relevance: "Relevance",
|
|
242
|
+
selected: "Selected",
|
|
243
|
+
"clear-all": "Clear all",
|
|
244
|
+
options: "Options",
|
|
245
|
+
"hotellerie-suisse": "Classification HotellerieSuisse",
|
|
246
|
+
trustyou: "Reviews from travelers on TrustYou\xAE",
|
|
247
|
+
"select-all": "Select all",
|
|
248
|
+
reset: "Reset",
|
|
249
|
+
"breakfast-included": "Breakfast included"
|
|
250
|
+
},
|
|
251
|
+
headline: {
|
|
252
|
+
"no-results": "No stays match your search right now"
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// src/locales/fr.json
|
|
257
|
+
var fr_default = {
|
|
258
|
+
button: {
|
|
259
|
+
order: "Commander",
|
|
260
|
+
"order-navigation": "Commander",
|
|
261
|
+
"order-hc": "Commander l'HotelCard",
|
|
262
|
+
"my-account": "Mon compte",
|
|
263
|
+
search: "Rechercher",
|
|
264
|
+
"back-to-top": "Haut de page"
|
|
265
|
+
},
|
|
266
|
+
link: {
|
|
267
|
+
"member-benefits": "Member Benefits",
|
|
268
|
+
"view-all-hotels": "D\xE9couvrez toutes nos offres",
|
|
269
|
+
"search-by-map": "Recherche sur la carte",
|
|
270
|
+
"search-by-region": "H\xF4tels par r\xE9gion",
|
|
271
|
+
"search-by-experience": "H\xF4tels par exp\xE9rience",
|
|
272
|
+
"travel-inspiration": "Inspiration voyage",
|
|
273
|
+
"booking-tips-and-tricks": "Conseils r\xE9servation",
|
|
274
|
+
home: "Accueil",
|
|
275
|
+
"all-hotel-deals": "Toutes les offres d\u2019h\xF4tels",
|
|
276
|
+
"search-results": "R\xE9sultats de recherche"
|
|
277
|
+
},
|
|
278
|
+
general: {
|
|
279
|
+
"signed-out": "Se connecter et r\xE9server",
|
|
280
|
+
"room-price": "\xE0 partir de CHF XXX par chambre",
|
|
281
|
+
guarantee: "Garantie de remboursement de 14 jours",
|
|
282
|
+
contact: "D\u2019autres questions ? Contactez-nous.",
|
|
283
|
+
"breakfast-included": "Petit-d\xE9jeuner inclus",
|
|
284
|
+
"free-cancellation": "Annulation gratuite",
|
|
285
|
+
"suggested-destinations": "Suggestions de destinations",
|
|
286
|
+
"when-months": "Quand souhaitez-vous partir ?",
|
|
287
|
+
"hotel-deals-found": "offres d\u2019h\xF4tel trouv\xE9es",
|
|
288
|
+
"no-results": "Explorez d\u2019autres destinations, modifiez vos dates ou retirez certains filtres.",
|
|
289
|
+
"unavailable-for-selected-days": "Indisponible aux dates s\xE9lectionn\xE9es.",
|
|
290
|
+
"cant-accommodate-all": "L\u2019h\xF4tel ne peut pas accueillir tous les voyageurs.",
|
|
291
|
+
"reset-destination": "R\xE9initialiser la destination et filtrer par r\xE9gion"
|
|
292
|
+
},
|
|
293
|
+
label: {
|
|
294
|
+
"price-from": "\xE0 partir de ",
|
|
295
|
+
"price-for": "par chambre",
|
|
296
|
+
"per-room-night": "par chambre & nuit d\xE8s",
|
|
297
|
+
new: "Nouveau",
|
|
298
|
+
anytime: "\xC0 tout moment",
|
|
299
|
+
anywhere: "Toutes les destinations",
|
|
300
|
+
dates: "Dates",
|
|
301
|
+
flexible: "Flexible",
|
|
302
|
+
where: "Destination",
|
|
303
|
+
when: "Quand",
|
|
304
|
+
who: "Voyageurs",
|
|
305
|
+
nearby: "\xC0 proximit\xE9",
|
|
306
|
+
hotels: "H\xF4tel",
|
|
307
|
+
filter: "Filtrer",
|
|
308
|
+
sort: "Trier",
|
|
309
|
+
map: "Carte",
|
|
310
|
+
rating: "Note",
|
|
311
|
+
"rating-excellent": "Excellent",
|
|
312
|
+
"rating-very-good": "Tr\xE8s bien",
|
|
313
|
+
"rating-good": "Bien",
|
|
314
|
+
"rating-fair": "Moyen",
|
|
315
|
+
"rating-none": "Aucune notation"
|
|
316
|
+
},
|
|
317
|
+
product: {
|
|
318
|
+
"6m": "Abonnement de 6 mois",
|
|
319
|
+
"1y": "Abonnement 1 an",
|
|
320
|
+
"2y": "Abonnement 2 ans",
|
|
321
|
+
"3y": "Abonnement 3 ans",
|
|
322
|
+
"price-6m": "79.-",
|
|
323
|
+
"price-6m-disc": "59.-",
|
|
324
|
+
"price-1y": "99.-",
|
|
325
|
+
"price-1y-disc": "79.-",
|
|
326
|
+
"price-2y": "198.-",
|
|
327
|
+
"price-2y-disc": "173.-",
|
|
328
|
+
"price-3y": "297.-",
|
|
329
|
+
"price-3y-disc": "247.-",
|
|
330
|
+
"price-gift": "99.-",
|
|
331
|
+
"price-gift-disc": "59.-"
|
|
332
|
+
},
|
|
333
|
+
subheadline: {
|
|
334
|
+
"your-hc": "Votre HotelCard",
|
|
335
|
+
"popular-hotels": "Offres d\u2019h\xF4tels populaires",
|
|
336
|
+
"no-results": "Explorez d\u2019autres destinations, modifiez vos dates ou retirez certains filtres.",
|
|
337
|
+
"sort-by": "Trier par"
|
|
338
|
+
},
|
|
339
|
+
form: {
|
|
340
|
+
guests: "personnes",
|
|
341
|
+
guest: "personne",
|
|
342
|
+
adults: "Adultes",
|
|
343
|
+
children: "Enfants",
|
|
344
|
+
pet: "Animal domestique",
|
|
345
|
+
"age-of-child": "\xC2ge de l\u2019enfant",
|
|
346
|
+
age: "\xC2ge",
|
|
347
|
+
"age-error": "Veuillez s\xE9lectionner l\u2019\xE2ge"
|
|
348
|
+
},
|
|
349
|
+
filter: {
|
|
350
|
+
filters: "Filtres",
|
|
351
|
+
destination: "Destination",
|
|
352
|
+
experience: "Exp\xE9rience",
|
|
353
|
+
"show-all": "Tout afficher",
|
|
354
|
+
price: "Prix",
|
|
355
|
+
discount: "R\xE9duction",
|
|
356
|
+
services: "Services",
|
|
357
|
+
meals: "Repas",
|
|
358
|
+
"hotel-category": "Cat\xE9gorie d\u2019h\xF4tel",
|
|
359
|
+
reviews: "Avis",
|
|
360
|
+
mobility: "Mobilit\xE9",
|
|
361
|
+
"wellness-spa": "Bien-\xEAtre & Spa",
|
|
362
|
+
"price-high-low": "Prix : du plus bas",
|
|
363
|
+
"price-low-high": "Prix : du plus \xE9lev\xE9",
|
|
364
|
+
"best-rating": "Meilleure note",
|
|
365
|
+
"most-popular": "Plus populaires",
|
|
366
|
+
"newest-hotels": "Plus r\xE9cents",
|
|
367
|
+
relevance: "Pertinence",
|
|
368
|
+
selected: "String value",
|
|
369
|
+
"clear-all": "Tout effacer",
|
|
370
|
+
options: "Services",
|
|
371
|
+
"hotellerie-suisse": "Classification HotellerieSuisse",
|
|
372
|
+
trustyou: "Avis de voyageurs sur TrustYou\xAE",
|
|
373
|
+
"select-all": "Tout s\xE9lectionner",
|
|
374
|
+
reset: "R\xE9initialiser",
|
|
375
|
+
"breakfast-included": "Petit-d\xE9jeuner inclus"
|
|
376
|
+
},
|
|
377
|
+
headline: {
|
|
378
|
+
"no-results": "Aucun s\xE9jour ne correspond \xE0 votre recherche pour le moment"
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// src/locales/it.json
|
|
383
|
+
var it_default = {
|
|
384
|
+
button: {
|
|
385
|
+
order: "Ordina ora",
|
|
386
|
+
"order-navigation": "Ordina ora",
|
|
387
|
+
"order-hc": "Ordina HotelCard",
|
|
388
|
+
"my-account": "Il mio profilo",
|
|
389
|
+
search: "Cerca",
|
|
390
|
+
"back-to-top": "Torna su"
|
|
391
|
+
},
|
|
392
|
+
link: {
|
|
393
|
+
"member-benefits": "Member Benefits",
|
|
394
|
+
"view-all-hotels": "Tutte le offerte hotel",
|
|
395
|
+
"search-by-map": "Ricerca sulla mappa",
|
|
396
|
+
"search-by-region": "Hotel per regione",
|
|
397
|
+
"search-by-experience": "Hotel per esperienza",
|
|
398
|
+
"travel-inspiration": "Ispirazioni di viaggio",
|
|
399
|
+
"booking-tips-and-tricks": "Consigli prenotazione",
|
|
400
|
+
home: "Home",
|
|
401
|
+
"all-hotel-deals": "Tutte le offerte hotel",
|
|
402
|
+
"search-results": "Risultati di ricerca"
|
|
403
|
+
},
|
|
404
|
+
general: {
|
|
405
|
+
"signed-out": "Accedi e prenota",
|
|
406
|
+
"room-price": "a partire da CHF xxx per camera",
|
|
407
|
+
guarantee: "Garanzia di rimborso di 14 giorni",
|
|
408
|
+
contact: "Altre domande? Contattaci.",
|
|
409
|
+
"breakfast-included": "Colazione inclusa",
|
|
410
|
+
"free-cancellation": "Cancellazione gratuita",
|
|
411
|
+
"suggested-destinations": "Destinazioni suggerite",
|
|
412
|
+
"when-months": "Quando vuoi viaggiare?",
|
|
413
|
+
"hotel-deals-found": "offerte hotel trovate",
|
|
414
|
+
"no-results": "Prova altre destinazioni, cambia le date o rimuovi qualche filtro.",
|
|
415
|
+
"unavailable-for-selected-days": "Non disponibile per le date selezionate.",
|
|
416
|
+
"cant-accommodate-all": "L\u2019hotel non pu\xF2 accogliere tutti gli ospiti.",
|
|
417
|
+
"reset-destination": "Reimposta la destinazione e filtra per regione"
|
|
418
|
+
},
|
|
419
|
+
label: {
|
|
420
|
+
"price-from": "a partire da ",
|
|
421
|
+
"price-for": "per camera",
|
|
422
|
+
"per-room-night": "per camera e notte da",
|
|
423
|
+
new: "Nuovo",
|
|
424
|
+
anytime: "In qualsiasi momento",
|
|
425
|
+
anywhere: "Tutte le destinazioni",
|
|
426
|
+
dates: "Date",
|
|
427
|
+
flexible: "Flessibile",
|
|
428
|
+
where: "Dove",
|
|
429
|
+
when: "Date",
|
|
430
|
+
who: "Chi",
|
|
431
|
+
nearby: "Nelle vicinanze",
|
|
432
|
+
hotels: "Hotel",
|
|
433
|
+
filter: "Filtra",
|
|
434
|
+
sort: "Ordina",
|
|
435
|
+
map: "Mappa",
|
|
436
|
+
rating: "Rating",
|
|
437
|
+
"rating-excellent": "Eccellente",
|
|
438
|
+
"rating-very-good": "Ottimo",
|
|
439
|
+
"rating-good": "Buono",
|
|
440
|
+
"rating-fair": "Sufficiente",
|
|
441
|
+
"rating-none": "Nessun voto"
|
|
442
|
+
},
|
|
443
|
+
product: {
|
|
444
|
+
"6m": "Abbonamento di 6 mesi",
|
|
445
|
+
"1y": "Abbonamento 1 anno",
|
|
446
|
+
"2y": "Abbonamento 2 anni",
|
|
447
|
+
"3y": "Abbonamento 3 anni",
|
|
448
|
+
"price-6m": "79.-",
|
|
449
|
+
"price-6m-disc": "59.-",
|
|
450
|
+
"price-1y": "99.-",
|
|
451
|
+
"price-1y-disc": "79.-",
|
|
452
|
+
"price-2y": "198.-",
|
|
453
|
+
"price-2y-disc": "173.-",
|
|
454
|
+
"price-3y": "297.-",
|
|
455
|
+
"price-3y-disc": "247.-",
|
|
456
|
+
"price-gift": "99.-",
|
|
457
|
+
"price-gift-disc": "59.-"
|
|
458
|
+
},
|
|
459
|
+
subheadline: {
|
|
460
|
+
"your-hc": "La sua HotelCard",
|
|
461
|
+
"popular-hotels": "Offerte hotel popolari",
|
|
462
|
+
"no-results": "Prova altre destinazioni, cambia le date o rimuovi qualche filtro.",
|
|
463
|
+
"sort-by": "Ordina per"
|
|
464
|
+
},
|
|
465
|
+
form: {
|
|
466
|
+
guests: "ospiti",
|
|
467
|
+
guest: "ospite",
|
|
468
|
+
adults: "Adulti",
|
|
469
|
+
children: "Bambini",
|
|
470
|
+
pet: "Animale domestico",
|
|
471
|
+
"age-of-child": "L'et\xE0 del bambino",
|
|
472
|
+
age: "L'et\xE0",
|
|
473
|
+
"age-error": "Seleziona l\u2019et\xE0"
|
|
474
|
+
},
|
|
475
|
+
filter: {
|
|
476
|
+
filters: "Filtri",
|
|
477
|
+
destination: "Destinazione",
|
|
478
|
+
experience: "Esperienza",
|
|
479
|
+
"show-all": "Mostra tutto",
|
|
480
|
+
price: "Prezzo",
|
|
481
|
+
discount: "Sconto",
|
|
482
|
+
services: "Servizi",
|
|
483
|
+
meals: "Pasti",
|
|
484
|
+
"hotel-category": "Categoria hotel",
|
|
485
|
+
reviews: "Recensioni",
|
|
486
|
+
mobility: "Mobilit\xE0",
|
|
487
|
+
"wellness-spa": "Wellness & Spa",
|
|
488
|
+
"price-high-low": "Prezzo: dal pi\xF9 basso",
|
|
489
|
+
"price-low-high": "Prezzo: dal pi\xF9 alto",
|
|
490
|
+
"best-rating": "Miglior voto",
|
|
491
|
+
"most-popular": "Pi\xF9 popolari",
|
|
492
|
+
"newest-hotels": "Pi\xF9 recenti",
|
|
493
|
+
relevance: "Rilevanza",
|
|
494
|
+
selected: "String value",
|
|
495
|
+
"clear-all": "Cancella tutto",
|
|
496
|
+
options: "Servizi",
|
|
497
|
+
"hotellerie-suisse": "Classificazione HotellerieSuisse",
|
|
498
|
+
trustyou: "Recensioni dei viaggiatori su TrustYou\xAE",
|
|
499
|
+
"select-all": "Seleziona tutto",
|
|
500
|
+
reset: "Reimposta",
|
|
501
|
+
"breakfast-included": "Colazione inclusa"
|
|
502
|
+
},
|
|
503
|
+
headline: {
|
|
504
|
+
"no-results": "Al momento nessun soggiorno corrisponde alla tua ricerca"
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
// src/locales/index.ts
|
|
509
|
+
var translations = { de: de_default, en: en_default, fr: fr_default, it: it_default };
|
|
510
|
+
|
|
511
|
+
// src/context/UIContext.tsx
|
|
3
512
|
import { jsx } from "react/jsx-runtime";
|
|
513
|
+
function getNestedValue(obj, path) {
|
|
514
|
+
const keys = path.split(".");
|
|
515
|
+
let current = obj;
|
|
516
|
+
for (const key of keys) {
|
|
517
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
518
|
+
return void 0;
|
|
519
|
+
}
|
|
520
|
+
current = current[key];
|
|
521
|
+
}
|
|
522
|
+
return typeof current === "string" ? current : void 0;
|
|
523
|
+
}
|
|
524
|
+
function createTranslateFunction(locale) {
|
|
525
|
+
const localeTranslations = translations[locale] || translations.en;
|
|
526
|
+
return (key, fallback) => {
|
|
527
|
+
const value = getNestedValue(localeTranslations, key);
|
|
528
|
+
return value ?? fallback ?? key;
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
var defaultT = createTranslateFunction("de");
|
|
4
532
|
var defaultValue = {
|
|
5
533
|
locale: "de",
|
|
6
534
|
currency: "CHF",
|
|
7
|
-
isDesktop: false
|
|
535
|
+
isDesktop: false,
|
|
536
|
+
t: defaultT
|
|
8
537
|
};
|
|
9
538
|
var UIContext = createContext(defaultValue);
|
|
10
539
|
var HotelCardUIProvider = ({
|
|
11
540
|
locale = "de",
|
|
12
541
|
currency = "CHF",
|
|
13
542
|
isDesktop = false,
|
|
543
|
+
t: customT,
|
|
14
544
|
children
|
|
15
545
|
}) => {
|
|
16
|
-
const
|
|
546
|
+
const t = useMemo(
|
|
547
|
+
() => customT ?? createTranslateFunction(locale),
|
|
548
|
+
[locale, customT]
|
|
549
|
+
);
|
|
550
|
+
const value = useMemo(
|
|
551
|
+
() => ({ locale, currency, isDesktop, t }),
|
|
552
|
+
[locale, currency, isDesktop, t]
|
|
553
|
+
);
|
|
17
554
|
return /* @__PURE__ */ jsx(UIContext.Provider, { value, children });
|
|
18
555
|
};
|
|
19
556
|
var useUIContext = () => {
|
|
@@ -1246,7 +1783,7 @@ var Pin = forwardRef2(
|
|
|
1246
1783
|
Pin.displayName = "Pin";
|
|
1247
1784
|
|
|
1248
1785
|
// src/components/DateSelector/DateSelector.tsx
|
|
1249
|
-
import { useState as useState9, useRef as useRef4, useEffect as useEffect6, useMemo } from "react";
|
|
1786
|
+
import { useState as useState9, useRef as useRef4, useEffect as useEffect6, useMemo as useMemo2 } from "react";
|
|
1250
1787
|
|
|
1251
1788
|
// src/hooks/useDebounce.ts
|
|
1252
1789
|
import { useState as useState5, useEffect as useEffect3 } from "react";
|
|
@@ -1493,14 +2030,6 @@ var getDateLocale = (locale) => {
|
|
|
1493
2030
|
};
|
|
1494
2031
|
return localeMap[locale] || "de-CH";
|
|
1495
2032
|
};
|
|
1496
|
-
var defaultLabels = {
|
|
1497
|
-
when: "When",
|
|
1498
|
-
dates: "Dates",
|
|
1499
|
-
flexible: "Flexible",
|
|
1500
|
-
apply: "Apply",
|
|
1501
|
-
selectMonths: "Select months",
|
|
1502
|
-
anytime: "Anytime"
|
|
1503
|
-
};
|
|
1504
2033
|
var WhenContent = ({
|
|
1505
2034
|
initialDateRange = { start: null, end: null },
|
|
1506
2035
|
initialMonthFilter = null,
|
|
@@ -1510,14 +2039,21 @@ var WhenContent = ({
|
|
|
1510
2039
|
showApplyButton = true,
|
|
1511
2040
|
onApply,
|
|
1512
2041
|
className = "",
|
|
1513
|
-
labels: labelsProp,
|
|
1514
2042
|
locale: localeProp
|
|
1515
2043
|
}) => {
|
|
1516
2044
|
const { locale: contextLocale } = useWindowData();
|
|
1517
2045
|
const { isDesktop } = useResponsive();
|
|
2046
|
+
const { t } = useUIContext();
|
|
1518
2047
|
const locale = localeProp || contextLocale;
|
|
1519
2048
|
const dateLocale = getDateLocale(locale);
|
|
1520
|
-
const labels = {
|
|
2049
|
+
const labels = {
|
|
2050
|
+
when: t("label.when", "When"),
|
|
2051
|
+
dates: t("label.dates", "Dates"),
|
|
2052
|
+
flexible: t("label.flexible", "Flexible"),
|
|
2053
|
+
apply: t("button.search", "Apply"),
|
|
2054
|
+
selectMonths: t("general.when-months", "Select months"),
|
|
2055
|
+
anytime: t("label.anytime", "Anytime")
|
|
2056
|
+
};
|
|
1521
2057
|
const [dateRange, setDateRange] = useState8(initialDateRange);
|
|
1522
2058
|
const [mode, setMode] = useState8(
|
|
1523
2059
|
initialDateRange.start ? "dates" : "anytime"
|
|
@@ -1723,7 +2259,7 @@ var DateSelector = ({
|
|
|
1723
2259
|
className,
|
|
1724
2260
|
icon
|
|
1725
2261
|
}) => {
|
|
1726
|
-
const { t } =
|
|
2262
|
+
const { t } = useUIContext();
|
|
1727
2263
|
const { locale } = useWindowData();
|
|
1728
2264
|
const { isDesktop } = useResponsive();
|
|
1729
2265
|
const dateLocale = getDateLocale2(locale);
|
|
@@ -1762,7 +2298,7 @@ var DateSelector = ({
|
|
|
1762
2298
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
1763
2299
|
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
1764
2300
|
}, [isOpen, dateRange, selectedMonths, onChange, onMonthFilterChange, onClose]);
|
|
1765
|
-
const months =
|
|
2301
|
+
const months = useMemo2(() => {
|
|
1766
2302
|
const now = /* @__PURE__ */ new Date();
|
|
1767
2303
|
return Array.from({ length: 12 }, (_, i) => {
|
|
1768
2304
|
const date = new Date(now.getFullYear(), now.getMonth() + i, 1);
|
|
@@ -1780,12 +2316,12 @@ var DateSelector = ({
|
|
|
1780
2316
|
}
|
|
1781
2317
|
if (selectedMonths.length === 1) {
|
|
1782
2318
|
const month = months.find((m) => m.value === selectedMonths[0]);
|
|
1783
|
-
return month ? `${month.label} ${month.year}` : t("
|
|
2319
|
+
return month ? `${month.label} ${month.year}` : t("label.flexible", "Flexible");
|
|
1784
2320
|
}
|
|
1785
2321
|
if (selectedMonths.length > 1) {
|
|
1786
|
-
return
|
|
2322
|
+
return `${selectedMonths.length} months`;
|
|
1787
2323
|
}
|
|
1788
|
-
return t("
|
|
2324
|
+
return t("label.flexible", "Flexible");
|
|
1789
2325
|
};
|
|
1790
2326
|
const handleDateRangeChange = (range) => {
|
|
1791
2327
|
setDateRange(range ?? { start: null, end: null });
|
|
@@ -1873,18 +2409,6 @@ var DropdownIcon = () => /* @__PURE__ */ jsx22(
|
|
|
1873
2409
|
)
|
|
1874
2410
|
}
|
|
1875
2411
|
);
|
|
1876
|
-
var defaultLabels2 = {
|
|
1877
|
-
adults: "Adults",
|
|
1878
|
-
children: "Children",
|
|
1879
|
-
pet: "Pet",
|
|
1880
|
-
ageOfChild: "Age of child",
|
|
1881
|
-
age: "Age",
|
|
1882
|
-
decreaseAdults: "Decrease adults",
|
|
1883
|
-
increaseAdults: "Increase adults",
|
|
1884
|
-
decreaseChildren: "Decrease children",
|
|
1885
|
-
increaseChildren: "Increase children",
|
|
1886
|
-
togglePets: "Toggle pets"
|
|
1887
|
-
};
|
|
1888
2412
|
var GuestContent = ({
|
|
1889
2413
|
guests,
|
|
1890
2414
|
onChange,
|
|
@@ -1893,10 +2417,21 @@ var GuestContent = ({
|
|
|
1893
2417
|
showPetToggle = true,
|
|
1894
2418
|
className = "",
|
|
1895
2419
|
childAgeErrors = [],
|
|
1896
|
-
onErrorClear
|
|
1897
|
-
labels: labelsProp
|
|
2420
|
+
onErrorClear
|
|
1898
2421
|
}) => {
|
|
1899
|
-
const
|
|
2422
|
+
const { t } = useUIContext();
|
|
2423
|
+
const labels = {
|
|
2424
|
+
adults: t("form.adults", "Adults"),
|
|
2425
|
+
children: t("form.children", "Children"),
|
|
2426
|
+
pet: t("form.pet", "Pet"),
|
|
2427
|
+
ageOfChild: t("form.age-of-child", "Age of child"),
|
|
2428
|
+
age: t("form.age", "Age"),
|
|
2429
|
+
decreaseAdults: "Decrease adults",
|
|
2430
|
+
increaseAdults: "Increase adults",
|
|
2431
|
+
decreaseChildren: "Decrease children",
|
|
2432
|
+
increaseChildren: "Increase children",
|
|
2433
|
+
togglePets: "Toggle pets"
|
|
2434
|
+
};
|
|
1900
2435
|
const childrenAges = Array.isArray(guests.childrenAges) ? guests.childrenAges : [];
|
|
1901
2436
|
const handleIncrement = (type) => {
|
|
1902
2437
|
if (type === "children" && guests.children >= 6) return;
|
|
@@ -2083,21 +2618,19 @@ var HeartIcon2 = ({ filled }) => /* @__PURE__ */ jsxs22(
|
|
|
2083
2618
|
]
|
|
2084
2619
|
}
|
|
2085
2620
|
);
|
|
2086
|
-
var defaultLabels3 = {
|
|
2087
|
-
removeFromFavorites: "Remove from favorites",
|
|
2088
|
-
addToFavorites: "Add to favorites",
|
|
2089
|
-
previousImage: "Previous image",
|
|
2090
|
-
nextImage: "Next image"
|
|
2091
|
-
};
|
|
2092
2621
|
var HotelCardImage = ({
|
|
2093
2622
|
images,
|
|
2094
2623
|
hotelName,
|
|
2095
2624
|
badges,
|
|
2096
2625
|
isFavorite,
|
|
2097
|
-
onFavoriteClick
|
|
2098
|
-
labels: labelsProp
|
|
2626
|
+
onFavoriteClick
|
|
2099
2627
|
}) => {
|
|
2100
|
-
const labels = {
|
|
2628
|
+
const labels = {
|
|
2629
|
+
removeFromFavorites: "Remove from favorites",
|
|
2630
|
+
addToFavorites: "Add to favorites",
|
|
2631
|
+
previousImage: "Previous image",
|
|
2632
|
+
nextImage: "Next image"
|
|
2633
|
+
};
|
|
2101
2634
|
const displayImages = images.slice(0, MAX_IMAGES);
|
|
2102
2635
|
const [currentImageIndex, setCurrentImageIndex] = useState10(0);
|
|
2103
2636
|
const [failedImages, setFailedImages] = useState10(/* @__PURE__ */ new Set());
|
|
@@ -2240,16 +2773,6 @@ var BreakfastIcon = () => /* @__PURE__ */ jsxs23("svg", { xmlns: "http://www.w3.
|
|
|
2240
2773
|
var FreeCancellationIcon = () => /* @__PURE__ */ jsx24("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx24("path", { d: "M0.838695 4.18584L2.62218 6.00458C2.85502 6.24202 3.23153 6.24202 3.4619 6.00458C3.69227 5.76713 3.69474 5.38317 3.4619 5.14825L2.69401 4.36518L3.66406 4.36518C3.9974 4.36518 4.33073 4.36518 4.37346 4.36518C4.66406 4.36518 4.66406 4.36518 4.9974 4.36518L5.22309 4.36518H5.22804H11.5644C11.5644 5.25687 12.2753 5.98184 13.1497 5.98184V8.61902C13.5386 8.66196 13.9151 8.83625 14.2123 9.13938L14.3387 9.26821V4.76682C14.3387 3.87513 13.6278 3.15016 12.7533 3.15016H4.37346H2.69649L3.46438 2.3671C3.69722 2.12965 3.69722 1.74569 3.46438 1.51077C3.23153 1.27585 2.85502 1.27332 2.62218 1.50825L0.838695 3.32699C0.605852 3.56443 0.605852 3.94839 0.838695 4.18331V4.18584ZM1.65612 6.73207V11.2335C1.65612 12.1251 2.36704 12.8501 3.24144 12.8501H13.3008L12.5329 13.6332C12.3 13.8706 12.3 14.2546 12.5329 14.4895C12.7657 14.7244 13.1422 14.727 13.3726 14.4895L15.1561 12.6708C15.3889 12.4333 15.3889 12.0494 15.1561 11.8144L13.3726 9.9957C13.1398 9.75826 12.7633 9.75826 12.5329 9.9957C12.3025 10.2331 12.3 10.6171 12.5329 10.852L13.3008 11.6351L12.3307 11.6351C11.974 11.6351 11.9036 11.6351 11.737 11.6351C11.6641 11.6351 11.6354 11.6351 11.5644 11.6351H4.43043C4.43043 10.7434 3.71952 10.0184 2.84511 10.0184V7.38126C2.45622 7.33832 2.0797 7.16402 1.78245 6.8609L1.65612 6.73207ZM10.3754 8.00014C10.3754 7.35699 10.1248 6.74019 9.67888 6.28541C9.23292 5.83064 8.62807 5.57515 7.9974 5.57515C7.36672 5.57515 6.76187 5.83064 6.31591 6.28541C5.86996 6.74019 5.61942 7.35699 5.61942 8.00014C5.61942 8.64329 5.86996 9.26009 6.31591 9.71486C6.76187 10.1696 7.36672 10.4251 7.9974 10.4251C8.62807 10.4251 9.23292 10.1696 9.67888 9.71486C10.1248 9.26009 10.3754 8.64329 10.3754 8.00014Z", fill: "#006962" }) });
|
|
2241
2774
|
var CheckmarkIcon = () => /* @__PURE__ */ jsx24("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx24("path", { d: "M13.5 4.5L6 12L2.5 8.5", stroke: "#006962", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
2242
2775
|
var RatingBadgeSvg = () => /* @__PURE__ */ jsx24("svg", { width: "32", height: "24", viewBox: "0 0 36 38", fill: "#478EFA", className: "hc-hotel-card__rating-badge-bg", children: /* @__PURE__ */ jsx24("path", { d: "M4 0C1.79086 0 0 1.79086 0 4V32V38L9 32H32C34.2091 32 36 30.2091 36 28V0H4Z" }) });
|
|
2243
|
-
var defaultLabels4 = {
|
|
2244
|
-
ratingExcellent: "Excellent",
|
|
2245
|
-
ratingVeryGood: "Very Good",
|
|
2246
|
-
ratingGood: "Good",
|
|
2247
|
-
ratingFair: "Fair",
|
|
2248
|
-
rating: "Rating",
|
|
2249
|
-
priceFrom: "per room & night from",
|
|
2250
|
-
notAvailable: "Not available",
|
|
2251
|
-
swissLodge: "Swiss Lodge"
|
|
2252
|
-
};
|
|
2253
2776
|
var HotelCardContent = ({
|
|
2254
2777
|
name,
|
|
2255
2778
|
stars,
|
|
@@ -2260,10 +2783,19 @@ var HotelCardContent = ({
|
|
|
2260
2783
|
price,
|
|
2261
2784
|
currency = "CHF",
|
|
2262
2785
|
isAvailable = true,
|
|
2263
|
-
onClick
|
|
2264
|
-
labels: labelsProp
|
|
2786
|
+
onClick
|
|
2265
2787
|
}) => {
|
|
2266
|
-
const
|
|
2788
|
+
const { t } = useUIContext();
|
|
2789
|
+
const labels = {
|
|
2790
|
+
ratingExcellent: t("label.rating-excellent", "Excellent"),
|
|
2791
|
+
ratingVeryGood: t("label.rating-very-good", "Very good"),
|
|
2792
|
+
ratingGood: t("label.rating-good", "Good"),
|
|
2793
|
+
ratingFair: t("label.rating-fair", "Fair"),
|
|
2794
|
+
rating: t("label.rating", "Rating"),
|
|
2795
|
+
priceFrom: t("label.per-room-night", "per room & night from"),
|
|
2796
|
+
notAvailable: t("general.unavailable-for-selected-days", "Not available"),
|
|
2797
|
+
swissLodge: "Swiss Lodge"
|
|
2798
|
+
};
|
|
2267
2799
|
const getRatingCategory = (score) => {
|
|
2268
2800
|
if (score >= 4.4) return labels.ratingExcellent;
|
|
2269
2801
|
if (score >= 4.1) return labels.ratingVeryGood;
|
|
@@ -2314,20 +2846,22 @@ var HotelCardContent = ({
|
|
|
2314
2846
|
/* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__pin-icon", children: /* @__PURE__ */ jsx24(PinIcon, {}) }),
|
|
2315
2847
|
/* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__location", children: location })
|
|
2316
2848
|
] }),
|
|
2317
|
-
|
|
2318
|
-
/* @__PURE__ */ jsx24("
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
/* @__PURE__ */
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
"-",
|
|
2329
|
-
|
|
2330
|
-
|
|
2849
|
+
/* @__PURE__ */ jsxs23("div", { className: "hc-hotel-card__benefits-and-pricing", children: [
|
|
2850
|
+
benefits.length > 0 && /* @__PURE__ */ jsx24("div", { className: "hc-hotel-card__benefits-section", children: benefits.slice(0, 3).map((benefit, index) => /* @__PURE__ */ jsxs23("div", { className: "hc-hotel-card__benefit", children: [
|
|
2851
|
+
/* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__benefit-icon", children: getBenefitIcon(benefit.id) }),
|
|
2852
|
+
/* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__benefit-text", children: benefit.label })
|
|
2853
|
+
] }, index)) }),
|
|
2854
|
+
/* @__PURE__ */ jsxs23("div", { className: "hc-hotel-card__pricing-section", children: [
|
|
2855
|
+
isAvailable && /* @__PURE__ */ jsx24("div", { className: "hc-hotel-card__price-label", children: labels.priceFrom }),
|
|
2856
|
+
!isAvailable && /* @__PURE__ */ jsx24("div", { className: "hc-hotel-card__not-available", children: labels.notAvailable }),
|
|
2857
|
+
isAvailable && /* @__PURE__ */ jsxs23("div", { className: "hc-hotel-card__price-container", children: [
|
|
2858
|
+
/* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__current-price", children: `${currency} ${price.current}` }),
|
|
2859
|
+
price.original && price.original > price.current && /* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__original-price", children: `${currency} ${price.original}` }),
|
|
2860
|
+
price.discount && price.discount > 0 && /* @__PURE__ */ jsxs23("span", { className: "hc-hotel-card__discount-badge", children: [
|
|
2861
|
+
"-",
|
|
2862
|
+
price.discount,
|
|
2863
|
+
" %"
|
|
2864
|
+
] })
|
|
2331
2865
|
] })
|
|
2332
2866
|
] })
|
|
2333
2867
|
] })
|
|
@@ -2342,7 +2876,6 @@ var HotelCard = ({
|
|
|
2342
2876
|
hotel,
|
|
2343
2877
|
onFavoriteClick,
|
|
2344
2878
|
onContentClick,
|
|
2345
|
-
labels = {},
|
|
2346
2879
|
className
|
|
2347
2880
|
}) => {
|
|
2348
2881
|
return /* @__PURE__ */ jsxs24("div", { className: `hc-hotel-card ${className || ""}`, children: [
|
|
@@ -2353,13 +2886,7 @@ var HotelCard = ({
|
|
|
2353
2886
|
hotelName: hotel.name,
|
|
2354
2887
|
badges: hotel.badges,
|
|
2355
2888
|
isFavorite: hotel.isFavorite,
|
|
2356
|
-
onFavoriteClick
|
|
2357
|
-
labels: {
|
|
2358
|
-
removeFromFavorites: labels.removeFromFavorites,
|
|
2359
|
-
addToFavorites: labels.addToFavorites,
|
|
2360
|
-
previousImage: labels.previousImage,
|
|
2361
|
-
nextImage: labels.nextImage
|
|
2362
|
-
}
|
|
2889
|
+
onFavoriteClick
|
|
2363
2890
|
}
|
|
2364
2891
|
),
|
|
2365
2892
|
hotel.usp && /* @__PURE__ */ jsx25("div", { className: "hc-hotel-card__usp-banner", children: hotel.usp }),
|
|
@@ -2375,25 +2902,866 @@ var HotelCard = ({
|
|
|
2375
2902
|
price: hotel.price,
|
|
2376
2903
|
currency: hotel.currency,
|
|
2377
2904
|
isAvailable: hotel.isAvailable,
|
|
2378
|
-
onClick: onContentClick
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2905
|
+
onClick: onContentClick
|
|
2906
|
+
}
|
|
2907
|
+
)
|
|
2908
|
+
] });
|
|
2909
|
+
};
|
|
2910
|
+
|
|
2911
|
+
// src/components/Filters/FilterCheckboxItem.module.css
|
|
2912
|
+
var FilterCheckboxItem_default = {};
|
|
2913
|
+
|
|
2914
|
+
// src/components/Filters/FilterCheckboxItem.tsx
|
|
2915
|
+
import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2916
|
+
var FilterCheckboxItem = ({
|
|
2917
|
+
id,
|
|
2918
|
+
label,
|
|
2919
|
+
count,
|
|
2920
|
+
checked,
|
|
2921
|
+
disabled = false,
|
|
2922
|
+
onChange,
|
|
2923
|
+
className = "",
|
|
2924
|
+
trackName
|
|
2925
|
+
}) => {
|
|
2926
|
+
return /* @__PURE__ */ jsxs25(
|
|
2927
|
+
"label",
|
|
2928
|
+
{
|
|
2929
|
+
className: `${FilterCheckboxItem_default.filterRow} ${disabled ? FilterCheckboxItem_default.filterRowDisabled : ""} ${className}`,
|
|
2930
|
+
tabIndex: disabled ? -1 : 0,
|
|
2931
|
+
"data-track": trackName,
|
|
2932
|
+
children: [
|
|
2933
|
+
/* @__PURE__ */ jsxs25("div", { className: FilterCheckboxItem_default.checkboxLabel, children: [
|
|
2934
|
+
/* @__PURE__ */ jsxs25("div", { className: FilterCheckboxItem_default.checkboxButton, children: [
|
|
2935
|
+
/* @__PURE__ */ jsx26(
|
|
2936
|
+
"input",
|
|
2937
|
+
{
|
|
2938
|
+
id,
|
|
2939
|
+
type: "checkbox",
|
|
2940
|
+
className: FilterCheckboxItem_default.checkbox,
|
|
2941
|
+
checked,
|
|
2942
|
+
disabled,
|
|
2943
|
+
onChange
|
|
2944
|
+
}
|
|
2945
|
+
),
|
|
2946
|
+
/* @__PURE__ */ jsx26("span", { className: `${FilterCheckboxItem_default.checkboxBox} ${disabled ? FilterCheckboxItem_default.checkboxBoxDisabled : ""}`, children: checked && /* @__PURE__ */ jsx26("svg", { viewBox: "0 0 12 10", fill: "none", className: FilterCheckboxItem_default.checkIcon, children: /* @__PURE__ */ jsx26(
|
|
2947
|
+
"path",
|
|
2948
|
+
{
|
|
2949
|
+
d: "M1 5L4.5 8.5L11 1",
|
|
2950
|
+
stroke: "currentColor",
|
|
2951
|
+
strokeWidth: "2",
|
|
2952
|
+
strokeLinecap: "round",
|
|
2953
|
+
strokeLinejoin: "round"
|
|
2954
|
+
}
|
|
2955
|
+
) }) })
|
|
2956
|
+
] }),
|
|
2957
|
+
/* @__PURE__ */ jsx26("span", { className: `${FilterCheckboxItem_default.filterLabel} ${disabled ? FilterCheckboxItem_default.filterLabelDisabled : ""}`, children: label })
|
|
2958
|
+
] }),
|
|
2959
|
+
count !== void 0 && /* @__PURE__ */ jsx26("span", { className: `${FilterCheckboxItem_default.filterCount} ${disabled ? FilterCheckboxItem_default.filterCountDisabled : ""}`, children: count })
|
|
2960
|
+
]
|
|
2961
|
+
}
|
|
2962
|
+
);
|
|
2963
|
+
};
|
|
2964
|
+
|
|
2965
|
+
// src/components/Filters/CollapsibleFilterSection.tsx
|
|
2966
|
+
import React10, { useState as useState11, useEffect as useEffect7 } from "react";
|
|
2967
|
+
|
|
2968
|
+
// src/components/Filters/CollapsibleFilterSection.module.css
|
|
2969
|
+
var CollapsibleFilterSection_default = {};
|
|
2970
|
+
|
|
2971
|
+
// src/components/Filters/CollapsibleFilterSection.tsx
|
|
2972
|
+
import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2973
|
+
var CollapsibleFilterSection = ({
|
|
2974
|
+
title,
|
|
2975
|
+
children,
|
|
2976
|
+
defaultExpanded = true,
|
|
2977
|
+
showAllText,
|
|
2978
|
+
showLessText,
|
|
2979
|
+
hasShowAll = false,
|
|
2980
|
+
initialItemsToShow = 5,
|
|
2981
|
+
className = ""
|
|
2982
|
+
}) => {
|
|
2983
|
+
const { t } = useUIContext();
|
|
2984
|
+
const [isExpanded, setIsExpanded] = useState11(defaultExpanded);
|
|
2985
|
+
const [showAll, setShowAll] = useState11(false);
|
|
2986
|
+
const resolvedShowAllText = showAllText ?? t("filter.show-all", "Show all");
|
|
2987
|
+
const resolvedShowLessText = showLessText ?? t("filter.show-less", "Show less");
|
|
2988
|
+
useEffect7(() => {
|
|
2989
|
+
if (defaultExpanded && !isExpanded) {
|
|
2990
|
+
setIsExpanded(true);
|
|
2991
|
+
}
|
|
2992
|
+
}, [defaultExpanded]);
|
|
2993
|
+
const toggleExpanded = () => {
|
|
2994
|
+
setIsExpanded(!isExpanded);
|
|
2995
|
+
};
|
|
2996
|
+
const toggleShowAll = () => {
|
|
2997
|
+
setShowAll(!showAll);
|
|
2998
|
+
};
|
|
2999
|
+
const childrenArray = React10.Children.toArray(children);
|
|
3000
|
+
const shouldShowToggle = hasShowAll && childrenArray.length > initialItemsToShow;
|
|
3001
|
+
const displayedChildren = shouldShowToggle && !showAll ? childrenArray.slice(0, initialItemsToShow) : childrenArray;
|
|
3002
|
+
return /* @__PURE__ */ jsxs26("div", { className: `${CollapsibleFilterSection_default.section} ${className}`, children: [
|
|
3003
|
+
/* @__PURE__ */ jsxs26(
|
|
3004
|
+
"button",
|
|
3005
|
+
{
|
|
3006
|
+
type: "button",
|
|
3007
|
+
className: CollapsibleFilterSection_default.header,
|
|
3008
|
+
onClick: toggleExpanded,
|
|
3009
|
+
"aria-expanded": isExpanded,
|
|
3010
|
+
children: [
|
|
3011
|
+
/* @__PURE__ */ jsx27("span", { className: CollapsibleFilterSection_default.title, children: title }),
|
|
3012
|
+
/* @__PURE__ */ jsx27(
|
|
3013
|
+
"svg",
|
|
3014
|
+
{
|
|
3015
|
+
className: `${CollapsibleFilterSection_default.chevron} ${isExpanded ? CollapsibleFilterSection_default.chevronExpanded : ""}`,
|
|
3016
|
+
viewBox: "0 0 24 24",
|
|
3017
|
+
fill: "none",
|
|
3018
|
+
"aria-hidden": "true",
|
|
3019
|
+
children: /* @__PURE__ */ jsx27(
|
|
3020
|
+
"path",
|
|
3021
|
+
{
|
|
3022
|
+
d: "M6 9L12 15L18 9",
|
|
3023
|
+
stroke: "currentColor",
|
|
3024
|
+
strokeWidth: "2",
|
|
3025
|
+
strokeLinecap: "round",
|
|
3026
|
+
strokeLinejoin: "round"
|
|
3027
|
+
}
|
|
3028
|
+
)
|
|
3029
|
+
}
|
|
3030
|
+
)
|
|
3031
|
+
]
|
|
3032
|
+
}
|
|
3033
|
+
),
|
|
3034
|
+
/* @__PURE__ */ jsx27(
|
|
3035
|
+
"div",
|
|
3036
|
+
{
|
|
3037
|
+
className: `${CollapsibleFilterSection_default.content} ${isExpanded ? CollapsibleFilterSection_default.contentExpanded : ""}`,
|
|
3038
|
+
"aria-hidden": !isExpanded,
|
|
3039
|
+
children: /* @__PURE__ */ jsxs26("div", { className: CollapsibleFilterSection_default.contentInner, children: [
|
|
3040
|
+
displayedChildren,
|
|
3041
|
+
shouldShowToggle && /* @__PURE__ */ jsxs26(
|
|
3042
|
+
"button",
|
|
3043
|
+
{
|
|
3044
|
+
type: "button",
|
|
3045
|
+
className: CollapsibleFilterSection_default.showAllButton,
|
|
3046
|
+
onClick: toggleShowAll,
|
|
3047
|
+
children: [
|
|
3048
|
+
showAll ? resolvedShowLessText : resolvedShowAllText,
|
|
3049
|
+
/* @__PURE__ */ jsx27(
|
|
3050
|
+
"svg",
|
|
3051
|
+
{
|
|
3052
|
+
className: `${CollapsibleFilterSection_default.showAllChevron} ${showAll ? CollapsibleFilterSection_default.showAllChevronUp : ""}`,
|
|
3053
|
+
viewBox: "0 0 24 24",
|
|
3054
|
+
fill: "none",
|
|
3055
|
+
"aria-hidden": "true",
|
|
3056
|
+
children: /* @__PURE__ */ jsx27(
|
|
3057
|
+
"path",
|
|
3058
|
+
{
|
|
3059
|
+
d: "M6 9L12 15L18 9",
|
|
3060
|
+
stroke: "currentColor",
|
|
3061
|
+
strokeWidth: "2",
|
|
3062
|
+
strokeLinecap: "round",
|
|
3063
|
+
strokeLinejoin: "round"
|
|
3064
|
+
}
|
|
3065
|
+
)
|
|
3066
|
+
}
|
|
3067
|
+
)
|
|
3068
|
+
]
|
|
3069
|
+
}
|
|
3070
|
+
)
|
|
3071
|
+
] })
|
|
3072
|
+
}
|
|
3073
|
+
)
|
|
3074
|
+
] });
|
|
3075
|
+
};
|
|
3076
|
+
|
|
3077
|
+
// src/components/Filters/PriceRangeFilter.tsx
|
|
3078
|
+
import { useState as useState12, useRef as useRef6, useCallback, useEffect as useEffect8 } from "react";
|
|
3079
|
+
|
|
3080
|
+
// src/components/Filters/PriceRangeFilter.module.css
|
|
3081
|
+
var PriceRangeFilter_default = {};
|
|
3082
|
+
|
|
3083
|
+
// src/components/Filters/PriceRangeFilter.tsx
|
|
3084
|
+
import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3085
|
+
var DEFAULT_HISTOGRAM = [
|
|
3086
|
+
12,
|
|
3087
|
+
25,
|
|
3088
|
+
38,
|
|
3089
|
+
45,
|
|
3090
|
+
52,
|
|
3091
|
+
48,
|
|
3092
|
+
42,
|
|
3093
|
+
35,
|
|
3094
|
+
28,
|
|
3095
|
+
22,
|
|
3096
|
+
18,
|
|
3097
|
+
15,
|
|
3098
|
+
12,
|
|
3099
|
+
10,
|
|
3100
|
+
8,
|
|
3101
|
+
6,
|
|
3102
|
+
5,
|
|
3103
|
+
4,
|
|
3104
|
+
3,
|
|
3105
|
+
2
|
|
3106
|
+
];
|
|
3107
|
+
var PriceRangeFilter = ({
|
|
3108
|
+
minPrice,
|
|
3109
|
+
maxPrice,
|
|
3110
|
+
value,
|
|
3111
|
+
onChange,
|
|
3112
|
+
onApply,
|
|
3113
|
+
histogram = DEFAULT_HISTOGRAM,
|
|
3114
|
+
currency,
|
|
3115
|
+
onDragStart,
|
|
3116
|
+
onDragEnd,
|
|
3117
|
+
debounceDelay = 500
|
|
3118
|
+
}) => {
|
|
3119
|
+
const { t, currency: contextCurrency } = useUIContext();
|
|
3120
|
+
const displayCurrency = currency ?? contextCurrency;
|
|
3121
|
+
const sliderRef = useRef6(null);
|
|
3122
|
+
const [isDragging, setIsDragging] = useState12(null);
|
|
3123
|
+
const [isDraggingExternal, setIsDraggingExternal] = useState12(false);
|
|
3124
|
+
const lastValueRef = useRef6(value);
|
|
3125
|
+
const timeoutRef = useRef6(null);
|
|
3126
|
+
const [minInputValue, setMinInputValue] = useState12("");
|
|
3127
|
+
const [maxInputValue, setMaxInputValue] = useState12("");
|
|
3128
|
+
const [minInputFocused, setMinInputFocused] = useState12(false);
|
|
3129
|
+
const [maxInputFocused, setMaxInputFocused] = useState12(false);
|
|
3130
|
+
const range = maxPrice - minPrice;
|
|
3131
|
+
const minPercent = range > 0 ? (value.min - minPrice) / range * 100 : 0;
|
|
3132
|
+
const maxPercent = range > 0 ? (value.max - minPrice) / range * 100 : 100;
|
|
3133
|
+
const maxHistogramValue = Math.max(...histogram, 1);
|
|
3134
|
+
const getBarActive = useCallback((index) => {
|
|
3135
|
+
const barStartPercent = index / histogram.length * 100;
|
|
3136
|
+
const barEndPercent = (index + 1) / histogram.length * 100;
|
|
3137
|
+
return barStartPercent < maxPercent && barEndPercent > minPercent;
|
|
3138
|
+
}, [histogram.length, minPercent, maxPercent]);
|
|
3139
|
+
const trackInset = 12;
|
|
3140
|
+
const triggerOnApply = useCallback((newValue) => {
|
|
3141
|
+
if (!onApply) return;
|
|
3142
|
+
if (timeoutRef.current) {
|
|
3143
|
+
clearTimeout(timeoutRef.current);
|
|
3144
|
+
}
|
|
3145
|
+
timeoutRef.current = setTimeout(() => {
|
|
3146
|
+
onApply(newValue);
|
|
3147
|
+
}, debounceDelay);
|
|
3148
|
+
}, [onApply, debounceDelay]);
|
|
3149
|
+
const handleDrag = useCallback((clientX) => {
|
|
3150
|
+
if (!sliderRef.current || !isDragging) return;
|
|
3151
|
+
const rect = sliderRef.current.getBoundingClientRect();
|
|
3152
|
+
const trackWidth = rect.width - trackInset * 2;
|
|
3153
|
+
const trackLeft = rect.left + trackInset;
|
|
3154
|
+
const percent = Math.max(0, Math.min(100, (clientX - trackLeft) / trackWidth * 100));
|
|
3155
|
+
const newValue = Math.round(minPrice + percent / 100 * range);
|
|
3156
|
+
let newMin = value.min;
|
|
3157
|
+
let newMax = value.max;
|
|
3158
|
+
if (isDragging === "min") {
|
|
3159
|
+
const clampedValue = Math.min(newValue, value.max - 1);
|
|
3160
|
+
newMin = Math.max(minPrice, clampedValue);
|
|
3161
|
+
} else {
|
|
3162
|
+
const clampedValue = Math.max(newValue, value.min + 1);
|
|
3163
|
+
newMax = Math.min(maxPrice, clampedValue);
|
|
3164
|
+
}
|
|
3165
|
+
const newRange = { min: newMin, max: newMax };
|
|
3166
|
+
onChange(newRange);
|
|
3167
|
+
lastValueRef.current = newRange;
|
|
3168
|
+
if (!isDraggingExternal) {
|
|
3169
|
+
triggerOnApply(newRange);
|
|
3170
|
+
}
|
|
3171
|
+
}, [isDragging, minPrice, maxPrice, range, value, onChange, isDraggingExternal, triggerOnApply]);
|
|
3172
|
+
const handleMouseDown = (handle) => (e) => {
|
|
3173
|
+
e.preventDefault();
|
|
3174
|
+
setIsDragging(handle);
|
|
3175
|
+
setIsDraggingExternal(true);
|
|
3176
|
+
onDragStart?.();
|
|
3177
|
+
};
|
|
3178
|
+
const handleTouchStart = (handle) => (e) => {
|
|
3179
|
+
e.preventDefault();
|
|
3180
|
+
setIsDragging(handle);
|
|
3181
|
+
setIsDraggingExternal(true);
|
|
3182
|
+
onDragStart?.();
|
|
3183
|
+
};
|
|
3184
|
+
const handleDragEnd = useCallback(() => {
|
|
3185
|
+
if (isDraggingExternal && onApply) {
|
|
3186
|
+
onApply(lastValueRef.current);
|
|
3187
|
+
}
|
|
3188
|
+
setIsDragging(null);
|
|
3189
|
+
setIsDraggingExternal(false);
|
|
3190
|
+
onDragEnd?.();
|
|
3191
|
+
}, [isDraggingExternal, onApply, onDragEnd]);
|
|
3192
|
+
useEffect8(() => {
|
|
3193
|
+
if (!isDragging) return;
|
|
3194
|
+
const handleMouseMove = (e) => {
|
|
3195
|
+
handleDrag(e.clientX);
|
|
3196
|
+
};
|
|
3197
|
+
const handleTouchMove = (e) => {
|
|
3198
|
+
if (e.touches.length > 0) {
|
|
3199
|
+
handleDrag(e.touches[0].clientX);
|
|
3200
|
+
}
|
|
3201
|
+
};
|
|
3202
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
3203
|
+
document.addEventListener("mouseup", handleDragEnd);
|
|
3204
|
+
document.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
3205
|
+
document.addEventListener("touchend", handleDragEnd);
|
|
3206
|
+
return () => {
|
|
3207
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
3208
|
+
document.removeEventListener("mouseup", handleDragEnd);
|
|
3209
|
+
document.removeEventListener("touchmove", handleTouchMove);
|
|
3210
|
+
document.removeEventListener("touchend", handleDragEnd);
|
|
3211
|
+
if (timeoutRef.current) {
|
|
3212
|
+
clearTimeout(timeoutRef.current);
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
}, [isDragging, handleDrag, handleDragEnd]);
|
|
3216
|
+
const handleMinInputFocus = () => {
|
|
3217
|
+
setMinInputFocused(true);
|
|
3218
|
+
setMinInputValue(value.min.toString());
|
|
3219
|
+
};
|
|
3220
|
+
const handleMaxInputFocus = () => {
|
|
3221
|
+
setMaxInputFocused(true);
|
|
3222
|
+
setMaxInputValue(value.max.toString());
|
|
3223
|
+
};
|
|
3224
|
+
const handleMinInputChange = (e) => {
|
|
3225
|
+
const val = e.target.value.replace(/[^0-9]/g, "");
|
|
3226
|
+
setMinInputValue(val);
|
|
3227
|
+
};
|
|
3228
|
+
const handleMaxInputChange = (e) => {
|
|
3229
|
+
const val = e.target.value.replace(/[^0-9]/g, "");
|
|
3230
|
+
setMaxInputValue(val);
|
|
3231
|
+
};
|
|
3232
|
+
const handleMinInputBlur = () => {
|
|
3233
|
+
setMinInputFocused(false);
|
|
3234
|
+
const numValue = parseInt(minInputValue, 10);
|
|
3235
|
+
if (!isNaN(numValue)) {
|
|
3236
|
+
const clampedValue = Math.max(minPrice, Math.min(numValue, value.max - 1));
|
|
3237
|
+
const newRange = { min: clampedValue, max: value.max };
|
|
3238
|
+
onChange(newRange);
|
|
3239
|
+
if (onApply) {
|
|
3240
|
+
triggerOnApply(newRange);
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
};
|
|
3244
|
+
const handleMaxInputBlur = () => {
|
|
3245
|
+
setMaxInputFocused(false);
|
|
3246
|
+
const numValue = parseInt(maxInputValue, 10);
|
|
3247
|
+
if (!isNaN(numValue)) {
|
|
3248
|
+
const clampedValue = Math.min(maxPrice, Math.max(numValue, value.min + 1));
|
|
3249
|
+
const newRange = { min: value.min, max: clampedValue };
|
|
3250
|
+
onChange(newRange);
|
|
3251
|
+
if (onApply) {
|
|
3252
|
+
triggerOnApply(newRange);
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
};
|
|
3256
|
+
useEffect8(() => {
|
|
3257
|
+
return () => {
|
|
3258
|
+
if (timeoutRef.current) {
|
|
3259
|
+
clearTimeout(timeoutRef.current);
|
|
3260
|
+
}
|
|
3261
|
+
};
|
|
3262
|
+
}, []);
|
|
3263
|
+
return /* @__PURE__ */ jsxs27("div", { className: PriceRangeFilter_default.priceRangeWrapper, children: [
|
|
3264
|
+
/* @__PURE__ */ jsxs27("div", { className: PriceRangeFilter_default.priceInputs, children: [
|
|
3265
|
+
/* @__PURE__ */ jsx28("div", { className: PriceRangeFilter_default.priceInputWrapper, children: /* @__PURE__ */ jsx28(
|
|
3266
|
+
"input",
|
|
3267
|
+
{
|
|
3268
|
+
type: "text",
|
|
3269
|
+
inputMode: "numeric",
|
|
3270
|
+
className: PriceRangeFilter_default.priceInput,
|
|
3271
|
+
value: minInputFocused ? minInputValue : `${displayCurrency} ${value.min}`,
|
|
3272
|
+
onChange: handleMinInputChange,
|
|
3273
|
+
onFocus: handleMinInputFocus,
|
|
3274
|
+
onBlur: handleMinInputBlur,
|
|
3275
|
+
"aria-label": t("filter.min-price", "Minimum price")
|
|
3276
|
+
}
|
|
3277
|
+
) }),
|
|
3278
|
+
/* @__PURE__ */ jsx28("div", { className: PriceRangeFilter_default.priceInputDivider, children: "\u2014" }),
|
|
3279
|
+
/* @__PURE__ */ jsx28("div", { className: PriceRangeFilter_default.priceInputWrapper, children: /* @__PURE__ */ jsx28(
|
|
3280
|
+
"input",
|
|
3281
|
+
{
|
|
3282
|
+
type: "text",
|
|
3283
|
+
inputMode: "numeric",
|
|
3284
|
+
className: PriceRangeFilter_default.priceInput,
|
|
3285
|
+
value: maxInputFocused ? maxInputValue : `${displayCurrency} ${value.max}`,
|
|
3286
|
+
onChange: handleMaxInputChange,
|
|
3287
|
+
onFocus: handleMaxInputFocus,
|
|
3288
|
+
onBlur: handleMaxInputBlur,
|
|
3289
|
+
"aria-label": t("filter.max-price", "Maximum price")
|
|
3290
|
+
}
|
|
3291
|
+
) })
|
|
3292
|
+
] }),
|
|
3293
|
+
/* @__PURE__ */ jsx28("div", { className: PriceRangeFilter_default.histogram, children: histogram.map((histValue, index) => {
|
|
3294
|
+
const height = histValue / maxHistogramValue * 100;
|
|
3295
|
+
const isActive = getBarActive(index);
|
|
3296
|
+
return /* @__PURE__ */ jsx28(
|
|
3297
|
+
"div",
|
|
3298
|
+
{
|
|
3299
|
+
className: `${PriceRangeFilter_default.histogramBar} ${isActive ? PriceRangeFilter_default.histogramBarActive : ""}`,
|
|
3300
|
+
style: { height: `${Math.max(height, 10)}%` }
|
|
3301
|
+
},
|
|
3302
|
+
index
|
|
3303
|
+
);
|
|
3304
|
+
}) }),
|
|
3305
|
+
/* @__PURE__ */ jsxs27("div", { className: PriceRangeFilter_default.sliderContainer, ref: sliderRef, children: [
|
|
3306
|
+
/* @__PURE__ */ jsx28("div", { className: PriceRangeFilter_default.sliderTrack }),
|
|
3307
|
+
/* @__PURE__ */ jsx28(
|
|
3308
|
+
"div",
|
|
3309
|
+
{
|
|
3310
|
+
className: PriceRangeFilter_default.sliderActiveTrack,
|
|
3311
|
+
style: {
|
|
3312
|
+
left: `calc(12px + (100% - 24px) * ${minPercent / 100})`,
|
|
3313
|
+
width: `calc((100% - 24px) * ${(maxPercent - minPercent) / 100})`
|
|
3314
|
+
}
|
|
2388
3315
|
}
|
|
3316
|
+
),
|
|
3317
|
+
/* @__PURE__ */ jsx28(
|
|
3318
|
+
"div",
|
|
3319
|
+
{
|
|
3320
|
+
className: `${PriceRangeFilter_default.sliderHandle} ${isDragging === "min" ? PriceRangeFilter_default.sliderHandleActive : ""}`,
|
|
3321
|
+
style: { left: `calc(12px + (100% - 24px) * ${minPercent / 100})` },
|
|
3322
|
+
onMouseDown: handleMouseDown("min"),
|
|
3323
|
+
onTouchStart: handleTouchStart("min"),
|
|
3324
|
+
role: "slider",
|
|
3325
|
+
"aria-label": t("filter.min-price", "Minimum price"),
|
|
3326
|
+
"aria-valuenow": value.min,
|
|
3327
|
+
"aria-valuemin": minPrice,
|
|
3328
|
+
"aria-valuemax": value.max,
|
|
3329
|
+
tabIndex: 0
|
|
3330
|
+
}
|
|
3331
|
+
),
|
|
3332
|
+
/* @__PURE__ */ jsx28(
|
|
3333
|
+
"div",
|
|
3334
|
+
{
|
|
3335
|
+
className: `${PriceRangeFilter_default.sliderHandle} ${isDragging === "max" ? PriceRangeFilter_default.sliderHandleActive : ""}`,
|
|
3336
|
+
style: { left: `calc(12px + (100% - 24px) * ${maxPercent / 100})` },
|
|
3337
|
+
onMouseDown: handleMouseDown("max"),
|
|
3338
|
+
onTouchStart: handleTouchStart("max"),
|
|
3339
|
+
role: "slider",
|
|
3340
|
+
"aria-label": t("filter.max-price", "Maximum price"),
|
|
3341
|
+
"aria-valuenow": value.max,
|
|
3342
|
+
"aria-valuemin": value.min,
|
|
3343
|
+
"aria-valuemax": maxPrice,
|
|
3344
|
+
tabIndex: 0
|
|
3345
|
+
}
|
|
3346
|
+
)
|
|
3347
|
+
] })
|
|
3348
|
+
] });
|
|
3349
|
+
};
|
|
3350
|
+
|
|
3351
|
+
// src/components/Filters/HotelCategoryFilter.module.css
|
|
3352
|
+
var HotelCategoryFilter_default = {};
|
|
3353
|
+
|
|
3354
|
+
// src/components/Filters/HotelCategoryFilter.tsx
|
|
3355
|
+
import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3356
|
+
var CATEGORY_OPTIONS = [
|
|
3357
|
+
{ value: "5", stars: 5, label: null },
|
|
3358
|
+
{ value: "4", stars: 4, label: null },
|
|
3359
|
+
{ value: "3", stars: 3, label: null },
|
|
3360
|
+
{ value: "2", stars: 2, label: null },
|
|
3361
|
+
{ value: "swiss_lodge", stars: 0, label: "Swiss Lodge" },
|
|
3362
|
+
{ value: "not_classified", stars: 0, label: "No category" }
|
|
3363
|
+
];
|
|
3364
|
+
var HotelCategoryFilter = ({
|
|
3365
|
+
selected,
|
|
3366
|
+
counts = {},
|
|
3367
|
+
onChange,
|
|
3368
|
+
className = ""
|
|
3369
|
+
}) => {
|
|
3370
|
+
const { t } = useUIContext();
|
|
3371
|
+
const handleToggle = (value) => {
|
|
3372
|
+
if (selected.includes(value)) {
|
|
3373
|
+
onChange(selected.filter((v) => v !== value));
|
|
3374
|
+
} else {
|
|
3375
|
+
onChange([...selected, value]);
|
|
3376
|
+
}
|
|
3377
|
+
};
|
|
3378
|
+
const getLabel = (option) => {
|
|
3379
|
+
if (option.stars > 0) return null;
|
|
3380
|
+
if (option.value === "swiss_lodge") return t("filter.swiss-lodge", "Swiss Lodge");
|
|
3381
|
+
if (option.value === "not_classified") return t("filter.no-category", "No category");
|
|
3382
|
+
return option.label;
|
|
3383
|
+
};
|
|
3384
|
+
return /* @__PURE__ */ jsxs28("div", { className, children: [
|
|
3385
|
+
/* @__PURE__ */ jsx29("div", { className: HotelCategoryFilter_default.filterList, children: CATEGORY_OPTIONS.map((option) => {
|
|
3386
|
+
const count = counts[option.value];
|
|
3387
|
+
const isDisabled = count === 0 && !selected.includes(option.value);
|
|
3388
|
+
return /* @__PURE__ */ jsx29(
|
|
3389
|
+
FilterCheckboxItem,
|
|
3390
|
+
{
|
|
3391
|
+
id: `category-${option.value}`,
|
|
3392
|
+
label: option.stars > 0 ? /* @__PURE__ */ jsx29("div", { className: HotelCategoryFilter_default.starsContainer, children: Array.from({ length: option.stars }).map((_, i) => /* @__PURE__ */ jsx29("svg", { className: HotelCategoryFilter_default.starIcon, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx29("path", { d: "M12 0L14.6942 8.2918H23.4127L16.3593 13.4164L19.0534 21.7082L12 16.5836L4.94658 21.7082L7.64074 13.4164L0.587322 8.2918H9.30583L12 0Z" }) }, i)) }) : getLabel(option),
|
|
3393
|
+
count,
|
|
3394
|
+
checked: selected.includes(option.value),
|
|
3395
|
+
disabled: isDisabled,
|
|
3396
|
+
onChange: () => handleToggle(option.value),
|
|
3397
|
+
trackName: `filter-category-${option.value}`
|
|
3398
|
+
},
|
|
3399
|
+
option.value
|
|
3400
|
+
);
|
|
3401
|
+
}) }),
|
|
3402
|
+
/* @__PURE__ */ jsx29("div", { className: HotelCategoryFilter_default.footer, children: /* @__PURE__ */ jsx29("span", { className: HotelCategoryFilter_default.footerText, children: t("filter.hotellerie-suisse", "Classification HotellerieSuisse") }) })
|
|
3403
|
+
] });
|
|
3404
|
+
};
|
|
3405
|
+
|
|
3406
|
+
// src/components/Filters/ReviewsFilter.module.css
|
|
3407
|
+
var ReviewsFilter_default = {};
|
|
3408
|
+
|
|
3409
|
+
// src/components/Filters/ReviewsFilter.tsx
|
|
3410
|
+
import { Fragment as Fragment6, jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3411
|
+
var REVIEW_OPTIONS = [
|
|
3412
|
+
{ value: "excellent", labelKey: "rating-excellent", range: "(4.4+)" },
|
|
3413
|
+
{ value: "very_good", labelKey: "rating-very-good", range: "(4.1 \u2013 4.3)" },
|
|
3414
|
+
{ value: "good", labelKey: "rating-good", range: "(3.8 \u2013 4.0)" },
|
|
3415
|
+
{ value: "fair", labelKey: "rating-fair", range: "(3.5 \u2013 3.7)" },
|
|
3416
|
+
{ value: "no_rating", labelKey: "rating-none", range: "" }
|
|
3417
|
+
];
|
|
3418
|
+
var ReviewsFilter = ({
|
|
3419
|
+
selected,
|
|
3420
|
+
counts = {},
|
|
3421
|
+
onChange,
|
|
3422
|
+
className = "",
|
|
3423
|
+
isPlaceSearchActive = false
|
|
3424
|
+
}) => {
|
|
3425
|
+
const { t } = useUIContext();
|
|
3426
|
+
const handleToggle = (value) => {
|
|
3427
|
+
if (selected.includes(value)) {
|
|
3428
|
+
onChange(selected.filter((v) => v !== value));
|
|
3429
|
+
} else {
|
|
3430
|
+
onChange([...selected, value]);
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
const getRatingLabel = (labelKey) => {
|
|
3434
|
+
const labelMap = {
|
|
3435
|
+
"rating-excellent": t("label.rating-excellent", "Excellent"),
|
|
3436
|
+
"rating-very-good": t("label.rating-very-good", "Very Good"),
|
|
3437
|
+
"rating-good": t("label.rating-good", "Good"),
|
|
3438
|
+
"rating-fair": t("label.rating-fair", "Fair"),
|
|
3439
|
+
"rating-none": t("label.rating-none", "No rating")
|
|
3440
|
+
};
|
|
3441
|
+
return labelMap[labelKey] ?? labelKey;
|
|
3442
|
+
};
|
|
3443
|
+
return /* @__PURE__ */ jsxs29("div", { className, children: [
|
|
3444
|
+
/* @__PURE__ */ jsx30("div", { className: ReviewsFilter_default.filterList, children: REVIEW_OPTIONS.map((option) => {
|
|
3445
|
+
const count = counts[option.value];
|
|
3446
|
+
const isDisabled = !isPlaceSearchActive && count === 0 && !selected.includes(option.value);
|
|
3447
|
+
return /* @__PURE__ */ jsx30(
|
|
3448
|
+
FilterCheckboxItem,
|
|
3449
|
+
{
|
|
3450
|
+
id: `review-${option.value}`,
|
|
3451
|
+
label: /* @__PURE__ */ jsxs29(Fragment6, { children: [
|
|
3452
|
+
getRatingLabel(option.labelKey),
|
|
3453
|
+
option.range && /* @__PURE__ */ jsxs29("span", { className: ReviewsFilter_default.filterRange, children: [
|
|
3454
|
+
" ",
|
|
3455
|
+
option.range
|
|
3456
|
+
] })
|
|
3457
|
+
] }),
|
|
3458
|
+
count,
|
|
3459
|
+
checked: selected.includes(option.value),
|
|
3460
|
+
disabled: isDisabled,
|
|
3461
|
+
onChange: () => handleToggle(option.value),
|
|
3462
|
+
trackName: `filter-review-${option.value}`
|
|
3463
|
+
},
|
|
3464
|
+
option.value
|
|
3465
|
+
);
|
|
3466
|
+
}) }),
|
|
3467
|
+
/* @__PURE__ */ jsx30("div", { className: ReviewsFilter_default.footer, children: /* @__PURE__ */ jsx30("span", { className: ReviewsFilter_default.footerText, children: t("filter.trustyou", "Reviews from TrustYou\xAE") }) })
|
|
3468
|
+
] });
|
|
3469
|
+
};
|
|
3470
|
+
|
|
3471
|
+
// src/components/Filters/ExperienceFilter.tsx
|
|
3472
|
+
import { useState as useState13 } from "react";
|
|
3473
|
+
|
|
3474
|
+
// src/components/Filters/ExperienceFilter.module.css
|
|
3475
|
+
var ExperienceFilter_default = {};
|
|
3476
|
+
|
|
3477
|
+
// src/components/Filters/ExperienceFilter.tsx
|
|
3478
|
+
import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3479
|
+
var ExperienceFilter = ({
|
|
3480
|
+
selected,
|
|
3481
|
+
themes = [],
|
|
3482
|
+
onChange,
|
|
3483
|
+
className = ""
|
|
3484
|
+
}) => {
|
|
3485
|
+
const { t } = useUIContext();
|
|
3486
|
+
const [expanded, setExpanded] = useState13(false);
|
|
3487
|
+
const visibleThemes = expanded ? themes : themes.slice(0, 5);
|
|
3488
|
+
const hasMoreThemes = themes.length > 5;
|
|
3489
|
+
const handleToggle = (value) => {
|
|
3490
|
+
if (selected.includes(value)) {
|
|
3491
|
+
onChange(selected.filter((v) => v !== value));
|
|
3492
|
+
} else {
|
|
3493
|
+
onChange([...selected, value]);
|
|
3494
|
+
}
|
|
3495
|
+
};
|
|
3496
|
+
if (themes.length === 0) {
|
|
3497
|
+
return null;
|
|
3498
|
+
}
|
|
3499
|
+
return /* @__PURE__ */ jsxs30("div", { className: `${ExperienceFilter_default.filterList} ${className}`, children: [
|
|
3500
|
+
visibleThemes.map((theme) => {
|
|
3501
|
+
const themeIdStr = String(theme.id);
|
|
3502
|
+
const isDisabled = theme.count === 0 && !selected.includes(themeIdStr);
|
|
3503
|
+
return /* @__PURE__ */ jsx31(
|
|
3504
|
+
FilterCheckboxItem,
|
|
3505
|
+
{
|
|
3506
|
+
id: `experience-${theme.id}`,
|
|
3507
|
+
label: theme.name,
|
|
3508
|
+
count: theme.count > 0 ? theme.count : void 0,
|
|
3509
|
+
checked: selected.includes(themeIdStr),
|
|
3510
|
+
disabled: isDisabled,
|
|
3511
|
+
onChange: () => handleToggle(themeIdStr),
|
|
3512
|
+
trackName: `filter-experience-${theme.id}`
|
|
3513
|
+
},
|
|
3514
|
+
theme.id
|
|
3515
|
+
);
|
|
3516
|
+
}),
|
|
3517
|
+
hasMoreThemes && /* @__PURE__ */ jsxs30(
|
|
3518
|
+
"button",
|
|
3519
|
+
{
|
|
3520
|
+
type: "button",
|
|
3521
|
+
className: ExperienceFilter_default.showMoreBtn,
|
|
3522
|
+
onClick: () => setExpanded(!expanded),
|
|
3523
|
+
children: [
|
|
3524
|
+
expanded ? t("filter.show-less", "Show less") : t("filter.show-all", "Show all"),
|
|
3525
|
+
/* @__PURE__ */ jsx31("span", { className: `${ExperienceFilter_default.arrowIcon} ${expanded ? ExperienceFilter_default.arrowUp : ""}`, children: /* @__PURE__ */ jsx31("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsx31("path", { d: "M9.36927 13.9061C9.71908 14.2535 10.2847 14.2535 10.6308 13.9061L16.4069 8.1803C16.7567 7.83285 16.7567 7.27102 16.4069 6.92727C16.0571 6.58352 15.4915 6.57983 15.1454 6.92727L10.0019 12.0247L4.85845 6.92727C4.50864 6.57983 3.94299 6.57983 3.5969 6.92727C3.25081 7.27472 3.24709 7.83655 3.5969 8.1803L9.37299 13.9061H9.36927Z", fill: "currentColor" }) }) })
|
|
3526
|
+
]
|
|
2389
3527
|
}
|
|
2390
3528
|
)
|
|
2391
3529
|
] });
|
|
2392
3530
|
};
|
|
2393
3531
|
|
|
3532
|
+
// src/components/Filters/RegionsFilter.tsx
|
|
3533
|
+
import { useState as useState14, useEffect as useEffect9, useRef as useRef7 } from "react";
|
|
3534
|
+
|
|
3535
|
+
// src/components/Filters/RegionsFilter.module.css
|
|
3536
|
+
var RegionsFilter_default = {};
|
|
3537
|
+
|
|
3538
|
+
// src/components/Filters/RegionsFilter.tsx
|
|
3539
|
+
import { jsx as jsx32, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3540
|
+
var RegionsFilter = ({
|
|
3541
|
+
regions,
|
|
3542
|
+
selected,
|
|
3543
|
+
onChange,
|
|
3544
|
+
className = "",
|
|
3545
|
+
isPlaceSearchActive = false
|
|
3546
|
+
}) => {
|
|
3547
|
+
const { t } = useUIContext();
|
|
3548
|
+
const [expandedCountries, setExpandedCountries] = useState14(/* @__PURE__ */ new Set(["country_215"]));
|
|
3549
|
+
const hasInitializedRef = useRef7(false);
|
|
3550
|
+
useEffect9(() => {
|
|
3551
|
+
if (hasInitializedRef.current) return;
|
|
3552
|
+
if (regions.length === 0 || selected.length === 0) return;
|
|
3553
|
+
const countriesWithSelectedRegions = /* @__PURE__ */ new Set();
|
|
3554
|
+
regions.forEach((region) => {
|
|
3555
|
+
if (region.subRegions?.some((sub) => selected.includes(sub.value))) {
|
|
3556
|
+
countriesWithSelectedRegions.add(region.value);
|
|
3557
|
+
}
|
|
3558
|
+
});
|
|
3559
|
+
if (countriesWithSelectedRegions.size > 0) {
|
|
3560
|
+
setExpandedCountries(countriesWithSelectedRegions);
|
|
3561
|
+
hasInitializedRef.current = true;
|
|
3562
|
+
}
|
|
3563
|
+
}, [regions, selected]);
|
|
3564
|
+
const handleCountryToggle = (countryValue) => {
|
|
3565
|
+
setExpandedCountries((prev) => {
|
|
3566
|
+
const next = new Set(prev);
|
|
3567
|
+
if (next.has(countryValue)) {
|
|
3568
|
+
next.delete(countryValue);
|
|
3569
|
+
} else {
|
|
3570
|
+
next.add(countryValue);
|
|
3571
|
+
}
|
|
3572
|
+
return next;
|
|
3573
|
+
});
|
|
3574
|
+
};
|
|
3575
|
+
const handleRegionToggle = (regionValue) => {
|
|
3576
|
+
if (selected.includes(regionValue)) {
|
|
3577
|
+
onChange(selected.filter((r) => r !== regionValue));
|
|
3578
|
+
} else {
|
|
3579
|
+
onChange([...selected, regionValue]);
|
|
3580
|
+
}
|
|
3581
|
+
};
|
|
3582
|
+
if (regions.length === 0) {
|
|
3583
|
+
return null;
|
|
3584
|
+
}
|
|
3585
|
+
return /* @__PURE__ */ jsx32("div", { className: `${RegionsFilter_default.filterList} ${className}`, children: regions.map((region) => {
|
|
3586
|
+
const hasSubRegions = region.subRegions && region.subRegions.length > 0;
|
|
3587
|
+
const isExpanded = expandedCountries.has(region.value);
|
|
3588
|
+
return /* @__PURE__ */ jsxs31("div", { className: RegionsFilter_default.regionItem, children: [
|
|
3589
|
+
/* @__PURE__ */ jsxs31(
|
|
3590
|
+
"button",
|
|
3591
|
+
{
|
|
3592
|
+
type: "button",
|
|
3593
|
+
className: `${RegionsFilter_default.countryRow} ${isExpanded ? RegionsFilter_default.countryRowExpanded : ""}`,
|
|
3594
|
+
onClick: () => handleCountryToggle(region.value),
|
|
3595
|
+
"aria-expanded": isExpanded,
|
|
3596
|
+
disabled: isPlaceSearchActive,
|
|
3597
|
+
children: [
|
|
3598
|
+
/* @__PURE__ */ jsxs31("div", { className: RegionsFilter_default.countryInfo, children: [
|
|
3599
|
+
/* @__PURE__ */ jsx32("span", { className: RegionsFilter_default.countryName, children: region.label }),
|
|
3600
|
+
region.count !== void 0 && /* @__PURE__ */ jsx32("span", { className: RegionsFilter_default.countBadge, children: region.count })
|
|
3601
|
+
] }),
|
|
3602
|
+
hasSubRegions && /* @__PURE__ */ jsx32(
|
|
3603
|
+
"svg",
|
|
3604
|
+
{
|
|
3605
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3606
|
+
width: "20",
|
|
3607
|
+
height: "20",
|
|
3608
|
+
viewBox: "0 0 20 20",
|
|
3609
|
+
fill: "none",
|
|
3610
|
+
className: `${RegionsFilter_default.chevron} ${isExpanded ? RegionsFilter_default.chevronExpanded : ""}`,
|
|
3611
|
+
children: /* @__PURE__ */ jsx32("path", { d: "M9.36927 13.9061C9.71908 14.2535 10.2847 14.2535 10.6308 13.9061L16.4069 8.18027C16.7567 7.83283 16.7567 7.271 16.4069 6.92725C16.0571 6.5835 15.4915 6.5798 15.1454 6.92725L10.0019 12.0247L4.85845 6.92725C4.50864 6.5798 3.94299 6.5798 3.5969 6.92725C3.25081 7.2747 3.24709 7.83652 3.5969 8.18027L9.37299 13.9061H9.36927Z", fill: "#6B7280" })
|
|
3612
|
+
}
|
|
3613
|
+
)
|
|
3614
|
+
]
|
|
3615
|
+
}
|
|
3616
|
+
),
|
|
3617
|
+
hasSubRegions && isExpanded && (() => {
|
|
3618
|
+
const hasSelectableRegions = region.subRegions.some(
|
|
3619
|
+
(sr) => sr.count === void 0 || sr.count > 0
|
|
3620
|
+
);
|
|
3621
|
+
const subValues = region.subRegions.map((sr) => sr.value);
|
|
3622
|
+
const hasSelectedRegions = subValues.some((v) => selected.includes(v));
|
|
3623
|
+
return /* @__PURE__ */ jsxs31("div", { className: RegionsFilter_default.mobileSelectAllActions, children: [
|
|
3624
|
+
/* @__PURE__ */ jsx32(
|
|
3625
|
+
"button",
|
|
3626
|
+
{
|
|
3627
|
+
type: "button",
|
|
3628
|
+
className: RegionsFilter_default.selectAllBtn,
|
|
3629
|
+
disabled: !hasSelectableRegions,
|
|
3630
|
+
onClick: () => {
|
|
3631
|
+
const selectableSubValues = region.subRegions.filter((sr) => sr.count === void 0 || sr.count > 0).map((sr) => sr.value);
|
|
3632
|
+
const merged = Array.from(/* @__PURE__ */ new Set([...selected, ...selectableSubValues]));
|
|
3633
|
+
onChange(merged);
|
|
3634
|
+
},
|
|
3635
|
+
children: t("filter.select-all", "Select all")
|
|
3636
|
+
}
|
|
3637
|
+
),
|
|
3638
|
+
/* @__PURE__ */ jsx32(
|
|
3639
|
+
"button",
|
|
3640
|
+
{
|
|
3641
|
+
type: "button",
|
|
3642
|
+
className: RegionsFilter_default.resetAllBtn,
|
|
3643
|
+
disabled: !hasSelectedRegions,
|
|
3644
|
+
onClick: () => {
|
|
3645
|
+
onChange(selected.filter((v) => !subValues.includes(v)));
|
|
3646
|
+
},
|
|
3647
|
+
children: t("filter.reset", "Reset")
|
|
3648
|
+
}
|
|
3649
|
+
)
|
|
3650
|
+
] });
|
|
3651
|
+
})(),
|
|
3652
|
+
hasSubRegions && isExpanded && /* @__PURE__ */ jsx32("div", { className: RegionsFilter_default.subRegions, children: region.subRegions.map((subRegion) => {
|
|
3653
|
+
const isDisabled = subRegion.count === 0 && !selected.includes(subRegion.value) || isPlaceSearchActive && !selected.includes(subRegion.value);
|
|
3654
|
+
return /* @__PURE__ */ jsx32(
|
|
3655
|
+
FilterCheckboxItem,
|
|
3656
|
+
{
|
|
3657
|
+
id: `region-${subRegion.value}`,
|
|
3658
|
+
label: subRegion.label,
|
|
3659
|
+
count: subRegion.count,
|
|
3660
|
+
checked: selected.includes(subRegion.value),
|
|
3661
|
+
disabled: isDisabled,
|
|
3662
|
+
onChange: () => handleRegionToggle(subRegion.value),
|
|
3663
|
+
trackName: `filter-region-${subRegion.value}`
|
|
3664
|
+
},
|
|
3665
|
+
subRegion.value
|
|
3666
|
+
);
|
|
3667
|
+
}) })
|
|
3668
|
+
] }, region.value);
|
|
3669
|
+
}) });
|
|
3670
|
+
};
|
|
3671
|
+
|
|
3672
|
+
// src/components/Filters/CheckboxFilter.module.css
|
|
3673
|
+
var CheckboxFilter_default = {};
|
|
3674
|
+
|
|
3675
|
+
// src/components/Filters/CheckboxFilter.tsx
|
|
3676
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
3677
|
+
var CheckboxFilter = ({
|
|
3678
|
+
selected,
|
|
3679
|
+
counts = {},
|
|
3680
|
+
options = [],
|
|
3681
|
+
onChange,
|
|
3682
|
+
className = "",
|
|
3683
|
+
trackPrefix = "filter"
|
|
3684
|
+
}) => {
|
|
3685
|
+
const handleToggle = (value) => {
|
|
3686
|
+
if (selected.includes(value)) {
|
|
3687
|
+
onChange(selected.filter((v) => v !== value));
|
|
3688
|
+
} else {
|
|
3689
|
+
onChange([...selected, value]);
|
|
3690
|
+
}
|
|
3691
|
+
};
|
|
3692
|
+
if (options.length === 0) {
|
|
3693
|
+
return null;
|
|
3694
|
+
}
|
|
3695
|
+
return /* @__PURE__ */ jsx33("div", { className: `${CheckboxFilter_default.filterList} ${className}`, children: options.map((option) => {
|
|
3696
|
+
const count = counts[option.key];
|
|
3697
|
+
const isDisabled = count === 0 && !selected.includes(option.key);
|
|
3698
|
+
return /* @__PURE__ */ jsx33(
|
|
3699
|
+
FilterCheckboxItem,
|
|
3700
|
+
{
|
|
3701
|
+
id: `${trackPrefix}-${option.key}`,
|
|
3702
|
+
label: option.name,
|
|
3703
|
+
count,
|
|
3704
|
+
checked: selected.includes(option.key),
|
|
3705
|
+
disabled: isDisabled,
|
|
3706
|
+
onChange: () => handleToggle(option.key),
|
|
3707
|
+
trackName: `filter-${trackPrefix}-${option.key}`
|
|
3708
|
+
},
|
|
3709
|
+
option.key
|
|
3710
|
+
);
|
|
3711
|
+
}) });
|
|
3712
|
+
};
|
|
3713
|
+
var MealsFilter = (props) => /* @__PURE__ */ jsx33(CheckboxFilter, { ...props, trackPrefix: "meals" });
|
|
3714
|
+
var TransportFilter = (props) => /* @__PURE__ */ jsx33(CheckboxFilter, { ...props, trackPrefix: "transport" });
|
|
3715
|
+
var WellnessFilter = (props) => /* @__PURE__ */ jsx33(CheckboxFilter, { ...props, trackPrefix: "wellness" });
|
|
3716
|
+
|
|
3717
|
+
// src/components/Filters/SelectedFiltersRow.module.css
|
|
3718
|
+
var SelectedFiltersRow_default = {};
|
|
3719
|
+
|
|
3720
|
+
// src/components/Filters/SelectedFiltersRow.tsx
|
|
3721
|
+
import { jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3722
|
+
var SelectedFiltersRow = ({
|
|
3723
|
+
filters,
|
|
3724
|
+
onRemove,
|
|
3725
|
+
onClearAll,
|
|
3726
|
+
className = ""
|
|
3727
|
+
}) => {
|
|
3728
|
+
const { t } = useUIContext();
|
|
3729
|
+
if (filters.length === 0) {
|
|
3730
|
+
return null;
|
|
3731
|
+
}
|
|
3732
|
+
return /* @__PURE__ */ jsx34("div", { className: `${SelectedFiltersRow_default.container} ${className}`, children: /* @__PURE__ */ jsxs32("div", { className: SelectedFiltersRow_default.chipsWrapper, children: [
|
|
3733
|
+
/* @__PURE__ */ jsxs32("p", { className: SelectedFiltersRow_default.selectedText, children: [
|
|
3734
|
+
t("filter.selected", "Selected:"),
|
|
3735
|
+
" "
|
|
3736
|
+
] }),
|
|
3737
|
+
/* @__PURE__ */ jsxs32("div", { className: SelectedFiltersRow_default.chips, children: [
|
|
3738
|
+
filters.map((filter) => /* @__PURE__ */ jsx34(
|
|
3739
|
+
Chip,
|
|
3740
|
+
{
|
|
3741
|
+
label: filter.label,
|
|
3742
|
+
size: "small",
|
|
3743
|
+
state: "idle",
|
|
3744
|
+
removable: true,
|
|
3745
|
+
onRemove: () => onRemove(filter)
|
|
3746
|
+
},
|
|
3747
|
+
filter.id
|
|
3748
|
+
)),
|
|
3749
|
+
onClearAll && /* @__PURE__ */ jsx34(
|
|
3750
|
+
Button,
|
|
3751
|
+
{
|
|
3752
|
+
variant: "link",
|
|
3753
|
+
className: SelectedFiltersRow_default.clearAllBtn,
|
|
3754
|
+
onClick: onClearAll,
|
|
3755
|
+
children: t("filter.clear-all", "Clear all")
|
|
3756
|
+
}
|
|
3757
|
+
)
|
|
3758
|
+
] })
|
|
3759
|
+
] }) });
|
|
3760
|
+
};
|
|
3761
|
+
|
|
2394
3762
|
// src/components/icons/HeartIcon.tsx
|
|
2395
|
-
import { jsx as
|
|
2396
|
-
var HeartIcon3 = ({ filled = false, className = "", size = 24 }) => /* @__PURE__ */
|
|
3763
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
3764
|
+
var HeartIcon3 = ({ filled = false, className = "", size = 24 }) => /* @__PURE__ */ jsx35(
|
|
2397
3765
|
"svg",
|
|
2398
3766
|
{
|
|
2399
3767
|
width: size,
|
|
@@ -2405,14 +3773,14 @@ var HeartIcon3 = ({ filled = false, className = "", size = 24 }) => /* @__PURE__
|
|
|
2405
3773
|
strokeWidth: 2,
|
|
2406
3774
|
strokeLinecap: "round",
|
|
2407
3775
|
strokeLinejoin: "round",
|
|
2408
|
-
children: /* @__PURE__ */
|
|
3776
|
+
children: /* @__PURE__ */ jsx35("path", { d: "M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" })
|
|
2409
3777
|
}
|
|
2410
3778
|
);
|
|
2411
3779
|
HeartIcon3.displayName = "HeartIcon";
|
|
2412
3780
|
|
|
2413
3781
|
// src/components/icons/StarIcon.tsx
|
|
2414
|
-
import { jsx as
|
|
2415
|
-
var StarIcon4 = ({ filled = true, className = "", size = 9 }) => /* @__PURE__ */
|
|
3782
|
+
import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3783
|
+
var StarIcon4 = ({ filled = true, className = "", size = 9 }) => /* @__PURE__ */ jsxs33(
|
|
2416
3784
|
"svg",
|
|
2417
3785
|
{
|
|
2418
3786
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2422,22 +3790,22 @@ var StarIcon4 = ({ filled = true, className = "", size = 9 }) => /* @__PURE__ */
|
|
|
2422
3790
|
fill: "none",
|
|
2423
3791
|
className,
|
|
2424
3792
|
children: [
|
|
2425
|
-
/* @__PURE__ */
|
|
3793
|
+
/* @__PURE__ */ jsx36("g", { clipPath: "url(#clip0_star_icon)", children: /* @__PURE__ */ jsx36(
|
|
2426
3794
|
"path",
|
|
2427
3795
|
{
|
|
2428
3796
|
d: "M4.80018 0.366577C4.93104 0.366577 5.05173 0.440968 5.11135 0.557659L6.18011 2.66102L8.50521 3.03152C8.63462 3.05194 8.74222 3.14383 8.78294 3.26927C8.82365 3.39472 8.79021 3.53183 8.6986 3.62518L7.03366 5.29533L7.40155 7.6277C7.42191 7.75752 7.3681 7.88879 7.26195 7.9661C7.15581 8.04341 7.01476 8.05508 6.89843 7.99528L4.80018 6.92463L2.70192 7.99528C2.58559 8.05508 2.44454 8.04341 2.33839 7.9661C2.23225 7.88879 2.17844 7.75898 2.1988 7.6277L2.56523 5.29533L0.901751 3.62518C0.808689 3.53183 0.776699 3.39472 0.817413 3.26927C0.858128 3.14383 0.964277 3.05194 1.09515 3.03152L3.42024 2.66102L4.49045 0.557659C4.55007 0.440968 4.67076 0.366577 4.80163 0.366577H4.80018Z",
|
|
2429
3797
|
fill: filled ? "#1F2937" : "#D1D5DB"
|
|
2430
3798
|
}
|
|
2431
3799
|
) }),
|
|
2432
|
-
/* @__PURE__ */
|
|
3800
|
+
/* @__PURE__ */ jsx36("defs", { children: /* @__PURE__ */ jsx36("clipPath", { id: "clip0_star_icon", children: /* @__PURE__ */ jsx36("rect", { width: "8", height: "8", fill: "white", transform: "translate(0.800049 0.199951)" }) }) })
|
|
2433
3801
|
]
|
|
2434
3802
|
}
|
|
2435
3803
|
);
|
|
2436
3804
|
StarIcon4.displayName = "StarIcon";
|
|
2437
3805
|
|
|
2438
3806
|
// src/components/icons/ChevronLeftIcon.tsx
|
|
2439
|
-
import { jsx as
|
|
2440
|
-
var ChevronLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */
|
|
3807
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
3808
|
+
var ChevronLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx37(
|
|
2441
3809
|
"svg",
|
|
2442
3810
|
{
|
|
2443
3811
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2450,14 +3818,14 @@ var ChevronLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx28(
|
|
|
2450
3818
|
strokeLinecap: "round",
|
|
2451
3819
|
strokeLinejoin: "round",
|
|
2452
3820
|
className,
|
|
2453
|
-
children: /* @__PURE__ */
|
|
3821
|
+
children: /* @__PURE__ */ jsx37("polyline", { points: "15 18 9 12 15 6" })
|
|
2454
3822
|
}
|
|
2455
3823
|
);
|
|
2456
3824
|
ChevronLeftIcon.displayName = "ChevronLeftIcon";
|
|
2457
3825
|
|
|
2458
3826
|
// src/components/icons/ChevronRightIcon.tsx
|
|
2459
|
-
import { jsx as
|
|
2460
|
-
var ChevronRightIcon2 = ({ className = "", size = 20 }) => /* @__PURE__ */
|
|
3827
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
3828
|
+
var ChevronRightIcon2 = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx38(
|
|
2461
3829
|
"svg",
|
|
2462
3830
|
{
|
|
2463
3831
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2470,14 +3838,14 @@ var ChevronRightIcon2 = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx29
|
|
|
2470
3838
|
strokeLinecap: "round",
|
|
2471
3839
|
strokeLinejoin: "round",
|
|
2472
3840
|
className,
|
|
2473
|
-
children: /* @__PURE__ */
|
|
3841
|
+
children: /* @__PURE__ */ jsx38("polyline", { points: "9 18 15 12 9 6" })
|
|
2474
3842
|
}
|
|
2475
3843
|
);
|
|
2476
3844
|
ChevronRightIcon2.displayName = "ChevronRightIcon";
|
|
2477
3845
|
|
|
2478
3846
|
// src/components/icons/PinIcon.tsx
|
|
2479
|
-
import { jsx as
|
|
2480
|
-
var PinIcon2 = ({ className = "", size = 16 }) => /* @__PURE__ */
|
|
3847
|
+
import { jsx as jsx39, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3848
|
+
var PinIcon2 = ({ className = "", size = 16 }) => /* @__PURE__ */ jsxs34(
|
|
2481
3849
|
"svg",
|
|
2482
3850
|
{
|
|
2483
3851
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2487,7 +3855,7 @@ var PinIcon2 = ({ className = "", size = 16 }) => /* @__PURE__ */ jsxs26(
|
|
|
2487
3855
|
fill: "none",
|
|
2488
3856
|
className,
|
|
2489
3857
|
children: [
|
|
2490
|
-
/* @__PURE__ */
|
|
3858
|
+
/* @__PURE__ */ jsx39(
|
|
2491
3859
|
"path",
|
|
2492
3860
|
{
|
|
2493
3861
|
fillRule: "evenodd",
|
|
@@ -2496,7 +3864,7 @@ var PinIcon2 = ({ className = "", size = 16 }) => /* @__PURE__ */ jsxs26(
|
|
|
2496
3864
|
fill: "currentColor"
|
|
2497
3865
|
}
|
|
2498
3866
|
),
|
|
2499
|
-
/* @__PURE__ */
|
|
3867
|
+
/* @__PURE__ */ jsx39(
|
|
2500
3868
|
"path",
|
|
2501
3869
|
{
|
|
2502
3870
|
fillRule: "evenodd",
|
|
@@ -2544,36 +3912,51 @@ export {
|
|
|
2544
3912
|
Benefits,
|
|
2545
3913
|
Block,
|
|
2546
3914
|
Button,
|
|
3915
|
+
CATEGORY_OPTIONS,
|
|
2547
3916
|
Card,
|
|
2548
3917
|
Checkbox,
|
|
3918
|
+
CheckboxFilter,
|
|
2549
3919
|
ChevronLeftIcon,
|
|
2550
3920
|
ChevronRightIcon2 as ChevronRightIcon,
|
|
2551
3921
|
Chip,
|
|
3922
|
+
CollapsibleFilterSection,
|
|
2552
3923
|
DateSelector,
|
|
2553
3924
|
Divider,
|
|
2554
3925
|
Dropdown,
|
|
2555
3926
|
DualCalendar,
|
|
3927
|
+
ExperienceFilter,
|
|
2556
3928
|
FAQ,
|
|
3929
|
+
FilterCheckboxItem,
|
|
2557
3930
|
GuestContent,
|
|
2558
3931
|
HeartIcon3 as HeartIcon,
|
|
2559
3932
|
HotelCard,
|
|
2560
3933
|
HotelCardContent,
|
|
2561
3934
|
HotelCardImage,
|
|
2562
3935
|
HotelCardUIProvider,
|
|
3936
|
+
HotelCategoryFilter,
|
|
2563
3937
|
Input,
|
|
3938
|
+
MealsFilter,
|
|
2564
3939
|
Modal,
|
|
2565
3940
|
Pin,
|
|
2566
3941
|
PinIcon2 as PinIcon,
|
|
3942
|
+
PriceRangeFilter,
|
|
3943
|
+
REVIEW_OPTIONS,
|
|
2567
3944
|
RadioButton,
|
|
2568
3945
|
Rating,
|
|
3946
|
+
RegionsFilter,
|
|
2569
3947
|
ReviewCard,
|
|
3948
|
+
ReviewsFilter,
|
|
2570
3949
|
SectionHeader,
|
|
3950
|
+
SelectedFiltersRow,
|
|
2571
3951
|
StarIcon4 as StarIcon,
|
|
3952
|
+
TransportFilter,
|
|
3953
|
+
WellnessFilter,
|
|
2572
3954
|
WhenContent,
|
|
2573
3955
|
calculateDiscount,
|
|
2574
3956
|
formatDate,
|
|
2575
3957
|
formatDateRange,
|
|
2576
3958
|
formatPrice,
|
|
3959
|
+
translations,
|
|
2577
3960
|
useDebounce,
|
|
2578
3961
|
useResponsive,
|
|
2579
3962
|
useTranslation,
|