@travories/frontend-sdk 0.1.0

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.
package/dist/index.mjs ADDED
@@ -0,0 +1,2373 @@
1
+ import { createContext, useState, useRef, useEffect, useContext, useMemo } from 'react';
2
+ import { Icon } from '@iconify/react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+
5
+ // src/api/http.ts
6
+ var TravoriesApiError = class extends Error {
7
+ constructor(message, status, url, body) {
8
+ super(message);
9
+ this.name = "TravoriesApiError";
10
+ this.status = status;
11
+ this.url = url;
12
+ this.body = body;
13
+ }
14
+ };
15
+ var HttpClient = class {
16
+ constructor(config) {
17
+ if (!config.baseUrl) {
18
+ throw new Error("[TravoriesClient] baseUrl is required");
19
+ }
20
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
21
+ this.apiKey = config.apiKey;
22
+ this.authToken = config.authToken;
23
+ this.defaultHeaders = config.defaultHeaders ?? {};
24
+ this.fetchImpl = config.fetchImpl ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0);
25
+ if (!this.fetchImpl) {
26
+ throw new Error(
27
+ "[TravoriesClient] no `fetch` available. Pass `fetchImpl` (e.g. node-fetch) in the config."
28
+ );
29
+ }
30
+ }
31
+ async resolveAuthToken() {
32
+ if (!this.authToken) return void 0;
33
+ if (typeof this.authToken === "function") {
34
+ const v = this.authToken();
35
+ return v instanceof Promise ? await v : v;
36
+ }
37
+ return this.authToken;
38
+ }
39
+ async request(path, options = {}) {
40
+ const url = path.startsWith("http") ? path : `${this.baseUrl}/${path.replace(/^\//, "")}`;
41
+ const token = await this.resolveAuthToken();
42
+ const headers = {
43
+ "Content-Type": "application/json",
44
+ Accept: "application/json",
45
+ ...this.defaultHeaders,
46
+ ...options.headers ?? {},
47
+ ...this.apiKey ? { "x-api-key": this.apiKey } : {},
48
+ ...token ? { Authorization: `Bearer ${token}` } : {}
49
+ };
50
+ const init = {
51
+ method: options.method ?? "GET",
52
+ headers,
53
+ signal: options.signal
54
+ };
55
+ if (options.body !== void 0) {
56
+ init.body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
57
+ }
58
+ try {
59
+ const res = await this.fetchImpl(url, init);
60
+ if (!res.ok) {
61
+ const text = await res.text().catch(() => "");
62
+ if (options.silent) {
63
+ console.error(`[TravoriesClient] ${res.status} ${url}`);
64
+ return null;
65
+ }
66
+ throw new TravoriesApiError(
67
+ `Travories API error ${res.status} for ${url}`,
68
+ res.status,
69
+ url,
70
+ text
71
+ );
72
+ }
73
+ if (res.status === 204) return null;
74
+ return await res.json();
75
+ } catch (err) {
76
+ if (options.silent) {
77
+ console.error(`[TravoriesClient] fetch failed for ${url}:`, err);
78
+ return null;
79
+ }
80
+ throw err;
81
+ }
82
+ }
83
+ };
84
+
85
+ // src/api/packages.ts
86
+ var normalizeImage = (img) => ({
87
+ id: img?.id ?? "",
88
+ key: img?.key ?? "",
89
+ type: img?.type ?? "image",
90
+ alt: img?.alt ?? "",
91
+ preview: img?.preview ?? null,
92
+ url: {
93
+ original: img?.url?.original ?? null,
94
+ hero: img?.url?.hero ?? null,
95
+ hero_fit: img?.url?.hero_fit ?? null,
96
+ section: img?.url?.section ?? null,
97
+ portrait: img?.url?.portrait ?? null,
98
+ general: img?.url?.general ?? null,
99
+ jpeg: img?.url?.jpeg ?? null
100
+ }
101
+ });
102
+ var normalizeHomeCard = (raw) => ({
103
+ id: raw?.id ?? "",
104
+ title: raw?.title ?? "",
105
+ slug: raw?.slug ?? "",
106
+ agencySlug: raw?.agencySlug ?? "",
107
+ totalDays: Number(raw?.totalDays ?? 0),
108
+ minPrice: Number(raw?.minPrice ?? 0),
109
+ maxPrice: Number(raw?.maxPrice ?? 0),
110
+ rating: Number(raw?.rating ?? 0),
111
+ packageCategory: raw?.packageCategory ?? "",
112
+ thumbnail: normalizeImage(raw?.thumbnail)
113
+ });
114
+ var normalizePackage = (raw) => ({
115
+ id: raw.id,
116
+ title: raw.title,
117
+ packageSlug: raw.packageSlug,
118
+ slug: raw.slug,
119
+ packageType: raw.packageType,
120
+ description: raw.description,
121
+ difficulty: raw.difficulty,
122
+ packageFlexibility: raw.packageFlexibility,
123
+ packageCategory: raw.packageCategory,
124
+ totalDays: raw.totalDays,
125
+ media: (raw.media ?? []).map(normalizeImage),
126
+ thumbnail: raw.thumbnail ? normalizeImage(raw.thumbnail) : null,
127
+ days: raw.days ?? [],
128
+ prices: raw.prices ?? [],
129
+ discounts: raw.discounts ?? [],
130
+ thingsIncluded: raw.thingsIncluded ?? [],
131
+ thingsExcluded: raw.thingsExcluded ?? [],
132
+ thingsToPack: raw.thingsToPack ?? [],
133
+ rating: raw.rating ?? 0,
134
+ maxAllowedPeople: raw.maxAllowedPeople ?? 10,
135
+ minAllowedPeople: raw.minAllowedPeople ?? 1
136
+ });
137
+ var PackagesResource = class {
138
+ constructor(http) {
139
+ this.http = http;
140
+ }
141
+ /** Fetch a single package by its public slug. Returns null on 404 / network error in silent mode. */
142
+ async getBySlug(slug, options) {
143
+ if (!slug) throw new Error("[TravoriesClient] getBySlug requires a slug");
144
+ const raw = await this.http.request(`/agency-package/by-slug/${slug}`, {
145
+ silent: true,
146
+ ...options
147
+ });
148
+ if (!raw) return null;
149
+ return normalizePackage(raw);
150
+ }
151
+ /** Fetch host (agency) information for the package. */
152
+ async getHost(slug, options) {
153
+ if (!slug) throw new Error("[TravoriesClient] getHost requires a slug");
154
+ return this.http.request(`/agency-info/by-package-slug/${slug}`, {
155
+ silent: true,
156
+ ...options
157
+ });
158
+ }
159
+ /** Fetch major attractions tied to the package. */
160
+ async getMajorAttractions(slug, options) {
161
+ if (!slug) throw new Error("[TravoriesClient] getMajorAttractions requires a slug");
162
+ return this.http.request(`/major-attractions/package/${slug}`, {
163
+ silent: true,
164
+ ...options
165
+ });
166
+ }
167
+ /**
168
+ * Fetch the four home/landing sections in one request:
169
+ * popular, topRated, trending, moreToExplore.
170
+ * Each item is a compact card (id, title, slug, thumbnail, price range, rating).
171
+ */
172
+ async getHomeSections(options) {
173
+ const raw = await this.http.request(`/agency-package/home/sections`, {
174
+ silent: true,
175
+ ...options
176
+ });
177
+ if (!raw) return null;
178
+ return {
179
+ popular: (raw.popular ?? []).map(normalizeHomeCard),
180
+ topRated: (raw.topRated ?? []).map(normalizeHomeCard),
181
+ trending: (raw.trending ?? []).map(normalizeHomeCard),
182
+ moreToExplore: (raw.moreToExplore ?? []).map(normalizeHomeCard)
183
+ };
184
+ }
185
+ /**
186
+ * Fetch per-day GeoJSON routes for the package. Used by the map on the
187
+ * itinerary section to draw actual road/trail paths between stops.
188
+ */
189
+ async getRoutes(slug, options) {
190
+ if (!slug) throw new Error("[TravoriesClient] getRoutes requires a slug");
191
+ return this.http.request(`/agency-package/routes/${slug}`, {
192
+ silent: true,
193
+ ...options
194
+ });
195
+ }
196
+ /**
197
+ * Convenience: fetch the package + host + attractions + per-day routes in
198
+ * parallel. This is the payload `<PackageDetailView />` consumes.
199
+ */
200
+ async getBundle(slug, options) {
201
+ const [pkg, hostRes, attractionsRes, routesRes] = await Promise.all([
202
+ this.getBySlug(slug, options),
203
+ this.getHost(slug, options),
204
+ this.getMajorAttractions(slug, options),
205
+ this.getRoutes(slug, options)
206
+ ]);
207
+ if (!pkg) return null;
208
+ return {
209
+ pkg,
210
+ host: hostRes?.host ?? null,
211
+ attractions: attractionsRes?.data ?? [],
212
+ routes: routesRes?.days ?? []
213
+ };
214
+ }
215
+ };
216
+
217
+ // src/client/TravoriesClient.ts
218
+ var TravoriesClient = class {
219
+ constructor(config) {
220
+ /** Shortcut for `client.packages.getBySlug(slug)`. */
221
+ this.getPackageBySlug = (slug) => this.packages.getBySlug(slug);
222
+ /** Shortcut for `client.packages.getBundle(slug)` — package + host + attractions in one call. */
223
+ this.getPackageBundle = (slug) => this.packages.getBundle(slug);
224
+ this.http = new HttpClient(config);
225
+ this.packages = new PackagesResource(this.http);
226
+ }
227
+ };
228
+ function createTravoriesClient(config) {
229
+ return new TravoriesClient(config);
230
+ }
231
+ function usePackageBySlug(client, slug) {
232
+ const [data, setData] = useState(null);
233
+ const [loading, setLoading] = useState(Boolean(slug));
234
+ const [error, setError] = useState(null);
235
+ const reqId = useRef(0);
236
+ const run = () => {
237
+ if (!slug) {
238
+ setData(null);
239
+ setLoading(false);
240
+ setError(null);
241
+ return;
242
+ }
243
+ const myReq = ++reqId.current;
244
+ setLoading(true);
245
+ setError(null);
246
+ client.packages.getBySlug(slug).then((res) => {
247
+ if (myReq !== reqId.current) return;
248
+ setData(res);
249
+ }).catch((err) => {
250
+ if (myReq !== reqId.current) return;
251
+ setError(err instanceof Error ? err : new Error(String(err)));
252
+ }).finally(() => {
253
+ if (myReq !== reqId.current) return;
254
+ setLoading(false);
255
+ });
256
+ };
257
+ useEffect(() => {
258
+ run();
259
+ return () => {
260
+ reqId.current++;
261
+ };
262
+ }, [client, slug]);
263
+ return { data, loading, error, refetch: run };
264
+ }
265
+ function usePackageBundle(client, slug) {
266
+ const [data, setData] = useState(null);
267
+ const [loading, setLoading] = useState(Boolean(slug));
268
+ const [error, setError] = useState(null);
269
+ const reqId = useRef(0);
270
+ const run = () => {
271
+ if (!slug) {
272
+ setData(null);
273
+ setLoading(false);
274
+ setError(null);
275
+ return;
276
+ }
277
+ const myReq = ++reqId.current;
278
+ setLoading(true);
279
+ setError(null);
280
+ client.packages.getBundle(slug).then((res) => {
281
+ if (myReq !== reqId.current) return;
282
+ setData(res);
283
+ }).catch((err) => {
284
+ if (myReq !== reqId.current) return;
285
+ setError(err instanceof Error ? err : new Error(String(err)));
286
+ }).finally(() => {
287
+ if (myReq !== reqId.current) return;
288
+ setLoading(false);
289
+ });
290
+ };
291
+ useEffect(() => {
292
+ run();
293
+ return () => {
294
+ reqId.current++;
295
+ };
296
+ }, [client, slug]);
297
+ return { data, loading, error, refetch: run };
298
+ }
299
+ function useHomeSections(client) {
300
+ const [data, setData] = useState(null);
301
+ const [loading, setLoading] = useState(Boolean(client));
302
+ const [error, setError] = useState(null);
303
+ const reqId = useRef(0);
304
+ const run = () => {
305
+ if (!client) {
306
+ setData(null);
307
+ setLoading(false);
308
+ setError(null);
309
+ return;
310
+ }
311
+ const myReq = ++reqId.current;
312
+ setLoading(true);
313
+ setError(null);
314
+ client.packages.getHomeSections().then((res) => {
315
+ if (myReq !== reqId.current) return;
316
+ setData(res);
317
+ }).catch((err) => {
318
+ if (myReq !== reqId.current) return;
319
+ setError(err instanceof Error ? err : new Error(String(err)));
320
+ }).finally(() => {
321
+ if (myReq !== reqId.current) return;
322
+ setLoading(false);
323
+ });
324
+ };
325
+ useEffect(() => {
326
+ run();
327
+ return () => {
328
+ reqId.current++;
329
+ };
330
+ }, [client]);
331
+ return { data, loading, error, refetch: run };
332
+ }
333
+
334
+ // src/utils/format.ts
335
+ function pickImageUrl(img) {
336
+ if (!img?.url) return "";
337
+ return img.url.hero || img.url.general || img.url.hero_fit || img.url.section || img.url.portrait || img.url.original || img.url.jpeg || "";
338
+ }
339
+ function startingPrice(prices) {
340
+ if (!prices || prices.length === 0) return 0;
341
+ return prices.reduce(
342
+ (min, p) => p.pricePerPerson > 0 && p.pricePerPerson < min ? p.pricePerPerson : min,
343
+ prices[0].pricePerPerson
344
+ );
345
+ }
346
+ function formatCurrency(amount, currency = "USD") {
347
+ try {
348
+ return new Intl.NumberFormat("en-US", {
349
+ style: "currency",
350
+ currency,
351
+ maximumFractionDigits: 0
352
+ }).format(amount);
353
+ } catch {
354
+ return `${currency} ${amount}`;
355
+ }
356
+ }
357
+ function formatRating(rating) {
358
+ if (!rating || rating <= 0) return "New";
359
+ return rating.toFixed(1);
360
+ }
361
+ var PackageCard = ({
362
+ pkg,
363
+ currency = "USD",
364
+ onSelect,
365
+ href,
366
+ openInNewTab = false,
367
+ showHeart = true,
368
+ liked,
369
+ onLike
370
+ }) => {
371
+ const img = pickImageUrl(pkg.thumbnail);
372
+ const rating = Math.round(pkg.rating ?? 0);
373
+ const price = pkg.minPrice || pkg.maxPrice || 0;
374
+ const [localLiked, setLocalLiked] = useState(Boolean(liked));
375
+ const isLiked = liked ?? localLiked;
376
+ const toggleLike = (e) => {
377
+ e.preventDefault();
378
+ e.stopPropagation();
379
+ const next = !isLiked;
380
+ if (onLike) onLike(pkg, next);
381
+ else setLocalLiked(next);
382
+ };
383
+ const handleAnchorClick = (e) => {
384
+ if (e.metaKey || e.ctrlKey || e.button === 1) return;
385
+ if (openInNewTab) return;
386
+ if (onSelect) {
387
+ e.preventDefault();
388
+ onSelect(pkg);
389
+ }
390
+ };
391
+ return /* @__PURE__ */ jsxs("div", { className: "relative w-[300px] md:w-[320px] shrink-0 transition-all duration-300 ease-out hover:-translate-y-1 cursor-pointer", children: [
392
+ href ? /* @__PURE__ */ jsx(
393
+ "a",
394
+ {
395
+ href,
396
+ target: openInNewTab ? "_blank" : void 0,
397
+ rel: openInNewTab ? "noopener noreferrer" : void 0,
398
+ onClick: handleAnchorClick,
399
+ className: "absolute inset-0 z-0 rounded-lg",
400
+ "aria-label": openInNewTab ? `${pkg.title} (opens in a new tab)` : pkg.title
401
+ }
402
+ ) : /* @__PURE__ */ jsx(
403
+ "button",
404
+ {
405
+ type: "button",
406
+ onClick: () => onSelect?.(pkg),
407
+ className: "absolute inset-0 z-0 rounded-lg bg-transparent border-0 cursor-pointer p-0",
408
+ "aria-label": pkg.title
409
+ }
410
+ ),
411
+ /* @__PURE__ */ jsxs("div", { className: "relative z-10 pointer-events-none", children: [
412
+ /* @__PURE__ */ jsxs("div", { className: "relative border border-[#E0E4E8] overflow-hidden rounded-xl h-44 md:h-48 bg-[#F0EEF4]", children: [
413
+ img ? /* @__PURE__ */ jsx(
414
+ "img",
415
+ {
416
+ src: img,
417
+ alt: pkg.thumbnail?.alt || pkg.title,
418
+ loading: "lazy",
419
+ className: "absolute inset-0 w-full h-full object-cover"
420
+ }
421
+ ) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-primary-normal/40 text-xs", children: "No image" }),
422
+ /* @__PURE__ */ jsx(
423
+ "div",
424
+ {
425
+ className: "absolute inset-0 rounded-xl",
426
+ style: { background: "rgba(0, 0, 0, 0.18)" }
427
+ }
428
+ ),
429
+ pkg.packageCategory && /* @__PURE__ */ jsx("div", { className: "absolute top-3 left-3 z-10", children: /* @__PURE__ */ jsx(
430
+ "div",
431
+ {
432
+ className: "h-[26px] w-fit min-w-[70px] rounded-full flex items-center justify-center px-3 box-border text-white",
433
+ style: {
434
+ background: "rgba(0, 0, 0, 0.45)",
435
+ backdropFilter: "blur(18px)",
436
+ WebkitBackdropFilter: "blur(18px)"
437
+ },
438
+ children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium tracking-[-0.02em] whitespace-nowrap", children: pkg.packageCategory })
439
+ }
440
+ ) }),
441
+ showHeart && /* @__PURE__ */ jsx(
442
+ "button",
443
+ {
444
+ type: "button",
445
+ onClick: toggleLike,
446
+ "aria-pressed": isLiked,
447
+ "aria-label": isLiked ? "Remove from wishlist" : "Save to wishlist",
448
+ className: "absolute top-3 right-3 z-10 w-9 h-9 rounded-full flex items-center justify-center pointer-events-auto transition-transform hover:scale-110",
449
+ style: {
450
+ background: "rgba(0, 0, 0, 0.45)",
451
+ backdropFilter: "blur(18px)",
452
+ WebkitBackdropFilter: "blur(18px)"
453
+ },
454
+ children: /* @__PURE__ */ jsx(
455
+ Icon,
456
+ {
457
+ icon: isLiked ? "mdi:heart" : "mdi:heart-outline",
458
+ className: `w-5 h-5 ${isLiked ? "text-red-500" : "text-white"}`
459
+ }
460
+ )
461
+ }
462
+ )
463
+ ] }),
464
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 relative w-full", children: [
465
+ /* @__PURE__ */ jsx("h3", { className: "text-primary-normal text-base md:text-lg font-semibold line-clamp-2 mr-2 w-auto sm:w-full leading-snug tracking-[-0.01em]", children: pkg.title || "Unknown Destination" }),
466
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mt-1", children: [
467
+ pkg.totalDays > 0 && /* @__PURE__ */ jsxs("p", { className: "text-secondary-normal-hover text-sm md:text-base font-light truncate", children: [
468
+ pkg.totalDays,
469
+ " ",
470
+ pkg.totalDays === 1 ? "Day" : "Days"
471
+ ] }),
472
+ /* @__PURE__ */ jsx("div", { className: "w-1 h-1 rounded-full bg-gray-20" }),
473
+ rating > 0 ? /* @__PURE__ */ jsx("div", { className: "flex gap-x-0.5 flex-shrink-0", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(
474
+ Icon,
475
+ {
476
+ icon: "material-symbols:star",
477
+ className: `text-sm md:text-base ${i < rating ? "text-primary-normal" : "text-gray-300"}`
478
+ },
479
+ i
480
+ )) }) : /* @__PURE__ */ jsx("span", { className: "text-xs md:text-sm text-primary-normal font-medium", children: "N/A" })
481
+ ] }),
482
+ /* @__PURE__ */ jsxs("p", { className: "text-secondary text-sm sm:text-base font-light truncate mt-1", children: [
483
+ "Starting from ",
484
+ formatCurrency(price, currency)
485
+ ] })
486
+ ] })
487
+ ] })
488
+ ] });
489
+ };
490
+ var PackageCard_default = PackageCard;
491
+ var PackagesCarousel = ({
492
+ title,
493
+ subtitle,
494
+ packages,
495
+ currency = "USD",
496
+ onSelect,
497
+ hrefFor,
498
+ openInNewTab,
499
+ hideWhenEmpty = true
500
+ }) => {
501
+ const scrollRef = useRef(null);
502
+ if (hideWhenEmpty && (!packages || packages.length === 0)) return null;
503
+ const scrollBy = (dir) => {
504
+ const node = scrollRef.current;
505
+ if (!node) return;
506
+ node.scrollBy({ left: dir * 320 * 2, behavior: "smooth" });
507
+ };
508
+ return /* @__PURE__ */ jsxs("section", { className: "w-full py-6 md:py-8", children: [
509
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between gap-4 mb-4 md:mb-6 px-1", children: [
510
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
511
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal text-xl md:text-2xl font-semibold tracking-[-0.04em]", children: title }),
512
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-secondary-normal-hover text-sm md:text-base mt-1", children: subtitle })
513
+ ] }),
514
+ /* @__PURE__ */ jsxs("div", { className: "hidden sm:flex items-center gap-2", children: [
515
+ /* @__PURE__ */ jsx(
516
+ "button",
517
+ {
518
+ type: "button",
519
+ onClick: () => scrollBy(-1),
520
+ "aria-label": "Scroll left",
521
+ className: "w-10 h-10 rounded-full bg-primary-background hover:bg-primary-light-hover flex items-center justify-center transition-colors",
522
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:arrow-left", className: "w-4 h-4 text-primary-normal" })
523
+ }
524
+ ),
525
+ /* @__PURE__ */ jsx(
526
+ "button",
527
+ {
528
+ type: "button",
529
+ onClick: () => scrollBy(1),
530
+ "aria-label": "Scroll right",
531
+ className: "w-10 h-10 rounded-full bg-primary-background hover:bg-primary-light-hover flex items-center justify-center transition-colors",
532
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:arrow-right", className: "w-4 h-4 text-primary-normal" })
533
+ }
534
+ )
535
+ ] })
536
+ ] }),
537
+ /* @__PURE__ */ jsx(
538
+ "div",
539
+ {
540
+ ref: scrollRef,
541
+ className: "flex gap-4 overflow-x-auto hide-scrollbar scroll-smooth -mx-1 px-1 pb-2 snap-x snap-mandatory",
542
+ children: packages.map((pkg) => /* @__PURE__ */ jsx("div", { className: "snap-start", children: /* @__PURE__ */ jsx(
543
+ PackageCard_default,
544
+ {
545
+ pkg,
546
+ currency,
547
+ onSelect,
548
+ href: hrefFor?.(pkg),
549
+ openInNewTab
550
+ }
551
+ ) }, pkg.id))
552
+ }
553
+ )
554
+ ] });
555
+ };
556
+ var PackagesCarousel_default = PackagesCarousel;
557
+ var DEFAULT_TITLES = {
558
+ popular: "Popular Nepal Trekking Packages",
559
+ trending: "Trending Right Now",
560
+ topRated: "Top Rated Packages",
561
+ moreToExplore: "More to Explore"
562
+ };
563
+ var DEFAULT_ORDER = [
564
+ "popular",
565
+ "trending",
566
+ "topRated",
567
+ "moreToExplore"
568
+ ];
569
+ function HomeSections({
570
+ client,
571
+ initialSections,
572
+ currency = "USD",
573
+ onSelect,
574
+ hrefFor,
575
+ openInNewTab,
576
+ titles,
577
+ order,
578
+ className,
579
+ renderLoading,
580
+ renderError
581
+ }) {
582
+ const effectiveOrder = order ?? DEFAULT_ORDER;
583
+ if (!initialSections && !client) {
584
+ throw new Error(
585
+ "[HomeSections] Provide either `initialSections` or `client`."
586
+ );
587
+ }
588
+ const remote = useHomeSections(initialSections ? null : client ?? null);
589
+ const sections = initialSections ?? remote.data;
590
+ const loading = !initialSections && Boolean(client) && remote.loading;
591
+ const error = !initialSections && Boolean(client) ? remote.error : null;
592
+ const mergedTitles = { ...DEFAULT_TITLES, ...titles ?? {} };
593
+ if (loading) {
594
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-[1440px] px-6 md:px-12 py-8", children: [
595
+ renderLoading ? renderLoading() : /* @__PURE__ */ jsx(SkeletonCarousel, {}),
596
+ renderLoading ? null : /* @__PURE__ */ jsx(SkeletonCarousel, {})
597
+ ] }) });
598
+ }
599
+ if (error) {
600
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-[1440px] px-6 md:px-12 py-16 text-center text-red-600 text-sm", children: renderError ? renderError(error) : `Failed to load: ${error.message}` }) });
601
+ }
602
+ if (!sections) {
603
+ return null;
604
+ }
605
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-[1440px] px-6 md:px-12 py-4 md:py-6", children: effectiveOrder.map((key) => /* @__PURE__ */ jsx(
606
+ PackagesCarousel_default,
607
+ {
608
+ title: mergedTitles[key],
609
+ packages: sections[key] ?? [],
610
+ currency,
611
+ onSelect,
612
+ hrefFor,
613
+ openInNewTab
614
+ },
615
+ key
616
+ )) }) });
617
+ }
618
+ function SkeletonCarousel() {
619
+ return /* @__PURE__ */ jsxs("div", { className: "py-6 md:py-8", children: [
620
+ /* @__PURE__ */ jsx("div", { className: "h-7 w-72 bg-gray-200 rounded mb-4 animate-pulse" }),
621
+ /* @__PURE__ */ jsx("div", { className: "flex gap-4 overflow-hidden", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsx(
622
+ "div",
623
+ {
624
+ className: "w-[300px] shrink-0 rounded-2xl bg-gray-100 animate-pulse",
625
+ style: { height: 360 }
626
+ },
627
+ i
628
+ )) })
629
+ ] });
630
+ }
631
+ var HomeSectionsContext = createContext(null);
632
+ function HomeSectionsProvider({
633
+ client,
634
+ initialSections,
635
+ children
636
+ }) {
637
+ if (!initialSections && !client) {
638
+ throw new Error(
639
+ "[HomeSectionsProvider] Provide either `initialSections` or `client`."
640
+ );
641
+ }
642
+ const remote = useHomeSections(initialSections ? null : client ?? null);
643
+ const value = {
644
+ data: initialSections ?? remote.data,
645
+ loading: !initialSections && remote.loading,
646
+ error: !initialSections ? remote.error : null,
647
+ refetch: remote.refetch
648
+ };
649
+ return /* @__PURE__ */ jsx(HomeSectionsContext.Provider, { value, children });
650
+ }
651
+ function useHomeSectionsContext() {
652
+ const ctx = useContext(HomeSectionsContext);
653
+ if (!ctx) {
654
+ throw new Error(
655
+ "useHomeSectionsContext must be used inside <HomeSectionsProvider>."
656
+ );
657
+ }
658
+ return ctx;
659
+ }
660
+ var DEFAULT_TITLES2 = {
661
+ popular: "Popular Nepal Trekking Packages",
662
+ trending: "Trending Right Now",
663
+ topRated: "Top Rated Packages",
664
+ moreToExplore: "More to Explore"
665
+ };
666
+ var PackagesSection = ({
667
+ section,
668
+ title,
669
+ subtitle,
670
+ currency,
671
+ onSelect,
672
+ hrefFor,
673
+ openInNewTab,
674
+ hideWhenLoading = false,
675
+ hideWhenEmpty = true
676
+ }) => {
677
+ const { data, loading, error } = useHomeSectionsContext();
678
+ const packages = data?.[section] ?? [];
679
+ if (loading) {
680
+ if (hideWhenLoading) return null;
681
+ return /* @__PURE__ */ jsx("div", { className: "tvr-package-detail", children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-[1440px] px-6 md:px-12", children: /* @__PURE__ */ jsx(SkeletonCarousel2, { title: title ?? DEFAULT_TITLES2[section] }) }) });
682
+ }
683
+ if (error) {
684
+ console.error(`[PackagesSection:${section}]`, error);
685
+ return null;
686
+ }
687
+ if (hideWhenEmpty && packages.length === 0) return null;
688
+ return /* @__PURE__ */ jsx("div", { className: "tvr-package-detail", children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-[1440px] px-6 md:px-12", children: /* @__PURE__ */ jsx(
689
+ PackagesCarousel_default,
690
+ {
691
+ title: title ?? DEFAULT_TITLES2[section],
692
+ subtitle,
693
+ packages,
694
+ currency,
695
+ onSelect,
696
+ hrefFor,
697
+ openInNewTab,
698
+ hideWhenEmpty
699
+ }
700
+ ) }) });
701
+ };
702
+ function SkeletonCarousel2({ title }) {
703
+ return /* @__PURE__ */ jsxs("div", { className: "py-6 md:py-8", children: [
704
+ /* @__PURE__ */ jsx("div", { className: "text-primary-normal text-xl md:text-2xl font-semibold tracking-[-0.04em] mb-4", children: title }),
705
+ /* @__PURE__ */ jsx("div", { className: "flex gap-4 overflow-hidden", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsx(
706
+ "div",
707
+ {
708
+ className: "w-[300px] md:w-[320px] shrink-0 rounded-xl bg-gray-100 animate-pulse",
709
+ style: { height: 280 }
710
+ },
711
+ i
712
+ )) })
713
+ ] });
714
+ }
715
+ var PackagesSection_default = PackagesSection;
716
+ var initialOptions = [
717
+ { id: "Adult", name: "Adult", count: 1, ageRange: { min: 18, max: 64 }, countInTotal: true },
718
+ { id: "Senior Citizen", name: "Senior Citizen", count: 0, ageRange: { min: 65, max: 100 }, countInTotal: true },
719
+ { id: "Children", name: "Children", count: 0, ageRange: { min: 4, max: 17 }, countInTotal: true },
720
+ { id: "Infant", name: "Infant", count: 0, ageRange: { min: 0, max: 3 }, countInTotal: false }
721
+ ];
722
+ var getPluralizedName = (name, count) => {
723
+ const map = {
724
+ Adult: ["Adult", "Adults"],
725
+ "Senior Citizen": ["Senior Citizen", "Senior Citizens"],
726
+ Children: ["Child", "Children"],
727
+ Infant: ["Infant", "Infants"]
728
+ };
729
+ const [s, p] = map[name] || [name, name];
730
+ return count <= 1 ? s : p;
731
+ };
732
+ var BookingCardLite = ({
733
+ DescriptionData,
734
+ currency = "USD",
735
+ onReserve
736
+ }) => {
737
+ const prices = DescriptionData.Price ?? [];
738
+ const discounts = DescriptionData.Discounts ?? [];
739
+ const totalDays = DescriptionData.TotalDays || 1;
740
+ const [options, setOptions] = useState(initialOptions);
741
+ const [arrival, setArrival] = useState("");
742
+ const [isOpen, setIsOpen] = useState(false);
743
+ const [isPriceDialogOpen, setIsPriceDialogOpen] = useState(false);
744
+ const dropdownRef = useRef(null);
745
+ const departure = useMemo(() => {
746
+ if (!arrival) return "";
747
+ const d = new Date(arrival);
748
+ if (isNaN(d.getTime())) return "";
749
+ d.setDate(d.getDate() + Math.max(0, totalDays - 1));
750
+ return d.toISOString().split("T")[0];
751
+ }, [arrival, totalDays]);
752
+ useEffect(() => {
753
+ const onDocClick = (e) => {
754
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
755
+ setIsOpen(false);
756
+ }
757
+ };
758
+ document.addEventListener("mousedown", onDocClick);
759
+ return () => document.removeEventListener("mousedown", onDocClick);
760
+ }, []);
761
+ const allPeopleCount = useMemo(
762
+ () => options.filter((o) => o.countInTotal).reduce((s, o) => s + o.count, 0),
763
+ [options]
764
+ );
765
+ const totalPeople = useMemo(() => options.reduce((s, o) => s + o.count, 0), [options]);
766
+ const currentPriceGroup = useMemo(() => {
767
+ if (prices.length === 0) return null;
768
+ const sorted = [...prices].sort((a, b) => a.groupSizeMin - b.groupSizeMin);
769
+ if (allPeopleCount === 0) return sorted[0];
770
+ return sorted.find(
771
+ (p) => allPeopleCount >= p.groupSizeMin && allPeopleCount <= p.groupSizeMax
772
+ ) ?? sorted[sorted.length - 1];
773
+ }, [prices, allPeopleCount]);
774
+ const minPriceGroup = useMemo(() => {
775
+ if (prices.length === 0) return null;
776
+ return [...prices].sort((a, b) => a.pricePerPerson - b.pricePerPerson)[0];
777
+ }, [prices]);
778
+ const currentPrice = currentPriceGroup?.pricePerPerson ?? 0;
779
+ const maxPrice = useMemo(
780
+ () => prices.reduce((m, p) => Math.max(m, p.pricePerPerson), 0),
781
+ [prices]
782
+ );
783
+ const minPrice = minPriceGroup?.pricePerPerson ?? 0;
784
+ const categoryPrices = useMemo(() => {
785
+ const result = {};
786
+ for (const opt of options) {
787
+ if (!opt.ageRange) {
788
+ result[opt.id] = currentPrice;
789
+ continue;
790
+ }
791
+ const matched = discounts.find(
792
+ (d) => opt.ageRange.min >= d.ageMin && opt.ageRange.min <= d.ageMax || opt.ageRange.max >= d.ageMin && opt.ageRange.max <= d.ageMax
793
+ );
794
+ const pct = matched?.discountPercentage ?? 0;
795
+ result[opt.id] = Math.max(0, currentPrice * (1 - pct / 100));
796
+ }
797
+ return result;
798
+ }, [options, currentPrice, discounts]);
799
+ const costBreakdown = useMemo(
800
+ () => options.filter((o) => o.count > 0).map((o) => {
801
+ const discountedPrice = categoryPrices[o.id] ?? currentPrice;
802
+ const discountPercentage = currentPrice > 0 ? (currentPrice - discountedPrice) / currentPrice * 100 : 0;
803
+ return {
804
+ category: o.name,
805
+ count: o.count,
806
+ discountedPrice,
807
+ discountPercentage
808
+ };
809
+ }),
810
+ [options, categoryPrices, currentPrice]
811
+ );
812
+ const totalCost = useMemo(
813
+ () => costBreakdown.reduce((s, x) => s + x.discountedPrice * x.count, 0),
814
+ [costBreakdown]
815
+ );
816
+ const updateTraveler = (id, inc) => setOptions(
817
+ (prev) => prev.map(
818
+ (o) => o.id === id ? { ...o, count: Math.max(0, o.count + (inc ? 1 : -1)) } : o
819
+ )
820
+ );
821
+ const handleReserve = () => {
822
+ if (!onReserve) return;
823
+ if (allPeopleCount === 0) return;
824
+ onReserve({
825
+ arrival,
826
+ departure,
827
+ travelers: options.filter((o) => o.count > 0),
828
+ totalCost,
829
+ pricePerPerson: currentPrice
830
+ });
831
+ };
832
+ return /* @__PURE__ */ jsxs("div", { className: "w-full sm:w-full lg:w-[520px] h-fit border rounded-xl shadow-md px-4 sm:px-6 bg-white flex flex-col gap-6 py-8 sm:py-10", children: [
833
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
834
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 md:gap-3", children: [
835
+ /* @__PURE__ */ jsx("div", { className: "text-lg md:text-xl lg:text-2xl font-medium text-primary-normal flex flex-col gap-2 pb-2 border-b border-[#E0E4E8]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center lg:justify-between justify-center gap-1", children: [
836
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
837
+ /* @__PURE__ */ jsx("p", { className: "text-sm lg:text-base font-medium text-secondary-normal-hover tracking-[-0.02em] mr-2", children: "Price For Single Adult" }),
838
+ currentPriceGroup?.isNegotiable && /* @__PURE__ */ jsx("span", { className: "text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full", children: "Negotiable" }),
839
+ /* @__PURE__ */ jsx(
840
+ "button",
841
+ {
842
+ type: "button",
843
+ onClick: () => setIsPriceDialogOpen(true),
844
+ className: "ml-2 p-1 h-6 w-6 flex items-center justify-center rounded hover:bg-gray-100 transition-colors",
845
+ "aria-label": "Show pricing details",
846
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:info", className: "w-4 h-4 text-gray-500" })
847
+ }
848
+ )
849
+ ] }),
850
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxs("p", { className: "text-lg md:text-xl font-medium tracking-[-0.04em] text-primary-normal", children: [
851
+ formatCurrency(
852
+ totalCost && totalPeople > 0 ? categoryPrices["Adult"] ?? currentPrice : currentPrice,
853
+ currency
854
+ ),
855
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: "/-" })
856
+ ] }) })
857
+ ] }) }),
858
+ /* @__PURE__ */ jsx("div", { className: "w-full h-[2px] bg-primary-background/10" }),
859
+ /* @__PURE__ */ jsxs("div", { className: "grid lg:grid-cols-2 md:grid-cols-1 sm:grid-cols-1 gap-4 mt-4", children: [
860
+ /* @__PURE__ */ jsxs("div", { children: [
861
+ /* @__PURE__ */ jsx(
862
+ "label",
863
+ {
864
+ htmlFor: "tvr-arrival",
865
+ className: "text-sm md:text-base text-secondary-normal-hover",
866
+ children: "Arrival Date"
867
+ }
868
+ ),
869
+ /* @__PURE__ */ jsx(
870
+ "input",
871
+ {
872
+ id: "tvr-arrival",
873
+ type: "date",
874
+ value: arrival,
875
+ onChange: (e) => setArrival(e.target.value),
876
+ className: "w-full max-h-10 h-10 mt-1 px-4 text-sm md:text-base rounded-xl border text-primary-normal focus:outline-none focus:ring-1 focus:ring-primary-normal-active"
877
+ }
878
+ ),
879
+ departure && /* @__PURE__ */ jsxs("p", { className: "text-xs text-secondary-normal-hover mt-1", children: [
880
+ "Returns: ",
881
+ departure
882
+ ] })
883
+ ] }),
884
+ /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
885
+ /* @__PURE__ */ jsx("label", { className: "text-sm md:text-base text-secondary-normal-hover", children: "Number of people" }),
886
+ /* @__PURE__ */ jsxs(
887
+ "button",
888
+ {
889
+ type: "button",
890
+ onClick: () => setIsOpen((v) => !v),
891
+ className: "w-full max-h-10 h-10 overflow-y-scroll mt-1 flex justify-between px-4 items-center text-sm md:text-base rounded-xl border text-primary-normal focus:outline-none focus:ring-1 focus:ring-primary-normal-active",
892
+ children: [
893
+ options.some((o) => o.count > 0) ? options.filter((o) => o.count > 0).map((o) => `${o.count} ${getPluralizedName(o.name, o.count)}`).join(", ") : "Eg : 2 Adults",
894
+ /* @__PURE__ */ jsx(
895
+ Icon,
896
+ {
897
+ icon: isOpen ? "lucide:chevron-up" : "lucide:chevron-down",
898
+ className: "w-4 h-4"
899
+ }
900
+ )
901
+ ]
902
+ }
903
+ ),
904
+ isOpen && /* @__PURE__ */ jsx("div", { className: "absolute z-10 sm:min-w-[360px] md:min-w-[400px] bg-white border rounded-xl shadow-lg mt-2 left-0 sm:left-auto sm:-ml-[200px]", children: options.map((option) => {
905
+ const price = categoryPrices[option.id] ?? currentPrice;
906
+ const discountPercentage = currentPrice > 0 ? (currentPrice - price) / currentPrice * 100 : 0;
907
+ return /* @__PURE__ */ jsxs(
908
+ "div",
909
+ {
910
+ className: "py-3 border-b last:border-b-0 hover:bg-primary-light/30 transition-colors flex justify-between items-center gap-3 px-4 sm:px-5",
911
+ children: [
912
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
913
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
914
+ /* @__PURE__ */ jsx("p", { className: "text-xs md:text-lg font-medium text-secondary-normal-hover leading-tight", children: getPluralizedName(option.name, option.count || 1) }),
915
+ /* @__PURE__ */ jsx("p", { className: "text-xs md:text-sm text-gray-500 whitespace-nowrap leading-tight mt-0.5", children: option.ageRange && `( Ages ${option.ageRange.min}-${option.ageRange.max} )` })
916
+ ] }),
917
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col items-start whitespace-nowrap", children: Math.round(discountPercentage) === 100 ? /* @__PURE__ */ jsx("span", { className: "text-green-600 text-xs font-medium text-start w-full", children: "(FREE)" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
918
+ maxPrice !== price && /* @__PURE__ */ jsxs("span", { className: "text-xs line-through text-gray-400", children: [
919
+ formatCurrency(maxPrice, currency),
920
+ /* @__PURE__ */ jsx("span", { className: "text-[10px]", children: "pp" })
921
+ ] }),
922
+ /* @__PURE__ */ jsxs("p", { className: "text-sm md:text-base font-semibold text-primary-normal leading-tight", children: [
923
+ formatCurrency(price, currency),
924
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] md:text-xs", children: "pp" })
925
+ ] }),
926
+ Math.round(discountPercentage) > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-green-600", children: [
927
+ "(",
928
+ discountPercentage.toFixed(0),
929
+ "% off)"
930
+ ] })
931
+ ] }) })
932
+ ] }) }),
933
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
934
+ /* @__PURE__ */ jsx(
935
+ "button",
936
+ {
937
+ type: "button",
938
+ onClick: () => updateTraveler(option.id, false),
939
+ className: "w-8 h-8 md:w-9 md:h-9 border rounded-full text-primary-normal flex items-center justify-center hover:bg-primary-light/40 transition-colors",
940
+ "aria-label": `Remove one ${option.name}`,
941
+ children: "-"
942
+ }
943
+ ),
944
+ /* @__PURE__ */ jsx("h1", { className: "text-base text-primary-normal w-5 text-center", children: option.count }),
945
+ /* @__PURE__ */ jsx(
946
+ "button",
947
+ {
948
+ type: "button",
949
+ onClick: () => updateTraveler(option.id, true),
950
+ className: "w-8 h-8 md:w-9 md:h-9 border rounded-full text-primary-normal flex items-center justify-center hover:bg-primary-light/40 transition-colors",
951
+ "aria-label": `Add one ${option.name}`,
952
+ children: "+"
953
+ }
954
+ )
955
+ ] })
956
+ ]
957
+ },
958
+ option.id
959
+ );
960
+ }) })
961
+ ] })
962
+ ] }),
963
+ allPeopleCount > 0 && /* @__PURE__ */ jsxs("div", { className: "p-2 mt-4 mb-2 rounded-lg hidden lg:block text-sm md:text-base text-gray-600 border border-secondary/50", children: [
964
+ costBreakdown.map((item, idx) => /* @__PURE__ */ jsxs("span", { children: [
965
+ item.count,
966
+ " ",
967
+ getPluralizedName(item.category, item.count),
968
+ " \xD7",
969
+ " ",
970
+ formatCurrency(item.discountedPrice, currency),
971
+ item.discountedPrice === 0 && /* @__PURE__ */ jsx("span", { className: "text-green-600 text-xs ml-1", children: "(FREE)" }),
972
+ item.discountPercentage > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-green-600 ml-1", children: [
973
+ item.discountPercentage.toFixed(0),
974
+ "% discount applied"
975
+ ] }),
976
+ idx !== costBreakdown.length - 1 && " + "
977
+ ] }, item.category)),
978
+ /* @__PURE__ */ jsxs("div", { className: "pt-2 flex gap-4 items-center font-semibold text-primary-normal", children: [
979
+ /* @__PURE__ */ jsx("span", { children: "Total :" }),
980
+ /* @__PURE__ */ jsx("span", { className: "text-primary-normal text-xl font-bold", children: formatCurrency(totalCost, currency) })
981
+ ] })
982
+ ] })
983
+ ] }),
984
+ /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
985
+ /* @__PURE__ */ jsx(
986
+ "button",
987
+ {
988
+ type: "button",
989
+ onClick: handleReserve,
990
+ disabled: allPeopleCount === 0 || !onReserve,
991
+ className: "w-full py-2 md:py-3 bg-primary-normal text-white font-semibold rounded-lg hover:bg-primary-normal-hover transition text-sm md:text-base disabled:opacity-60 disabled:cursor-not-allowed",
992
+ children: allPeopleCount === 0 ? "Reserve Now" : /* @__PURE__ */ jsxs(Fragment, { children: [
993
+ "Book Now - ",
994
+ formatCurrency(totalCost, currency)
995
+ ] })
996
+ }
997
+ ),
998
+ /* @__PURE__ */ jsxs("p", { className: "text-center text-xs md:text-sm text-secondary-normal-hover mt-2 md:mt-3 pb-4 tracking-[-0.02em]", children: [
999
+ "*Price Varies According to",
1000
+ /* @__PURE__ */ jsx("span", { className: "text-primary-normal text-sm md:text-sm", children: " age group " }),
1001
+ "and",
1002
+ /* @__PURE__ */ jsxs("span", { className: "text-primary-normal text-sm md:text-sm", children: [
1003
+ " ",
1004
+ "number of people.",
1005
+ " "
1006
+ ] })
1007
+ ] })
1008
+ ] })
1009
+ ] }),
1010
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0 justify-center p-4 border-2 rounded-lg", children: [
1011
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0 font-medium", children: [
1012
+ /* @__PURE__ */ jsx("span", { className: "text-primary-normal text-lg md:text-lg tracking-[-0.02em]", children: formatCurrency(minPrice, currency) }),
1013
+ /* @__PURE__ */ jsx("span", { className: "text-secondary-normal-hover text-sm md:text-sm ml-2", children: "Per Person" })
1014
+ ] }),
1015
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:items-start md:items-center sm:flex-row whitespace-nowrap text-xs md:text-sm", children: [
1016
+ /* @__PURE__ */ jsxs("span", { className: "text-secondary-normal-hover", children: [
1017
+ "Best Price for group of ",
1018
+ minPriceGroup?.groupSizeMin,
1019
+ " -",
1020
+ " ",
1021
+ minPriceGroup?.groupSizeMax,
1022
+ " people"
1023
+ ] }),
1024
+ /* @__PURE__ */ jsx("span", { className: "text-primary-normal sm:ml-2", children: "(Lowest Price)" })
1025
+ ] })
1026
+ ] }),
1027
+ isPriceDialogOpen && /* @__PURE__ */ jsx(
1028
+ "div",
1029
+ {
1030
+ className: "fixed inset-0 z-[1000] bg-black/50 flex items-center justify-center p-4",
1031
+ onClick: () => setIsPriceDialogOpen(false),
1032
+ children: /* @__PURE__ */ jsxs(
1033
+ "div",
1034
+ {
1035
+ className: "bg-white rounded-2xl border border-[#E0E4E8] max-w-md w-full p-6 max-h-[80vh] overflow-y-auto",
1036
+ onClick: (e) => e.stopPropagation(),
1037
+ children: [
1038
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-4", children: [
1039
+ /* @__PURE__ */ jsxs("div", { children: [
1040
+ /* @__PURE__ */ jsx("h3", { className: "text-primary-normal text-lg font-semibold", children: "Pricing Details" }),
1041
+ /* @__PURE__ */ jsx("p", { className: "text-secondary-normal-hover text-sm mt-1", children: "Prices vary based on group size and age. All prices are per person." })
1042
+ ] }),
1043
+ /* @__PURE__ */ jsx(
1044
+ "button",
1045
+ {
1046
+ type: "button",
1047
+ onClick: () => setIsPriceDialogOpen(false),
1048
+ className: "text-gray-500 hover:bg-gray-100 rounded p-1",
1049
+ "aria-label": "Close",
1050
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:x", className: "w-5 h-5" })
1051
+ }
1052
+ )
1053
+ ] }),
1054
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1055
+ /* @__PURE__ */ jsxs("div", { children: [
1056
+ /* @__PURE__ */ jsx("h4", { className: "font-semibold mb-2 text-primary-normal", children: "Group Size Pricing" }),
1057
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: prices.map((p, i) => /* @__PURE__ */ jsxs(
1058
+ "div",
1059
+ {
1060
+ className: "flex justify-between items-center p-2 bg-primary-background/10 rounded border border-primary-border/20",
1061
+ children: [
1062
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-secondary-normal-hover", children: [
1063
+ "Group of ",
1064
+ p.groupSizeMin,
1065
+ " - ",
1066
+ p.groupSizeMax,
1067
+ " people"
1068
+ ] }),
1069
+ /* @__PURE__ */ jsxs("div", { className: "font-medium text-primary-normal text-sm", children: [
1070
+ formatCurrency(p.pricePerPerson, currency),
1071
+ p.isNegotiable && /* @__PURE__ */ jsx("span", { className: "text-xs text-green-600 ml-1", children: "(Negotiable)" })
1072
+ ] })
1073
+ ]
1074
+ },
1075
+ i
1076
+ )) })
1077
+ ] }),
1078
+ discounts.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
1079
+ /* @__PURE__ */ jsx("h4", { className: "font-semibold mb-2 text-primary-normal", children: "Age-Based Discounts" }),
1080
+ /* @__PURE__ */ jsx("div", { className: "space-y-1 text-sm text-secondary-normal-hover", children: discounts.map((d, i) => /* @__PURE__ */ jsxs("div", { children: [
1081
+ "Ages ",
1082
+ d.ageMin,
1083
+ " - ",
1084
+ d.ageMax,
1085
+ ": ",
1086
+ d.discountPercentage,
1087
+ "% discount"
1088
+ ] }, i)) })
1089
+ ] })
1090
+ ] })
1091
+ ]
1092
+ }
1093
+ )
1094
+ }
1095
+ )
1096
+ ] });
1097
+ };
1098
+ var BookingCardLite_default = BookingCardLite;
1099
+ var DAY_COLORS = [
1100
+ "#8b5cf6",
1101
+ // violet
1102
+ "#f59e0b",
1103
+ // amber
1104
+ "#14b8a6",
1105
+ // teal
1106
+ "#6366f1",
1107
+ // indigo
1108
+ "#f97316",
1109
+ // orange
1110
+ "#84cc16",
1111
+ // lime
1112
+ "#ec4899",
1113
+ // pink
1114
+ "#0ea5e9"
1115
+ // sky
1116
+ ];
1117
+ var dayColor = (n) => DAY_COLORS[((n ?? 1) - 1) % DAY_COLORS.length];
1118
+ function PackageMap({
1119
+ locations,
1120
+ dayNumber,
1121
+ routes,
1122
+ className
1123
+ }) {
1124
+ const [Leaflet, setLeaflet] = useState(null);
1125
+ useEffect(() => {
1126
+ let cancelled = false;
1127
+ (async () => {
1128
+ const [rl, leaflet] = await Promise.all([
1129
+ import('react-leaflet'),
1130
+ import('leaflet')
1131
+ ]);
1132
+ await import('leaflet/dist/leaflet.css').catch(
1133
+ () => void 0
1134
+ );
1135
+ if (cancelled) return;
1136
+ const Lns = leaflet.default ?? leaflet;
1137
+ delete Lns.Icon.Default.prototype._getIconUrl;
1138
+ Lns.Icon.Default.mergeOptions({
1139
+ iconRetinaUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png",
1140
+ iconUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png",
1141
+ shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png"
1142
+ });
1143
+ setLeaflet({
1144
+ MapContainer: rl.MapContainer,
1145
+ TileLayer: rl.TileLayer,
1146
+ Marker: rl.Marker,
1147
+ Popup: rl.Popup,
1148
+ Polyline: rl.Polyline,
1149
+ useMap: rl.useMap,
1150
+ L: Lns
1151
+ });
1152
+ })();
1153
+ return () => {
1154
+ cancelled = true;
1155
+ };
1156
+ }, []);
1157
+ const valid = useMemo(
1158
+ () => (locations || []).filter(
1159
+ (l) => l?.coord && Number.isFinite(l.coord[0]) && Number.isFinite(l.coord[1])
1160
+ ),
1161
+ [locations]
1162
+ );
1163
+ if (valid.length === 0) {
1164
+ return /* @__PURE__ */ jsx(
1165
+ "div",
1166
+ {
1167
+ className: `h-full w-full flex items-center justify-center bg-slate-100 text-slate-500 rounded-lg border border-[#E0E4E8] text-sm ${className ?? ""}`,
1168
+ children: "No locations available"
1169
+ }
1170
+ );
1171
+ }
1172
+ if (!Leaflet) {
1173
+ return /* @__PURE__ */ jsx(
1174
+ "div",
1175
+ {
1176
+ className: `h-full w-full flex items-center justify-center bg-slate-100 text-slate-500 rounded-lg border border-[#E0E4E8] text-sm animate-pulse ${className ?? ""}`,
1177
+ children: "Loading map\u2026"
1178
+ }
1179
+ );
1180
+ }
1181
+ const { MapContainer, TileLayer, Marker, Popup, Polyline, useMap, L } = Leaflet;
1182
+ const color = dayColor(dayNumber);
1183
+ const lats = valid.map((l) => l.coord[0]);
1184
+ const lngs = valid.map((l) => l.coord[1]);
1185
+ const center = [
1186
+ (Math.min(...lats) + Math.max(...lats)) / 2,
1187
+ (Math.min(...lngs) + Math.max(...lngs)) / 2
1188
+ ];
1189
+ const hasRealRoutes = (routes?.length ?? 0) > 0;
1190
+ const FitBounds = () => {
1191
+ const map = useMap();
1192
+ useEffect(() => {
1193
+ const points = valid.map((l) => l.coord);
1194
+ if (hasRealRoutes) {
1195
+ for (const line of routes) {
1196
+ for (const p of line) points.push(p);
1197
+ }
1198
+ }
1199
+ if (!points.length) return;
1200
+ const b = L.latLngBounds(points.map((p) => L.latLng(p[0], p[1])));
1201
+ const padding = [60, 60];
1202
+ map.flyToBounds(b, {
1203
+ paddingTopLeft: padding,
1204
+ paddingBottomRight: padding,
1205
+ duration: 1.2,
1206
+ easeLinearity: 0.5
1207
+ });
1208
+ }, [
1209
+ dayNumber,
1210
+ valid.length,
1211
+ valid.map((l) => `${l.coord[0]},${l.coord[1]}`).join("|"),
1212
+ hasRealRoutes,
1213
+ routes?.length
1214
+ ]);
1215
+ return null;
1216
+ };
1217
+ return /* @__PURE__ */ jsx(
1218
+ "div",
1219
+ {
1220
+ className: `h-full w-full overflow-hidden rounded-lg border border-[#E0E4E8] ${className ?? ""}`,
1221
+ style: { minHeight: 500 },
1222
+ children: /* @__PURE__ */ jsxs(
1223
+ MapContainer,
1224
+ {
1225
+ center,
1226
+ zoom: 8,
1227
+ scrollWheelZoom: false,
1228
+ style: { height: "100%", width: "100%" },
1229
+ children: [
1230
+ /* @__PURE__ */ jsx(
1231
+ TileLayer,
1232
+ {
1233
+ attribution: '\xA9 <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
1234
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
1235
+ }
1236
+ ),
1237
+ /* @__PURE__ */ jsx(FitBounds, {}),
1238
+ hasRealRoutes ? routes.map((line, i) => /* @__PURE__ */ jsx(
1239
+ Polyline,
1240
+ {
1241
+ positions: line,
1242
+ pathOptions: { color, weight: 4, opacity: 0.9 }
1243
+ },
1244
+ `route-${dayNumber}-${i}`
1245
+ )) : valid.length > 1 && /* @__PURE__ */ jsx(
1246
+ Polyline,
1247
+ {
1248
+ positions: valid.map((l) => l.coord),
1249
+ pathOptions: {
1250
+ color,
1251
+ weight: 3,
1252
+ opacity: 0.6,
1253
+ dashArray: "6 8"
1254
+ // dashed fallback so it reads as "no real route"
1255
+ }
1256
+ }
1257
+ ),
1258
+ valid.map((loc, i) => /* @__PURE__ */ jsx(Marker, { position: loc.coord, children: /* @__PURE__ */ jsx(Popup, { children: /* @__PURE__ */ jsxs("div", { style: { fontFamily: "inherit" }, children: [
1259
+ /* @__PURE__ */ jsx("strong", { style: { color }, children: loc.displayName }),
1260
+ dayNumber !== void 0 && /* @__PURE__ */ jsxs("div", { style: { fontSize: 11, color: "#64748b", marginTop: 4 }, children: [
1261
+ "Day ",
1262
+ dayNumber
1263
+ ] })
1264
+ ] }) }) }, `${dayNumber}-${i}-${loc.coord[0]}-${loc.coord[1]}`))
1265
+ ]
1266
+ }
1267
+ )
1268
+ }
1269
+ );
1270
+ }
1271
+ var DifficultyProgressBar = ({ level }) => {
1272
+ const normalizedLevel = (level || "").toLowerCase();
1273
+ let width = "30%";
1274
+ let colorClass = "bg-green-500";
1275
+ let label = "Easy";
1276
+ if (normalizedLevel.includes("moderate") || normalizedLevel.includes("medium")) {
1277
+ width = "70%";
1278
+ colorClass = "bg-secondary";
1279
+ label = "Moderate";
1280
+ } else if (normalizedLevel.includes("challenging") || normalizedLevel.includes("challenge")) {
1281
+ width = "100%";
1282
+ colorClass = "bg-orange-500";
1283
+ label = "Challenging";
1284
+ } else if (normalizedLevel.includes("extreme") || normalizedLevel.includes("hard")) {
1285
+ width = "100%";
1286
+ colorClass = "bg-primary-dark";
1287
+ label = "Extreme";
1288
+ } else {
1289
+ width = "30%";
1290
+ colorClass = "bg-green-500";
1291
+ label = level || "Easy";
1292
+ }
1293
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 w-full", children: [
1294
+ /* @__PURE__ */ jsx("div", { className: "w-[80px] h-1.5 bg-gray-200 rounded-full overflow-hidden shrink-0", children: /* @__PURE__ */ jsx(
1295
+ "div",
1296
+ {
1297
+ className: `h-full ${colorClass} transition-all duration-500`,
1298
+ style: { width }
1299
+ }
1300
+ ) }),
1301
+ /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base text-[#47586E] whitespace-nowrap", children: [
1302
+ "Difficulty: ",
1303
+ label
1304
+ ] })
1305
+ ] });
1306
+ };
1307
+ var getStopStyles = (label) => {
1308
+ if (label === "Start") {
1309
+ return {
1310
+ labelClass: "text-emerald-600",
1311
+ dotClass: "bg-emerald-500 border-emerald-500",
1312
+ lineClass: "bg-emerald-300"
1313
+ };
1314
+ }
1315
+ if (label === "End") {
1316
+ return {
1317
+ labelClass: "text-[#3b82f6]",
1318
+ dotClass: "bg-[#3b82f6] border-[#3b82f6]",
1319
+ lineClass: "bg-[#3b82f6] opacity-30"
1320
+ };
1321
+ }
1322
+ return {
1323
+ labelClass: "text-[#8b5cf6]",
1324
+ dotClass: "bg-[#8b5cf6] border-[#8b5cf6]",
1325
+ lineClass: "bg-[#8b5cf6] opacity-30"
1326
+ };
1327
+ };
1328
+ var Itinerary = ({ Description, routes, currency = "USD", onReserveClick }) => {
1329
+ const [selectedDay, setSelectedDay] = useState(1);
1330
+ const [descriptionExpanded, setDescriptionExpanded] = useState(false);
1331
+ const scrollRef = useRef(null);
1332
+ const detailCardRef = useRef(null);
1333
+ const hasUserSelectedDayRef = useRef(false);
1334
+ const routesByDay = useMemo(() => {
1335
+ const map = /* @__PURE__ */ new Map();
1336
+ for (const day of routes ?? []) {
1337
+ const lines = [];
1338
+ for (const r of day.routes ?? []) {
1339
+ let geom = r.geometry;
1340
+ if (typeof geom === "string") {
1341
+ try {
1342
+ geom = JSON.parse(geom);
1343
+ } catch {
1344
+ continue;
1345
+ }
1346
+ }
1347
+ if (!geom?.coordinates || !Array.isArray(geom.coordinates)) continue;
1348
+ const flipped = geom.coordinates.map(
1349
+ (c) => Array.isArray(c) && Number.isFinite(c[0]) && Number.isFinite(c[1]) ? [c[1], c[0]] : null
1350
+ ).filter(Boolean);
1351
+ if (flipped.length >= 2) lines.push(flipped);
1352
+ }
1353
+ if (lines.length) map.set(day.dayNumber, lines);
1354
+ }
1355
+ return map;
1356
+ }, [routes]);
1357
+ const dayItems = useMemo(() => {
1358
+ if (!Description?.Days?.length) return [];
1359
+ return Description.Days.map((day, index) => {
1360
+ const actualDayNumber = day?.DayNumber ?? day?.dayNumber ?? index + 1;
1361
+ const flattenedLocs = [];
1362
+ (day?.locations || []).forEach((item) => {
1363
+ if (item?.locations && Array.isArray(item.locations)) {
1364
+ flattenedLocs.push(...item.locations);
1365
+ } else {
1366
+ flattenedLocs.push(item);
1367
+ }
1368
+ });
1369
+ const locationsData = flattenedLocs.map((loc, idx) => {
1370
+ const lat = Number(loc?.lat ?? loc?.coord?.[0]);
1371
+ const lng = Number(loc?.lng ?? loc?.coord?.[1]);
1372
+ if (isNaN(lat) || isNaN(lng)) return null;
1373
+ return {
1374
+ coord: [lat, lng],
1375
+ displayName: loc?.name || loc?.displayName || `Location ${loc?.Sequence || loc?.sequence || idx + 1}`,
1376
+ sequence: loc?.sequence || loc?.position || idx + 1
1377
+ };
1378
+ }).filter(Boolean);
1379
+ const locationName = locationsData.length > 0 ? locationsData.length > 1 ? `${locationsData[0].displayName} - ${locationsData[locationsData.length - 1].displayName}` : locationsData[0].displayName : "";
1380
+ return {
1381
+ key: `Day ${actualDayNumber}`,
1382
+ data: {
1383
+ title: locationName || `Location ${actualDayNumber}`,
1384
+ locationsData,
1385
+ duration: `${day?.travelDuration || day?.travelDurationHours || "N/A"} hrs`,
1386
+ difficulty: day?.difficulty || "N/A",
1387
+ transportation: day?.transportation?.join(", ") || "N/A",
1388
+ food: Array.isArray(day?.foodService) ? day.foodService.join(", ") : day?.foodService || "N/A",
1389
+ accommodation: day?.accommodation || "N/A",
1390
+ content: day?.description || "No description available",
1391
+ activities: day?.activities || []
1392
+ }
1393
+ };
1394
+ });
1395
+ }, [Description?.Days]);
1396
+ useEffect(() => {
1397
+ if (scrollRef.current) {
1398
+ const activeTab = scrollRef.current.children[selectedDay - 1];
1399
+ if (activeTab) {
1400
+ const containerWidth = scrollRef.current.offsetWidth;
1401
+ const tabWidth = activeTab.offsetWidth;
1402
+ const tabLeft = activeTab.offsetLeft;
1403
+ const scrollLeft = tabLeft - containerWidth / 2 + tabWidth / 2;
1404
+ scrollRef.current.scrollTo({ left: scrollLeft, behavior: "smooth" });
1405
+ }
1406
+ }
1407
+ }, [selectedDay]);
1408
+ useEffect(() => {
1409
+ if (!hasUserSelectedDayRef.current) return;
1410
+ if (!detailCardRef.current) return;
1411
+ const raf = window.requestAnimationFrame(() => {
1412
+ const stickyTabsHeight = 76;
1413
+ const safetyGap = 12;
1414
+ const elementPosition = detailCardRef.current?.getBoundingClientRect().top ?? 0;
1415
+ const offsetPosition = elementPosition + window.scrollY - (stickyTabsHeight + safetyGap);
1416
+ window.scrollTo({ top: offsetPosition, behavior: "smooth" });
1417
+ });
1418
+ return () => window.cancelAnimationFrame(raf);
1419
+ }, [selectedDay]);
1420
+ if (!dayItems.length) {
1421
+ return /* @__PURE__ */ jsx("p", { className: "text-secondary-normal-hover text-base mt-4", children: "No itinerary information available." });
1422
+ }
1423
+ const selectedItem = dayItems[selectedDay - 1] ?? dayItems[0];
1424
+ const lowestPrice = startingPrice(Description.Price ?? []);
1425
+ return /* @__PURE__ */ jsxs("div", { className: "mt-4 h-full w-full text-[#5B4D81]", children: [
1426
+ /* @__PURE__ */ jsx("div", { className: "w-full sticky top-0 z-30 mb-6 bg-white py-2 -mx-4 px-4 sm:-mx-6 sm:px-6 border-b border-[#E0E4E8]/60", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1427
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-2 p-1.5 rounded-full overflow-hidden bg-white", children: [
1428
+ /* @__PURE__ */ jsx(
1429
+ "button",
1430
+ {
1431
+ type: "button",
1432
+ onClick: () => scrollRef.current?.scrollBy({ left: -151, behavior: "smooth" }),
1433
+ className: "flex w-8 h-8 rounded-full bg-primary-background items-center justify-center hover:bg-[#65558F15] transition-all shrink-0",
1434
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:arrow-left", className: "w-4 h-4 text-[#65558F]" })
1435
+ }
1436
+ ),
1437
+ /* @__PURE__ */ jsx(
1438
+ "div",
1439
+ {
1440
+ ref: scrollRef,
1441
+ className: "flex items-center gap-2 overflow-x-auto hide-scrollbar scroll-smooth px-1 flex-1",
1442
+ children: dayItems.map((_, index) => {
1443
+ const dayNum = index + 1;
1444
+ const isActive = selectedDay === dayNum;
1445
+ return /* @__PURE__ */ jsxs(
1446
+ "button",
1447
+ {
1448
+ type: "button",
1449
+ onClick: () => {
1450
+ hasUserSelectedDayRef.current = true;
1451
+ setSelectedDay(dayNum);
1452
+ },
1453
+ className: `cursor-pointer rounded-full px-4 py-2.5 text-sm font-medium tracking-[-0.02em] transition-all shrink-0 ${isActive ? "bg-secondary text-white shadow-sm" : "bg-primary-background text-primary-normal hover:bg-primary-light-hover"}`,
1454
+ children: [
1455
+ "Day ",
1456
+ dayNum
1457
+ ]
1458
+ },
1459
+ index
1460
+ );
1461
+ })
1462
+ }
1463
+ ),
1464
+ /* @__PURE__ */ jsx(
1465
+ "button",
1466
+ {
1467
+ type: "button",
1468
+ onClick: () => scrollRef.current?.scrollBy({ left: 151, behavior: "smooth" }),
1469
+ className: "w-10 h-10 rounded-full bg-[#65558F0D] flex items-center justify-center hover:bg-[#65558F15] transition-all shrink-0",
1470
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:arrow-right", className: "w-4 h-4 text-[#65558F]" })
1471
+ }
1472
+ )
1473
+ ] }),
1474
+ lowestPrice > 0 && /* @__PURE__ */ jsxs("div", { className: "hidden md:flex items-center gap-3 shrink-0 pl-2", children: [
1475
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end leading-tight", children: [
1476
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-secondary-normal-hover whitespace-nowrap", children: "1x Adult Price" }),
1477
+ /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary-normal whitespace-nowrap", children: formatCurrency(lowestPrice, currency) })
1478
+ ] }),
1479
+ /* @__PURE__ */ jsx(
1480
+ "button",
1481
+ {
1482
+ type: "button",
1483
+ onClick: onReserveClick,
1484
+ disabled: !onReserveClick,
1485
+ className: "bg-primary-normal text-white rounded-lg px-4 py-2 font-medium text-sm hover:bg-primary-normal-hover transition-colors whitespace-nowrap disabled:opacity-60 disabled:cursor-not-allowed",
1486
+ children: "Reserve Now"
1487
+ }
1488
+ )
1489
+ ] })
1490
+ ] }) }),
1491
+ /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-5 gap-6 lg:gap-10 w-full h-full", children: [
1492
+ /* @__PURE__ */ jsx("div", { className: "col-span-1 lg:col-span-3 flex flex-col gap-7", children: /* @__PURE__ */ jsxs("div", { ref: detailCardRef, className: "self-stretch rounded-2xl bg-white border border-[#E0E4E8] p-4 sm:p-5 sm:px-7 shadow-sm gap-4 flex flex-col scroll-mt-[130px]", children: [
1493
+ /* @__PURE__ */ jsxs("div", { className: "self-stretch flex items-start flex-col md:flex-row md:justify-between gap-3 md:gap-5", children: [
1494
+ /* @__PURE__ */ jsx("h3", { className: "w-full md:w-[448px] font-medium tracking-[-0.04em] text-lg md:text-xl leading-snug", children: selectedItem.data.title }),
1495
+ /* @__PURE__ */ jsxs("div", { className: "rounded-2xl bg-[#65558F1A] py-1 px-3 text-center text-[10px] md:text-xs text-[#65558F] font-medium shrink-0", children: [
1496
+ "Duration: ",
1497
+ selectedItem.data.duration
1498
+ ] })
1499
+ ] }),
1500
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col md:flex-row items-start md:items-center md:justify-between gap-6", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 flex-1 min-w-0", children: [
1501
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start md:items-center flex-wrap gap-2 text-sm md:text-base text-secondary-normal-hover", children: [
1502
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [
1503
+ /* @__PURE__ */ jsx(Icon, { icon: "solar:bed-outline", className: "w-4 h-4 md:w-5 md:h-5" }),
1504
+ /* @__PURE__ */ jsx("span", { children: selectedItem.data.accommodation || "Yes" })
1505
+ ] }),
1506
+ /* @__PURE__ */ jsx("div", { className: "w-1 h-1 rounded-full bg-[#B2BBC6]" }),
1507
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [
1508
+ /* @__PURE__ */ jsx(Icon, { icon: "solar:bus-outline", className: "w-4 h-4 md:w-5 md:h-5" }),
1509
+ /* @__PURE__ */ jsx("span", { className: "max-w-[100px] md:max-w-none truncate", children: selectedItem.data.transportation || "Car" })
1510
+ ] }),
1511
+ selectedItem.data.food && selectedItem.data.food !== "N/A" && /* @__PURE__ */ jsxs(Fragment, { children: [
1512
+ /* @__PURE__ */ jsx("div", { className: "w-1 h-1 rounded-full bg-[#B2BBC6]" }),
1513
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [
1514
+ /* @__PURE__ */ jsx(Icon, { icon: "solar:cup-hot-outline", className: "w-4 h-4 md:w-5 md:h-5" }),
1515
+ /* @__PURE__ */ jsx("span", { className: "max-w-[100px] md:max-w-none truncate", children: selectedItem.data.food })
1516
+ ] })
1517
+ ] })
1518
+ ] }),
1519
+ /* @__PURE__ */ jsx(DifficultyProgressBar, { level: selectedItem.data.difficulty })
1520
+ ] }) }),
1521
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 md:gap-6 mt-2", children: [
1522
+ selectedItem.data.locationsData.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
1523
+ /* @__PURE__ */ jsx("h4", { className: "text-primary-normal font-medium tracking-[-0.04em] text-lg", children: "Stops in a Day" }),
1524
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col", children: selectedItem.data.locationsData.map((stop, idx, arr) => {
1525
+ const total = arr.length;
1526
+ const label = idx === 0 ? "Start" : idx === total - 1 ? "End" : `Stop ${idx}`;
1527
+ const stopStyles = getStopStyles(label);
1528
+ return /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
1529
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col items-start min-w-[50px] pt-1 shrink-0", children: /* @__PURE__ */ jsx("span", { className: `text-sm font-medium ${stopStyles.labelClass}`, children: label }) }),
1530
+ /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col items-center shrink-0", children: [
1531
+ /* @__PURE__ */ jsx("div", { className: `w-4 h-4 rounded-full border-2 z-10 ${stopStyles.dotClass}` }),
1532
+ idx !== total - 1 && /* @__PURE__ */ jsx("div", { className: `absolute top-4 left-1/2 -ml-[1px] w-0.5 h-full z-0 ${stopStyles.lineClass}` })
1533
+ ] }),
1534
+ /* @__PURE__ */ jsx("div", { className: "text-base text-secondary-normal-hover pt-px pb-6 min-w-0 flex-1", children: stop.displayName })
1535
+ ] }, idx);
1536
+ }) })
1537
+ ] }),
1538
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
1539
+ /* @__PURE__ */ jsx("h4", { className: "text-primary-normal font-medium tracking-[-0.04em] text-lg", children: "Description" }),
1540
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1541
+ /* @__PURE__ */ jsx(
1542
+ "div",
1543
+ {
1544
+ className: `text-base text-secondary-normal-hover leading-relaxed ${!descriptionExpanded ? "line-clamp-3 md:line-clamp-none" : ""}`,
1545
+ dangerouslySetInnerHTML: {
1546
+ __html: (selectedItem.data.content || "").replace(/&nbsp;/g, " ")
1547
+ }
1548
+ }
1549
+ ),
1550
+ (selectedItem.data.content || "").length > 150 && /* @__PURE__ */ jsx(
1551
+ "button",
1552
+ {
1553
+ type: "button",
1554
+ onClick: () => setDescriptionExpanded((v) => !v),
1555
+ className: "text-secondary text-sm font-medium mt-2 hover:underline md:hidden",
1556
+ children: descriptionExpanded ? "See less" : "See more"
1557
+ }
1558
+ )
1559
+ ] })
1560
+ ] }),
1561
+ selectedItem.data.activities?.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-4 mt-2", children: selectedItem.data.activities.map((activity, i) => /* @__PURE__ */ jsx(
1562
+ "div",
1563
+ {
1564
+ className: "bg-[#F0EEF4CC] rounded-2xl py-1 px-3 text-xs text-[#65558F] font-medium",
1565
+ children: activity.activityName
1566
+ },
1567
+ i
1568
+ )) })
1569
+ ] })
1570
+ ] }) }),
1571
+ /* @__PURE__ */ jsx("div", { className: "col-span-1 lg:col-span-2 flex-shrink-0 rounded-lg lg:flex items-center justify-center min-h-[500px] hidden relative z-0", children: /* @__PURE__ */ jsx(
1572
+ PackageMap,
1573
+ {
1574
+ locations: selectedItem.data.locationsData,
1575
+ dayNumber: selectedDay,
1576
+ routes: routesByDay.get(selectedDay) ?? []
1577
+ }
1578
+ ) })
1579
+ ] }) })
1580
+ ] });
1581
+ };
1582
+ var Itinerary_default = Itinerary;
1583
+
1584
+ // src/components/PackageDetail/_checklistUtils.ts
1585
+ var normalizeChecklist = (data) => {
1586
+ if (!data) return [];
1587
+ if (Array.isArray(data)) {
1588
+ return data.map((group) => ({
1589
+ category: typeof group?.category === "string" ? group.category.trim() : "",
1590
+ items: Array.isArray(group?.items) ? group.items.filter(
1591
+ (item) => typeof item === "string" && item.trim() !== ""
1592
+ ) : []
1593
+ })).filter((group) => group.category !== "" && group.items.length > 0);
1594
+ }
1595
+ return Object.entries(data).map(([category, items]) => ({
1596
+ category: category.trim(),
1597
+ items: Array.isArray(items) ? items.filter(
1598
+ (item) => typeof item === "string" && item.trim() !== ""
1599
+ ) : []
1600
+ })).filter((group) => group.category !== "" && group.items.length > 0);
1601
+ };
1602
+ var getChecklistPreviewCount = (isMobile) => isMobile ? 1 : 2;
1603
+ var iconMapping = {
1604
+ clothing: "mdi:tshirt-crew-outline",
1605
+ clothes: "mdi:tshirt-crew-outline",
1606
+ footwear: "mdi:shoe-sneaker",
1607
+ shoes: "mdi:shoe-sneaker",
1608
+ "toiletries and personal items": "lucide:spray-can",
1609
+ "gadgets and extras": "lucide:smartphone",
1610
+ "optional but useful": "lucide:badge-help",
1611
+ "what not to carry": "material-symbols:do-not-disturb-on-outline-rounded",
1612
+ general: "material-symbols:check-circle-outline-rounded"
1613
+ };
1614
+ var getIconForCategory = (category) => {
1615
+ const normalizedCategory = category.trim().toLowerCase();
1616
+ return iconMapping[normalizedCategory] || "material-symbols:check-circle-outline-rounded";
1617
+ };
1618
+ var getDisplayCategory = (category) => {
1619
+ const normalizedCategory = category.trim().toLowerCase();
1620
+ if (normalizedCategory === "clothing" || normalizedCategory === "clothes") {
1621
+ return "Clothing and Backpack";
1622
+ }
1623
+ return category;
1624
+ };
1625
+ var PackageExcludedAndToPack = ({
1626
+ thingsExcluded,
1627
+ thingsToPack
1628
+ }) => {
1629
+ const excludedGroups = normalizeChecklist(thingsExcluded);
1630
+ const toPackGroups = normalizeChecklist(thingsToPack);
1631
+ const [isMobile, setIsMobile] = useState(false);
1632
+ const [expandedGroups, setExpandedGroups] = useState({});
1633
+ const hasExcluded = excludedGroups.length > 0;
1634
+ const hasToPack = toPackGroups.length > 0;
1635
+ useEffect(() => {
1636
+ const checkScreenSize = () => setIsMobile(window.innerWidth < 768);
1637
+ checkScreenSize();
1638
+ window.addEventListener("resize", checkScreenSize);
1639
+ return () => window.removeEventListener("resize", checkScreenSize);
1640
+ }, []);
1641
+ if (!hasExcluded && !hasToPack) return null;
1642
+ const toggleGroup = (groupKey) => setExpandedGroups((current) => ({ ...current, [groupKey]: !current[groupKey] }));
1643
+ const previewCount = getChecklistPreviewCount(isMobile);
1644
+ const renderGroups = (data, sectionKey) => /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-4 md:gap-x-6 lg:gap-x-12 gap-y-4 md:gap-y-6 lg:gap-y-10 mt-2 md:mt-3 lg:mt-4", children: data.map((group, groupIndex) => /* @__PURE__ */ jsxs(
1645
+ "div",
1646
+ {
1647
+ className: "flex flex-col gap-2 md:gap-2.5 lg:gap-3",
1648
+ children: [
1649
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 md:gap-2.5 lg:gap-3", children: [
1650
+ /* @__PURE__ */ jsx("div", { className: "p-2 rounded-lg text-primary-normal", children: /* @__PURE__ */ jsx(Icon, { icon: getIconForCategory(group.category), className: "w-6 h-6" }) }),
1651
+ /* @__PURE__ */ jsx("h3", { className: "text-primary-normal text-lg font-semibold tracking-tight", children: getDisplayCategory(group.category) })
1652
+ ] }),
1653
+ /* @__PURE__ */ jsxs("ul", { className: "flex flex-col gap-1.5 md:gap-2 pl-11", children: [
1654
+ group.items.slice(
1655
+ 0,
1656
+ !expandedGroups[`${sectionKey}-${group.category}-${groupIndex}`] ? previewCount : group.items.length
1657
+ ).map((item, index) => /* @__PURE__ */ jsxs(
1658
+ "li",
1659
+ {
1660
+ className: "flex items-start gap-2 text-secondary-normal-hover text-base leading-relaxed relative",
1661
+ children: [
1662
+ /* @__PURE__ */ jsx("span", { className: "absolute -left-4 top-2.5 w-1 h-1 bg-secondary-normal-hover rounded-full" }),
1663
+ item
1664
+ ]
1665
+ },
1666
+ `${group.category}-${index}`
1667
+ )),
1668
+ group.items.length > previewCount && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
1669
+ "button",
1670
+ {
1671
+ type: "button",
1672
+ onClick: () => toggleGroup(`${sectionKey}-${group.category}-${groupIndex}`),
1673
+ "aria-expanded": Boolean(
1674
+ expandedGroups[`${sectionKey}-${group.category}-${groupIndex}`]
1675
+ ),
1676
+ className: "text-secondary text-sm font-medium hover:underline",
1677
+ children: expandedGroups[`${sectionKey}-${group.category}-${groupIndex}`] ? "See less" : "See more"
1678
+ }
1679
+ ) })
1680
+ ] })
1681
+ ]
1682
+ },
1683
+ `${group.category}-${groupIndex}`
1684
+ )) });
1685
+ return /* @__PURE__ */ jsxs("div", { className: "w-full py-2", children: [
1686
+ hasExcluded && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:gap-3 lg:gap-4", children: [
1687
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal text-xl md:text-2xl font-medium tracking-[-0.04em]", children: "Things Excluded" }),
1688
+ renderGroups(excludedGroups, "excluded")
1689
+ ] }),
1690
+ hasToPack && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:gap-3 lg:gap-4 mt-6 md:mt-8 lg:mt-10", children: [
1691
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal text-xl md:text-2xl font-medium tracking-[-0.04em]", children: "Things To Pack" }),
1692
+ renderGroups(toPackGroups, "to-pack")
1693
+ ] })
1694
+ ] });
1695
+ };
1696
+ var PackageExcludedAndToPack_default = PackageExcludedAndToPack;
1697
+ var iconMapping2 = {
1698
+ "Support Team": "lucide:headset",
1699
+ Permits: "lucide:file-text",
1700
+ "Pickup and Drop Service": "lucide:plane",
1701
+ "Airport Pickup & Drop Service": "lucide:plane",
1702
+ "Pickup and Drop": "lucide:plane",
1703
+ "Travel Insurance": "lucide:shield-check",
1704
+ Accommodation: "lucide:hotel",
1705
+ Transport: "lucide:bus",
1706
+ Food: "lucide:utensils-crossed",
1707
+ "Additional Perks": "lucide:plus-circle",
1708
+ "First Aid Services": "material-symbols:medical-services-outline"
1709
+ };
1710
+ var PackageIncluded = ({ thingsToDo }) => {
1711
+ const [isMobile, setIsMobile] = useState(false);
1712
+ const [expandedGroups, setExpandedGroups] = useState({});
1713
+ const normalizedThingsToDo = normalizeChecklist(thingsToDo);
1714
+ useEffect(() => {
1715
+ const checkScreenSize = () => setIsMobile(window.innerWidth < 768);
1716
+ checkScreenSize();
1717
+ window.addEventListener("resize", checkScreenSize);
1718
+ return () => window.removeEventListener("resize", checkScreenSize);
1719
+ }, []);
1720
+ if (normalizedThingsToDo.length === 0) return null;
1721
+ const toggleGroup = (groupKey) => setExpandedGroups((current) => ({ ...current, [groupKey]: !current[groupKey] }));
1722
+ const previewCount = getChecklistPreviewCount(isMobile);
1723
+ return /* @__PURE__ */ jsx("div", { className: "w-full py-2", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-4 md:gap-x-6 lg:gap-x-12 gap-y-4 md:gap-y-6 lg:gap-y-10", children: normalizedThingsToDo.map((category, index) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 md:gap-2.5 lg:gap-3", children: [
1724
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 md:gap-2.5 lg:gap-3", children: [
1725
+ /* @__PURE__ */ jsx("div", { className: "p-2 rounded-lg text-primary-normal", children: /* @__PURE__ */ jsx(
1726
+ Icon,
1727
+ {
1728
+ icon: iconMapping2[category.category] || "material-symbols:check-circle-outline-rounded",
1729
+ className: "w-6 h-6"
1730
+ }
1731
+ ) }),
1732
+ /* @__PURE__ */ jsx("h3", { className: "text-primary-normal text-lg font-semibold tracking-tight", children: category.category })
1733
+ ] }),
1734
+ /* @__PURE__ */ jsxs("ul", { className: "flex flex-col gap-1.5 md:gap-2 pl-11", children: [
1735
+ category.items.slice(
1736
+ 0,
1737
+ !expandedGroups[`${category.category}-${index}`] ? previewCount : category.items.length
1738
+ ).map((item, itemIndex) => /* @__PURE__ */ jsxs(
1739
+ "li",
1740
+ {
1741
+ className: "flex items-start gap-2 text-secondary-normal-hover text-base leading-relaxed relative",
1742
+ children: [
1743
+ /* @__PURE__ */ jsx("span", { className: "absolute -left-4 top-2.5 w-1 h-1 bg-secondary-normal-hover rounded-full" }),
1744
+ item
1745
+ ]
1746
+ },
1747
+ itemIndex
1748
+ )),
1749
+ category.items.length > previewCount && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
1750
+ "button",
1751
+ {
1752
+ type: "button",
1753
+ onClick: () => toggleGroup(`${category.category}-${index}`),
1754
+ "aria-expanded": Boolean(expandedGroups[`${category.category}-${index}`]),
1755
+ className: "text-secondary text-sm font-medium hover:underline",
1756
+ children: expandedGroups[`${category.category}-${index}`] ? "See less" : "See more"
1757
+ }
1758
+ ) })
1759
+ ] })
1760
+ ] }, index)) }) });
1761
+ };
1762
+ var PackageIncluded_default = PackageIncluded;
1763
+ var PackageOverview = ({
1764
+ description,
1765
+ isMobile,
1766
+ topData
1767
+ }) => {
1768
+ const [expanded, setExpanded] = useState(false);
1769
+ const isLong = (description || "").length > 400;
1770
+ return /* @__PURE__ */ jsxs("div", { className: "w-full pb-4", children: [
1771
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal font-medium text-xl md:text-2xl tracking-[-0.04em]", children: "Overview" }),
1772
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 text-secondary-normal-hover lg:text-base text-sm font-light leading-relaxed", children: [
1773
+ /* @__PURE__ */ jsx(
1774
+ "div",
1775
+ {
1776
+ className: `w-full break-words whitespace-pre-wrap overflow-hidden transition-[max-height] duration-300
1777
+ [&_ul]:list-disc [&_ul]:pl-5 [&_li]:mb-1
1778
+ [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:mb-1
1779
+ [&_p]:mb-2 [&_img]:max-w-full [&_img]:h-auto
1780
+ [&_table]:w-full [&_table]:overflow-x-auto
1781
+ [&_strong]:font-bold [&_underline]:underline
1782
+ ${isMobile && !expanded ? "max-h-40" : "max-h-none"}`,
1783
+ dangerouslySetInnerHTML: {
1784
+ __html: (description || "").replace(/&nbsp;/g, " ") || "No description available."
1785
+ }
1786
+ }
1787
+ ),
1788
+ isLong && /* @__PURE__ */ jsx(
1789
+ "button",
1790
+ {
1791
+ type: "button",
1792
+ onClick: () => setExpanded((p) => !p),
1793
+ "aria-expanded": expanded,
1794
+ className: "text-secondary text-sm font-medium mt-1 hover:underline md:hidden",
1795
+ children: expanded ? "See less" : "See more"
1796
+ }
1797
+ )
1798
+ ] }),
1799
+ /* @__PURE__ */ jsxs("div", { className: "mt-5 mb-4 pt-5 border-t border-gray-100", children: [
1800
+ /* @__PURE__ */ jsx("h2", { className: "text-[#65558F] font-medium text-xl tracking-[-0.04em] mb-3", children: "Key Facts" }),
1801
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1802
+ /* @__PURE__ */ jsx(
1803
+ KeyFact,
1804
+ {
1805
+ icon: "solar:suitcase-tag-outline",
1806
+ label: "Trip Style",
1807
+ value: topData?.PackageType || "Sightseeing"
1808
+ }
1809
+ ),
1810
+ /* @__PURE__ */ jsx(
1811
+ KeyFact,
1812
+ {
1813
+ icon: "icon-park-outline:level",
1814
+ label: "Difficulty",
1815
+ value: topData?.Difficulty || "Easy"
1816
+ }
1817
+ ),
1818
+ /* @__PURE__ */ jsx(
1819
+ KeyFact,
1820
+ {
1821
+ icon: "iconoir:calendar",
1822
+ label: "Number Of Days",
1823
+ value: topData?.TotalDays ? `${topData.TotalDays} Days & ${Math.max(0, topData.TotalDays - 1)} Nights` : "Duration"
1824
+ }
1825
+ ),
1826
+ /* @__PURE__ */ jsx(
1827
+ KeyFact,
1828
+ {
1829
+ icon: "iconoir:packages",
1830
+ label: "Package Category",
1831
+ value: topData?.PackageCategory || "Luxury"
1832
+ }
1833
+ )
1834
+ ] })
1835
+ ] })
1836
+ ] });
1837
+ };
1838
+ var KeyFact = ({
1839
+ icon,
1840
+ label,
1841
+ value
1842
+ }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
1843
+ /* @__PURE__ */ jsx(Icon, { icon, className: "w-6 h-6 text-[#47586E] flex-shrink-0" }),
1844
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 grid grid-cols-[110px_1fr] sm:grid-cols-[200px_1fr] gap-4 items-center", children: [
1845
+ /* @__PURE__ */ jsx("span", { className: "text-sm sm:text-base text-[#47586E]", children: label }),
1846
+ /* @__PURE__ */ jsx("span", { className: "text-base text-[#65558F] font-medium", children: value })
1847
+ ] })
1848
+ ] });
1849
+ var PackageOverview_default = PackageOverview;
1850
+ var DescriptionSection = ({
1851
+ DescriptionData,
1852
+ topData,
1853
+ currency,
1854
+ onReserve,
1855
+ pkg,
1856
+ routes
1857
+ }) => {
1858
+ const [isMobile, setIsMobile] = useState(false);
1859
+ const bookingRef = useRef(null);
1860
+ useEffect(() => {
1861
+ const checkScreenSize = () => setIsMobile(window.innerWidth < 768);
1862
+ checkScreenSize();
1863
+ window.addEventListener("resize", checkScreenSize);
1864
+ return () => window.removeEventListener("resize", checkScreenSize);
1865
+ }, []);
1866
+ const scrollToBooking = () => {
1867
+ if (!bookingRef.current) return;
1868
+ const rect = bookingRef.current.getBoundingClientRect();
1869
+ const offset = 90;
1870
+ window.scrollTo({
1871
+ top: window.scrollY + rect.top - offset,
1872
+ behavior: "smooth"
1873
+ });
1874
+ };
1875
+ return /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col items-center", children: /* @__PURE__ */ jsxs("div", { className: "w-full relative border-gray-200 flex flex-col gap-8", children: [
1876
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-6 w-full justify-between", children: [
1877
+ /* @__PURE__ */ jsx("div", { className: "lg:col-span-7 w-full flex flex-col gap-3 border-b-2 pb-6", children: /* @__PURE__ */ jsx(
1878
+ PackageOverview_default,
1879
+ {
1880
+ description: DescriptionData.Description,
1881
+ isMobile,
1882
+ topData
1883
+ }
1884
+ ) }),
1885
+ /* @__PURE__ */ jsxs(
1886
+ "div",
1887
+ {
1888
+ ref: bookingRef,
1889
+ className: "lg:col-span-5 flex justify-start items-end flex-col gap-2 scroll-mt-[100px]",
1890
+ children: [
1891
+ /* @__PURE__ */ jsx("p", { className: "md:hidden text-primary-normal text-start w-full flex justify-start text-xl md:text-2xl font-medium tracking-[-0.04em]", children: "Book Now" }),
1892
+ /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsx(
1893
+ BookingCardLite_default,
1894
+ {
1895
+ DescriptionData,
1896
+ currency,
1897
+ onReserve: onReserve ? () => onReserve(pkg) : void 0
1898
+ }
1899
+ ) })
1900
+ ]
1901
+ }
1902
+ )
1903
+ ] }),
1904
+ /* @__PURE__ */ jsxs("div", { className: "relative pb-7 border-b-2 border-gray-200", children: [
1905
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal text-xl md:text-2xl font-medium tracking-[-0.04em]", children: "Itinerary" }),
1906
+ /* @__PURE__ */ jsx(
1907
+ Itinerary_default,
1908
+ {
1909
+ Description: DescriptionData,
1910
+ routes,
1911
+ currency,
1912
+ onReserveClick: scrollToBooking
1913
+ }
1914
+ )
1915
+ ] }),
1916
+ DescriptionData?.thingsToDo && DescriptionData.thingsToDo.length > 0 && /* @__PURE__ */ jsxs("div", { className: "relative pt-5 pb-7 border-b-2 border-gray-200", children: [
1917
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal text-xl md:text-2xl font-medium tracking-[-0.04em] mb-6", children: "Things Included" }),
1918
+ /* @__PURE__ */ jsx(PackageIncluded_default, { thingsToDo: DescriptionData.thingsToDo })
1919
+ ] }),
1920
+ (DescriptionData?.thingsExcluded && DescriptionData.thingsExcluded.length > 0 || DescriptionData?.thingsToPack && DescriptionData.thingsToPack.length > 0) && /* @__PURE__ */ jsx("div", { className: "relative pb-7", children: /* @__PURE__ */ jsx(
1921
+ PackageExcludedAndToPack_default,
1922
+ {
1923
+ thingsExcluded: DescriptionData?.thingsExcluded || [],
1924
+ thingsToPack: DescriptionData?.thingsToPack || []
1925
+ }
1926
+ ) })
1927
+ ] }) });
1928
+ };
1929
+ var DescriptionSection_default = DescriptionSection;
1930
+ var HostAbout = ({
1931
+ hostName,
1932
+ description,
1933
+ className = ""
1934
+ }) => /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-4 ${className}`, children: [
1935
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxs("h3", { className: "text-xl md:text-2xl font-medium tracking-[-0.04em] text-primary-normal", children: [
1936
+ "About ",
1937
+ hostName
1938
+ ] }) }),
1939
+ /* @__PURE__ */ jsx("p", { className: "text-secondary-normal-hover text-base md:text-lg leading-relaxed line-clamp-4", children: description || "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium, deleniti! Obcaecati atque, ex itaque voluptatem vel perferendis." })
1940
+ ] });
1941
+ var HostAbout_default = HostAbout;
1942
+ var getUserInitials = (name) => name?.charAt(0)?.toUpperCase() || "H";
1943
+ var getMonthsHosting = (createdDate) => {
1944
+ if (!createdDate) return 1;
1945
+ const now = /* @__PURE__ */ new Date();
1946
+ const created = new Date(createdDate);
1947
+ const monthsDiff = Math.floor(
1948
+ (now.getTime() - created.getTime()) / (1e3 * 60 * 60 * 24 * 30)
1949
+ );
1950
+ return Math.max(1, monthsDiff);
1951
+ };
1952
+ var HostCard = ({ hostData, className = "" }) => {
1953
+ const logoUrl = pickImageUrl(hostData?.logo);
1954
+ return /* @__PURE__ */ jsxs(
1955
+ "div",
1956
+ {
1957
+ className: `w-full sm:min-w-[320px] rounded-2xl border border-[#E0E4E8] bg-white flex flex-col gap-6 p-6 lg:p-8 shadow-md ${className}`,
1958
+ children: [
1959
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
1960
+ /* @__PURE__ */ jsx("div", { className: "relative rounded-full h-20 w-20 bg-gray-200 flex items-center justify-center text-xl text-primary-normal overflow-hidden", children: logoUrl ? /* @__PURE__ */ jsx(
1961
+ "img",
1962
+ {
1963
+ src: logoUrl,
1964
+ alt: `${hostData?.username}'s logo`,
1965
+ className: "object-cover w-full h-full"
1966
+ }
1967
+ ) : /* @__PURE__ */ jsx("span", { children: getUserInitials(hostData?.username) }) }),
1968
+ /* @__PURE__ */ jsx("span", { className: "text-[18px] tracking-[-0.02em] font-medium text-primary-normal whitespace-normal break-words", children: hostData?.username })
1969
+ ] }),
1970
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-center mt-2", children: [
1971
+ /* @__PURE__ */ jsxs("div", { children: [
1972
+ /* @__PURE__ */ jsx("p", { className: "text-base md:text-lg text-primary-normal tracking-[-0.02em] font-medium", children: hostData?.review ?? 0 }),
1973
+ /* @__PURE__ */ jsx("p", { className: "text-sm md:text-base text-secondary-normal-hover tracking-[-0.02em]", children: "Reviews" })
1974
+ ] }),
1975
+ /* @__PURE__ */ jsxs("div", { children: [
1976
+ /* @__PURE__ */ jsx("p", { className: "text-base md:text-lg text-primary-normal tracking-[-0.02em] font-medium", children: (hostData?.rating ?? 0).toFixed(2) }),
1977
+ /* @__PURE__ */ jsx("p", { className: "text-sm md:text-base text-secondary-normal-hover tracking-[-0.02em]", children: "Rating" })
1978
+ ] }),
1979
+ /* @__PURE__ */ jsxs("div", { children: [
1980
+ /* @__PURE__ */ jsxs("p", { className: "text-base md:text-lg text-primary-normal tracking-[-0.02em] font-medium", children: [
1981
+ getMonthsHosting(hostData?.agencyCreatedDate),
1982
+ " mth"
1983
+ ] }),
1984
+ /* @__PURE__ */ jsx("p", { className: "text-sm md:text-base text-secondary-normal-hover tracking-[-0.02em]", children: "Hosting" })
1985
+ ] })
1986
+ ] })
1987
+ ]
1988
+ }
1989
+ );
1990
+ };
1991
+ var HostCard_default = HostCard;
1992
+ var GalleryImg = ({
1993
+ src,
1994
+ alt,
1995
+ onClick,
1996
+ className
1997
+ }) => src ? /* @__PURE__ */ jsx(
1998
+ "img",
1999
+ {
2000
+ src,
2001
+ alt,
2002
+ onClick,
2003
+ className,
2004
+ loading: "lazy"
2005
+ }
2006
+ ) : /* @__PURE__ */ jsx(
2007
+ "div",
2008
+ {
2009
+ className: `${className ?? ""} bg-[#F0EEF4] flex items-center justify-center text-primary-normal/40 text-sm`,
2010
+ children: "No image"
2011
+ }
2012
+ );
2013
+ var GalleryCell = ({
2014
+ src,
2015
+ alt,
2016
+ onClick,
2017
+ colSpan = ""
2018
+ }) => /* @__PURE__ */ jsx(
2019
+ "div",
2020
+ {
2021
+ onClick,
2022
+ className: `relative h-full w-full overflow-hidden rounded-lg ${colSpan}`.trim(),
2023
+ children: /* @__PURE__ */ jsx(
2024
+ GalleryImg,
2025
+ {
2026
+ src,
2027
+ alt,
2028
+ className: "absolute inset-0 w-full h-full object-cover cursor-pointer transition duration-200"
2029
+ }
2030
+ )
2031
+ }
2032
+ );
2033
+ var GallerySection = ({ media, packageTitle }) => {
2034
+ const [overlayIndex, setOverlayIndex] = useState(null);
2035
+ const images = media.map((m) => m.url);
2036
+ const imageAlts = media.map((m) => m.alt || packageTitle);
2037
+ const open = (i) => setOverlayIndex(i);
2038
+ const close = () => setOverlayIndex(null);
2039
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2040
+ /* @__PURE__ */ jsxs("div", { className: "md:grid lg:grid md:grid-cols-5 grid-cols-1 gap-2 mt-4 h-[546px] cursor-pointer relative hidden overflow-hidden", children: [
2041
+ /* @__PURE__ */ jsxs(
2042
+ "div",
2043
+ {
2044
+ onClick: () => open(0),
2045
+ className: "px-2 py-1 bg-white cursor-pointer flex justify-center items-center text-primary-normal absolute bottom-2 right-2 rounded-lg text-sm md:text-base lg:text-lg z-10",
2046
+ children: [
2047
+ /* @__PURE__ */ jsx(
2048
+ Icon,
2049
+ {
2050
+ icon: "material-symbols-light:space-dashboard-outline",
2051
+ className: "text-2xl text-gray-500"
2052
+ }
2053
+ ),
2054
+ " ",
2055
+ "See all photos"
2056
+ ]
2057
+ }
2058
+ ),
2059
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 col-span-3 gap-4 h-[546px]", children: [
2060
+ /* @__PURE__ */ jsx(GalleryCell, { src: images[0], alt: imageAlts[0] || packageTitle, onClick: () => open(0), colSpan: "col-span-6" }),
2061
+ /* @__PURE__ */ jsx(GalleryCell, { src: images[1], alt: imageAlts[1] || packageTitle, onClick: () => open(1), colSpan: "col-span-6" })
2062
+ ] }),
2063
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 h-[546px] lg:grid md:grid hidden grid-rows-2 gap-2", children: [
2064
+ /* @__PURE__ */ jsx(GalleryCell, { src: images[2], alt: imageAlts[2] || packageTitle, onClick: () => open(2) }),
2065
+ /* @__PURE__ */ jsxs("div", { className: "hidden lg:grid md:grid grid-cols-2 gap-2 h-full", children: [
2066
+ /* @__PURE__ */ jsx(GalleryCell, { src: images[3], alt: imageAlts[3] || packageTitle, onClick: () => open(3) }),
2067
+ /* @__PURE__ */ jsxs("div", { className: "relative hidden lg:grid md:grid grid-rows-2 gap-2 h-full", children: [
2068
+ /* @__PURE__ */ jsx(GalleryCell, { src: images[4], alt: imageAlts[4] || packageTitle, onClick: () => open(4) }),
2069
+ /* @__PURE__ */ jsx(GalleryCell, { src: images[5], alt: imageAlts[5] || packageTitle, onClick: () => open(5) })
2070
+ ] })
2071
+ ] })
2072
+ ] })
2073
+ ] }),
2074
+ /* @__PURE__ */ jsx("div", { className: "grid cursor-pointer gap-3 pt-2 md:pt-5 lg:hidden md:hidden", children: /* @__PURE__ */ jsxs("div", { className: "col-span-2 relative h-[320px] md:h-[350px]", children: [
2075
+ /* @__PURE__ */ jsx(
2076
+ GalleryImg,
2077
+ {
2078
+ src: images[0],
2079
+ alt: imageAlts[0] || packageTitle,
2080
+ className: "w-full h-full rounded-lg object-cover",
2081
+ onClick: () => open(0)
2082
+ }
2083
+ ),
2084
+ /* @__PURE__ */ jsx(
2085
+ "button",
2086
+ {
2087
+ className: "absolute bottom-2 right-2 bg-white text-primary-normal px-3 py-2 rounded-lg z-10 text-sm md:text-base font-medium",
2088
+ onClick: () => open(0),
2089
+ children: "See All Photos"
2090
+ }
2091
+ )
2092
+ ] }) }),
2093
+ overlayIndex !== null && /* @__PURE__ */ jsx(
2094
+ LightboxOverlay,
2095
+ {
2096
+ images,
2097
+ alts: imageAlts,
2098
+ startIndex: overlayIndex,
2099
+ onClose: close
2100
+ }
2101
+ )
2102
+ ] });
2103
+ };
2104
+ function LightboxOverlay({
2105
+ images,
2106
+ alts,
2107
+ startIndex,
2108
+ onClose
2109
+ }) {
2110
+ const [i, setI] = useState(startIndex);
2111
+ const prev = () => setI((v) => (v - 1 + images.length) % images.length);
2112
+ const next = () => setI((v) => (v + 1) % images.length);
2113
+ return /* @__PURE__ */ jsxs(
2114
+ "div",
2115
+ {
2116
+ className: "fixed inset-0 z-[1000] bg-black/90 flex items-center justify-center",
2117
+ onClick: onClose,
2118
+ children: [
2119
+ /* @__PURE__ */ jsx(
2120
+ "button",
2121
+ {
2122
+ type: "button",
2123
+ onClick: (e) => {
2124
+ e.stopPropagation();
2125
+ onClose();
2126
+ },
2127
+ className: "absolute top-4 right-4 text-white p-2 rounded-full hover:bg-white/10",
2128
+ "aria-label": "Close gallery",
2129
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:x", className: "w-6 h-6" })
2130
+ }
2131
+ ),
2132
+ /* @__PURE__ */ jsx(
2133
+ "button",
2134
+ {
2135
+ type: "button",
2136
+ onClick: (e) => {
2137
+ e.stopPropagation();
2138
+ prev();
2139
+ },
2140
+ className: "absolute left-4 text-white p-3 rounded-full hover:bg-white/10",
2141
+ "aria-label": "Previous",
2142
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:chevron-left", className: "w-7 h-7" })
2143
+ }
2144
+ ),
2145
+ /* @__PURE__ */ jsx(
2146
+ "img",
2147
+ {
2148
+ src: images[i],
2149
+ alt: alts[i] || "",
2150
+ className: "max-w-[92vw] max-h-[88vh] object-contain rounded-lg",
2151
+ onClick: (e) => e.stopPropagation()
2152
+ }
2153
+ ),
2154
+ /* @__PURE__ */ jsx(
2155
+ "button",
2156
+ {
2157
+ type: "button",
2158
+ onClick: (e) => {
2159
+ e.stopPropagation();
2160
+ next();
2161
+ },
2162
+ className: "absolute right-4 text-white p-3 rounded-full hover:bg-white/10",
2163
+ "aria-label": "Next",
2164
+ children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:chevron-right", className: "w-7 h-7" })
2165
+ }
2166
+ ),
2167
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 text-white text-sm bg-black/40 px-3 py-1 rounded-full", children: [
2168
+ i + 1,
2169
+ " / ",
2170
+ images.length
2171
+ ] })
2172
+ ]
2173
+ }
2174
+ );
2175
+ }
2176
+ var GallerySection_default = GallerySection;
2177
+ var renderStars = (rating) => {
2178
+ const fullStars = Math.floor(rating);
2179
+ const hasHalfStar = rating % 1 >= 0.5;
2180
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center", children: [1, 2, 3, 4, 5].map((star) => {
2181
+ let icon = "mdi-light:star";
2182
+ if (star <= fullStars) {
2183
+ icon = "material-symbols:star";
2184
+ } else if (star === fullStars + 1 && hasHalfStar) {
2185
+ icon = "material-symbols:star-half";
2186
+ }
2187
+ return /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4 text-secondary" }, star);
2188
+ }) });
2189
+ };
2190
+ var TopSection = ({ topData }) => {
2191
+ const galleryMedia = topData.AgencyPackageMedias.map((item) => ({
2192
+ url: item.url,
2193
+ previewUrl: item.previewUrl,
2194
+ alt: item.alt || topData.PackageTitle
2195
+ }));
2196
+ return /* @__PURE__ */ jsxs("div", { className: "lg:px-4 px-0 py-2 md:py-4 lg:py-6", children: [
2197
+ /* @__PURE__ */ jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-2 text-sm", children: [
2198
+ /* @__PURE__ */ jsx("a", { href: "/", className: "text-primary-normal hover:underline", children: "Home" }),
2199
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-primary-normal", children: "\u203A" }),
2200
+ /* @__PURE__ */ jsx("span", { className: "text-primary-normal underline truncate w-[70vw] md:w-full", children: topData.PackageTitle })
2201
+ ] }),
2202
+ /* @__PURE__ */ jsx("div", { className: "w-full flex justify-between items-center mt-2 py-0 md:py-4", children: /* @__PURE__ */ jsx("h1", { className: "text-xl md:text-2xl lg:text-3xl font-semibold tracking-[-0.04em] text-primary-normal leading-tight", children: topData.PackageTitle }) }),
2203
+ /* @__PURE__ */ jsx("div", { className: "text-sm py-0 md:py-2", children: topData.Rating ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2204
+ /* @__PURE__ */ jsx("p", { className: "text-primary-normal font-medium", children: topData.Rating.toFixed(1) }),
2205
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2206
+ renderStars(topData.Rating),
2207
+ /* @__PURE__ */ jsx("p", { className: "text-secondary-normal-hover underline text-xs", children: topData.ReviewCount ? `(${topData.ReviewCount})` : null })
2208
+ ] })
2209
+ ] }) : /* @__PURE__ */ jsx("p", { className: "text-secondary-normal-hover", children: "Not yet rated" }) }),
2210
+ /* @__PURE__ */ jsx(GallerySection_default, { media: galleryMedia, packageTitle: topData.PackageTitle })
2211
+ ] });
2212
+ };
2213
+ var TopSection_default = TopSection;
2214
+
2215
+ // src/components/PackageDetail/_projectToLegacy.ts
2216
+ var mediaFromImage = (img, fallbackAlt) => {
2217
+ const u = pickImageUrl(img);
2218
+ if (!u) return null;
2219
+ return {
2220
+ url: u,
2221
+ previewUrl: img?.preview ?? "",
2222
+ alt: img?.alt || fallbackAlt
2223
+ };
2224
+ };
2225
+ var buildGalleryMedia = (pkg) => {
2226
+ const list = (pkg.media ?? []).map((m) => mediaFromImage(m, pkg.title)).filter((m) => Boolean(m));
2227
+ if (list.length > 0) return list;
2228
+ const thumb = mediaFromImage(pkg.thumbnail, pkg.title);
2229
+ return thumb ? [thumb] : [];
2230
+ };
2231
+ var buildTopData = (pkg, host) => ({
2232
+ id: pkg.id,
2233
+ slug: pkg.slug,
2234
+ PackageTitle: pkg.title,
2235
+ AgencyName: host?.username ?? "",
2236
+ AgencySlug: host?.slug ?? "",
2237
+ AgencyPackageMedias: buildGalleryMedia(pkg),
2238
+ Rating: pkg.rating ?? 0,
2239
+ ReviewCount: host?.review ?? 0,
2240
+ PackageType: pkg.packageType || "N/A",
2241
+ TotalDays: pkg.totalDays || 0,
2242
+ MaxAllowedPeople: pkg.maxAllowedPeople ?? 10,
2243
+ thingsToDo: pkg.thingsIncluded,
2244
+ thingsExcluded: pkg.thingsExcluded,
2245
+ thingsToPack: pkg.thingsToPack,
2246
+ PackageCategory: pkg.packageCategory || "Standard",
2247
+ Difficulty: pkg.difficulty || "Easy"
2248
+ });
2249
+ var buildDescriptionData = (pkg) => ({
2250
+ id: pkg.id,
2251
+ Description: pkg.description ?? "",
2252
+ Price: pkg.prices ?? [],
2253
+ Discounts: pkg.discounts ?? [],
2254
+ TotalDays: pkg.totalDays ?? 0,
2255
+ MaxAllowedPeople: pkg.maxAllowedPeople ?? 10,
2256
+ MinAllowedPeople: pkg.minAllowedPeople ?? 1,
2257
+ Days: (pkg.days ?? []).map((d) => ({
2258
+ id: d.id,
2259
+ dayNumber: d.dayNumber,
2260
+ description: d.description,
2261
+ activities: d.activities,
2262
+ locations: d.locations,
2263
+ travelDuration: d.travelDuration,
2264
+ difficulty: d.difficulty,
2265
+ foodService: d.foodService,
2266
+ transportation: d.transportation,
2267
+ accommodation: d.accommodation
2268
+ })),
2269
+ thingsToDo: pkg.thingsIncluded,
2270
+ thingsExcluded: pkg.thingsExcluded,
2271
+ thingsToPack: pkg.thingsToPack
2272
+ });
2273
+ function PackageDetailView({
2274
+ client,
2275
+ slug,
2276
+ initialBundle,
2277
+ currency = "USD",
2278
+ onReserve,
2279
+ className,
2280
+ renderLoading,
2281
+ renderNotFound
2282
+ }) {
2283
+ if (!initialBundle && (!client || !slug)) {
2284
+ throw new Error(
2285
+ "[PackageDetailView] Provide either `initialBundle` or both `client` and `slug`."
2286
+ );
2287
+ }
2288
+ const remote = usePackageBundle(client, initialBundle ? null : slug);
2289
+ const bundle = initialBundle ?? remote.data;
2290
+ const loading = !initialBundle && remote.loading;
2291
+ const error = !initialBundle && remote.error;
2292
+ if (loading) {
2293
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-[1440px]", children: renderLoading ? renderLoading() : /* @__PURE__ */ jsx(DefaultLoading, {}) }) });
2294
+ }
2295
+ if (error) {
2296
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: /* @__PURE__ */ jsxs("div", { className: "max-w-screen-xl mx-auto px-6 py-16 text-center text-red-600 text-sm", children: [
2297
+ "Failed to load package: ",
2298
+ error.message
2299
+ ] }) });
2300
+ }
2301
+ if (!bundle?.pkg) {
2302
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: renderNotFound ? renderNotFound() : /* @__PURE__ */ jsx("div", { className: "max-w-screen-xl mx-auto px-6 py-16 text-center text-secondary-normal-hover text-sm", children: "Package not found." }) });
2303
+ }
2304
+ return /* @__PURE__ */ jsx(
2305
+ DetailContent,
2306
+ {
2307
+ pkg: bundle.pkg,
2308
+ host: bundle.host,
2309
+ routes: bundle.routes ?? [],
2310
+ currency,
2311
+ onReserve,
2312
+ className
2313
+ }
2314
+ );
2315
+ }
2316
+ function DetailContent({
2317
+ pkg,
2318
+ host,
2319
+ routes,
2320
+ currency,
2321
+ onReserve,
2322
+ className
2323
+ }) {
2324
+ const topData = buildTopData(pkg, host);
2325
+ const descriptionData = buildDescriptionData(pkg);
2326
+ return /* @__PURE__ */ jsx("div", { className: `tvr-package-detail ${className ?? ""}`.trim(), children: /* @__PURE__ */ jsxs("article", { className: "mx-auto max-w-[1440px] flex flex-col gap-5 md:px-12 px-6 lg:py-12 mt-4", children: [
2327
+ /* @__PURE__ */ jsx(TopSection_default, { topData }),
2328
+ /* @__PURE__ */ jsx(
2329
+ DescriptionSection_default,
2330
+ {
2331
+ DescriptionData: descriptionData,
2332
+ topData,
2333
+ currency,
2334
+ onReserve,
2335
+ pkg,
2336
+ routes
2337
+ }
2338
+ ),
2339
+ host && /* @__PURE__ */ jsxs("div", { className: "py-6 sm:py-8 border-b-2 border-gray-200 flex flex-col gap-6", children: [
2340
+ /* @__PURE__ */ jsx("h2", { className: "text-primary-normal text-xl md:text-2xl font-medium tracking-[-0.04em]", children: "Host Details" }),
2341
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row gap-8 lg:gap-10 h-full items-start lg:items-center", children: [
2342
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-6 sm:gap-8 w-full sm:w-[320px]", children: /* @__PURE__ */ jsx(HostCard_default, { hostData: host, className: "w-full" }) }),
2343
+ /* @__PURE__ */ jsx("div", { className: "w-full lg:w-4/5 h-full flex flex-col justify-center", children: /* @__PURE__ */ jsx(
2344
+ HostAbout_default,
2345
+ {
2346
+ hostName: host.username,
2347
+ description: host.description,
2348
+ className: "pr-0 lg:pr-10"
2349
+ }
2350
+ ) })
2351
+ ] })
2352
+ ] })
2353
+ ] }) });
2354
+ }
2355
+ function DefaultLoading() {
2356
+ return /* @__PURE__ */ jsxs("div", { className: "max-w-screen-xl mx-auto px-6 py-8 animate-pulse", children: [
2357
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-1/2 bg-gray-200 rounded mb-4" }),
2358
+ /* @__PURE__ */ jsx("div", { className: "h-[546px] bg-gray-100 rounded-lg mb-6" }),
2359
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-6", children: [
2360
+ /* @__PURE__ */ jsxs("div", { className: "lg:col-span-7 space-y-3", children: [
2361
+ /* @__PURE__ */ jsx("div", { className: "h-5 w-1/3 bg-gray-200 rounded" }),
2362
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-full bg-gray-100 rounded" }),
2363
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-5/6 bg-gray-100 rounded" }),
2364
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-4/6 bg-gray-100 rounded" })
2365
+ ] }),
2366
+ /* @__PURE__ */ jsx("div", { className: "lg:col-span-5 h-64 bg-gray-100 rounded-2xl" })
2367
+ ] })
2368
+ ] });
2369
+ }
2370
+
2371
+ export { BookingCardLite_default as BookingCardLite, DescriptionSection_default as DescriptionSection, GallerySection_default as GallerySection, HomeSections, HomeSectionsProvider, HostAbout_default as HostAbout, HostCard_default as HostCard, Itinerary_default as Itinerary, PackageCard_default as PackageCard, PackageDetailView, PackageExcludedAndToPack_default as PackageExcludedAndToPack, PackageIncluded_default as PackageIncluded, PackageMap, PackageOverview_default as PackageOverview, PackagesCarousel_default as PackagesCarousel, PackagesResource, PackagesSection_default as PackagesSection, TopSection_default as TopSection, TravoriesApiError, TravoriesClient, buildDescriptionData, buildGalleryMedia, buildTopData, createTravoriesClient, formatCurrency, formatRating, pickImageUrl, startingPrice, useHomeSections, useHomeSectionsContext, usePackageBundle, usePackageBySlug };
2372
+ //# sourceMappingURL=index.mjs.map
2373
+ //# sourceMappingURL=index.mjs.map