@burdenoff/microfe-ggnomad 2026.1029.1 → 2026.1029.3
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/BookingPanel.d.ts.map +1 -1
- package/dist/ggnomad/components/BookingPanel.js +47 -64
- package/dist/ggnomad/components/BookingPanel.js.map +1 -1
- package/dist/ggnomad/components/ListingEditDialog.d.ts.map +1 -1
- package/dist/ggnomad/components/ListingEditDialog.js +130 -96
- package/dist/ggnomad/components/ListingEditDialog.js.map +1 -1
- package/dist/ggnomad/components/TicketDialog.d.ts +2 -1
- package/dist/ggnomad/components/TicketDialog.d.ts.map +1 -1
- package/dist/ggnomad/components/TicketDialog.js +4 -1
- package/dist/ggnomad/components/TicketDialog.js.map +1 -1
- package/dist/ggnomad/graphql.js +31 -33
- package/dist/ggnomad/graphql.js.map +1 -1
- package/dist/ggnomad/pages/BookingsPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/BookingsPage.js +54 -52
- package/dist/ggnomad/pages/BookingsPage.js.map +1 -1
- package/dist/ggnomad/pages/TripPlanDetailPage.d.ts.map +1 -1
- package/dist/ggnomad/pages/TripPlanDetailPage.js +278 -273
- package/dist/ggnomad/pages/TripPlanDetailPage.js.map +1 -1
- package/dist/ggnomad/utils/bookingDates.d.ts +21 -0
- package/dist/ggnomad/utils/bookingDates.d.ts.map +1 -0
- package/dist/ggnomad/utils/bookingDates.js +22 -0
- package/dist/ggnomad/utils/bookingDates.js.map +1 -0
- package/dist/stories/ListingEditDialog.stories.d.ts +6 -0
- package/dist/stories/ListingEditDialog.stories.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BookingPanel.d.ts","sourceRoot":"","sources":["../../../src/ggnomad/components/BookingPanel.tsx"],"names":[],"mappings":"AAeA,KAAK,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;AAE9D,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"BookingPanel.d.ts","sourceRoot":"","sources":["../../../src/ggnomad/components/BookingPanel.tsx"],"names":[],"mappings":"AAeA,KAAK,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;AAE9D,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+BAgUnB"}
|
|
@@ -13,7 +13,7 @@ import { Button as f, GlassCard as p, Input as m } from "@burdenoff/fe-libs/ui";
|
|
|
13
13
|
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
14
14
|
//#region src/ggnomad/components/BookingPanel.tsx
|
|
15
15
|
function v({ bookingType: v, itemId: y, itemName: b, unitPrice: x, currency: S, eventDate: C }) {
|
|
16
|
-
let { t: w } = l(), T = u(), { basePath: E = "/" } = r(), [D, O] = o(""), [k, A] = o(""), [j, M] = o(""), [N, P] = o(1), [F, { loading: I }] = d(e), L = v === "PROPERTY" ? t(k, j) : 0, R = x * (v === "PROPERTY" ? L : N), z = R
|
|
16
|
+
let { t: w } = l(), T = u(), { basePath: E = "/" } = r(), [D, O] = o(""), [k, A] = o(""), [j, M] = o(""), [N, P] = o(1), [F, { loading: I }] = d(e), L = v === "PROPERTY" ? t(k, j) : 0, R = x * (v === "PROPERTY" ? L : N), z = R, B = async () => {
|
|
17
17
|
if (v === "PROPERTY") {
|
|
18
18
|
if (!k || !j) {
|
|
19
19
|
a.warning(w("ggnomad.booking.validation.missingDates", "Missing dates"), w("ggnomad.booking.validation.propertyDatesRequired", "Please select both check-in and check-out dates."));
|
|
@@ -40,7 +40,7 @@ function v({ bookingType: v, itemId: y, itemName: b, unitPrice: x, currency: S,
|
|
|
40
40
|
guestName: w("ggnomad.booking.defaultGuestName", "Demo Guest"),
|
|
41
41
|
guestEmail: "demo@burdenoff.com",
|
|
42
42
|
guests: N,
|
|
43
|
-
totalPrice: Math.round(
|
|
43
|
+
totalPrice: Math.round(z * 100) / 100,
|
|
44
44
|
currency: S,
|
|
45
45
|
paymentMethod: "card"
|
|
46
46
|
}, t = v === "PROPERTY" ? {
|
|
@@ -63,7 +63,7 @@ function v({ bookingType: v, itemId: y, itemName: b, unitPrice: x, currency: S,
|
|
|
63
63
|
} catch (e) {
|
|
64
64
|
a.error(w("ggnomad.booking.toast.createErrorTitle", "Could not create booking"), e instanceof Error ? e.message : String(e));
|
|
65
65
|
}
|
|
66
|
-
},
|
|
66
|
+
}, V = "text-sm font-medium text-text-primary", H = "w-full";
|
|
67
67
|
return /* @__PURE__ */ _(p, {
|
|
68
68
|
treatment: "glass",
|
|
69
69
|
glow: !0,
|
|
@@ -77,18 +77,18 @@ function v({ bookingType: v, itemId: y, itemName: b, unitPrice: x, currency: S,
|
|
|
77
77
|
className: "space-y-4 mb-6",
|
|
78
78
|
children: [v === "PROPERTY" ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
79
79
|
htmlFor: "check-in",
|
|
80
|
-
className:
|
|
80
|
+
className: V,
|
|
81
81
|
children: w("ggnomad.booking.checkIn", "Check-in")
|
|
82
82
|
}), /* @__PURE__ */ g(m, {
|
|
83
83
|
id: "check-in",
|
|
84
84
|
type: "date",
|
|
85
85
|
value: k,
|
|
86
86
|
onChange: (e) => A(e.target.value),
|
|
87
|
-
className: n(
|
|
87
|
+
className: n(H, "mt-2"),
|
|
88
88
|
"aria-label": w("ggnomad.booking.checkIn", "Check-in")
|
|
89
89
|
})] }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
90
90
|
htmlFor: "check-out",
|
|
91
|
-
className:
|
|
91
|
+
className: V,
|
|
92
92
|
children: w("ggnomad.booking.checkOut", "Check-out")
|
|
93
93
|
}), /* @__PURE__ */ g(m, {
|
|
94
94
|
id: "check-out",
|
|
@@ -96,32 +96,32 @@ function v({ bookingType: v, itemId: y, itemName: b, unitPrice: x, currency: S,
|
|
|
96
96
|
min: k || void 0,
|
|
97
97
|
value: j,
|
|
98
98
|
onChange: (e) => M(e.target.value),
|
|
99
|
-
className: n(
|
|
99
|
+
className: n(H, "mt-2"),
|
|
100
100
|
"aria-label": w("ggnomad.booking.checkOut", "Check-out")
|
|
101
101
|
})] })] }) : v === "EVENT" ? /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
102
102
|
htmlFor: "event-date",
|
|
103
|
-
className:
|
|
103
|
+
className: V,
|
|
104
104
|
children: w("ggnomad.booking.date", "Date")
|
|
105
105
|
}), /* @__PURE__ */ g(m, {
|
|
106
106
|
id: "event-date",
|
|
107
107
|
type: "date",
|
|
108
108
|
value: C ? C.split("T")[0] : "",
|
|
109
109
|
disabled: !0,
|
|
110
|
-
className: n(
|
|
110
|
+
className: n(H, "mt-2"),
|
|
111
111
|
"aria-label": w("ggnomad.booking.date", "Date")
|
|
112
112
|
})] }) : /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
113
113
|
htmlFor: "booking-date",
|
|
114
|
-
className:
|
|
114
|
+
className: V,
|
|
115
115
|
children: w("ggnomad.booking.date", "Date")
|
|
116
116
|
}), /* @__PURE__ */ g(m, {
|
|
117
117
|
id: "booking-date",
|
|
118
118
|
type: "date",
|
|
119
119
|
value: D,
|
|
120
120
|
onChange: (e) => O(e.target.value),
|
|
121
|
-
className: n(
|
|
121
|
+
className: n(H, "mt-2"),
|
|
122
122
|
"aria-label": w("ggnomad.booking.date", "Date")
|
|
123
123
|
})] }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
124
|
-
className:
|
|
124
|
+
className: V,
|
|
125
125
|
children: v === "PROPERTY" ? w("ggnomad.booking.guests", "Guests") : v === "EVENT" ? w("ggnomad.booking.tickets", "Tickets") : w("ggnomad.booking.participants", "Participants")
|
|
126
126
|
}), /* @__PURE__ */ _("div", {
|
|
127
127
|
className: "flex items-center gap-2 mt-2",
|
|
@@ -160,60 +160,43 @@ function v({ bookingType: v, itemId: y, itemName: b, unitPrice: x, currency: S,
|
|
|
160
160
|
children: w("ggnomad.booking.selectDatesForTotal", "Select check-in and check-out dates to see the total.")
|
|
161
161
|
}) : /* @__PURE__ */ _("div", {
|
|
162
162
|
className: "space-y-2 mb-6 p-3 rounded-md bg-bg-sunken",
|
|
163
|
-
children: [
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
/* @__PURE__ */
|
|
186
|
-
className: "
|
|
187
|
-
children:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
})]
|
|
198
|
-
}),
|
|
199
|
-
/* @__PURE__ */ _("div", {
|
|
200
|
-
className: "border-t border-border-seam pt-2 flex justify-between",
|
|
201
|
-
children: [/* @__PURE__ */ g("span", {
|
|
202
|
-
className: "font-semibold text-text-primary",
|
|
203
|
-
children: w("ggnomad.booking.total", "Total")
|
|
204
|
-
}), /* @__PURE__ */ _("span", {
|
|
205
|
-
className: "font-bold text-lg text-text-primary",
|
|
206
|
-
children: [
|
|
207
|
-
S,
|
|
208
|
-
" ",
|
|
209
|
-
B.toFixed(2)
|
|
210
|
-
]
|
|
211
|
-
})]
|
|
212
|
-
})
|
|
213
|
-
]
|
|
163
|
+
children: [/* @__PURE__ */ _("div", {
|
|
164
|
+
className: "flex justify-between text-sm",
|
|
165
|
+
children: [/* @__PURE__ */ _("span", {
|
|
166
|
+
className: "text-text-secondary",
|
|
167
|
+
children: [
|
|
168
|
+
S,
|
|
169
|
+
" ",
|
|
170
|
+
x.toFixed(2),
|
|
171
|
+
" ×",
|
|
172
|
+
" ",
|
|
173
|
+
v === "PROPERTY" ? L === 1 ? `1 ${w("ggnomad.booking.night", "night")}` : `${L} ${w("ggnomad.booking.nights", "nights")}` : `${N} ${w("ggnomad.booking.item", "item")}`
|
|
174
|
+
]
|
|
175
|
+
}), /* @__PURE__ */ _("span", {
|
|
176
|
+
className: "text-text-primary font-medium",
|
|
177
|
+
children: [
|
|
178
|
+
S,
|
|
179
|
+
" ",
|
|
180
|
+
R.toFixed(2)
|
|
181
|
+
]
|
|
182
|
+
})]
|
|
183
|
+
}), /* @__PURE__ */ _("div", {
|
|
184
|
+
className: "border-t border-border-seam pt-2 flex justify-between",
|
|
185
|
+
children: [/* @__PURE__ */ g("span", {
|
|
186
|
+
className: "font-semibold text-text-primary",
|
|
187
|
+
children: w("ggnomad.booking.total", "Total")
|
|
188
|
+
}), /* @__PURE__ */ _("span", {
|
|
189
|
+
className: "font-bold text-lg text-text-primary",
|
|
190
|
+
children: [
|
|
191
|
+
S,
|
|
192
|
+
" ",
|
|
193
|
+
z.toFixed(2)
|
|
194
|
+
]
|
|
195
|
+
})]
|
|
196
|
+
})]
|
|
214
197
|
}),
|
|
215
198
|
/* @__PURE__ */ g(f, {
|
|
216
|
-
onClick: () => void
|
|
199
|
+
onClick: () => void B(),
|
|
217
200
|
disabled: I,
|
|
218
201
|
className: "w-full bg-gradient-to-r from-action-primary-bg to-action-success-bg text-white font-semibold",
|
|
219
202
|
size: "lg",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BookingPanel.js","names":[],"sources":["../../../src/ggnomad/components/BookingPanel.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate } from 'react-router';\nimport { Minus, Plus } from 'lucide-react';\nimport { Button, GlassCard, Input } from '@burdenoff/fe-libs/ui';\n\nimport { CREATE_GGNOMAD_BOOKING_MUTATION } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { notify } from '../utils/notify';\nimport { nightsBetween } from '../utils/format';\nimport { cn } from '../utils/cn';\n\ntype BookingType = 'PROPERTY' | 'TOUR' | 'EVENT' | 'ACTIVITY';\n\ntype BookingPanelProps = {\n bookingType: BookingType;\n itemId: string;\n itemName: string;\n unitPrice: number;\n currency: string;\n /** For EVENT bookings, the event date (ISO string) */\n eventDate?: string;\n};\n\n/** Frosted glass booking panel with type-specific inputs and real createGgnomadBooking mutation. */\nexport function BookingPanel({\n bookingType,\n itemId,\n itemName,\n unitPrice,\n currency,\n eventDate,\n}: BookingPanelProps) {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n\n // For properties: check-in and check-out dates\n // For events/tours/activities: a single date\n const [selectedDate, setSelectedDate] = useState<string>('');\n const [checkInDate, setCheckInDate] = useState<string>('');\n const [checkOutDate, setCheckOutDate] = useState<string>('');\n\n // Quantity: guests (property), participants (tour/activity), tickets (event)\n const [quantity, setQuantity] = useState(1);\n\n type BookingInput = {\n bookingType: BookingType;\n itemId: string;\n itemName: string;\n guestName: string;\n guestEmail: string;\n guests: number;\n totalPrice: number;\n currency: string;\n paymentMethod: string;\n checkIn?: string;\n checkOut?: string;\n eventDate?: string;\n };\n\n const [createBooking, { loading: creating }] = useMutation(\n CREATE_GGNOMAD_BOOKING_MUTATION as TypedDocumentNode<\n { createGgnomadBooking: { id: string; referenceCode: string; itemName: string } },\n { input: BookingInput }\n >\n );\n\n // A property is priced per night, so the multiplier is the length of the selected\n // stay — derived from the two date inputs above rather than assumed. Every other\n // listing type is priced per ticket / seat / participant.\n const nights = bookingType === 'PROPERTY' ? nightsBetween(checkInDate, checkOutDate) : 0;\n const multiplier = bookingType === 'PROPERTY' ? nights : quantity;\n const subtotal = unitPrice * multiplier;\n const taxAmount = subtotal * 0.1; // 10% tax\n const total = subtotal + taxAmount;\n\n const handleBooking = async () => {\n // Validate required fields\n if (bookingType === 'PROPERTY') {\n if (!checkInDate || !checkOutDate) {\n notify.warning(\n t('ggnomad.booking.validation.missingDates', 'Missing dates'),\n t(\n 'ggnomad.booking.validation.propertyDatesRequired',\n 'Please select both check-in and check-out dates.'\n )\n );\n return;\n }\n if (nights < 1) {\n notify.warning(\n t('ggnomad.booking.validation.invalidStayTitle', 'Check-out must be after check-in'),\n t(\n 'ggnomad.booking.validation.invalidStayBody',\n 'Pick a check-out date at least one night after check-in.'\n )\n );\n return;\n }\n } else if (bookingType === 'EVENT') {\n if (!eventDate) {\n notify.warning(\n t('ggnomad.booking.validation.missingDate', 'Missing date'),\n t('ggnomad.booking.validation.eventDateRequired', 'Event date is required for booking.')\n );\n return;\n }\n } else {\n if (!selectedDate) {\n notify.warning(\n t('ggnomad.booking.validation.missingDate', 'Missing date'),\n t('ggnomad.booking.validation.dateRequired', 'Please select a date for your booking.')\n );\n return;\n }\n }\n\n try {\n const baseInput = {\n bookingType,\n itemId,\n itemName,\n guestName: t('ggnomad.booking.defaultGuestName', 'Demo Guest'),\n guestEmail: 'demo@burdenoff.com',\n guests: quantity,\n totalPrice: Math.round(total * 100) / 100,\n currency,\n paymentMethod: 'card',\n };\n\n const input: BookingInput =\n bookingType === 'PROPERTY'\n ? { ...baseInput, checkIn: checkInDate, checkOut: checkOutDate }\n : bookingType === 'EVENT'\n ? { ...baseInput, eventDate: eventDate }\n : { ...baseInput, eventDate: selectedDate };\n\n const result = await createBooking({\n variables: { input },\n });\n\n if (result.error) {\n notify.error(\n t('ggnomad.booking.toast.createErrorTitle', 'Could not create booking'),\n result.error.message\n );\n return;\n }\n\n const created = result.data?.createGgnomadBooking;\n notify.success(\n t('ggnomad.booking.toast.createSuccessTitle', 'Booking confirmed'),\n created\n ? t('ggnomad.booking.toast.createSuccessBody', '{{ref}} · {{item}}')\n .replace('{{ref}}', created.referenceCode)\n .replace('{{item}}', created.itemName)\n : itemName\n );\n\n // Navigate to bookings list\n navigate(joinPath(basePath, 'bookings'));\n } catch (err) {\n notify.error(\n t('ggnomad.booking.toast.createErrorTitle', 'Could not create booking'),\n err instanceof Error ? err.message : String(err)\n );\n }\n };\n\n const labelClass = 'text-sm font-medium text-text-primary';\n const inputClass = 'w-full';\n\n return (\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5 sticky top-6\">\n <h2 className=\"mb-4 text-lg font-medium tracking-tight text-text-primary\">\n {bookingType === 'PROPERTY'\n ? t('ggnomad.booking.title.property', 'Book this stay')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.title.event', 'Book tickets')\n : bookingType === 'TOUR'\n ? t('ggnomad.booking.title.tour', 'Book this tour')\n : t('ggnomad.booking.title.activity', 'Book this activity')}\n </h2>\n\n <div className=\"space-y-4 mb-6\">\n {/* Dates section */}\n {bookingType === 'PROPERTY' ? (\n <>\n <div>\n <label htmlFor=\"check-in\" className={labelClass}>\n {t('ggnomad.booking.checkIn', 'Check-in')}\n </label>\n <Input\n id=\"check-in\"\n type=\"date\"\n value={checkInDate}\n onChange={(e) => setCheckInDate(e.target.value)}\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.checkIn', 'Check-in')}\n />\n </div>\n <div>\n <label htmlFor=\"check-out\" className={labelClass}>\n {t('ggnomad.booking.checkOut', 'Check-out')}\n </label>\n <Input\n id=\"check-out\"\n type=\"date\"\n min={checkInDate || undefined}\n value={checkOutDate}\n onChange={(e) => setCheckOutDate(e.target.value)}\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.checkOut', 'Check-out')}\n />\n </div>\n </>\n ) : bookingType === 'EVENT' ? (\n <div>\n <label htmlFor=\"event-date\" className={labelClass}>\n {t('ggnomad.booking.date', 'Date')}\n </label>\n <Input\n id=\"event-date\"\n type=\"date\"\n value={eventDate ? eventDate.split('T')[0] : ''}\n disabled\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.date', 'Date')}\n />\n </div>\n ) : (\n <div>\n <label htmlFor=\"booking-date\" className={labelClass}>\n {t('ggnomad.booking.date', 'Date')}\n </label>\n <Input\n id=\"booking-date\"\n type=\"date\"\n value={selectedDate}\n onChange={(e) => setSelectedDate(e.target.value)}\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.date', 'Date')}\n />\n </div>\n )}\n\n {/* Quantity section */}\n <div>\n <label className={labelClass}>\n {bookingType === 'PROPERTY'\n ? t('ggnomad.booking.guests', 'Guests')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.tickets', 'Tickets')\n : t('ggnomad.booking.participants', 'Participants')}\n </label>\n <div className=\"flex items-center gap-2 mt-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setQuantity(Math.max(1, quantity - 1))}\n disabled={quantity <= 1 || creating}\n aria-label={t('ggnomad.booking.decreaseQuantity', 'Decrease quantity')}\n className=\"flex-shrink-0\"\n >\n <Minus className=\"size-4\" />\n </Button>\n <input\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => setQuantity(Math.max(1, parseInt(e.target.value) || 1))}\n className=\"flex-1 h-9 rounded-input border border-border-default bg-bg-surface px-3 py-1 text-center text-sm text-text-primary\"\n aria-label={\n bookingType === 'PROPERTY'\n ? t('ggnomad.booking.guests', 'Guests')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.tickets', 'Tickets')\n : t('ggnomad.booking.participants', 'Participants')\n }\n />\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setQuantity(quantity + 1)}\n disabled={creating}\n aria-label={t('ggnomad.booking.increaseQuantity', 'Increase quantity')}\n className=\"flex-shrink-0\"\n >\n <Plus className=\"size-4\" />\n </Button>\n </div>\n </div>\n </div>\n\n {/* Pricing breakdown — a per-night total is only meaningful once the stay\n length is known, so it is withheld until both dates are chosen. */}\n {bookingType === 'PROPERTY' && nights < 1 ? (\n <div className=\"mb-6 rounded-md bg-bg-sunken p-3 text-sm text-text-secondary\">\n {t(\n 'ggnomad.booking.selectDatesForTotal',\n 'Select check-in and check-out dates to see the total.'\n )}\n </div>\n ) : (\n <div className=\"space-y-2 mb-6 p-3 rounded-md bg-bg-sunken\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {currency} {unitPrice.toFixed(2)} ×{' '}\n {bookingType === 'PROPERTY'\n ? nights === 1\n ? `1 ${t('ggnomad.booking.night', 'night')}`\n : `${nights} ${t('ggnomad.booking.nights', 'nights')}`\n : `${quantity} ${t('ggnomad.booking.item', 'item')}`}\n </span>\n <span className=\"text-text-primary font-medium\">\n {currency} {subtotal.toFixed(2)}\n </span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">{t('ggnomad.booking.tax', 'Tax (10%)')}</span>\n <span className=\"text-text-primary\">\n {currency} {taxAmount.toFixed(2)}\n </span>\n </div>\n <div className=\"border-t border-border-seam pt-2 flex justify-between\">\n <span className=\"font-semibold text-text-primary\">\n {t('ggnomad.booking.total', 'Total')}\n </span>\n <span className=\"font-bold text-lg text-text-primary\">\n {currency} {total.toFixed(2)}\n </span>\n </div>\n </div>\n )}\n\n {/* Book button */}\n <Button\n onClick={() => void handleBooking()}\n disabled={creating}\n className=\"w-full bg-gradient-to-r from-action-primary-bg to-action-success-bg text-white font-semibold\"\n size=\"lg\"\n >\n {creating\n ? t('ggnomad.booking.button.creating', 'Creating booking…')\n : bookingType === 'PROPERTY'\n ? t('ggnomad.booking.button.property', 'Book this stay')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.button.event', 'Book tickets')\n : bookingType === 'TOUR'\n ? t('ggnomad.booking.button.tour', 'Book this tour')\n : t('ggnomad.booking.button.activity', 'Book this activity')}\n </Button>\n </GlassCard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BookingPanel.js","names":[],"sources":["../../../src/ggnomad/components/BookingPanel.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate } from 'react-router';\nimport { Minus, Plus } from 'lucide-react';\nimport { Button, GlassCard, Input } from '@burdenoff/fe-libs/ui';\n\nimport { CREATE_GGNOMAD_BOOKING_MUTATION } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { notify } from '../utils/notify';\nimport { nightsBetween } from '../utils/format';\nimport { cn } from '../utils/cn';\n\ntype BookingType = 'PROPERTY' | 'TOUR' | 'EVENT' | 'ACTIVITY';\n\ntype BookingPanelProps = {\n bookingType: BookingType;\n itemId: string;\n itemName: string;\n unitPrice: number;\n currency: string;\n /** For EVENT bookings, the event date (ISO string) */\n eventDate?: string;\n};\n\n/** Frosted glass booking panel with type-specific inputs and real createGgnomadBooking mutation. */\nexport function BookingPanel({\n bookingType,\n itemId,\n itemName,\n unitPrice,\n currency,\n eventDate,\n}: BookingPanelProps) {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n\n // For properties: check-in and check-out dates\n // For events/tours/activities: a single date\n const [selectedDate, setSelectedDate] = useState<string>('');\n const [checkInDate, setCheckInDate] = useState<string>('');\n const [checkOutDate, setCheckOutDate] = useState<string>('');\n\n // Quantity: guests (property), participants (tour/activity), tickets (event)\n const [quantity, setQuantity] = useState(1);\n\n type BookingInput = {\n bookingType: BookingType;\n itemId: string;\n itemName: string;\n guestName: string;\n guestEmail: string;\n guests: number;\n totalPrice: number;\n currency: string;\n paymentMethod: string;\n checkIn?: string;\n checkOut?: string;\n eventDate?: string;\n };\n\n const [createBooking, { loading: creating }] = useMutation(\n CREATE_GGNOMAD_BOOKING_MUTATION as TypedDocumentNode<\n { createGgnomadBooking: { id: string; referenceCode: string; itemName: string } },\n { input: BookingInput }\n >\n );\n\n // A property is priced per night, so the multiplier is the length of the selected\n // stay — derived from the two date inputs above rather than assumed. Every other\n // listing type is priced per ticket / seat / participant.\n const nights = bookingType === 'PROPERTY' ? nightsBetween(checkInDate, checkOutDate) : 0;\n const multiplier = bookingType === 'PROPERTY' ? nights : quantity;\n const subtotal = unitPrice * multiplier;\n // BOFF-10193 — the service prices the booking from the listing (nightly or\n // per-person rate x the quantity, plus any demand surcharge on busy dates)\n // and does not add tax, so the panel shows that same amount. The 10% \"tax\"\n // line this panel used to add had no counterpart in the booking record.\n const total = subtotal;\n\n const handleBooking = async () => {\n // Validate required fields\n if (bookingType === 'PROPERTY') {\n if (!checkInDate || !checkOutDate) {\n notify.warning(\n t('ggnomad.booking.validation.missingDates', 'Missing dates'),\n t(\n 'ggnomad.booking.validation.propertyDatesRequired',\n 'Please select both check-in and check-out dates.'\n )\n );\n return;\n }\n if (nights < 1) {\n notify.warning(\n t('ggnomad.booking.validation.invalidStayTitle', 'Check-out must be after check-in'),\n t(\n 'ggnomad.booking.validation.invalidStayBody',\n 'Pick a check-out date at least one night after check-in.'\n )\n );\n return;\n }\n } else if (bookingType === 'EVENT') {\n if (!eventDate) {\n notify.warning(\n t('ggnomad.booking.validation.missingDate', 'Missing date'),\n t('ggnomad.booking.validation.eventDateRequired', 'Event date is required for booking.')\n );\n return;\n }\n } else {\n if (!selectedDate) {\n notify.warning(\n t('ggnomad.booking.validation.missingDate', 'Missing date'),\n t('ggnomad.booking.validation.dateRequired', 'Please select a date for your booking.')\n );\n return;\n }\n }\n\n try {\n const baseInput = {\n bookingType,\n itemId,\n itemName,\n guestName: t('ggnomad.booking.defaultGuestName', 'Demo Guest'),\n guestEmail: 'demo@burdenoff.com',\n guests: quantity,\n totalPrice: Math.round(total * 100) / 100,\n currency,\n paymentMethod: 'card',\n };\n\n const input: BookingInput =\n bookingType === 'PROPERTY'\n ? { ...baseInput, checkIn: checkInDate, checkOut: checkOutDate }\n : bookingType === 'EVENT'\n ? { ...baseInput, eventDate: eventDate }\n : { ...baseInput, eventDate: selectedDate };\n\n const result = await createBooking({\n variables: { input },\n });\n\n if (result.error) {\n notify.error(\n t('ggnomad.booking.toast.createErrorTitle', 'Could not create booking'),\n result.error.message\n );\n return;\n }\n\n const created = result.data?.createGgnomadBooking;\n notify.success(\n t('ggnomad.booking.toast.createSuccessTitle', 'Booking confirmed'),\n created\n ? t('ggnomad.booking.toast.createSuccessBody', '{{ref}} · {{item}}')\n .replace('{{ref}}', created.referenceCode)\n .replace('{{item}}', created.itemName)\n : itemName\n );\n\n // Navigate to bookings list\n navigate(joinPath(basePath, 'bookings'));\n } catch (err) {\n notify.error(\n t('ggnomad.booking.toast.createErrorTitle', 'Could not create booking'),\n err instanceof Error ? err.message : String(err)\n );\n }\n };\n\n const labelClass = 'text-sm font-medium text-text-primary';\n const inputClass = 'w-full';\n\n return (\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5 sticky top-6\">\n <h2 className=\"mb-4 text-lg font-medium tracking-tight text-text-primary\">\n {bookingType === 'PROPERTY'\n ? t('ggnomad.booking.title.property', 'Book this stay')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.title.event', 'Book tickets')\n : bookingType === 'TOUR'\n ? t('ggnomad.booking.title.tour', 'Book this tour')\n : t('ggnomad.booking.title.activity', 'Book this activity')}\n </h2>\n\n <div className=\"space-y-4 mb-6\">\n {/* Dates section */}\n {bookingType === 'PROPERTY' ? (\n <>\n <div>\n <label htmlFor=\"check-in\" className={labelClass}>\n {t('ggnomad.booking.checkIn', 'Check-in')}\n </label>\n <Input\n id=\"check-in\"\n type=\"date\"\n value={checkInDate}\n onChange={(e) => setCheckInDate(e.target.value)}\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.checkIn', 'Check-in')}\n />\n </div>\n <div>\n <label htmlFor=\"check-out\" className={labelClass}>\n {t('ggnomad.booking.checkOut', 'Check-out')}\n </label>\n <Input\n id=\"check-out\"\n type=\"date\"\n min={checkInDate || undefined}\n value={checkOutDate}\n onChange={(e) => setCheckOutDate(e.target.value)}\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.checkOut', 'Check-out')}\n />\n </div>\n </>\n ) : bookingType === 'EVENT' ? (\n <div>\n <label htmlFor=\"event-date\" className={labelClass}>\n {t('ggnomad.booking.date', 'Date')}\n </label>\n <Input\n id=\"event-date\"\n type=\"date\"\n value={eventDate ? eventDate.split('T')[0] : ''}\n disabled\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.date', 'Date')}\n />\n </div>\n ) : (\n <div>\n <label htmlFor=\"booking-date\" className={labelClass}>\n {t('ggnomad.booking.date', 'Date')}\n </label>\n <Input\n id=\"booking-date\"\n type=\"date\"\n value={selectedDate}\n onChange={(e) => setSelectedDate(e.target.value)}\n className={cn(inputClass, 'mt-2')}\n aria-label={t('ggnomad.booking.date', 'Date')}\n />\n </div>\n )}\n\n {/* Quantity section */}\n <div>\n <label className={labelClass}>\n {bookingType === 'PROPERTY'\n ? t('ggnomad.booking.guests', 'Guests')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.tickets', 'Tickets')\n : t('ggnomad.booking.participants', 'Participants')}\n </label>\n <div className=\"flex items-center gap-2 mt-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setQuantity(Math.max(1, quantity - 1))}\n disabled={quantity <= 1 || creating}\n aria-label={t('ggnomad.booking.decreaseQuantity', 'Decrease quantity')}\n className=\"flex-shrink-0\"\n >\n <Minus className=\"size-4\" />\n </Button>\n <input\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => setQuantity(Math.max(1, parseInt(e.target.value) || 1))}\n className=\"flex-1 h-9 rounded-input border border-border-default bg-bg-surface px-3 py-1 text-center text-sm text-text-primary\"\n aria-label={\n bookingType === 'PROPERTY'\n ? t('ggnomad.booking.guests', 'Guests')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.tickets', 'Tickets')\n : t('ggnomad.booking.participants', 'Participants')\n }\n />\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setQuantity(quantity + 1)}\n disabled={creating}\n aria-label={t('ggnomad.booking.increaseQuantity', 'Increase quantity')}\n className=\"flex-shrink-0\"\n >\n <Plus className=\"size-4\" />\n </Button>\n </div>\n </div>\n </div>\n\n {/* Pricing breakdown — a per-night total is only meaningful once the stay\n length is known, so it is withheld until both dates are chosen. */}\n {bookingType === 'PROPERTY' && nights < 1 ? (\n <div className=\"mb-6 rounded-md bg-bg-sunken p-3 text-sm text-text-secondary\">\n {t(\n 'ggnomad.booking.selectDatesForTotal',\n 'Select check-in and check-out dates to see the total.'\n )}\n </div>\n ) : (\n <div className=\"space-y-2 mb-6 p-3 rounded-md bg-bg-sunken\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {currency} {unitPrice.toFixed(2)} ×{' '}\n {bookingType === 'PROPERTY'\n ? nights === 1\n ? `1 ${t('ggnomad.booking.night', 'night')}`\n : `${nights} ${t('ggnomad.booking.nights', 'nights')}`\n : `${quantity} ${t('ggnomad.booking.item', 'item')}`}\n </span>\n <span className=\"text-text-primary font-medium\">\n {currency} {subtotal.toFixed(2)}\n </span>\n </div>\n <div className=\"border-t border-border-seam pt-2 flex justify-between\">\n <span className=\"font-semibold text-text-primary\">\n {t('ggnomad.booking.total', 'Total')}\n </span>\n <span className=\"font-bold text-lg text-text-primary\">\n {currency} {total.toFixed(2)}\n </span>\n </div>\n </div>\n )}\n\n {/* Book button */}\n <Button\n onClick={() => void handleBooking()}\n disabled={creating}\n className=\"w-full bg-gradient-to-r from-action-primary-bg to-action-success-bg text-white font-semibold\"\n size=\"lg\"\n >\n {creating\n ? t('ggnomad.booking.button.creating', 'Creating booking…')\n : bookingType === 'PROPERTY'\n ? t('ggnomad.booking.button.property', 'Book this stay')\n : bookingType === 'EVENT'\n ? t('ggnomad.booking.button.event', 'Book tickets')\n : bookingType === 'TOUR'\n ? t('ggnomad.booking.button.tour', 'Book this tour')\n : t('ggnomad.booking.button.activity', 'Book this activity')}\n </Button>\n </GlassCard>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListingEditDialog.d.ts","sourceRoot":"","sources":["../../../src/ggnomad/components/ListingEditDialog.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ListingEditDialog.d.ts","sourceRoot":"","sources":["../../../src/ggnomad/components/ListingEditDialog.tsx"],"names":[],"mappings":"AA2BA,KAAK,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;AAoB7D,UAAU,sBAAsB;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,UAAU,EAAE,UAAU,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,EAAE,EACF,OAAO,EACP,OAAO,GACR,EAAE,sBAAsB,+BAoXxB"}
|
|
@@ -1,161 +1,195 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { notify as
|
|
3
|
-
import { useMemo as
|
|
4
|
-
import { Pencil as
|
|
5
|
-
import { useI18n as
|
|
6
|
-
import { useMutation as
|
|
7
|
-
import { AlertDialog as
|
|
8
|
-
import { jsx as
|
|
1
|
+
import { PAUSE_GGNOMAD_LISTING_MUTATION as e, RESUME_GGNOMAD_LISTING_MUTATION as t, SUBMIT_GGNOMAD_LISTING_FOR_REVIEW_MUTATION as n, UPDATE_GGNOMAD_ACTIVITY_MUTATION as r, UPDATE_GGNOMAD_EVENT_MUTATION as i, UPDATE_GGNOMAD_PROPERTY_MUTATION as a, UPDATE_GGNOMAD_TOUR_MUTATION as o } from "../graphql.js";
|
|
2
|
+
import { notify as s } from "../utils/notify.js";
|
|
3
|
+
import { useMemo as c, useState as l } from "react";
|
|
4
|
+
import { Pencil as u } from "lucide-react";
|
|
5
|
+
import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
|
+
import { useMutation as f } from "@apollo/client/react";
|
|
7
|
+
import { AlertDialog as p, AlertDialogAction as m, AlertDialogCancel as ee, AlertDialogContent as h, AlertDialogDescription as g, AlertDialogFooter as _, AlertDialogHeader as v, AlertDialogTitle as te } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
9
9
|
//#region src/ggnomad/components/ListingEditDialog.tsx
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
var x = {
|
|
11
|
+
DRAFT: "SUBMIT",
|
|
12
|
+
ACTIVE: "PAUSE",
|
|
13
|
+
PAUSED: "RESUME"
|
|
14
|
+
};
|
|
15
|
+
function S({ open: S, onOpenChange: C, targetType: w, id: T, initial: E, onSaved: D }) {
|
|
16
|
+
let { t: O } = d(), [k, A] = l(E.name ?? ""), [j, M] = l(E.description ?? ""), N = E.pricePerNight ?? E.price ?? 0, [P, F] = l(String(N)), I = (E.status ?? "").toUpperCase(), L = x[I], [R, z] = l((E.images ?? []).join("\n")), [B, { loading: V }] = f(a), [H, { loading: U }] = f(o), [W, { loading: G }] = f(i), [K, { loading: q }] = f(r), [J, { loading: Y }] = f(n), [X, { loading: Z }] = f(e), [ne, { loading: Q }] = f(t), $ = c(() => V || U || G || q || Y || Z || Q, [
|
|
13
17
|
V,
|
|
14
18
|
U,
|
|
15
|
-
G
|
|
16
|
-
|
|
19
|
+
G,
|
|
20
|
+
q,
|
|
21
|
+
Y,
|
|
22
|
+
Z,
|
|
23
|
+
Q
|
|
24
|
+
]), re = async (e) => {
|
|
25
|
+
let t = e === "SUBMIT" ? J : e === "PAUSE" ? X : ne;
|
|
26
|
+
try {
|
|
27
|
+
let n = await t({ variables: {
|
|
28
|
+
listingType: w,
|
|
29
|
+
id: T
|
|
30
|
+
} });
|
|
31
|
+
if (n.error) {
|
|
32
|
+
s.error(O("ggnomad.listingEdit.lifecycleErrorTitle", "Could not change listing status"), n.error.message);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
s.success(O("ggnomad.listingEdit.lifecycleSuccessTitle", "Listing status updated"), e === "SUBMIT" ? O("ggnomad.listingEdit.submittedBody", "Submitted for review. It goes live once a marketplace operator approves it.") : e === "PAUSE" ? O("ggnomad.listingEdit.pausedBody", "The listing is paused and hidden from booking.") : O("ggnomad.listingEdit.resumedBody", "The listing is live again.")), C(!1), D?.();
|
|
36
|
+
} catch (e) {
|
|
37
|
+
s.error(O("ggnomad.listingEdit.lifecycleErrorTitle", "Could not change listing status"), e instanceof Error ? e.message : String(e));
|
|
38
|
+
}
|
|
39
|
+
}, ie = {
|
|
40
|
+
DRAFT: O("ggnomad.listingEdit.statusDraft", "Draft"),
|
|
41
|
+
PENDING_REVIEW: O("ggnomad.listingEdit.statusPendingReview", "Pending review"),
|
|
42
|
+
ACTIVE: O("ggnomad.listingEdit.statusActive", "Active"),
|
|
43
|
+
PAUSED: O("ggnomad.listingEdit.statusPaused", "Paused"),
|
|
44
|
+
ARCHIVED: O("ggnomad.listingEdit.statusArchived", "Archived")
|
|
45
|
+
}, ae = {
|
|
46
|
+
SUBMIT: O("ggnomad.listingEdit.submitForReview", "Submit for review"),
|
|
47
|
+
PAUSE: O("ggnomad.listingEdit.pause", "Pause listing"),
|
|
48
|
+
RESUME: O("ggnomad.listingEdit.resume", "Resume listing")
|
|
49
|
+
}, oe = async () => {
|
|
17
50
|
try {
|
|
18
51
|
let e = {};
|
|
19
|
-
|
|
20
|
-
let t = parseFloat(
|
|
21
|
-
t !== (
|
|
22
|
-
let n =
|
|
52
|
+
k !== (E.name ?? "") && (e.name = k), j !== (E.description ?? "") && (e.description = j);
|
|
53
|
+
let t = parseFloat(P);
|
|
54
|
+
t !== (E.pricePerNight ?? E.price ?? 0) && (w === "PROPERTY" ? e.pricePerNight = t : e.price = t);
|
|
55
|
+
let n = R.split("\n").map((e) => e.trim()).filter(Boolean), r = E.images ?? [];
|
|
23
56
|
if (JSON.stringify(n) !== JSON.stringify(r) && (e.images = n), Object.keys(e).length === 0) {
|
|
24
|
-
|
|
57
|
+
s.info(O("ggnomad.listingEdit.noChangesTitle", "No changes"), O("ggnomad.listingEdit.noChangesBody", "Nothing was modified.")), C(!1);
|
|
25
58
|
return;
|
|
26
59
|
}
|
|
27
|
-
let
|
|
28
|
-
if (
|
|
29
|
-
id:
|
|
60
|
+
let i;
|
|
61
|
+
if (i = w === "PROPERTY" ? await B({ variables: {
|
|
62
|
+
id: T,
|
|
30
63
|
input: e
|
|
31
|
-
} }) :
|
|
32
|
-
id:
|
|
64
|
+
} }) : w === "TOUR" ? await H({ variables: {
|
|
65
|
+
id: T,
|
|
33
66
|
input: e
|
|
34
|
-
} }) :
|
|
35
|
-
id:
|
|
67
|
+
} }) : w === "EVENT" ? await W({ variables: {
|
|
68
|
+
id: T,
|
|
36
69
|
input: e
|
|
37
|
-
} }) : await
|
|
38
|
-
id:
|
|
70
|
+
} }) : await K({ variables: {
|
|
71
|
+
id: T,
|
|
39
72
|
input: e
|
|
40
|
-
} }),
|
|
41
|
-
|
|
73
|
+
} }), i?.error) {
|
|
74
|
+
s.error(O("ggnomad.listingEdit.errorTitle", "Could not update listing"), i.error.message);
|
|
42
75
|
return;
|
|
43
76
|
}
|
|
44
|
-
|
|
77
|
+
s.success(O("ggnomad.listingEdit.successTitle", "Listing updated"), O("ggnomad.listingEdit.successBody", "Your changes have been saved.")), C(!1), D?.();
|
|
45
78
|
} catch (e) {
|
|
46
|
-
|
|
79
|
+
s.error(O("ggnomad.listingEdit.errorTitle", "Could not update listing"), e instanceof Error ? e.message : String(e));
|
|
47
80
|
}
|
|
48
|
-
},
|
|
49
|
-
return /* @__PURE__ */
|
|
50
|
-
open:
|
|
51
|
-
onOpenChange:
|
|
52
|
-
children: /* @__PURE__ */
|
|
81
|
+
}, se = w === "PROPERTY" ? "Price per night" : "Price";
|
|
82
|
+
return /* @__PURE__ */ y(p, {
|
|
83
|
+
open: S,
|
|
84
|
+
onOpenChange: C,
|
|
85
|
+
children: /* @__PURE__ */ b(h, {
|
|
53
86
|
className: "max-w-2xl",
|
|
54
87
|
children: [
|
|
55
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ b(v, { children: [/* @__PURE__ */ b(te, {
|
|
56
89
|
className: "flex items-center gap-2",
|
|
57
|
-
children: [/* @__PURE__ */
|
|
58
|
-
}), /* @__PURE__ */
|
|
59
|
-
/* @__PURE__ */
|
|
90
|
+
children: [/* @__PURE__ */ y(u, { className: "size-4" }), O("ggnomad.listingEdit.title", "Edit listing")]
|
|
91
|
+
}), /* @__PURE__ */ y(g, { children: O("ggnomad.listingEdit.description", "Update the details for this listing.") })] }),
|
|
92
|
+
/* @__PURE__ */ b("div", {
|
|
60
93
|
className: "space-y-4",
|
|
61
94
|
children: [
|
|
62
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
63
96
|
htmlFor: "listing-edit-name",
|
|
64
97
|
className: "block text-sm font-medium text-text-primary",
|
|
65
|
-
children:
|
|
66
|
-
}), /* @__PURE__ */
|
|
98
|
+
children: O("ggnomad.listingEdit.nameLabel", "Name")
|
|
99
|
+
}), /* @__PURE__ */ y("input", {
|
|
67
100
|
id: "listing-edit-name",
|
|
68
101
|
type: "text",
|
|
69
|
-
value:
|
|
70
|
-
onChange: (e) =>
|
|
71
|
-
disabled:
|
|
102
|
+
value: k,
|
|
103
|
+
onChange: (e) => A(e.target.value),
|
|
104
|
+
disabled: $,
|
|
72
105
|
className: "mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50",
|
|
73
|
-
placeholder:
|
|
106
|
+
placeholder: O("ggnomad.listingEdit.namePlaceholder", "Enter name")
|
|
74
107
|
})] }),
|
|
75
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
76
109
|
htmlFor: "listing-edit-description",
|
|
77
110
|
className: "block text-sm font-medium text-text-primary",
|
|
78
|
-
children:
|
|
79
|
-
}), /* @__PURE__ */
|
|
111
|
+
children: O("ggnomad.listingEdit.descriptionLabel", "Description")
|
|
112
|
+
}), /* @__PURE__ */ y("textarea", {
|
|
80
113
|
id: "listing-edit-description",
|
|
81
|
-
value:
|
|
82
|
-
onChange: (e) =>
|
|
83
|
-
disabled:
|
|
114
|
+
value: j,
|
|
115
|
+
onChange: (e) => M(e.target.value),
|
|
116
|
+
disabled: $,
|
|
84
117
|
rows: 3,
|
|
85
118
|
className: "mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50",
|
|
86
|
-
placeholder:
|
|
119
|
+
placeholder: O("ggnomad.listingEdit.descriptionPlaceholder", "Enter description")
|
|
87
120
|
})] }),
|
|
88
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
89
122
|
htmlFor: "listing-edit-price",
|
|
90
123
|
className: "block text-sm font-medium text-text-primary",
|
|
91
|
-
children:
|
|
92
|
-
}), /* @__PURE__ */
|
|
124
|
+
children: O("ggnomad.listingEdit.priceLabel", se)
|
|
125
|
+
}), /* @__PURE__ */ y("input", {
|
|
93
126
|
id: "listing-edit-price",
|
|
94
127
|
type: "number",
|
|
95
128
|
step: "0.01",
|
|
96
129
|
min: "0",
|
|
97
|
-
value:
|
|
98
|
-
onChange: (e) =>
|
|
99
|
-
disabled:
|
|
130
|
+
value: P,
|
|
131
|
+
onChange: (e) => F(e.target.value),
|
|
132
|
+
disabled: $,
|
|
100
133
|
className: "mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50",
|
|
101
134
|
placeholder: "0.00"
|
|
102
135
|
})] }),
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
className: "block text-sm font-medium text-text-primary",
|
|
106
|
-
children: E("ggnomad.listingEdit.statusLabel", "Status")
|
|
107
|
-
}), /* @__PURE__ */ y("select", {
|
|
108
|
-
id: "listing-edit-status",
|
|
109
|
-
value: P,
|
|
110
|
-
onChange: (e) => F(e.target.value),
|
|
111
|
-
disabled: K,
|
|
112
|
-
className: "mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm text-text-primary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50",
|
|
136
|
+
I ? /* @__PURE__ */ b("div", {
|
|
137
|
+
"data-testid": "listing-edit-status",
|
|
113
138
|
children: [
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
-
|
|
116
|
-
children:
|
|
139
|
+
/* @__PURE__ */ y("span", {
|
|
140
|
+
className: "block text-sm font-medium text-text-primary",
|
|
141
|
+
children: O("ggnomad.listingEdit.statusLabel", "Status")
|
|
117
142
|
}),
|
|
118
|
-
/* @__PURE__ */
|
|
119
|
-
|
|
120
|
-
children:
|
|
143
|
+
/* @__PURE__ */ b("div", {
|
|
144
|
+
className: "mt-1 flex flex-wrap items-center gap-3",
|
|
145
|
+
children: [/* @__PURE__ */ y("span", {
|
|
146
|
+
className: "rounded-md border border-border-seam bg-bg-sunken px-2 py-1 text-sm text-text-primary",
|
|
147
|
+
children: ie[I] ?? I
|
|
148
|
+
}), L ? /* @__PURE__ */ y("button", {
|
|
149
|
+
type: "button",
|
|
150
|
+
onClick: () => void re(L),
|
|
151
|
+
disabled: $,
|
|
152
|
+
className: "rounded-md border border-border-seam px-3 py-1 text-sm font-medium text-text-primary hover:bg-bg-surface disabled:opacity-50",
|
|
153
|
+
children: ae[L]
|
|
154
|
+
}) : null]
|
|
121
155
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
-
|
|
124
|
-
children:
|
|
125
|
-
})
|
|
156
|
+
I === "PENDING_REVIEW" ? /* @__PURE__ */ y("p", {
|
|
157
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
158
|
+
children: O("ggnomad.listingEdit.pendingReviewHint", "A marketplace operator is reviewing this listing. It goes live once approved.")
|
|
159
|
+
}) : null
|
|
126
160
|
]
|
|
127
|
-
})
|
|
128
|
-
/* @__PURE__ */
|
|
161
|
+
}) : null,
|
|
162
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
129
163
|
htmlFor: "listing-edit-images",
|
|
130
164
|
className: "block text-sm font-medium text-text-primary",
|
|
131
|
-
children:
|
|
132
|
-
}), /* @__PURE__ */
|
|
165
|
+
children: O("ggnomad.listingEdit.imagesLabel", "Images (one URL per line)")
|
|
166
|
+
}), /* @__PURE__ */ y("textarea", {
|
|
133
167
|
id: "listing-edit-images",
|
|
134
|
-
value:
|
|
135
|
-
onChange: (e) =>
|
|
136
|
-
disabled:
|
|
168
|
+
value: R,
|
|
169
|
+
onChange: (e) => z(e.target.value),
|
|
170
|
+
disabled: $,
|
|
137
171
|
rows: 3,
|
|
138
172
|
className: "mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm font-mono text-text-primary placeholder-text-secondary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50",
|
|
139
|
-
placeholder:
|
|
173
|
+
placeholder: O("ggnomad.listingEdit.imagesPlaceholder", "https://example.com/image1.jpg\nhttps://example.com/image2.jpg")
|
|
140
174
|
})] })
|
|
141
175
|
]
|
|
142
176
|
}),
|
|
143
|
-
/* @__PURE__ */
|
|
144
|
-
disabled:
|
|
145
|
-
children:
|
|
146
|
-
}), /* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ b(_, { children: [/* @__PURE__ */ y(ee, {
|
|
178
|
+
disabled: $,
|
|
179
|
+
children: O("ggnomad.listingEdit.cancel", "Cancel")
|
|
180
|
+
}), /* @__PURE__ */ y(m, {
|
|
147
181
|
onClick: (e) => {
|
|
148
|
-
e.preventDefault(),
|
|
182
|
+
e.preventDefault(), oe();
|
|
149
183
|
},
|
|
150
|
-
disabled:
|
|
184
|
+
disabled: $,
|
|
151
185
|
className: "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover",
|
|
152
|
-
children:
|
|
186
|
+
children: $ ? O("ggnomad.listingEdit.saving", "Saving…") : O("ggnomad.listingEdit.save", "Save changes")
|
|
153
187
|
})] })
|
|
154
188
|
]
|
|
155
189
|
})
|
|
156
190
|
});
|
|
157
191
|
}
|
|
158
192
|
//#endregion
|
|
159
|
-
export {
|
|
193
|
+
export { S as ListingEditDialog };
|
|
160
194
|
|
|
161
195
|
//# sourceMappingURL=ListingEditDialog.js.map
|