@zappie/theme-base 0.0.0-stage → 0.1.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +37 -2
  4. package/dist/address.d.ts +32 -0
  5. package/dist/address.js +4 -0
  6. package/dist/address.js.map +1 -0
  7. package/dist/cart.d.ts +12 -0
  8. package/dist/cart.js +1140 -0
  9. package/dist/cart.js.map +1 -0
  10. package/dist/catalogue.d.ts +60 -0
  11. package/dist/catalogue.js +1389 -0
  12. package/dist/catalogue.js.map +1 -0
  13. package/dist/checkout.d.ts +36 -0
  14. package/dist/checkout.js +4 -0
  15. package/dist/checkout.js.map +1 -0
  16. package/dist/chunk-2MV6KU3R.js +352 -0
  17. package/dist/chunk-2MV6KU3R.js.map +1 -0
  18. package/dist/chunk-FB5DRCU7.js +146 -0
  19. package/dist/chunk-FB5DRCU7.js.map +1 -0
  20. package/dist/chunk-IG63ONID.js +139 -0
  21. package/dist/chunk-IG63ONID.js.map +1 -0
  22. package/dist/chunk-ILOCSCZL.js +217 -0
  23. package/dist/chunk-ILOCSCZL.js.map +1 -0
  24. package/dist/chunk-JFEI2OUZ.js +13 -0
  25. package/dist/chunk-JFEI2OUZ.js.map +1 -0
  26. package/dist/chunk-NTJONY3N.js +95 -0
  27. package/dist/chunk-NTJONY3N.js.map +1 -0
  28. package/dist/chunk-QWST2TA2.js +22 -0
  29. package/dist/chunk-QWST2TA2.js.map +1 -0
  30. package/dist/chunk-USSLDBDY.js +48 -0
  31. package/dist/chunk-USSLDBDY.js.map +1 -0
  32. package/dist/chunk-VIAJ27YC.js +59 -0
  33. package/dist/chunk-VIAJ27YC.js.map +1 -0
  34. package/dist/host-bridge.d.ts +100 -0
  35. package/dist/host-bridge.js +4 -0
  36. package/dist/host-bridge.js.map +1 -0
  37. package/dist/index.d.ts +3 -0
  38. package/dist/index.js +6 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/item-frame.d.ts +20 -0
  41. package/dist/item-frame.js +5 -0
  42. package/dist/item-frame.js.map +1 -0
  43. package/dist/item.d.ts +20 -0
  44. package/dist/item.js +153 -0
  45. package/dist/item.js.map +1 -0
  46. package/dist/navigation.d.ts +64 -0
  47. package/dist/navigation.js +4 -0
  48. package/dist/navigation.js.map +1 -0
  49. package/dist/styles.css +842 -0
  50. package/package.json +74 -3
package/dist/cart.js ADDED
@@ -0,0 +1,1140 @@
1
+ "use client";
2
+ import { useAddressLookup } from './chunk-NTJONY3N.js';
3
+ import { ClearCart, CartLine } from './chunk-FB5DRCU7.js';
4
+ import './chunk-2MV6KU3R.js';
5
+ import { useBaseHostBridge } from './chunk-QWST2TA2.js';
6
+ import { ThemeClassProvider, useThemeClass } from './chunk-JFEI2OUZ.js';
7
+ import { useCheckoutHandoff } from './chunk-IG63ONID.js';
8
+ import { useOverlay, Overlay, Cart, Fulfilment, Branch, Totals as Totals$1, Money, Address, Schedule } from '@zappie/foundations';
9
+ import { countEvent } from '@zappie/sdk/visits';
10
+ import { useRef, useState, useEffect, Fragment, useId, useCallback } from 'react';
11
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
+ import { useStore, useCart, useCartCatalogue } from '@zappie/sdk/react';
13
+ import { isContactPhoneValid, payReadiness } from '@zappie/sdk/checkout';
14
+ import { format } from '@zappie/sdk';
15
+
16
+ var labels = {
17
+ remove_line: "Remove item",
18
+ accept_price: "Accept new price",
19
+ remove_promo: "Remove promo",
20
+ set_quantity: "Update quantity",
21
+ choose_option: "Choose options",
22
+ choose_other_option: "Change options",
23
+ change_address: "Change delivery address",
24
+ schedule: "Choose order time"
25
+ };
26
+ function Issue({
27
+ issue,
28
+ applyFix
29
+ }) {
30
+ const editor = useOverlay("cart_edit", issue.lineId ?? "");
31
+ const address = useOverlay("cart_sheet", "address");
32
+ const schedule = useOverlay("cart_sheet", "schedule");
33
+ const [error, setError] = useState(null);
34
+ const fix = (value) => {
35
+ setError(null);
36
+ try {
37
+ if (value.action === "choose_option" || value.action === "choose_other_option") {
38
+ editor.open();
39
+ } else if (value.action === "change_address") {
40
+ address.open();
41
+ } else if (value.action === "schedule") {
42
+ schedule.open();
43
+ } else {
44
+ applyFix(issue, value);
45
+ }
46
+ } catch (error2) {
47
+ setError(
48
+ error2 instanceof Error ? error2.message : "Unable to apply this change"
49
+ );
50
+ }
51
+ };
52
+ return /* @__PURE__ */ jsxs("li", { children: [
53
+ /* @__PURE__ */ jsx("p", { children: issue.message }),
54
+ issue.fixes.filter((value) => labels[value.action]).map((value, index) => /* @__PURE__ */ jsx(
55
+ "button",
56
+ {
57
+ type: "button",
58
+ className: "z-base-button-secondary",
59
+ onClick: () => fix(value),
60
+ children: value.action === "set_quantity" ? `Set quantity to ${value.quantity}` : labels[value.action]
61
+ },
62
+ index
63
+ )),
64
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error })
65
+ ] });
66
+ }
67
+ function CartIssues() {
68
+ return /* @__PURE__ */ jsx(Cart.Issues, { children: ({ issues, applyFix }) => issues.length > 0 && /* @__PURE__ */ jsxs("section", { className: "z-base-issues", "aria-label": "Cart issues", children: [
69
+ /* @__PURE__ */ jsx("h2", { children: "Review your cart" }),
70
+ /* @__PURE__ */ jsx("ul", { children: issues.map((issue, index) => /* @__PURE__ */ jsx(
71
+ Issue,
72
+ {
73
+ issue,
74
+ applyFix
75
+ },
76
+ `${issue.lineId}:${issue.code}:${index}`
77
+ )) })
78
+ ] }) });
79
+ }
80
+
81
+ // src/cart/cart-line-groups.ts
82
+ function groupCartLinesByMenu(lines, catalogue) {
83
+ const names = new Map(
84
+ (catalogue?.menus ?? []).map((menu) => [menu.id, menu.name])
85
+ );
86
+ const groups = /* @__PURE__ */ new Map();
87
+ for (const line of lines) {
88
+ const menuId = line.menuId ?? "unknown";
89
+ const group = groups.get(menuId);
90
+ if (group) {
91
+ group.lines.push(line);
92
+ continue;
93
+ }
94
+ const menuName = names.get(menuId);
95
+ groups.set(menuId, {
96
+ menuId,
97
+ ...menuName !== void 0 ? { menuName } : {},
98
+ lines: [line]
99
+ });
100
+ }
101
+ const ordered = [];
102
+ for (const menu of catalogue?.menus ?? []) {
103
+ const group = groups.get(menu.id);
104
+ if (group) {
105
+ ordered.push(group);
106
+ groups.delete(menu.id);
107
+ }
108
+ }
109
+ return [...ordered, ...groups.values()];
110
+ }
111
+ function CartLines() {
112
+ const { lines } = useCart();
113
+ const catalogue = useCartCatalogue();
114
+ const groups = groupCartLinesByMenu(lines, catalogue);
115
+ const grouped = (catalogue?.menus?.length ?? 0) > 1;
116
+ return /* @__PURE__ */ jsx("section", { "aria-label": "Cart items", className: "z-base-lines", children: groups.map((group) => /* @__PURE__ */ jsxs(
117
+ "section",
118
+ {
119
+ "aria-label": group.menuName ?? "Other items",
120
+ className: "z-base-line-group",
121
+ children: [
122
+ grouped && /* @__PURE__ */ jsx("h2", { children: group.menuName ?? "Other items" }),
123
+ group.lines.map((line) => /* @__PURE__ */ jsx(CartLine, { line }, line.id))
124
+ ]
125
+ },
126
+ group.menuId
127
+ )) });
128
+ }
129
+ var FIELDS = [
130
+ { field: "firstName", label: "First name", autoComplete: "given-name" },
131
+ { field: "lastName", label: "Last name", autoComplete: "family-name" },
132
+ { field: "email", label: "Email", autoComplete: "email" }
133
+ ];
134
+ function CustomerDetails({
135
+ contactPhone
136
+ } = {}) {
137
+ const { customerDetails } = useBaseHostBridge();
138
+ const handoff = useCheckoutHandoff();
139
+ const showPhone = Boolean(
140
+ contactPhone && handoff.contactPhone && handoff.customer
141
+ );
142
+ const inputId = useId();
143
+ const hintId = useId();
144
+ const errorId = useId();
145
+ const invalid = Boolean(
146
+ contactPhone?.touched && !isContactPhoneValid(contactPhone.value)
147
+ );
148
+ if (!customerDetails && !showPhone) {
149
+ return null;
150
+ }
151
+ return /* @__PURE__ */ jsxs("section", { className: "z-base-fulfilment-panel", "aria-label": "Your details", children: [
152
+ /* @__PURE__ */ jsx("h2", { children: "Your details" }),
153
+ customerDetails && FIELDS.filter(
154
+ ({ field }) => field !== "email" || customerDetails.requiresEmail
155
+ ).map(({ field, label, autoComplete }) => /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
156
+ label,
157
+ /* @__PURE__ */ jsx(
158
+ "input",
159
+ {
160
+ type: field === "email" ? "email" : "text",
161
+ autoComplete,
162
+ required: field !== "lastName",
163
+ value: customerDetails.values[field],
164
+ onChange: (event) => customerDetails.update(field, event.target.value)
165
+ }
166
+ )
167
+ ] }, field)),
168
+ showPhone && contactPhone && /* @__PURE__ */ jsxs("div", { className: "z-base-field", children: [
169
+ /* @__PURE__ */ jsx("label", { htmlFor: inputId, children: "Contact phone (optional)" }),
170
+ /* @__PURE__ */ jsx(
171
+ "input",
172
+ {
173
+ id: inputId,
174
+ type: "tel",
175
+ inputMode: "tel",
176
+ autoComplete: "tel",
177
+ value: contactPhone.value,
178
+ "aria-describedby": invalid ? `${hintId} ${errorId}` : hintId,
179
+ "aria-invalid": invalid,
180
+ onBlur: contactPhone.touch,
181
+ onChange: (event) => contactPhone.update(event.target.value)
182
+ }
183
+ ),
184
+ /* @__PURE__ */ jsx("span", { id: hintId, children: handoff.customer?.phoneLast4 ? `Leave blank to use your Zappie number ending ${handoff.customer.phoneLast4}` : "Leave blank to use your Zappie number" }),
185
+ invalid && /* @__PURE__ */ jsx("span", { id: errorId, role: "alert", children: "Enter a phone number with 7 to 15 digits" })
186
+ ] })
187
+ ] });
188
+ }
189
+ function DeliveryDistance() {
190
+ const distance = useBaseHostBridge().deliveryDistance;
191
+ if (!distance?.message) {
192
+ return null;
193
+ }
194
+ return /* @__PURE__ */ jsx(
195
+ "p",
196
+ {
197
+ role: distance.status === "too_far" ? "alert" : "status",
198
+ className: "z-base-notice",
199
+ "data-severity": distance.status === "too_far" ? "error" : "warning",
200
+ children: distance.message
201
+ }
202
+ );
203
+ }
204
+ function EmptyCart() {
205
+ return /* @__PURE__ */ jsxs(Cart.Empty, { className: "z-base-cart-empty", children: [
206
+ /* @__PURE__ */ jsx("h2", { children: "Your cart is empty" }),
207
+ /* @__PURE__ */ jsx("p", { children: "Add something from the menu to get started." }),
208
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button", children: "Browse menu" })
209
+ ] });
210
+ }
211
+ function CartSheet({
212
+ id,
213
+ title,
214
+ trigger,
215
+ children
216
+ }) {
217
+ const rootClass = useThemeClass("z-base-cart z-base-editor");
218
+ const overlay = useOverlay("cart_sheet", id);
219
+ return /* @__PURE__ */ jsxs(
220
+ Overlay.Root,
221
+ {
222
+ param: "cart_sheet",
223
+ id,
224
+ presentation: { base: "sheet", lg: "dialog" },
225
+ children: [
226
+ /* @__PURE__ */ jsx(Overlay.Trigger, { className: "z-base-button-secondary", children: trigger }),
227
+ /* @__PURE__ */ jsxs(Overlay.Content, { "data-zappie-theme": "base", className: rootClass, children: [
228
+ /* @__PURE__ */ jsxs("header", { className: "z-base-cart-header", children: [
229
+ /* @__PURE__ */ jsx(Overlay.Title, { children: title }),
230
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Cancel" })
231
+ ] }),
232
+ overlay.isOpen && /* @__PURE__ */ jsx("div", { className: "z-base-cart-body", children })
233
+ ] })
234
+ ]
235
+ }
236
+ );
237
+ }
238
+ function useAddressSelection(initial) {
239
+ const lookup = useAddressLookup();
240
+ const [selected, setSelected] = useState(initial);
241
+ const [query, setQuery] = useState(initial?.line1 ?? "");
242
+ const [busy, setBusy] = useState(false);
243
+ const [locating, setLocating] = useState(false);
244
+ const [error, setError] = useState(null);
245
+ const revision = useRef(0);
246
+ const sessions = useRef(/* @__PURE__ */ new Map());
247
+ const suggestions = useCallback(
248
+ async (query2) => {
249
+ const values = await lookup.suggest(query2);
250
+ return values.map((value) => {
251
+ sessions.current.set(value.placeId, value.sessionToken);
252
+ return {
253
+ id: value.placeId,
254
+ label: value.address,
255
+ address: { line1: value.address, placeId: value.placeId }
256
+ };
257
+ });
258
+ },
259
+ [lookup]
260
+ );
261
+ const changeQuery = (value) => {
262
+ revision.current++;
263
+ setQuery(value);
264
+ setSelected(void 0);
265
+ setBusy(false);
266
+ setLocating(false);
267
+ setError(null);
268
+ };
269
+ const run = async (request, operation, fillQuery) => {
270
+ try {
271
+ const resolved = await operation();
272
+ if (revision.current === request) {
273
+ setSelected(resolved);
274
+ if (fillQuery) {
275
+ setQuery(resolved.line1);
276
+ }
277
+ }
278
+ } catch (failure) {
279
+ const aborted = (failure instanceof Error || failure instanceof DOMException) && failure.name === "AbortError";
280
+ if (revision.current === request && !aborted) {
281
+ setError(
282
+ failure instanceof Error ? failure.message : "Unable to locate this address"
283
+ );
284
+ }
285
+ } finally {
286
+ if (revision.current === request) {
287
+ setBusy(false);
288
+ setLocating(false);
289
+ }
290
+ }
291
+ };
292
+ const select = (address) => {
293
+ const request = ++revision.current;
294
+ setLocating(false);
295
+ setBusy(true);
296
+ setError(null);
297
+ const resolve = lookup.resolve;
298
+ if (!resolve) {
299
+ setSelected(address);
300
+ setBusy(false);
301
+ return Promise.resolve();
302
+ }
303
+ return run(
304
+ request,
305
+ () => resolve(address, sessions.current.get(address.placeId ?? "")),
306
+ false
307
+ );
308
+ };
309
+ const findCurrentLocation = () => {
310
+ if (!lookup.reverse || !navigator.geolocation) {
311
+ return;
312
+ }
313
+ const reverse = lookup.reverse;
314
+ const request = ++revision.current;
315
+ setBusy(true);
316
+ setLocating(true);
317
+ setError(null);
318
+ navigator.geolocation.getCurrentPosition(
319
+ (position) => {
320
+ if (revision.current !== request) {
321
+ return;
322
+ }
323
+ void run(
324
+ request,
325
+ () => reverse({
326
+ lat: position.coords.latitude,
327
+ lng: position.coords.longitude
328
+ }),
329
+ true
330
+ );
331
+ },
332
+ (failure) => {
333
+ if (revision.current !== request) {
334
+ return;
335
+ }
336
+ if (failure.code === 1) {
337
+ setError("Location access is off. Search for your address instead.");
338
+ } else {
339
+ setError(
340
+ "We couldn't find your location. Search for your address instead."
341
+ );
342
+ }
343
+ setBusy(false);
344
+ setLocating(false);
345
+ },
346
+ { enableHighAccuracy: false, timeout: 1e4, maximumAge: 6e4 }
347
+ );
348
+ };
349
+ return {
350
+ selected,
351
+ query,
352
+ busy,
353
+ locating,
354
+ error,
355
+ suggestions,
356
+ changeQuery,
357
+ select,
358
+ findCurrentLocation
359
+ };
360
+ }
361
+ function AddressForm() {
362
+ const cart = useCart();
363
+ const lookup = useAddressLookup();
364
+ const bridge = useBaseHostBridge();
365
+ const overlay = useOverlay("cart_sheet", "address");
366
+ const current = cart.fulfilment?.type === "delivery" ? cart.fulfilment.address : void 0;
367
+ const {
368
+ selected,
369
+ query,
370
+ busy,
371
+ error: lookupError,
372
+ suggestions,
373
+ changeQuery,
374
+ select,
375
+ findCurrentLocation,
376
+ locating
377
+ } = useAddressSelection(current);
378
+ const [instructions, setInstructions] = useState(current?.instructions ?? "");
379
+ const [error, setError] = useState(null);
380
+ const save = () => {
381
+ if (!selected || !cart.branchId || busy) {
382
+ return;
383
+ }
384
+ setError(null);
385
+ try {
386
+ const fulfilment = {
387
+ type: "delivery",
388
+ branchId: cart.branchId,
389
+ address: { ...selected, instructions },
390
+ ...cart.fulfilment && "scheduledFor" in cart.fulfilment ? { scheduledFor: cart.fulfilment.scheduledFor } : {}
391
+ };
392
+ cart.actions.setFulfilment(fulfilment);
393
+ bridge.saveFulfilment?.(fulfilment);
394
+ overlay.close();
395
+ } catch (failure) {
396
+ setError(
397
+ failure instanceof Error ? failure.message : "Unable to save this address"
398
+ );
399
+ }
400
+ };
401
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
402
+ lookup.reverse && typeof navigator !== "undefined" && navigator.geolocation && /* @__PURE__ */ jsx(
403
+ "button",
404
+ {
405
+ type: "button",
406
+ className: "z-base-button-secondary",
407
+ disabled: busy,
408
+ onClick: findCurrentLocation,
409
+ children: locating ? "Finding your location\u2026" : "Use my current location"
410
+ }
411
+ ),
412
+ /* @__PURE__ */ jsx(
413
+ Address.Picker,
414
+ {
415
+ query,
416
+ onQueryChange: changeQuery,
417
+ getSuggestions: suggestions,
418
+ onSelect: (value) => {
419
+ if ("address" in value) {
420
+ void select(value.address);
421
+ }
422
+ },
423
+ children: ({ suggestions: suggestions2, status, isOpen }) => /* @__PURE__ */ jsxs(Fragment, { children: [
424
+ /* @__PURE__ */ jsxs("label", { className: "z-base-field", htmlFor: "z-base-delivery-address", children: [
425
+ "Delivery address",
426
+ /* @__PURE__ */ jsx(
427
+ Address.Input,
428
+ {
429
+ className: "z-base-input",
430
+ id: "z-base-delivery-address",
431
+ "aria-label": "Delivery address"
432
+ }
433
+ )
434
+ ] }),
435
+ status === "loading" && /* @__PURE__ */ jsx("p", { role: "status", children: "Finding addresses\u2026" }),
436
+ status === "error" && /* @__PURE__ */ jsx("p", { role: "alert", children: "Unable to find addresses. Try again." }),
437
+ isOpen && /* @__PURE__ */ jsx(Address.Suggestions, { className: "z-base-suggestions", children: suggestions2.map((value, index) => /* @__PURE__ */ jsx(
438
+ Address.Suggestion,
439
+ {
440
+ index,
441
+ className: "z-base-choice",
442
+ children: value.label
443
+ },
444
+ value.id
445
+ )) }),
446
+ isOpen && status === "ready" && query && suggestions2.length === 0 && /* @__PURE__ */ jsx("p", { children: "No matching addresses." })
447
+ ] })
448
+ }
449
+ ),
450
+ /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
451
+ "Delivery instructions",
452
+ /* @__PURE__ */ jsx(
453
+ "textarea",
454
+ {
455
+ className: "z-base-input",
456
+ maxLength: 500,
457
+ value: instructions,
458
+ onChange: (event) => setInstructions(event.target.value)
459
+ }
460
+ )
461
+ ] }),
462
+ selected && lookup.Map && /* @__PURE__ */ jsx(lookup.Map, { address: selected }),
463
+ lookupError && /* @__PURE__ */ jsx("p", { role: "alert", children: lookupError }),
464
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
465
+ /* @__PURE__ */ jsx(
466
+ "button",
467
+ {
468
+ type: "button",
469
+ className: "z-base-button",
470
+ disabled: !selected || busy,
471
+ onClick: () => {
472
+ void save();
473
+ },
474
+ children: busy ? "Locating address\u2026" : "Save address"
475
+ }
476
+ )
477
+ ] });
478
+ }
479
+ function AddressSheet() {
480
+ const cart = useCart();
481
+ return /* @__PURE__ */ jsx(
482
+ CartSheet,
483
+ {
484
+ id: "address",
485
+ title: "Delivery address",
486
+ trigger: cart.fulfilment?.type === "delivery" ? "Change address" : "Add delivery address",
487
+ children: /* @__PURE__ */ jsx(AddressForm, {})
488
+ }
489
+ );
490
+ }
491
+ function RegionPicker() {
492
+ const bridge = useBaseHostBridge();
493
+ const regions = bridge.deliveryRegions;
494
+ if (!regions?.length || !bridge.setDeliveryRegion) {
495
+ return null;
496
+ }
497
+ const sorted = [...regions].sort((a, b) => a.name.localeCompare(b.name));
498
+ return /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
499
+ "Delivery region",
500
+ /* @__PURE__ */ jsxs(
501
+ "select",
502
+ {
503
+ className: "z-base-input",
504
+ value: bridge.deliveryRegionId ?? "",
505
+ onChange: (event) => {
506
+ if (event.target.value) {
507
+ bridge.setDeliveryRegion?.(event.target.value);
508
+ }
509
+ },
510
+ children: [
511
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Choose a delivery region" }),
512
+ sorted.map((region) => /* @__PURE__ */ jsxs("option", { value: region.id, children: [
513
+ region.name,
514
+ " (",
515
+ format.money(region.fee),
516
+ ")"
517
+ ] }, region.id))
518
+ ]
519
+ }
520
+ )
521
+ ] });
522
+ }
523
+
524
+ // src/cart/cart-schedule.ts
525
+ function cartScheduleLimits(menu, lines, maxDays) {
526
+ const sections = (menu?.menus ?? []).filter(
527
+ (section) => section.schedule?.preorder && lines.some(
528
+ (line) => line.menuId ? line.menuId === section.id : section.categoryIds.some(
529
+ (id) => menu?.categories.find((category) => category.id === id)?.itemIds.includes(line.itemId)
530
+ )
531
+ )
532
+ );
533
+ const notice = Math.max(
534
+ 0,
535
+ ...sections.map((section) => section.schedule?.preorderNoticeHours ?? 0)
536
+ );
537
+ const horizons = sections.map((section) => section.schedule?.preorderMaxDays).filter((days) => typeof days === "number" && days > 0);
538
+ const limit = horizons.length > 0 ? Math.min(maxDays ?? Number.POSITIVE_INFINITY, ...horizons) : maxDays;
539
+ return {
540
+ noticeMinutes: notice * 60,
541
+ maxDays: limit === void 0 ? void 0 : Math.max(1, Math.min(90, limit))
542
+ };
543
+ }
544
+ function ScheduleForm({ branch }) {
545
+ const cart = useCart();
546
+ const bridge = useBaseHostBridge();
547
+ const overlay = useOverlay("cart_sheet", "schedule");
548
+ const menu = useCartCatalogue();
549
+ const limits = cartScheduleLimits(menu, cart.lines, bridge.scheduleMaxDays);
550
+ const [error, setError] = useState(null);
551
+ const fulfilment = cart.fulfilment;
552
+ if (!fulfilment || fulfilment.type === "dine_in") {
553
+ return /* @__PURE__ */ jsx("p", { children: "Add a delivery address or select pickup before choosing a time." });
554
+ }
555
+ return /* @__PURE__ */ jsx(
556
+ Schedule,
557
+ {
558
+ branch: bridge.scheduleOpeningTimes ? { ...branch, openingTimes: bridge.scheduleOpeningTimes } : branch,
559
+ maxDays: limits.maxDays,
560
+ noticeMinutes: limits.noticeMinutes,
561
+ defaultValue: fulfilment.scheduledFor ?? null,
562
+ children: ({ days, value, setValue, canAsap, isValid }) => /* @__PURE__ */ jsxs("div", { className: "z-base-field", children: [
563
+ /* @__PURE__ */ jsxs("p", { children: [
564
+ "Times are shown in ",
565
+ branch.timezone ?? "the store\u2019s timezone",
566
+ "."
567
+ ] }),
568
+ /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
569
+ "Order time",
570
+ /* @__PURE__ */ jsxs(
571
+ "select",
572
+ {
573
+ className: "z-base-input",
574
+ value: value ?? "",
575
+ onChange: (event) => setValue(event.target.value || null),
576
+ children: [
577
+ /* @__PURE__ */ jsx("option", { value: "", disabled: !canAsap, children: "As soon as possible" }),
578
+ days.map((day) => /* @__PURE__ */ jsx("optgroup", { label: day.date, children: day.slots.map((slot) => /* @__PURE__ */ jsx("option", { value: slot.value, children: slot.label }, slot.value)) }, day.date))
579
+ ]
580
+ }
581
+ )
582
+ ] }),
583
+ !isValid && /* @__PURE__ */ jsx("p", { role: "alert", children: "Choose an available order time." }),
584
+ days.length === 0 && /* @__PURE__ */ jsx("p", { children: "No scheduled times are currently available." }),
585
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
586
+ /* @__PURE__ */ jsx(
587
+ "button",
588
+ {
589
+ type: "button",
590
+ className: "z-base-button",
591
+ disabled: !isValid,
592
+ onClick: () => {
593
+ try {
594
+ const next = { ...fulfilment };
595
+ if (value === null) {
596
+ delete next.scheduledFor;
597
+ } else {
598
+ next.scheduledFor = value;
599
+ }
600
+ cart.actions.setFulfilment(next);
601
+ bridge.saveFulfilment?.(next);
602
+ overlay.close();
603
+ } catch (failure) {
604
+ setError(
605
+ failure instanceof Error ? failure.message : "Unable to save this time"
606
+ );
607
+ }
608
+ },
609
+ children: "Save time"
610
+ }
611
+ )
612
+ ] })
613
+ }
614
+ );
615
+ }
616
+ function ScheduleSheet({ branch }) {
617
+ return /* @__PURE__ */ jsx(CartSheet, { id: "schedule", title: "Schedule order", trigger: "Choose order time", children: /* @__PURE__ */ jsx(ScheduleForm, { branch }) });
618
+ }
619
+ function FulfilmentPanel() {
620
+ const cart = useCart();
621
+ const store = useStore();
622
+ const bridge = useBaseHostBridge();
623
+ const lookup = useAddressLookup();
624
+ const [error, setError] = useState(null);
625
+ const branch = store.data?.branches.find(
626
+ (branch2) => branch2.id === cart.branchId
627
+ );
628
+ const mode = bridge.fulfilmentMode ?? cart.fulfilment?.type ?? "delivery";
629
+ if (!branch) {
630
+ return null;
631
+ }
632
+ const scheduledFor = cart.fulfilment && "scheduledFor" in cart.fulfilment ? cart.fulfilment.scheduledFor : void 0;
633
+ return /* @__PURE__ */ jsxs("section", { className: "z-base-fulfilment-panel", "aria-label": "Fulfilment", children: [
634
+ /* @__PURE__ */ jsx("h2", { children: "Fulfilment" }),
635
+ /* @__PURE__ */ jsx(Fulfilment.Switch, { "aria-label": "Order fulfilment", children: ({ options }) => /* @__PURE__ */ jsx("div", { className: "z-base-line-actions", children: options.filter((option) => option !== "dine_in").map((option) => /* @__PURE__ */ jsx(
636
+ "button",
637
+ {
638
+ type: "button",
639
+ "aria-pressed": mode === option,
640
+ className: "z-base-button-secondary",
641
+ onClick: () => {
642
+ setError(null);
643
+ try {
644
+ if (!bridge.setFulfilmentMode(
645
+ option
646
+ )) {
647
+ setError(
648
+ "This menu does not allow that fulfilment option."
649
+ );
650
+ }
651
+ } catch (failure) {
652
+ setError(
653
+ failure instanceof Error ? failure.message : "Unable to change fulfilment"
654
+ );
655
+ }
656
+ },
657
+ children: option === "pickup" ? "Pickup" : "Delivery"
658
+ },
659
+ option
660
+ )) }) }),
661
+ /* @__PURE__ */ jsx(Branch.Picker, { branches: [branch], children: ({ selected }) => /* @__PURE__ */ jsxs("p", { children: [
662
+ mode === "pickup" ? "Collect from" : "Ordering from",
663
+ " ",
664
+ selected?.name,
665
+ selected?.address ? ` \u2014 ${selected.address}` : ""
666
+ ] }) }),
667
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
668
+ mode === "delivery" && /* @__PURE__ */ jsxs(Fragment, { children: [
669
+ cart.fulfilment?.type === "delivery" && /* @__PURE__ */ jsxs(Fragment, { children: [
670
+ /* @__PURE__ */ jsx("p", { children: cart.fulfilment.address.line1 }),
671
+ lookup.Map && /* @__PURE__ */ jsx(lookup.Map, { address: cart.fulfilment.address })
672
+ ] }),
673
+ /* @__PURE__ */ jsx(AddressSheet, {}),
674
+ /* @__PURE__ */ jsx(RegionPicker, {})
675
+ ] }),
676
+ scheduledFor && /* @__PURE__ */ jsxs("p", { children: [
677
+ "Scheduled for",
678
+ " ",
679
+ new Intl.DateTimeFormat("en", {
680
+ dateStyle: "medium",
681
+ timeStyle: "short",
682
+ timeZone: branch.timezone ?? store.data?.timezone
683
+ }).format(new Date(scheduledFor))
684
+ ] }),
685
+ branch.fulfilment.scheduling && /* @__PURE__ */ jsx(ScheduleSheet, { branch })
686
+ ] });
687
+ }
688
+ function Loading() {
689
+ const { error } = useStore();
690
+ if (error) {
691
+ return /* @__PURE__ */ jsx("p", { role: "alert", children: "Unable to load the cart. Reload the page to try again." });
692
+ }
693
+ return /* @__PURE__ */ jsxs("div", { className: "z-base-cart-empty", role: "status", "aria-busy": "true", children: [
694
+ /* @__PURE__ */ jsx("p", { children: "Loading cart\u2026" }),
695
+ /* @__PURE__ */ jsx("div", { className: "z-base-cart-placeholder", "aria-hidden": "true" })
696
+ ] });
697
+ }
698
+ function PromoForm() {
699
+ const cart = useCart();
700
+ const bridge = useBaseHostBridge();
701
+ const overlay = useOverlay("cart_sheet", "promo");
702
+ const [code, setCode] = useState(cart.promoCode ?? "");
703
+ const [error, setError] = useState(null);
704
+ const save = (value) => {
705
+ try {
706
+ cart.actions.setPromoCode(value);
707
+ overlay.close();
708
+ } catch (failure) {
709
+ setError(
710
+ failure instanceof Error ? failure.message : "Unable to apply this code"
711
+ );
712
+ }
713
+ };
714
+ return /* @__PURE__ */ jsxs(
715
+ "form",
716
+ {
717
+ className: "z-base-field",
718
+ onSubmit: (event) => {
719
+ event.preventDefault();
720
+ save(code.trim());
721
+ },
722
+ children: [
723
+ /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
724
+ "Promo code",
725
+ /* @__PURE__ */ jsx(
726
+ "input",
727
+ {
728
+ className: "z-base-input",
729
+ autoComplete: "off",
730
+ value: code,
731
+ onChange: (event) => setCode(event.target.value)
732
+ }
733
+ )
734
+ ] }),
735
+ /* @__PURE__ */ jsx("p", { children: "Discounts are confirmed when your order totals update." }),
736
+ bridge.availablePromos?.length ? /* @__PURE__ */ jsxs("section", { "aria-label": "Available promos", children: [
737
+ /* @__PURE__ */ jsx("h3", { children: "Available promos" }),
738
+ /* @__PURE__ */ jsx("ul", { className: "z-base-option-list", children: bridge.availablePromos.map((promo) => /* @__PURE__ */ jsxs("li", { children: [
739
+ /* @__PURE__ */ jsxs("div", { children: [
740
+ /* @__PURE__ */ jsx("strong", { children: promo.name }),
741
+ /* @__PURE__ */ jsx("p", { children: promo.description })
742
+ ] }),
743
+ /* @__PURE__ */ jsxs(
744
+ "button",
745
+ {
746
+ className: "z-base-button-secondary",
747
+ type: "button",
748
+ disabled: promo.disabled,
749
+ onClick: () => save(promo.code),
750
+ children: [
751
+ "Apply ",
752
+ promo.code
753
+ ]
754
+ }
755
+ )
756
+ ] }, promo.id)) })
757
+ ] }) : null,
758
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
759
+ /* @__PURE__ */ jsx("button", { className: "z-base-button", type: "submit", disabled: !code.trim(), children: "Apply code" }),
760
+ cart.promoCode && /* @__PURE__ */ jsx(
761
+ "button",
762
+ {
763
+ className: "z-base-button-secondary",
764
+ type: "button",
765
+ onClick: () => save(null),
766
+ children: "Remove code"
767
+ }
768
+ )
769
+ ]
770
+ }
771
+ );
772
+ }
773
+ function PromoSheet() {
774
+ const cart = useCart();
775
+ const handoff = useCheckoutHandoff();
776
+ if (!handoff.customer) {
777
+ return null;
778
+ }
779
+ return /* @__PURE__ */ jsx(
780
+ CartSheet,
781
+ {
782
+ id: "promo",
783
+ title: "Promo code",
784
+ trigger: cart.promoCode ? `Promo: ${cart.promoCode}` : "Add promo code",
785
+ children: /* @__PURE__ */ jsx(PromoForm, {})
786
+ }
787
+ );
788
+ }
789
+ function RewardsSheet() {
790
+ const bridge = useBaseHostBridge();
791
+ const handoff = useCheckoutHandoff();
792
+ const [error, setError] = useState(null);
793
+ const rewards = bridge.rewards;
794
+ if (!handoff.customer || !rewards) {
795
+ return null;
796
+ }
797
+ const appliedByPerk = new Map(
798
+ rewards.applied.map((reward) => [reward.perkId, reward])
799
+ );
800
+ return /* @__PURE__ */ jsxs(
801
+ CartSheet,
802
+ {
803
+ id: "rewards",
804
+ title: "Rewards",
805
+ trigger: rewards.applied.length ? `Rewards (${rewards.applied.length})` : "Use rewards",
806
+ children: [
807
+ /* @__PURE__ */ jsxs("p", { children: [
808
+ "Your points: ",
809
+ rewards.balance
810
+ ] }),
811
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
812
+ rewards.items.length ? /* @__PURE__ */ jsx("ul", { className: "z-base-option-list", children: rewards.items.map((reward) => {
813
+ const applied = appliedByPerk.get(reward.id);
814
+ const busy = rewards.busyPerkId === reward.id;
815
+ const unavailable = reward.disabled || !applied && reward.pointsCost > rewards.balance;
816
+ return /* @__PURE__ */ jsxs("li", { children: [
817
+ /* @__PURE__ */ jsxs("div", { children: [
818
+ /* @__PURE__ */ jsx("strong", { children: reward.name }),
819
+ /* @__PURE__ */ jsx("p", { children: reward.description }),
820
+ /* @__PURE__ */ jsxs("p", { children: [
821
+ reward.pointsCost,
822
+ " points \xB7 ",
823
+ reward.reward
824
+ ] })
825
+ ] }),
826
+ applied ? /* @__PURE__ */ jsx(
827
+ "button",
828
+ {
829
+ className: "z-base-button-secondary",
830
+ type: "button",
831
+ disabled: busy,
832
+ onClick: () => {
833
+ setError(null);
834
+ void rewards.cancel(applied.redemptionId).catch((failure) => {
835
+ setError(
836
+ failure instanceof Error ? failure.message : "Unable to remove this reward"
837
+ );
838
+ });
839
+ },
840
+ children: "Remove"
841
+ }
842
+ ) : /* @__PURE__ */ jsx(
843
+ "button",
844
+ {
845
+ className: "z-base-button-secondary",
846
+ type: "button",
847
+ disabled: busy || unavailable,
848
+ onClick: () => {
849
+ setError(null);
850
+ void rewards.redeem(reward.id).catch((failure) => {
851
+ setError(
852
+ failure instanceof Error ? failure.message : "Unable to redeem this reward"
853
+ );
854
+ });
855
+ },
856
+ children: reward.pointsCost > rewards.balance ? "Not enough points" : "Redeem"
857
+ }
858
+ )
859
+ ] }, reward.id);
860
+ }) }) : /* @__PURE__ */ jsx("p", { children: "No rewards available yet." })
861
+ ]
862
+ }
863
+ );
864
+ }
865
+ var labels2 = {
866
+ pay: "Continue to payment",
867
+ sign_in: "Sign in to continue",
868
+ busy: "Please wait\u2026",
869
+ quoting: "Updating total\u2026",
870
+ retry: "Update totals to continue",
871
+ address: "Add a delivery address",
872
+ choose_area: "Choose a delivery area",
873
+ fix_issues: "Review your cart",
874
+ too_far: "Too far for delivery",
875
+ phone: "Check your phone number"
876
+ };
877
+ function toPayReadinessQuoteState(cartState, totalsStatus) {
878
+ if (cartState.status === "quoting") {
879
+ return { status: "loading" };
880
+ }
881
+ if (totalsStatus === "stale" || totalsStatus === "offline") {
882
+ return { status: "error" };
883
+ }
884
+ if (cartState.status === "quoted") {
885
+ return { status: "ready", quote: cartState.quote };
886
+ }
887
+ if (cartState.status === "needs_attention") {
888
+ if (cartState.quote) {
889
+ return { status: "ready", quote: cartState.quote };
890
+ }
891
+ return { status: "error" };
892
+ }
893
+ return { status: "idle" };
894
+ }
895
+ function checkoutButtonState({
896
+ busy,
897
+ cartState,
898
+ totalsStatus,
899
+ fulfilment,
900
+ customer,
901
+ contactPhoneValid = true,
902
+ deliveryDistance
903
+ }) {
904
+ let status;
905
+ if (busy) {
906
+ status = "busy";
907
+ } else if (!customer) {
908
+ status = "sign_in";
909
+ } else if (deliveryDistance?.status === "too_far") {
910
+ status = "too_far";
911
+ } else {
912
+ const addressValid = fulfilment?.type !== "delivery" || Boolean(
913
+ fulfilment.address.line1 || fulfilment.address.placeId || fulfilment.address.coordinates
914
+ );
915
+ status = payReadiness(
916
+ toPayReadinessQuoteState(cartState, totalsStatus),
917
+ contactPhoneValid,
918
+ addressValid
919
+ );
920
+ if (status === "pay" && cartState.status === "needs_attention") {
921
+ status = "fix_issues";
922
+ }
923
+ }
924
+ return {
925
+ status,
926
+ label: labels2[status],
927
+ enabled: status === "pay" || status === "sign_in" || status === "phone"
928
+ };
929
+ }
930
+ function CheckoutCta({
931
+ totalsStatus,
932
+ contactPhone
933
+ }) {
934
+ const cart = useCart();
935
+ const bridge = useBaseHostBridge();
936
+ const handoff = useCheckoutHandoff();
937
+ const [busy, setBusy] = useState(false);
938
+ const [error, setError] = useState(null);
939
+ const showContactPhone = Boolean(
940
+ contactPhone && handoff.contactPhone && handoff.customer
941
+ );
942
+ const buttonInput = {
943
+ busy,
944
+ cartState: cart.state,
945
+ totalsStatus,
946
+ fulfilment: cart.fulfilment,
947
+ customer: handoff.customer,
948
+ contactPhoneValid: !showContactPhone || isContactPhoneValid(contactPhone?.value ?? "")
949
+ };
950
+ if (bridge.deliveryDistance) {
951
+ buttonInput.deliveryDistance = bridge.deliveryDistance;
952
+ }
953
+ const button = checkoutButtonState(buttonInput);
954
+ const checkout = async () => {
955
+ if (!button.enabled) {
956
+ return;
957
+ }
958
+ if (button.status === "phone") {
959
+ contactPhone?.touch();
960
+ return;
961
+ }
962
+ setBusy(true);
963
+ setError(null);
964
+ try {
965
+ if (!handoff.customer) {
966
+ await handoff.signIn();
967
+ } else {
968
+ const payload = cart.actions.toCheckoutPayload();
969
+ if (showContactPhone && contactPhone) {
970
+ await handoff.pay(payload, { contactPhone: contactPhone.value });
971
+ } else {
972
+ await handoff.pay(payload);
973
+ }
974
+ }
975
+ } catch (error2) {
976
+ setError(
977
+ error2 instanceof Error ? error2.message : "Unable to continue to checkout"
978
+ );
979
+ } finally {
980
+ setBusy(false);
981
+ }
982
+ };
983
+ return /* @__PURE__ */ jsxs("div", { className: "z-base-checkout", children: [
984
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
985
+ /* @__PURE__ */ jsx(
986
+ "button",
987
+ {
988
+ type: "button",
989
+ className: "z-base-button",
990
+ disabled: !button.enabled,
991
+ onClick: () => {
992
+ void checkout();
993
+ },
994
+ children: button.label
995
+ }
996
+ )
997
+ ] });
998
+ }
999
+ function Totals({
1000
+ contactPhone
1001
+ } = {}) {
1002
+ const cart = useCart();
1003
+ useBaseHostBridge();
1004
+ const [error, setError] = useState(null);
1005
+ const blocked = cart.issues.some((issue) => issue.severity === "blocking");
1006
+ const refresh = async () => {
1007
+ setError(null);
1008
+ try {
1009
+ await cart.actions.quote({ force: true });
1010
+ } catch (error2) {
1011
+ setError(
1012
+ error2 instanceof Error ? error2.message : "Unable to update totals"
1013
+ );
1014
+ }
1015
+ };
1016
+ return /* @__PURE__ */ jsx(Totals$1, { className: "z-base-summary", children: ({ quote, status }) => {
1017
+ const unpriced = blocked && (!quote || quote.subtotal.amountMinor === 0);
1018
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1019
+ /* @__PURE__ */ jsx("h2", { children: "Order summary" }),
1020
+ status === "loading" && /* @__PURE__ */ jsx("p", { role: "status", children: "Updating totals\u2026" }),
1021
+ status === "offline" && /* @__PURE__ */ jsx("p", { role: "alert", children: "Unable to connect. Try updating your totals again." }),
1022
+ status === "stale" && !blocked && /* @__PURE__ */ jsx("p", { children: "Update totals before continuing." }),
1023
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
1024
+ unpriced && /* @__PURE__ */ jsx("p", { children: "Totals appear once the issues above are resolved." }),
1025
+ blocked && !unpriced && /* @__PURE__ */ jsx("p", { children: "Your total may change once the issues above are resolved." }),
1026
+ quote && !unpriced && /* @__PURE__ */ jsxs("dl", { className: "z-base-totals", children: [
1027
+ /* @__PURE__ */ jsxs("div", { children: [
1028
+ /* @__PURE__ */ jsx("dt", { children: "Subtotal" }),
1029
+ /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Money, { value: quote.subtotal }) })
1030
+ ] }),
1031
+ quote.fees.map((fee, index) => /* @__PURE__ */ jsxs("div", { children: [
1032
+ /* @__PURE__ */ jsx("dt", { children: fee.label }),
1033
+ /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Money, { value: fee.amount }) })
1034
+ ] }, `${fee.code}:${index}`)),
1035
+ quote.delivery && /* @__PURE__ */ jsxs("div", { children: [
1036
+ /* @__PURE__ */ jsx("dt", { children: "Delivery" }),
1037
+ /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Money, { value: quote.delivery }) })
1038
+ ] }),
1039
+ quote.discounts.map((discount, index) => /* @__PURE__ */ jsxs("div", { children: [
1040
+ /* @__PURE__ */ jsx("dt", { children: discount.label }),
1041
+ /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Money, { value: discount.amount }) })
1042
+ ] }, `${discount.code}:${index}`)),
1043
+ /* @__PURE__ */ jsxs("div", { className: "z-base-total", children: [
1044
+ /* @__PURE__ */ jsx("dt", { children: "Total" }),
1045
+ /* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Money, { value: quote.total }) })
1046
+ ] })
1047
+ ] }),
1048
+ (status === "stale" || status === "offline") && !blocked && /* @__PURE__ */ jsx(
1049
+ "button",
1050
+ {
1051
+ type: "button",
1052
+ className: "z-base-button-secondary",
1053
+ onClick: () => {
1054
+ void refresh();
1055
+ },
1056
+ children: "Update totals"
1057
+ }
1058
+ ),
1059
+ /* @__PURE__ */ jsx(
1060
+ CheckoutCta,
1061
+ {
1062
+ totalsStatus: status,
1063
+ ...contactPhone ? { contactPhone } : {}
1064
+ }
1065
+ )
1066
+ ] });
1067
+ } });
1068
+ }
1069
+ function CartReview({ themeClass } = {}) {
1070
+ const bridge = useBaseHostBridge();
1071
+ const cartOverlay = useOverlay("modal_id", "review-menu");
1072
+ const countedOpen = useRef(false);
1073
+ const [contactPhone, setContactPhone] = useState("");
1074
+ const [contactPhoneTouched, setContactPhoneTouched] = useState(false);
1075
+ const contactPhoneState = {
1076
+ value: contactPhone,
1077
+ touched: contactPhoneTouched,
1078
+ update: setContactPhone,
1079
+ touch: () => setContactPhoneTouched(true)
1080
+ };
1081
+ useEffect(() => {
1082
+ if (cartOverlay.isOpen && !countedOpen.current) {
1083
+ countEvent("bag");
1084
+ }
1085
+ countedOpen.current = cartOverlay.isOpen;
1086
+ }, [cartOverlay.isOpen]);
1087
+ return /* @__PURE__ */ jsx(ThemeClassProvider, { value: themeClass, children: /* @__PURE__ */ jsx(
1088
+ Overlay.Root,
1089
+ {
1090
+ param: "modal_id",
1091
+ id: "review-menu",
1092
+ presentation: { base: "drawer", lg: "dialog" },
1093
+ children: /* @__PURE__ */ jsxs(
1094
+ Overlay.Content,
1095
+ {
1096
+ "data-zappie-theme": "base",
1097
+ className: themeClass ? `z-base-cart ${themeClass}` : "z-base-cart",
1098
+ children: [
1099
+ /* @__PURE__ */ jsxs("header", { className: "z-base-cart-header", children: [
1100
+ /* @__PURE__ */ jsx(Overlay.Title, { children: "Cart" }),
1101
+ /* @__PURE__ */ jsx(
1102
+ Overlay.Close,
1103
+ {
1104
+ "aria-label": "Close cart",
1105
+ className: "z-base-button-secondary",
1106
+ children: "Close"
1107
+ }
1108
+ )
1109
+ ] }),
1110
+ /* @__PURE__ */ jsx(Cart.Root, { className: "z-base-cart-body", children: ({ isHydrated, lines }) => /* @__PURE__ */ jsxs(Fragment, { children: [
1111
+ bridge.error && /* @__PURE__ */ jsx("p", { role: "alert", children: bridge.error }),
1112
+ !isHydrated ? /* @__PURE__ */ jsx(Loading, {}) : lines.length === 0 ? /* @__PURE__ */ jsx(EmptyCart, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
1113
+ /* @__PURE__ */ jsxs("div", { className: "z-base-cart-tools", children: [
1114
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Add more items" }),
1115
+ /* @__PURE__ */ jsx(ClearCart, {})
1116
+ ] }),
1117
+ /* @__PURE__ */ jsx(CartIssues, {}),
1118
+ /* @__PURE__ */ jsxs("div", { className: "z-base-cart-columns", children: [
1119
+ /* @__PURE__ */ jsx(CartLines, {}),
1120
+ /* @__PURE__ */ jsxs("div", { children: [
1121
+ /* @__PURE__ */ jsx(FulfilmentPanel, {}),
1122
+ /* @__PURE__ */ jsx(DeliveryDistance, {}),
1123
+ /* @__PURE__ */ jsx(CustomerDetails, { contactPhone: contactPhoneState }),
1124
+ /* @__PURE__ */ jsx(PromoSheet, {}),
1125
+ /* @__PURE__ */ jsx(RewardsSheet, {}),
1126
+ /* @__PURE__ */ jsx(Totals, { contactPhone: contactPhoneState })
1127
+ ] })
1128
+ ] })
1129
+ ] })
1130
+ ] }) })
1131
+ ]
1132
+ }
1133
+ )
1134
+ }
1135
+ ) });
1136
+ }
1137
+
1138
+ export { CartReview };
1139
+ //# sourceMappingURL=cart.js.map
1140
+ //# sourceMappingURL=cart.js.map