@burdenoff/microfe-ggnomad 2026.801.1 → 2026.827.1
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/ggnomad/components/AvailabilityPanel.d.ts +15 -0
- package/dist/ggnomad/components/AvailabilityPanel.d.ts.map +1 -0
- package/dist/ggnomad/components/AvailabilityPanel.js +91 -0
- package/dist/ggnomad/components/AvailabilityPanel.js.map +1 -0
- package/dist/ggnomad/components/BookingPanel.d.ts +1 -3
- package/dist/ggnomad/components/BookingPanel.d.ts.map +1 -1
- package/dist/ggnomad/components/BookingPanel.js +91 -82
- package/dist/ggnomad/components/BookingPanel.js.map +1 -1
- package/dist/ggnomad/components/EcoAccessPanel.d.ts +17 -0
- package/dist/ggnomad/components/EcoAccessPanel.d.ts.map +1 -0
- package/dist/ggnomad/components/EcoAccessPanel.js +68 -0
- package/dist/ggnomad/components/EcoAccessPanel.js.map +1 -0
- package/dist/ggnomad/components/FactGrid.d.ts +18 -0
- package/dist/ggnomad/components/FactGrid.d.ts.map +1 -0
- package/dist/ggnomad/components/FactGrid.js +29 -0
- package/dist/ggnomad/components/FactGrid.js.map +1 -0
- package/dist/ggnomad/components/GroupTripPanel.d.ts +22 -0
- package/dist/ggnomad/components/GroupTripPanel.d.ts.map +1 -0
- package/dist/ggnomad/components/GroupTripPanel.js +350 -0
- package/dist/ggnomad/components/GroupTripPanel.js.map +1 -0
- package/dist/ggnomad/components/ListingFilters.d.ts +29 -0
- package/dist/ggnomad/components/ListingFilters.d.ts.map +1 -0
- package/dist/ggnomad/components/ListingFilters.js +164 -0
- package/dist/ggnomad/components/ListingFilters.js.map +1 -0
- package/dist/ggnomad/components/PhotoGallery.d.ts +15 -0
- package/dist/ggnomad/components/PhotoGallery.d.ts.map +1 -0
- package/dist/ggnomad/components/PhotoGallery.js +54 -0
- package/dist/ggnomad/components/PhotoGallery.js.map +1 -0
- package/dist/ggnomad/components/ProviderCard.d.ts +19 -0
- package/dist/ggnomad/components/ProviderCard.d.ts.map +1 -0
- package/dist/ggnomad/components/ProviderCard.js +66 -0
- package/dist/ggnomad/components/ProviderCard.js.map +1 -0
- package/dist/ggnomad/components/RatingSummary.d.ts +14 -0
- package/dist/ggnomad/components/RatingSummary.d.ts.map +1 -0
- package/dist/ggnomad/components/RatingSummary.js +32 -0
- package/dist/ggnomad/components/RatingSummary.js.map +1 -0
- package/dist/ggnomad/components/TagChips.d.ts +16 -0
- package/dist/ggnomad/components/TagChips.d.ts.map +1 -0
- package/dist/ggnomad/components/TagChips.js +20 -0
- package/dist/ggnomad/components/TagChips.js.map +1 -0
- package/dist/ggnomad/components/index.d.ts +13 -0
- package/dist/ggnomad/components/index.d.ts.map +1 -1
- package/dist/ggnomad/components/index.js +9 -0
- package/dist/ggnomad/graphql.d.ts +10 -0
- package/dist/ggnomad/graphql.d.ts.map +1 -1
- package/dist/ggnomad/graphql.js +308 -20
- package/dist/ggnomad/graphql.js.map +1 -1
- package/dist/ggnomad/pages/ActivityDetailsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/ActivityDetailsPage.js +174 -86
- package/dist/ggnomad/pages/ActivityDetailsPage.js.map +1 -1
- package/dist/ggnomad/pages/AnalyticsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/AnalyticsPage.js +109 -77
- package/dist/ggnomad/pages/AnalyticsPage.js.map +1 -1
- package/dist/ggnomad/pages/BookingsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/BookingsPage.js +188 -137
- package/dist/ggnomad/pages/BookingsPage.js.map +1 -1
- package/dist/ggnomad/pages/DashboardPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/DashboardPage.js +245 -128
- package/dist/ggnomad/pages/DashboardPage.js.map +1 -1
- package/dist/ggnomad/pages/EntertainmentPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/EntertainmentPage.js +115 -53
- package/dist/ggnomad/pages/EntertainmentPage.js.map +1 -1
- package/dist/ggnomad/pages/EventDetailsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/EventDetailsPage.js +170 -87
- package/dist/ggnomad/pages/EventDetailsPage.js.map +1 -1
- package/dist/ggnomad/pages/FavoritesPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/FavoritesPage.js +201 -84
- package/dist/ggnomad/pages/FavoritesPage.js.map +1 -1
- package/dist/ggnomad/pages/HospitalityPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/HospitalityPage.js +99 -56
- package/dist/ggnomad/pages/HospitalityPage.js.map +1 -1
- package/dist/ggnomad/pages/PropertyDetailsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/PropertyDetailsPage.js +177 -93
- package/dist/ggnomad/pages/PropertyDetailsPage.js.map +1 -1
- package/dist/ggnomad/pages/ProviderPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/ProviderPage.js +112 -63
- package/dist/ggnomad/pages/ProviderPage.js.map +1 -1
- package/dist/ggnomad/pages/SearchPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/SearchPage.js +236 -65
- package/dist/ggnomad/pages/SearchPage.js.map +1 -1
- package/dist/ggnomad/pages/TourDetailsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/TourDetailsPage.js +171 -86
- package/dist/ggnomad/pages/TourDetailsPage.js.map +1 -1
- package/dist/ggnomad/pages/TourismPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/TourismPage.js +108 -54
- package/dist/ggnomad/pages/TourismPage.js.map +1 -1
- package/dist/ggnomad/pages/TravelPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/TravelPage.js +406 -43
- package/dist/ggnomad/pages/TravelPage.js.map +1 -1
- package/dist/ggnomad/pages/TripPlanDetailPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/TripPlanDetailPage.js +93 -70
- package/dist/ggnomad/pages/TripPlanDetailPage.js.map +1 -1
- package/dist/ggnomad/utils/format.d.ts +47 -0
- package/dist/ggnomad/utils/format.d.ts.map +1 -0
- package/dist/ggnomad/utils/format.js +125 -0
- package/dist/ggnomad/utils/format.js.map +1 -0
- package/dist/stories/BookingPanel.stories.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1,140 +1,225 @@
|
|
|
1
1
|
import { GGNOMAD_TOUR_QUERY as e } from "../graphql.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
import { humanizeEnum as t, jsonLabel as n } from "../utils/format.js";
|
|
3
|
+
import { PageShell as r } from "./PageShell.js";
|
|
4
|
+
import { StatusBadge as i } from "../components/StatusBadge.js";
|
|
5
|
+
import { SectionCard as a } from "../components/SectionCard.js";
|
|
6
|
+
import { DetailRow as o } from "../components/DetailRow.js";
|
|
7
|
+
import { DetailHero as s } from "../components/DetailHero.js";
|
|
8
|
+
import { useGGNomad as c } from "../providers/GGNomadProvider.js";
|
|
9
|
+
import { joinPath as l } from "../utils/navigation.js";
|
|
10
|
+
import { BookingPanel as u } from "../components/BookingPanel.js";
|
|
11
|
+
import { ReviewsSection as d } from "../components/ReviewsSection.js";
|
|
12
|
+
import { ListingEditDialog as f } from "../components/ListingEditDialog.js";
|
|
13
|
+
import { PhotoGallery as p } from "../components/PhotoGallery.js";
|
|
14
|
+
import { TagChips as m } from "../components/TagChips.js";
|
|
15
|
+
import { FactGrid as h } from "../components/FactGrid.js";
|
|
16
|
+
import { RatingSummary as g } from "../components/RatingSummary.js";
|
|
17
|
+
import { EcoAccessPanel as _ } from "../components/EcoAccessPanel.js";
|
|
18
|
+
import { ProviderCard as v } from "../components/ProviderCard.js";
|
|
19
|
+
import { AvailabilityPanel as y } from "../components/AvailabilityPanel.js";
|
|
11
20
|
import "../components/index.js";
|
|
12
|
-
import { useState as
|
|
13
|
-
import { CheckCircle2 as
|
|
14
|
-
import { useI18n as
|
|
15
|
-
import { useNavigate as
|
|
16
|
-
import { useQuery as
|
|
17
|
-
import { GlassCard as
|
|
18
|
-
import { Fragment as
|
|
21
|
+
import { useState as b } from "react";
|
|
22
|
+
import { CheckCircle2 as x, Clock as S, Compass as C, Gauge as w, Languages as T, MapPin as E, Pencil as D, UserRound as O, Users as k, Zap as A } from "lucide-react";
|
|
23
|
+
import { useI18n as j } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
24
|
+
import { useNavigate as M, useParams as N } from "react-router";
|
|
25
|
+
import { useQuery as P } from "@apollo/client/react";
|
|
26
|
+
import { GlassCard as F, IllustratedEmptyState as I, NextSteps as L, PagePurpose as R } from "@burdenoff/fe-libs/ui";
|
|
27
|
+
import { Fragment as z, jsx as B, jsxs as V } from "react/jsx-runtime";
|
|
19
28
|
//#region src/ggnomad/pages/TourDetailsPage.tsx
|
|
20
|
-
function
|
|
21
|
-
let { t:
|
|
22
|
-
variables: { id:
|
|
23
|
-
skip: !
|
|
24
|
-
}),
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
function H() {
|
|
30
|
+
let { t: H } = j(), U = M(), { basePath: W = "/" } = c(), { id: G = "" } = N(), [K, q] = b(!1), { data: J, refetch: Y } = P(e, {
|
|
31
|
+
variables: { id: G },
|
|
32
|
+
skip: !G
|
|
33
|
+
}), X = J?.ggnomadTour, Z = n(X?.location), Q = [];
|
|
34
|
+
return X && (Q.push({
|
|
35
|
+
id: "duration",
|
|
36
|
+
label: H("ggnomad.tour.duration", "Duration"),
|
|
37
|
+
value: X.duration,
|
|
38
|
+
icon: /* @__PURE__ */ B(S, {})
|
|
39
|
+
}), X.difficulty && Q.push({
|
|
40
|
+
id: "difficulty",
|
|
41
|
+
label: H("ggnomad.tour.difficulty", "Difficulty"),
|
|
42
|
+
value: t(X.difficulty),
|
|
43
|
+
icon: /* @__PURE__ */ B(w, {})
|
|
44
|
+
}), Q.push({
|
|
45
|
+
id: "group",
|
|
46
|
+
label: H("ggnomad.tour.maxGroupSize", "Max group size"),
|
|
47
|
+
value: String(X.maxGroupSize),
|
|
48
|
+
icon: /* @__PURE__ */ B(k, {})
|
|
49
|
+
}), X.languages.length > 0 && Q.push({
|
|
50
|
+
id: "languages",
|
|
51
|
+
label: H("ggnomad.tour.languages", "Languages"),
|
|
52
|
+
value: X.languages.join(", "),
|
|
53
|
+
icon: /* @__PURE__ */ B(T, {})
|
|
54
|
+
}), Z && Q.push({
|
|
55
|
+
id: "location",
|
|
56
|
+
label: H("ggnomad.tour.location", "Location"),
|
|
57
|
+
value: Z,
|
|
58
|
+
icon: /* @__PURE__ */ B(E, {})
|
|
59
|
+
}), X.guideName && Q.push({
|
|
60
|
+
id: "guide",
|
|
61
|
+
label: H("ggnomad.tour.guide", "Guide"),
|
|
62
|
+
value: X.guideName,
|
|
63
|
+
icon: /* @__PURE__ */ B(O, {})
|
|
64
|
+
})), /* @__PURE__ */ B(r, {
|
|
65
|
+
title: X?.name ?? H("ggnomad.tour.fallbackTitle", "Tour details"),
|
|
66
|
+
subtitle: H("ggnomad.tour.subtitle", "Tour package details and booking context"),
|
|
67
|
+
children: X ? /* @__PURE__ */ V(z, { children: [
|
|
68
|
+
X.images.length > 0 ? /* @__PURE__ */ B(p, {
|
|
69
|
+
images: X.images,
|
|
70
|
+
alt: X.name
|
|
71
|
+
}) : /* @__PURE__ */ B(s, { alt: X.name }),
|
|
72
|
+
/* @__PURE__ */ V("div", {
|
|
73
|
+
className: "flex flex-wrap items-center gap-3",
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ B("span", {
|
|
76
|
+
className: "rounded-full border border-border-seam bg-bg-sunken px-3 py-1 text-sm text-text-primary",
|
|
77
|
+
children: t(X.type)
|
|
78
|
+
}),
|
|
79
|
+
X.status ? /* @__PURE__ */ B(i, { status: X.status }) : null,
|
|
80
|
+
/* @__PURE__ */ B(g, {
|
|
81
|
+
rating: X.rating,
|
|
82
|
+
reviewCount: X.reviewCount
|
|
83
|
+
}),
|
|
84
|
+
X.instantBook ? /* @__PURE__ */ V("span", {
|
|
85
|
+
className: "inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-3 py-1 text-sm font-medium text-status-success-text",
|
|
86
|
+
children: [/* @__PURE__ */ B(A, {
|
|
87
|
+
className: "size-3.5",
|
|
88
|
+
"aria-hidden": "true"
|
|
89
|
+
}), H("ggnomad.listing.instantBook", "Instant book")]
|
|
90
|
+
}) : null
|
|
91
|
+
]
|
|
32
92
|
}),
|
|
33
|
-
/* @__PURE__ */
|
|
34
|
-
icon: /* @__PURE__ */ C
|
|
35
|
-
children:
|
|
93
|
+
/* @__PURE__ */ B(R, {
|
|
94
|
+
icon: /* @__PURE__ */ B(C, { className: "size-4" }),
|
|
95
|
+
children: H("ggnomad.tour.purpose", "See exactly what this tour involves — duration, difficulty, your guide, price and the highlights you’ll experience — so you can confirm it fits your trip before booking.")
|
|
36
96
|
}),
|
|
37
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ B(h, { facts: Q }),
|
|
98
|
+
/* @__PURE__ */ B(L, {
|
|
38
99
|
storageKey: "ggnomad-tour-detail",
|
|
39
100
|
steps: [{
|
|
40
101
|
id: "browse",
|
|
41
|
-
label:
|
|
42
|
-
description:
|
|
43
|
-
icon: /* @__PURE__ */ C
|
|
44
|
-
onClick: () =>
|
|
102
|
+
label: H("ggnomad.tour.next.browse", "Explore more experiences"),
|
|
103
|
+
description: H("ggnomad.tour.next.browseDesc", "Return to Tourism to compare tours and activities."),
|
|
104
|
+
icon: /* @__PURE__ */ B(C, { className: "size-4" }),
|
|
105
|
+
onClick: () => U(l(W, "tourism"))
|
|
45
106
|
}]
|
|
46
107
|
}),
|
|
47
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ V("div", {
|
|
48
109
|
className: "grid gap-4 lg:grid-cols-3",
|
|
49
|
-
children: [/* @__PURE__ */
|
|
110
|
+
children: [/* @__PURE__ */ V("div", {
|
|
50
111
|
className: "lg:col-span-2 space-y-4",
|
|
51
112
|
children: [
|
|
52
|
-
/* @__PURE__ */
|
|
113
|
+
X.description ? /* @__PURE__ */ B(a, {
|
|
114
|
+
title: H("ggnomad.tour.about", "About this tour"),
|
|
115
|
+
children: /* @__PURE__ */ B("p", {
|
|
116
|
+
className: "text-text-primary",
|
|
117
|
+
children: X.description
|
|
118
|
+
})
|
|
119
|
+
}) : null,
|
|
120
|
+
/* @__PURE__ */ V(F, {
|
|
53
121
|
treatment: "glass",
|
|
54
122
|
glow: !0,
|
|
55
123
|
className: "border-border-seam p-5",
|
|
56
|
-
children: [/* @__PURE__ */
|
|
124
|
+
children: [/* @__PURE__ */ V("div", {
|
|
57
125
|
className: "mb-4 flex items-center justify-between gap-3",
|
|
58
|
-
children: [/* @__PURE__ */
|
|
126
|
+
children: [/* @__PURE__ */ B("h2", {
|
|
59
127
|
className: "text-lg font-medium tracking-tight text-text-primary",
|
|
60
|
-
children:
|
|
61
|
-
}), /* @__PURE__ */
|
|
62
|
-
onClick: () =>
|
|
128
|
+
children: H("ggnomad.tour.details", "Details")
|
|
129
|
+
}), /* @__PURE__ */ B("button", {
|
|
130
|
+
onClick: () => q(!0),
|
|
63
131
|
className: "rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text",
|
|
64
|
-
"aria-label":
|
|
65
|
-
title:
|
|
66
|
-
children: /* @__PURE__ */
|
|
132
|
+
"aria-label": H("ggnomad.tour.editListing", "Edit listing"),
|
|
133
|
+
title: H("ggnomad.tour.editListing", "Edit listing"),
|
|
134
|
+
children: /* @__PURE__ */ B(D, { className: "size-4" })
|
|
67
135
|
})]
|
|
68
|
-
}), /* @__PURE__ */
|
|
136
|
+
}), /* @__PURE__ */ V("dl", {
|
|
69
137
|
className: "space-y-2 text-sm",
|
|
70
138
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
72
|
-
label:
|
|
73
|
-
value:
|
|
139
|
+
/* @__PURE__ */ B(o, {
|
|
140
|
+
label: H("ggnomad.tour.duration", "Duration"),
|
|
141
|
+
value: X.duration
|
|
74
142
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
-
label:
|
|
77
|
-
value:
|
|
143
|
+
/* @__PURE__ */ B(o, {
|
|
144
|
+
label: H("ggnomad.tour.difficulty", "Difficulty"),
|
|
145
|
+
value: X.difficulty ? t(X.difficulty) : H("ggnomad.tour.na", "N/A")
|
|
78
146
|
}),
|
|
79
|
-
/* @__PURE__ */
|
|
80
|
-
label:
|
|
81
|
-
value:
|
|
147
|
+
/* @__PURE__ */ B(o, {
|
|
148
|
+
label: H("ggnomad.tour.guide", "Guide"),
|
|
149
|
+
value: X.guideName ?? H("ggnomad.tour.na", "N/A")
|
|
82
150
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
-
label:
|
|
85
|
-
value: `${
|
|
151
|
+
/* @__PURE__ */ B(o, {
|
|
152
|
+
label: H("ggnomad.tour.price", "Price per person"),
|
|
153
|
+
value: `${X.currency} ${Number(X.price).toFixed(2)}`
|
|
86
154
|
})
|
|
87
155
|
]
|
|
88
156
|
})]
|
|
89
157
|
}),
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
title:
|
|
92
|
-
children: /* @__PURE__ */
|
|
158
|
+
X.highlights.length > 0 ? /* @__PURE__ */ B(a, {
|
|
159
|
+
title: H("ggnomad.tour.highlights", "Highlights"),
|
|
160
|
+
children: /* @__PURE__ */ B("ul", {
|
|
93
161
|
className: "space-y-2 text-sm",
|
|
94
|
-
children:
|
|
162
|
+
children: X.highlights.map((e) => /* @__PURE__ */ V("li", {
|
|
95
163
|
className: "flex items-start gap-2 text-text-primary",
|
|
96
|
-
children: [/* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ B(x, {
|
|
97
165
|
className: "mt-0.5 size-4 flex-shrink-0 text-status-success-text",
|
|
98
166
|
"aria-hidden": "true"
|
|
99
167
|
}), e]
|
|
100
168
|
}, e))
|
|
101
169
|
})
|
|
170
|
+
}) : null,
|
|
171
|
+
X.languages.length > 0 ? /* @__PURE__ */ B(a, {
|
|
172
|
+
title: H("ggnomad.tour.languagesTitle", "Guided in"),
|
|
173
|
+
children: /* @__PURE__ */ B(m, {
|
|
174
|
+
items: X.languages,
|
|
175
|
+
icon: /* @__PURE__ */ B(T, {})
|
|
176
|
+
})
|
|
177
|
+
}) : null,
|
|
178
|
+
/* @__PURE__ */ B(_, {
|
|
179
|
+
sustainabilityScore: X.sustainabilityScore,
|
|
180
|
+
sustainabilityPractices: X.sustainabilityPractices,
|
|
181
|
+
accessibilityFeatures: X.accessibilityFeatures
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ B(y, {
|
|
184
|
+
listingId: X.id ?? G,
|
|
185
|
+
listingType: "TOUR"
|
|
102
186
|
}),
|
|
103
|
-
/* @__PURE__ */
|
|
187
|
+
X.provider ? /* @__PURE__ */ B(v, { provider: X.provider }) : null,
|
|
188
|
+
/* @__PURE__ */ B(d, {
|
|
104
189
|
targetType: "TOUR",
|
|
105
|
-
targetId:
|
|
190
|
+
targetId: X.id ?? G
|
|
106
191
|
})
|
|
107
192
|
]
|
|
108
|
-
}), /* @__PURE__ */
|
|
193
|
+
}), /* @__PURE__ */ B("div", { children: /* @__PURE__ */ B(u, {
|
|
109
194
|
bookingType: "TOUR",
|
|
110
|
-
itemId:
|
|
111
|
-
itemName:
|
|
112
|
-
unitPrice:
|
|
113
|
-
currency:
|
|
195
|
+
itemId: X.id ?? G,
|
|
196
|
+
itemName: X.name,
|
|
197
|
+
unitPrice: X.price ?? 0,
|
|
198
|
+
currency: X.currency ?? "USD"
|
|
114
199
|
}) })]
|
|
115
200
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
open:
|
|
118
|
-
onOpenChange:
|
|
201
|
+
/* @__PURE__ */ B(f, {
|
|
202
|
+
open: K,
|
|
203
|
+
onOpenChange: q,
|
|
119
204
|
targetType: "TOUR",
|
|
120
|
-
id:
|
|
205
|
+
id: X.id ?? G,
|
|
121
206
|
initial: {
|
|
122
|
-
name:
|
|
123
|
-
description:
|
|
124
|
-
price:
|
|
125
|
-
status:
|
|
126
|
-
images:
|
|
207
|
+
name: X.name,
|
|
208
|
+
description: X.description ?? void 0,
|
|
209
|
+
price: X.price,
|
|
210
|
+
status: X.status,
|
|
211
|
+
images: X.images
|
|
127
212
|
},
|
|
128
|
-
onSaved: () =>
|
|
213
|
+
onSaved: () => Y()
|
|
129
214
|
})
|
|
130
|
-
] }) : /* @__PURE__ */
|
|
215
|
+
] }) : /* @__PURE__ */ B(I, {
|
|
131
216
|
illustration: "empty-data",
|
|
132
|
-
title:
|
|
133
|
-
description:
|
|
217
|
+
title: H("ggnomad.tour.notFoundTitle", "No tour found"),
|
|
218
|
+
description: H("ggnomad.tour.notFoundDescription", "This tour is unavailable or may have been removed.")
|
|
134
219
|
})
|
|
135
220
|
});
|
|
136
221
|
}
|
|
137
222
|
//#endregion
|
|
138
|
-
export {
|
|
223
|
+
export { H as TourDetailsPage };
|
|
139
224
|
|
|
140
225
|
//# sourceMappingURL=TourDetailsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourDetailsPage.js","names":[],"sources":["../../../src/ggnomad/pages/TourDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate, useParams } from 'react-router';\nimport { CheckCircle2, Compass, Pencil } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_TOUR_QUERY } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { PageShell } from './PageShell';\nimport {\n DetailRow,\n SectionCard,\n DetailHero,\n BookingPanel,\n ReviewsSection,\n ListingEditDialog,\n} from '../components';\n\nexport function TourDetailsPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n const { id = '' } = useParams();\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const { data, refetch } = useQuery(\n GGNOMAD_TOUR_QUERY as TypedDocumentNode<\n {\n ggnomadTour: {\n id: string;\n name: string;\n description?: string;\n duration: string;\n difficulty?: string;\n guideName?: string;\n currency: string;\n price: number;\n status?: string;\n highlights: string[];\n images?: string[];\n } | null;\n },\n { id: string }\n >,\n { variables: { id }, skip: !id }\n );\n const tour = data?.ggnomadTour;\n\n return (\n <PageShell\n title={tour?.name ?? t('ggnomad.tour.fallbackTitle', 'Tour details')}\n subtitle={t('ggnomad.tour.subtitle', 'Tour package details and booking context')}\n >\n {!tour ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.tour.notFoundTitle', 'No tour found')}\n description={t(\n 'ggnomad.tour.notFoundDescription',\n 'This tour is unavailable or may have been removed.'\n )}\n />\n ) : (\n <>\n <DetailHero image={tour.images?.[0]} alt={tour.name} />\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.tour.purpose',\n 'See exactly what this tour involves — duration, difficulty, your guide, price and the highlights you’ll experience — so you can confirm it fits your trip before booking.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-tour-detail\"\n steps={[\n {\n id: 'browse',\n label: t('ggnomad.tour.next.browse', 'Explore more experiences'),\n description: t(\n 'ggnomad.tour.next.browseDesc',\n 'Return to Tourism to compare tours and activities.'\n ),\n icon: <Compass className=\"size-4\" />,\n onClick: () => navigate(joinPath(basePath, 'tourism')),\n },\n ]}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.tour.details', 'Details')}\n </h2>\n <button\n onClick={() => setEditDialogOpen(true)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text\"\n aria-label={t('ggnomad.tour.editListing', 'Edit listing')}\n title={t('ggnomad.tour.editListing', 'Edit listing')}\n >\n <Pencil className=\"size-4\" />\n </button>\n </div>\n <dl className=\"space-y-2 text-sm\">\n <DetailRow label={t('ggnomad.tour.duration', 'Duration')} value={tour.duration} />\n <DetailRow\n label={t('ggnomad.tour.difficulty', 'Difficulty')}\n value={tour.difficulty ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.guide', 'Guide')}\n value={tour.guideName ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.price', 'Price')}\n value={`${tour.currency} ${Number(tour.price).toFixed(2)}`}\n />\n </dl>\n </GlassCard>\n <SectionCard title={t('ggnomad.tour.highlights', 'Highlights')}>\n <ul className=\"space-y-2 text-sm\">\n {(tour.highlights ?? []).map((highlight) => (\n <li key={highlight} className=\"flex items-start gap-2 text-text-primary\">\n <CheckCircle2\n className=\"mt-0.5 size-4 flex-shrink-0 text-status-success-text\"\n aria-hidden=\"true\"\n />\n {highlight}\n </li>\n ))}\n </ul>\n </SectionCard>\n <ReviewsSection targetType=\"TOUR\" targetId={tour.id ?? id} />\n </div>\n <div>\n <BookingPanel\n bookingType=\"TOUR\"\n itemId={tour.id ?? id}\n itemName={tour.name}\n unitPrice={tour.price ?? 0}\n currency={tour.currency ?? 'USD'}\n />\n </div>\n </div>\n\n <ListingEditDialog\n open={editDialogOpen}\n onOpenChange={setEditDialogOpen}\n targetType=\"TOUR\"\n id={tour.id ?? id}\n initial={{\n name: tour.name,\n description: tour.description,\n price: tour.price,\n status: tour.status,\n images: tour.images,\n }}\n onSaved={() => refetch()}\n />\n </>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TourDetailsPage.js","names":[],"sources":["../../../src/ggnomad/pages/TourDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate, useParams } from 'react-router';\nimport {\n CheckCircle2,\n Clock,\n Compass,\n Gauge,\n Languages as LanguagesIcon,\n MapPin,\n Pencil,\n UserRound,\n Users,\n Zap,\n} from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_TOUR_QUERY } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { humanizeEnum, jsonLabel } from '../utils/format';\nimport { PageShell } from './PageShell';\nimport {\n AvailabilityPanel,\n BookingPanel,\n DetailHero,\n DetailRow,\n EcoAccessPanel,\n FactGrid,\n ListingEditDialog,\n PhotoGallery,\n ProviderCard,\n RatingSummary,\n ReviewsSection,\n SectionCard,\n StatusBadge,\n TagChips,\n} from '../components';\nimport type { Fact } from '../components';\n\ntype TourDetail = {\n id: string;\n name: string;\n description?: string | null;\n type: string;\n status?: string;\n duration: string;\n difficulty?: string | null;\n guideName?: string | null;\n currency: string;\n price: number;\n rating?: number | null;\n reviewCount: number;\n highlights: string[];\n images: string[];\n languages: string[];\n location?: unknown;\n maxGroupSize: number;\n instantBook: boolean;\n sustainabilityScore: number;\n sustainabilityPractices: string[];\n accessibilityFeatures: string[];\n provider?: {\n id: string;\n name: string;\n type?: string | null;\n rating?: number | null;\n reviewCount?: number | null;\n listingCount?: number | null;\n contactEmail?: string | null;\n website?: string | null;\n } | null;\n};\n\nexport function TourDetailsPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n const { id = '' } = useParams();\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const { data, refetch } = useQuery(\n GGNOMAD_TOUR_QUERY as TypedDocumentNode<{ ggnomadTour: TourDetail | null }, { id: string }>,\n { variables: { id }, skip: !id }\n );\n const tour = data?.ggnomadTour;\n const locationLabel = jsonLabel(tour?.location);\n\n const facts: Fact[] = [];\n if (tour) {\n facts.push({\n id: 'duration',\n label: t('ggnomad.tour.duration', 'Duration'),\n value: tour.duration,\n icon: <Clock />,\n });\n if (tour.difficulty) {\n facts.push({\n id: 'difficulty',\n label: t('ggnomad.tour.difficulty', 'Difficulty'),\n value: humanizeEnum(tour.difficulty),\n icon: <Gauge />,\n });\n }\n facts.push({\n id: 'group',\n label: t('ggnomad.tour.maxGroupSize', 'Max group size'),\n value: String(tour.maxGroupSize),\n icon: <Users />,\n });\n if (tour.languages.length > 0) {\n facts.push({\n id: 'languages',\n label: t('ggnomad.tour.languages', 'Languages'),\n value: tour.languages.join(', '),\n icon: <LanguagesIcon />,\n });\n }\n if (locationLabel) {\n facts.push({\n id: 'location',\n label: t('ggnomad.tour.location', 'Location'),\n value: locationLabel,\n icon: <MapPin />,\n });\n }\n if (tour.guideName) {\n facts.push({\n id: 'guide',\n label: t('ggnomad.tour.guide', 'Guide'),\n value: tour.guideName,\n icon: <UserRound />,\n });\n }\n }\n\n return (\n <PageShell\n title={tour?.name ?? t('ggnomad.tour.fallbackTitle', 'Tour details')}\n subtitle={t('ggnomad.tour.subtitle', 'Tour package details and booking context')}\n >\n {!tour ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.tour.notFoundTitle', 'No tour found')}\n description={t(\n 'ggnomad.tour.notFoundDescription',\n 'This tour is unavailable or may have been removed.'\n )}\n />\n ) : (\n <>\n {tour.images.length > 0 ? (\n <PhotoGallery images={tour.images} alt={tour.name} />\n ) : (\n <DetailHero alt={tour.name} />\n )}\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"rounded-full border border-border-seam bg-bg-sunken px-3 py-1 text-sm text-text-primary\">\n {humanizeEnum(tour.type)}\n </span>\n {tour.status ? <StatusBadge status={tour.status} /> : null}\n <RatingSummary rating={tour.rating} reviewCount={tour.reviewCount} />\n {tour.instantBook ? (\n <span className=\"inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-3 py-1 text-sm font-medium text-status-success-text\">\n <Zap className=\"size-3.5\" aria-hidden=\"true\" />\n {t('ggnomad.listing.instantBook', 'Instant book')}\n </span>\n ) : null}\n </div>\n\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.tour.purpose',\n 'See exactly what this tour involves — duration, difficulty, your guide, price and the highlights you’ll experience — so you can confirm it fits your trip before booking.'\n )}\n </PagePurpose>\n\n <FactGrid facts={facts} />\n\n <NextSteps\n storageKey=\"ggnomad-tour-detail\"\n steps={[\n {\n id: 'browse',\n label: t('ggnomad.tour.next.browse', 'Explore more experiences'),\n description: t(\n 'ggnomad.tour.next.browseDesc',\n 'Return to Tourism to compare tours and activities.'\n ),\n icon: <Compass className=\"size-4\" />,\n onClick: () => navigate(joinPath(basePath, 'tourism')),\n },\n ]}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n {tour.description ? (\n <SectionCard title={t('ggnomad.tour.about', 'About this tour')}>\n <p className=\"text-text-primary\">{tour.description}</p>\n </SectionCard>\n ) : null}\n\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.tour.details', 'Details')}\n </h2>\n <button\n onClick={() => setEditDialogOpen(true)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text\"\n aria-label={t('ggnomad.tour.editListing', 'Edit listing')}\n title={t('ggnomad.tour.editListing', 'Edit listing')}\n >\n <Pencil className=\"size-4\" />\n </button>\n </div>\n <dl className=\"space-y-2 text-sm\">\n <DetailRow label={t('ggnomad.tour.duration', 'Duration')} value={tour.duration} />\n <DetailRow\n label={t('ggnomad.tour.difficulty', 'Difficulty')}\n value={\n tour.difficulty ? humanizeEnum(tour.difficulty) : t('ggnomad.tour.na', 'N/A')\n }\n />\n <DetailRow\n label={t('ggnomad.tour.guide', 'Guide')}\n value={tour.guideName ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.price', 'Price per person')}\n value={`${tour.currency} ${Number(tour.price).toFixed(2)}`}\n />\n </dl>\n </GlassCard>\n\n {tour.highlights.length > 0 ? (\n <SectionCard title={t('ggnomad.tour.highlights', 'Highlights')}>\n <ul className=\"space-y-2 text-sm\">\n {tour.highlights.map((highlight) => (\n <li key={highlight} className=\"flex items-start gap-2 text-text-primary\">\n <CheckCircle2\n className=\"mt-0.5 size-4 flex-shrink-0 text-status-success-text\"\n aria-hidden=\"true\"\n />\n {highlight}\n </li>\n ))}\n </ul>\n </SectionCard>\n ) : null}\n\n {tour.languages.length > 0 ? (\n <SectionCard title={t('ggnomad.tour.languagesTitle', 'Guided in')}>\n <TagChips items={tour.languages} icon={<LanguagesIcon />} />\n </SectionCard>\n ) : null}\n\n <EcoAccessPanel\n sustainabilityScore={tour.sustainabilityScore}\n sustainabilityPractices={tour.sustainabilityPractices}\n accessibilityFeatures={tour.accessibilityFeatures}\n />\n\n <AvailabilityPanel listingId={tour.id ?? id} listingType=\"TOUR\" />\n\n {tour.provider ? <ProviderCard provider={tour.provider} /> : null}\n\n <ReviewsSection targetType=\"TOUR\" targetId={tour.id ?? id} />\n </div>\n <div>\n <BookingPanel\n bookingType=\"TOUR\"\n itemId={tour.id ?? id}\n itemName={tour.name}\n unitPrice={tour.price ?? 0}\n currency={tour.currency ?? 'USD'}\n />\n </div>\n </div>\n\n <ListingEditDialog\n open={editDialogOpen}\n onOpenChange={setEditDialogOpen}\n targetType=\"TOUR\"\n id={tour.id ?? id}\n initial={{\n name: tour.name,\n description: tour.description ?? undefined,\n price: tour.price,\n status: tour.status,\n images: tour.images,\n }}\n onSaved={() => refetch()}\n />\n </>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourismPage.d.ts","sourceRoot":"","sources":["../../../src/ggnomad/pages/TourismPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TourismPage.d.ts","sourceRoot":"","sources":["../../../src/ggnomad/pages/TourismPage.tsx"],"names":[],"mappings":"AA8CA,wBAAgB,WAAW,gCAyK1B"}
|
|
@@ -1,79 +1,133 @@
|
|
|
1
1
|
import { GGNOMAD_ACTIVITIES_QUERY as e, GGNOMAD_TOURS_QUERY as t } from "../graphql.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { humanizeEnum as n } from "../utils/format.js";
|
|
3
|
+
import { PageShell as r } from "./PageShell.js";
|
|
4
|
+
import { SectionCard as i } from "../components/SectionCard.js";
|
|
5
|
+
import { EntityCard as a } from "../components/EntityCard.js";
|
|
6
|
+
import { LoadMoreButton as o } from "../components/LoadMoreButton.js";
|
|
7
|
+
import { RatingSummary as s } from "../components/RatingSummary.js";
|
|
8
|
+
import { EMPTY_LISTING_FILTERS as c, ListingFilters as l, hasActiveListingFilters as u } from "../components/ListingFilters.js";
|
|
6
9
|
import "../components/index.js";
|
|
7
|
-
import { useState as
|
|
8
|
-
import { Compass as
|
|
9
|
-
import { useI18n as
|
|
10
|
-
import { useQuery as
|
|
11
|
-
import { EmphasisPanel as
|
|
12
|
-
import { jsx as
|
|
10
|
+
import { useState as d } from "react";
|
|
11
|
+
import { Clock as f, Compass as p, Gauge as m, Leaf as h, Zap as g } from "lucide-react";
|
|
12
|
+
import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
13
|
+
import { useQuery as v } from "@apollo/client/react";
|
|
14
|
+
import { EmphasisPanel as y, IllustratedEmptyState as b, PagePurpose as x } from "@burdenoff/fe-libs/ui";
|
|
15
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
13
16
|
//#region src/ggnomad/pages/TourismPage.tsx
|
|
14
|
-
function
|
|
15
|
-
let { t:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
function w() {
|
|
18
|
+
let { t: w } = _(), [T, E] = d(12), [D, O] = d(12), [k, A] = d(c), j = {
|
|
19
|
+
status: k.status,
|
|
20
|
+
minSustainabilityScore: k.minSustainabilityScore,
|
|
21
|
+
hasAccessibilityFeatures: k.accessibilityFeatures.length > 0 ? k.accessibilityFeatures : void 0
|
|
22
|
+
}, { data: M } = v(t, { variables: {
|
|
23
|
+
limit: T,
|
|
24
|
+
offset: 0,
|
|
25
|
+
...j
|
|
26
|
+
} }), { data: N } = v(e, { variables: {
|
|
27
|
+
limit: D,
|
|
28
|
+
offset: 0,
|
|
29
|
+
...j
|
|
30
|
+
} }), P = M?.ggnomadTours ?? [], F = N?.ggnomadActivities ?? [], I = u(k), L = (e, t, r) => e.length === 0 ? /* @__PURE__ */ S(b, {
|
|
22
31
|
illustration: "empty-data",
|
|
23
|
-
title:
|
|
24
|
-
description:
|
|
25
|
-
}) : /* @__PURE__ */
|
|
32
|
+
title: I ? w("ggnomad.tourism.noMatchTitle", "Nothing matches these filters") : r,
|
|
33
|
+
description: I ? w("ggnomad.tourism.noMatchDescription", "Try clearing a filter — status, sustainability score and accessibility all narrow the catalogue.") : w("ggnomad.tourism.emptyDescription", "Curated experiences will appear here once published.")
|
|
34
|
+
}) : /* @__PURE__ */ S("div", {
|
|
26
35
|
className: "grid gap-3",
|
|
27
|
-
children: e.map((e) => /* @__PURE__ */
|
|
36
|
+
children: e.map((e) => /* @__PURE__ */ S(a, {
|
|
28
37
|
to: `${t}/${e.id}`,
|
|
29
38
|
image: e.images?.[0],
|
|
30
39
|
imageAlt: e.name,
|
|
31
40
|
title: e.name,
|
|
32
|
-
meta: e.
|
|
33
|
-
|
|
41
|
+
meta: n(e.type ?? e.category ?? ""),
|
|
42
|
+
badge: e.instantBook ? /* @__PURE__ */ C("span", {
|
|
43
|
+
className: "inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2.5 py-0.5 text-xs font-medium text-status-success-text",
|
|
44
|
+
children: [/* @__PURE__ */ S(g, {
|
|
45
|
+
className: "size-3",
|
|
46
|
+
"aria-hidden": "true"
|
|
47
|
+
}), w("ggnomad.listing.instantBook", "Instant book")]
|
|
48
|
+
}) : null,
|
|
49
|
+
price: `${e.currency} ${Number(e.price).toFixed(2)}`,
|
|
50
|
+
footer: /* @__PURE__ */ C("div", {
|
|
51
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1",
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ C("span", {
|
|
54
|
+
className: "inline-flex items-center gap-1",
|
|
55
|
+
children: [/* @__PURE__ */ S(f, {
|
|
56
|
+
className: "size-3.5",
|
|
57
|
+
"aria-hidden": "true"
|
|
58
|
+
}), e.duration]
|
|
59
|
+
}),
|
|
60
|
+
e.difficulty ? /* @__PURE__ */ C("span", {
|
|
61
|
+
className: "inline-flex items-center gap-1",
|
|
62
|
+
children: [/* @__PURE__ */ S(m, {
|
|
63
|
+
className: "size-3.5",
|
|
64
|
+
"aria-hidden": "true"
|
|
65
|
+
}), n(e.difficulty)]
|
|
66
|
+
}) : null,
|
|
67
|
+
/* @__PURE__ */ S(s, {
|
|
68
|
+
rating: e.rating,
|
|
69
|
+
reviewCount: e.reviewCount
|
|
70
|
+
}),
|
|
71
|
+
e.sustainabilityScore > 0 ? /* @__PURE__ */ C("span", {
|
|
72
|
+
className: "inline-flex items-center gap-1 tabular-nums text-status-success-text",
|
|
73
|
+
children: [/* @__PURE__ */ S(h, {
|
|
74
|
+
className: "size-3.5",
|
|
75
|
+
"aria-hidden": "true"
|
|
76
|
+
}), e.sustainabilityScore]
|
|
77
|
+
}) : null
|
|
78
|
+
]
|
|
79
|
+
})
|
|
34
80
|
}, e.id))
|
|
35
81
|
});
|
|
36
|
-
return /* @__PURE__ */
|
|
37
|
-
title:
|
|
38
|
-
titleAccent:
|
|
39
|
-
subtitle:
|
|
82
|
+
return /* @__PURE__ */ C(r, {
|
|
83
|
+
title: w("ggnomad.tourism.title", "Tourism"),
|
|
84
|
+
titleAccent: w("ggnomad.tourism.title.accent", "Tourism"),
|
|
85
|
+
subtitle: w("ggnomad.tourism.subtitle", "Tours and curated activity experiences"),
|
|
40
86
|
children: [
|
|
41
|
-
/* @__PURE__ */
|
|
42
|
-
icon: /* @__PURE__ */ p
|
|
43
|
-
children:
|
|
87
|
+
/* @__PURE__ */ S(x, {
|
|
88
|
+
icon: /* @__PURE__ */ S(p, { className: "size-4" }),
|
|
89
|
+
children: w("ggnomad.tourism.purpose", "Plan what you’ll actually do at a destination — guided tours and bookable activities curated by local operators. Open any experience to review duration, price and what’s included, then add it to a booking.")
|
|
44
90
|
}),
|
|
45
|
-
/* @__PURE__ */
|
|
91
|
+
/* @__PURE__ */ C(y, { children: [/* @__PURE__ */ C("div", {
|
|
46
92
|
className: "grid gap-4 sm:grid-cols-2",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
93
|
+
children: [/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
48
94
|
className: "text-sm text-text-secondary",
|
|
49
|
-
children:
|
|
50
|
-
}), /* @__PURE__ */
|
|
95
|
+
children: w("ggnomad.tourism.tours", "Tours")
|
|
96
|
+
}), /* @__PURE__ */ S("p", {
|
|
51
97
|
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
52
|
-
children:
|
|
53
|
-
})] }), /* @__PURE__ */
|
|
98
|
+
children: P.length
|
|
99
|
+
})] }), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
54
100
|
className: "text-sm text-text-secondary",
|
|
55
|
-
children:
|
|
56
|
-
}), /* @__PURE__ */
|
|
101
|
+
children: w("ggnomad.tourism.activities", "Activities")
|
|
102
|
+
}), /* @__PURE__ */ S("p", {
|
|
57
103
|
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
58
|
-
children:
|
|
104
|
+
children: F.length
|
|
59
105
|
})] })]
|
|
60
|
-
}), /* @__PURE__ */
|
|
106
|
+
}), /* @__PURE__ */ S("p", {
|
|
61
107
|
className: "mt-4 text-sm text-text-secondary",
|
|
62
|
-
children:
|
|
108
|
+
children: w("ggnomad.tourism.emphasisNote", "Curated, bookable experiences across your destinations — pick a tour or activity below to see full details.")
|
|
63
109
|
})] }),
|
|
64
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ S(l, {
|
|
111
|
+
idPrefix: "ggnomad-tourism",
|
|
112
|
+
value: k,
|
|
113
|
+
onChange: (e) => {
|
|
114
|
+
E(12), O(12), A(e);
|
|
115
|
+
},
|
|
116
|
+
resultCount: P.length + F.length
|
|
117
|
+
}),
|
|
118
|
+
/* @__PURE__ */ C("div", {
|
|
65
119
|
className: "grid gap-6 lg:grid-cols-2",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
67
|
-
title:
|
|
68
|
-
children: [
|
|
69
|
-
visible:
|
|
70
|
-
onLoadMore: () =>
|
|
120
|
+
children: [/* @__PURE__ */ C(i, {
|
|
121
|
+
title: w("ggnomad.tourism.tours", "Tours"),
|
|
122
|
+
children: [L(P, "tours", w("ggnomad.tourism.toursEmpty", "No tours yet")), /* @__PURE__ */ S(o, {
|
|
123
|
+
visible: P.length >= T,
|
|
124
|
+
onLoadMore: () => E((e) => e + 12)
|
|
71
125
|
})]
|
|
72
|
-
}), /* @__PURE__ */
|
|
73
|
-
title:
|
|
74
|
-
children: [
|
|
75
|
-
visible:
|
|
76
|
-
onLoadMore: () =>
|
|
126
|
+
}), /* @__PURE__ */ C(i, {
|
|
127
|
+
title: w("ggnomad.tourism.activities", "Activities"),
|
|
128
|
+
children: [L(F, "activities", w("ggnomad.tourism.activitiesEmpty", "No activities yet")), /* @__PURE__ */ S(o, {
|
|
129
|
+
visible: F.length >= D,
|
|
130
|
+
onLoadMore: () => O((e) => e + 12)
|
|
77
131
|
})]
|
|
78
132
|
})]
|
|
79
133
|
})
|
|
@@ -81,6 +135,6 @@ function h() {
|
|
|
81
135
|
});
|
|
82
136
|
}
|
|
83
137
|
//#endregion
|
|
84
|
-
export {
|
|
138
|
+
export { w as TourismPage };
|
|
85
139
|
|
|
86
140
|
//# sourceMappingURL=TourismPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourismPage.js","names":[],"sources":["../../../src/ggnomad/pages/TourismPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Compass } from 'lucide-react';\nimport { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_ACTIVITIES_QUERY, GGNOMAD_TOURS_QUERY } from '../graphql';\nimport { PageShell } from './PageShell';\nimport { EntityCard, SectionCard, LoadMoreButton } from '../components';\n\ntype TourismItem = {\n images?: string[];\n id: string;\n name: string;\n duration: string;\n price: number;\n currency: string;\n};\n\nexport function TourismPage() {\n const { t } = useI18n();\n const [tourLimit, setTourLimit] = useState(12);\n const [activityLimit, setActivityLimit] = useState(12);\n const { data: toursData } = useQuery(\n GGNOMAD_TOURS_QUERY as TypedDocumentNode<\n { ggnomadTours: TourismItem[] },\n { limit: number; offset: number }\n >,\n {\n variables: { limit: tourLimit, offset: 0 },\n }\n );\n const { data: activitiesData } = useQuery(\n GGNOMAD_ACTIVITIES_QUERY as TypedDocumentNode<\n { ggnomadActivities: TourismItem[] },\n { limit: number; offset: number }\n >,\n { variables: { limit: activityLimit, offset: 0 } }\n );\n const tours = toursData?.ggnomadTours ?? [];\n const activities = activitiesData?.ggnomadActivities ?? [];\n\n const renderList = (items: TourismItem[], basePath: string, emptyLabel: string) => {\n if (items.length === 0) {\n return (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={emptyLabel}\n description={t(\n 'ggnomad.tourism.emptyDescription',\n 'Curated experiences will appear here once published.'\n )}\n />\n );\n }\n return (\n <div className=\"grid gap-3\">\n {items.map((item) => (\n <EntityCard\n key={item.id}\n to={`${basePath}/${item.id}`}\n image={item.images?.[0]}\n imageAlt={item.name}\n title={item.name}\n meta={item.duration}\n price={`${item.currency} ${Number(item.price).toFixed(2)}`}\n />\n ))}\n </div>\n );\n };\n\n return (\n <PageShell\n title={t('ggnomad.tourism.title', 'Tourism')}\n titleAccent={t('ggnomad.tourism.title.accent', 'Tourism')}\n subtitle={t('ggnomad.tourism.subtitle', 'Tours and curated activity experiences')}\n >\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.tourism.purpose',\n 'Plan what you’ll actually do at a destination — guided tours and bookable activities curated by local operators. Open any experience to review duration, price and what’s included, then add it to a booking.'\n )}\n </PagePurpose>\n\n <EmphasisPanel>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <p className=\"text-sm text-text-secondary\">{t('ggnomad.tourism.tours', 'Tours')}</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {tours.length}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.tourism.activities', 'Activities')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {activities.length}\n </p>\n </div>\n </div>\n <p className=\"mt-4 text-sm text-text-secondary\">\n {t(\n 'ggnomad.tourism.emphasisNote',\n 'Curated, bookable experiences across your destinations — pick a tour or activity below to see full details.'\n )}\n </p>\n </EmphasisPanel>\n\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <SectionCard title={t('ggnomad.tourism.tours', 'Tours')}>\n {renderList(tours, 'tours', t('ggnomad.tourism.toursEmpty', 'No tours yet'))}\n <LoadMoreButton\n visible={tours.length >= tourLimit}\n onLoadMore={() => setTourLimit((l) => l + 12)}\n />\n </SectionCard>\n <SectionCard title={t('ggnomad.tourism.activities', 'Activities')}>\n {renderList(\n activities,\n 'activities',\n t('ggnomad.tourism.activitiesEmpty', 'No activities yet')\n )}\n <LoadMoreButton\n visible={activities.length >= activityLimit}\n onLoadMore={() => setActivityLimit((l) => l + 12)}\n />\n </SectionCard>\n </div>\n </PageShell>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,SAAgB,IAAc;CAC5B,IAAM,EAAE,SAAM,EAAQ,GAChB,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAe,KAAoB,EAAS,EAAE,GAC/C,EAAE,MAAM,MAAc,EAC1B,GAIA,EACE,WAAW;EAAE,OAAO;EAAW,QAAQ;CAAE,EAC3C,CACF,GACM,EAAE,MAAM,MAAmB,EAC/B,GAIA,EAAE,WAAW;EAAE,OAAO;EAAe,QAAQ;CAAE,EAAE,CACnD,GACM,IAAQ,GAAW,gBAAgB,CAAC,GACpC,IAAa,GAAgB,qBAAqB,CAAC,GAEnD,KAAc,GAAsB,GAAkB,MACtD,EAAM,WAAW,IAEjB,kBAAC,GAAD;EACE,cAAa;EACb,OAAO;EACP,aAAa,EACX,oCACA,sDACF;CACD,CAAA,IAIH,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAM,KAAK,MACV,kBAAC,GAAD;GAEE,IAAI,GAAG,EAAS,GAAG,EAAK;GACxB,OAAO,EAAK,SAAS;GACrB,UAAU,EAAK;GACf,OAAO,EAAK;GACZ,MAAM,EAAK;GACX,OAAO,GAAG,EAAK,SAAS,GAAG,OAAO,EAAK,KAAK,EAAE,QAAQ,CAAC;EACxD,GAPM,EAAK,EAOX,CACF;CACE,CAAA;CAIT,OACE,kBAAC,GAAD;EACE,OAAO,EAAE,yBAAyB,SAAS;EAC3C,aAAa,EAAE,gCAAgC,SAAS;EACxD,UAAU,EAAE,4BAA4B,wCAAwC;YAHlF;GAKE,kBAAC,GAAD;IAAa,MAAM,kBAAC,GAAD,EAAS,WAAU,SAAU,CAAA;cAC7C,EACC,2BACA,+MACF;GACW,CAAA;GAEb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eAA+B,EAAE,yBAAyB,OAAO;IAAK,CAAA,GACnF,kBAAC,KAAD;KAAG,WAAU;eACV,EAAM;IACN,CAAA,CACA,EAAA,CAAA,GACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eACV,EAAE,8BAA8B,YAAY;IAC5C,CAAA,GACH,kBAAC,KAAD;KAAG,WAAU;eACV,EAAW;IACX,CAAA,CACA,EAAA,CAAA,CACF;OACL,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,gCACA,6GACF;GACC,CAAA,CACU,EAAA,CAAA;GAEf,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAa,OAAO,EAAE,yBAAyB,OAAO;eAAtD,CACG,EAAW,GAAO,SAAS,EAAE,8BAA8B,cAAc,CAAC,GAC3E,kBAAC,GAAD;MACE,SAAS,EAAM,UAAU;MACzB,kBAAkB,GAAc,MAAM,IAAI,EAAE;KAC7C,CAAA,CACU;QACb,kBAAC,GAAD;KAAa,OAAO,EAAE,8BAA8B,YAAY;eAAhE,CACG,EACC,GACA,cACA,EAAE,mCAAmC,mBAAmB,CAC1D,GACA,kBAAC,GAAD;MACE,SAAS,EAAW,UAAU;MAC9B,kBAAkB,GAAkB,MAAM,IAAI,EAAE;KACjD,CAAA,CACU;MACV;;EACI;;AAEf"}
|
|
1
|
+
{"version":3,"file":"TourismPage.js","names":[],"sources":["../../../src/ggnomad/pages/TourismPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Clock, Compass, Gauge, Leaf, Zap } from 'lucide-react';\nimport { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_ACTIVITIES_QUERY, GGNOMAD_TOURS_QUERY } from '../graphql';\nimport { humanizeEnum } from '../utils/format';\nimport { PageShell } from './PageShell';\nimport {\n EntityCard,\n EMPTY_LISTING_FILTERS,\n ListingFilters,\n LoadMoreButton,\n RatingSummary,\n SectionCard,\n hasActiveListingFilters,\n} from '../components';\nimport type { ListingFilterState } from '../components';\n\ntype TourismItem = {\n id: string;\n name: string;\n /** Tours carry `type` (CULTURAL, ADVENTURE…), activities carry `category`. */\n type?: string;\n category?: string;\n duration: string;\n difficulty?: string | null;\n price: number;\n currency: string;\n rating?: number | null;\n reviewCount: number;\n images?: string[];\n instantBook: boolean;\n sustainabilityScore: number;\n};\n\ntype ListingVariables = {\n limit: number;\n offset: number;\n status?: string;\n minSustainabilityScore?: number;\n hasAccessibilityFeatures?: string[];\n};\n\nexport function TourismPage() {\n const { t } = useI18n();\n const [tourLimit, setTourLimit] = useState(12);\n const [activityLimit, setActivityLimit] = useState(12);\n const [filters, setFilters] = useState<ListingFilterState>(EMPTY_LISTING_FILTERS);\n\n const filterVariables = {\n status: filters.status,\n minSustainabilityScore: filters.minSustainabilityScore,\n hasAccessibilityFeatures:\n filters.accessibilityFeatures.length > 0 ? filters.accessibilityFeatures : undefined,\n };\n\n const { data: toursData } = useQuery(\n GGNOMAD_TOURS_QUERY as TypedDocumentNode<{ ggnomadTours: TourismItem[] }, ListingVariables>,\n { variables: { limit: tourLimit, offset: 0, ...filterVariables } }\n );\n const { data: activitiesData } = useQuery(\n GGNOMAD_ACTIVITIES_QUERY as TypedDocumentNode<\n { ggnomadActivities: TourismItem[] },\n ListingVariables\n >,\n { variables: { limit: activityLimit, offset: 0, ...filterVariables } }\n );\n const tours = toursData?.ggnomadTours ?? [];\n const activities = activitiesData?.ggnomadActivities ?? [];\n const filtered = hasActiveListingFilters(filters);\n\n const renderList = (items: TourismItem[], basePath: string, emptyLabel: string) => {\n if (items.length === 0) {\n return (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={\n filtered\n ? t('ggnomad.tourism.noMatchTitle', 'Nothing matches these filters')\n : emptyLabel\n }\n description={\n filtered\n ? t(\n 'ggnomad.tourism.noMatchDescription',\n 'Try clearing a filter — status, sustainability score and accessibility all narrow the catalogue.'\n )\n : t(\n 'ggnomad.tourism.emptyDescription',\n 'Curated experiences will appear here once published.'\n )\n }\n />\n );\n }\n return (\n <div className=\"grid gap-3\">\n {items.map((item) => (\n <EntityCard\n key={item.id}\n to={`${basePath}/${item.id}`}\n image={item.images?.[0]}\n imageAlt={item.name}\n title={item.name}\n meta={humanizeEnum(item.type ?? item.category ?? '')}\n badge={\n item.instantBook ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2.5 py-0.5 text-xs font-medium text-status-success-text\">\n <Zap className=\"size-3\" aria-hidden=\"true\" />\n {t('ggnomad.listing.instantBook', 'Instant book')}\n </span>\n ) : null\n }\n price={`${item.currency} ${Number(item.price).toFixed(2)}`}\n footer={\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1\">\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"size-3.5\" aria-hidden=\"true\" />\n {item.duration}\n </span>\n {item.difficulty ? (\n <span className=\"inline-flex items-center gap-1\">\n <Gauge className=\"size-3.5\" aria-hidden=\"true\" />\n {humanizeEnum(item.difficulty)}\n </span>\n ) : null}\n <RatingSummary rating={item.rating} reviewCount={item.reviewCount} />\n {item.sustainabilityScore > 0 ? (\n <span className=\"inline-flex items-center gap-1 tabular-nums text-status-success-text\">\n <Leaf className=\"size-3.5\" aria-hidden=\"true\" />\n {item.sustainabilityScore}\n </span>\n ) : null}\n </div>\n }\n />\n ))}\n </div>\n );\n };\n\n return (\n <PageShell\n title={t('ggnomad.tourism.title', 'Tourism')}\n titleAccent={t('ggnomad.tourism.title.accent', 'Tourism')}\n subtitle={t('ggnomad.tourism.subtitle', 'Tours and curated activity experiences')}\n >\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.tourism.purpose',\n 'Plan what you’ll actually do at a destination — guided tours and bookable activities curated by local operators. Open any experience to review duration, price and what’s included, then add it to a booking.'\n )}\n </PagePurpose>\n\n <EmphasisPanel>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <p className=\"text-sm text-text-secondary\">{t('ggnomad.tourism.tours', 'Tours')}</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {tours.length}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.tourism.activities', 'Activities')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {activities.length}\n </p>\n </div>\n </div>\n <p className=\"mt-4 text-sm text-text-secondary\">\n {t(\n 'ggnomad.tourism.emphasisNote',\n 'Curated, bookable experiences across your destinations — pick a tour or activity below to see full details.'\n )}\n </p>\n </EmphasisPanel>\n\n <ListingFilters\n idPrefix=\"ggnomad-tourism\"\n value={filters}\n onChange={(next) => {\n setTourLimit(12);\n setActivityLimit(12);\n setFilters(next);\n }}\n resultCount={tours.length + activities.length}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <SectionCard title={t('ggnomad.tourism.tours', 'Tours')}>\n {renderList(tours, 'tours', t('ggnomad.tourism.toursEmpty', 'No tours yet'))}\n <LoadMoreButton\n visible={tours.length >= tourLimit}\n onLoadMore={() => setTourLimit((l) => l + 12)}\n />\n </SectionCard>\n <SectionCard title={t('ggnomad.tourism.activities', 'Activities')}>\n {renderList(\n activities,\n 'activities',\n t('ggnomad.tourism.activitiesEmpty', 'No activities yet')\n )}\n <LoadMoreButton\n visible={activities.length >= activityLimit}\n onLoadMore={() => setActivityLimit((l) => l + 12)}\n />\n </SectionCard>\n </div>\n </PageShell>\n );\n}\n"],"mappings":"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"}
|