@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/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 value = { locale, currency, isDesktop };
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 = { ...defaultLabels, ...labelsProp };
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 } = useTranslation();
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 = useMemo(() => {
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("search:label.flexible", {}, "Flexible");
2319
+ return month ? `${month.label} ${month.year}` : t("label.flexible", "Flexible");
1784
2320
  }
1785
2321
  if (selectedMonths.length > 1) {
1786
- return t("search:date_selector.months_selected", { count: selectedMonths.length }, `${selectedMonths.length} months`);
2322
+ return `${selectedMonths.length} months`;
1787
2323
  }
1788
- return t("search:label.flexible", {}, "Flexible");
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 labels = { ...defaultLabels2, ...labelsProp };
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 = { ...defaultLabels3, ...labelsProp };
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 labels = { ...defaultLabels4, ...labelsProp };
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
- 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: [
2318
- /* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__benefit-icon", children: getBenefitIcon(benefit.id) }),
2319
- /* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__benefit-text", children: benefit.label })
2320
- ] }, index)) }),
2321
- /* @__PURE__ */ jsxs23("div", { className: "hc-hotel-card__pricing-section", children: [
2322
- isAvailable && /* @__PURE__ */ jsx24("div", { className: "hc-hotel-card__price-label", children: labels.priceFrom }),
2323
- !isAvailable && /* @__PURE__ */ jsx24("div", { className: "hc-hotel-card__not-available", children: labels.notAvailable }),
2324
- isAvailable && /* @__PURE__ */ jsxs23("div", { className: "hc-hotel-card__price-container", children: [
2325
- /* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__current-price", children: `${currency} ${price.current}` }),
2326
- price.original && price.original > price.current && /* @__PURE__ */ jsx24("span", { className: "hc-hotel-card__original-price", children: `${currency} ${price.original}` }),
2327
- price.discount && price.discount > 0 && /* @__PURE__ */ jsxs23("span", { className: "hc-hotel-card__discount-badge", children: [
2328
- "-",
2329
- price.discount,
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
- labels: {
2380
- ratingExcellent: labels.ratingExcellent,
2381
- ratingVeryGood: labels.ratingVeryGood,
2382
- ratingGood: labels.ratingGood,
2383
- ratingFair: labels.ratingFair,
2384
- rating: labels.rating,
2385
- priceFrom: labels.priceFrom,
2386
- notAvailable: labels.notAvailable,
2387
- swissLodge: labels.swissLodge
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 jsx26 } from "react/jsx-runtime";
2396
- var HeartIcon3 = ({ filled = false, className = "", size = 24 }) => /* @__PURE__ */ jsx26(
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__ */ jsx26("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" })
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 jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
2415
- var StarIcon4 = ({ filled = true, className = "", size = 9 }) => /* @__PURE__ */ jsxs25(
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__ */ jsx27("g", { clipPath: "url(#clip0_star_icon)", children: /* @__PURE__ */ jsx27(
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__ */ jsx27("defs", { children: /* @__PURE__ */ jsx27("clipPath", { id: "clip0_star_icon", children: /* @__PURE__ */ jsx27("rect", { width: "8", height: "8", fill: "white", transform: "translate(0.800049 0.199951)" }) }) })
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 jsx28 } from "react/jsx-runtime";
2440
- var ChevronLeftIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx28(
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__ */ jsx28("polyline", { points: "15 18 9 12 15 6" })
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 jsx29 } from "react/jsx-runtime";
2460
- var ChevronRightIcon2 = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx29(
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__ */ jsx29("polyline", { points: "9 18 15 12 9 6" })
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 jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
2480
- var PinIcon2 = ({ className = "", size = 16 }) => /* @__PURE__ */ jsxs26(
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__ */ jsx30(
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__ */ jsx30(
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,