@zappie/theme-base 0.1.1 → 0.1.2

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 (128) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/address.js +99 -2
  3. package/dist/address.js.map +7 -1
  4. package/dist/cart/address-sheet.js +143 -0
  5. package/dist/cart/address-sheet.js.map +7 -0
  6. package/dist/cart/cart-issues.js +72 -0
  7. package/dist/cart/cart-issues.js.map +7 -0
  8. package/dist/cart/cart-line-groups.js +34 -0
  9. package/dist/cart/cart-line-groups.js.map +7 -0
  10. package/dist/{chunk-FB5DRCU7.js → cart/cart-line.js} +9 -70
  11. package/dist/cart/cart-line.js.map +7 -0
  12. package/dist/cart/cart-lines.js +27 -0
  13. package/dist/cart/cart-lines.js.map +7 -0
  14. package/dist/cart/cart-schedule.js +24 -0
  15. package/dist/cart/cart-schedule.js.map +7 -0
  16. package/dist/cart/cart-sheet.js +35 -0
  17. package/dist/cart/cart-sheet.js.map +7 -0
  18. package/dist/cart/checkout-cta.js +81 -0
  19. package/dist/cart/checkout-cta.js.map +7 -0
  20. package/dist/cart/checkout-state.js +74 -0
  21. package/dist/cart/checkout-state.js.map +7 -0
  22. package/dist/cart/clear-cart.js +44 -0
  23. package/dist/cart/clear-cart.js.map +7 -0
  24. package/dist/cart/customer-details.js +70 -0
  25. package/dist/cart/customer-details.js.map +7 -0
  26. package/dist/cart/delivery-distance.js +22 -0
  27. package/dist/cart/delivery-distance.js.map +7 -0
  28. package/dist/cart/empty-cart.js +14 -0
  29. package/dist/cart/empty-cart.js.map +7 -0
  30. package/dist/cart/fulfilment-panel.js +83 -0
  31. package/dist/cart/fulfilment-panel.js.map +7 -0
  32. package/dist/cart/line-editor.js +35 -0
  33. package/dist/cart/line-editor.js.map +7 -0
  34. package/dist/cart/line-options.js +96 -0
  35. package/dist/cart/line-options.js.map +7 -0
  36. package/dist/cart/loading.js +17 -0
  37. package/dist/cart/loading.js.map +7 -0
  38. package/dist/cart/promo-sheet.js +103 -0
  39. package/dist/cart/promo-sheet.js.map +7 -0
  40. package/dist/cart/region-picker.js +40 -0
  41. package/dist/cart/region-picker.js.map +7 -0
  42. package/dist/cart/rewards-sheet.js +86 -0
  43. package/dist/cart/rewards-sheet.js.map +7 -0
  44. package/dist/cart/schedule-sheet.js +87 -0
  45. package/dist/cart/schedule-sheet.js.map +7 -0
  46. package/dist/{chunk-JFEI2OUZ.js → cart/theme-class.js} +7 -5
  47. package/dist/cart/theme-class.js.map +7 -0
  48. package/dist/cart/totals.js +81 -0
  49. package/dist/cart/totals.js.map +7 -0
  50. package/dist/cart/use-address-selection.js +130 -0
  51. package/dist/cart/use-address-selection.js.map +7 -0
  52. package/dist/cart.js +21 -1069
  53. package/dist/cart.js.map +7 -1
  54. package/dist/catalogue/catalogue-cart.js +25 -0
  55. package/dist/catalogue/catalogue-cart.js.map +7 -0
  56. package/dist/catalogue/catalogue-header.js +88 -0
  57. package/dist/catalogue/catalogue-header.js.map +7 -0
  58. package/dist/catalogue/catalogue-pages.js +68 -0
  59. package/dist/catalogue/catalogue-pages.js.map +7 -0
  60. package/dist/catalogue/catalogue-search.js +89 -0
  61. package/dist/catalogue/catalogue-search.js.map +7 -0
  62. package/dist/catalogue/category-navigation.js +98 -0
  63. package/dist/catalogue/category-navigation.js.map +7 -0
  64. package/dist/catalogue/category-section.js +113 -0
  65. package/dist/catalogue/category-section.js.map +7 -0
  66. package/dist/catalogue/info-banners.js +148 -0
  67. package/dist/catalogue/info-banners.js.map +7 -0
  68. package/dist/catalogue/item-tile.js +55 -0
  69. package/dist/catalogue/item-tile.js.map +7 -0
  70. package/dist/catalogue/loader.js +136 -0
  71. package/dist/catalogue/loader.js.map +7 -0
  72. package/dist/{chunk-USSLDBDY.js → catalogue/presentation.js} +12 -9
  73. package/dist/catalogue/presentation.js.map +7 -0
  74. package/dist/catalogue/saved-catalogue-sync.js +115 -0
  75. package/dist/catalogue/saved-catalogue-sync.js.map +7 -0
  76. package/dist/catalogue/types.js +1 -0
  77. package/dist/catalogue/types.js.map +7 -0
  78. package/dist/catalogue/use-catalogue-data.js +88 -0
  79. package/dist/catalogue/use-catalogue-data.js.map +7 -0
  80. package/dist/catalogue/use-category-scroll.js +115 -0
  81. package/dist/catalogue/use-category-scroll.js.map +7 -0
  82. package/dist/catalogue/use-item-opener.js +46 -0
  83. package/dist/catalogue/use-item-opener.js.map +7 -0
  84. package/dist/catalogue/use-search-source.js +132 -0
  85. package/dist/catalogue/use-search-source.js.map +7 -0
  86. package/dist/catalogue.js +26 -1216
  87. package/dist/catalogue.js.map +7 -1
  88. package/dist/checkout.js +149 -2
  89. package/dist/checkout.js.map +7 -1
  90. package/dist/host-bridge.js +22 -2
  91. package/dist/host-bridge.js.map +7 -1
  92. package/dist/index.js +3 -3
  93. package/dist/index.js.map +7 -1
  94. package/dist/item/configurator-commit.js +15 -0
  95. package/dist/item/configurator-commit.js.map +7 -0
  96. package/dist/item/configurator-draft.js +63 -0
  97. package/dist/item/configurator-draft.js.map +7 -0
  98. package/dist/item/configurator.js +135 -0
  99. package/dist/item/configurator.js.map +7 -0
  100. package/dist/item/note.js +65 -0
  101. package/dist/item/note.js.map +7 -0
  102. package/dist/item/variant-status.js +23 -0
  103. package/dist/item/variant-status.js.map +7 -0
  104. package/dist/item-frame.js +60 -3
  105. package/dist/item-frame.js.map +7 -1
  106. package/dist/item.js +11 -11
  107. package/dist/item.js.map +7 -1
  108. package/dist/navigation.js +39 -2
  109. package/dist/navigation.js.map +7 -1
  110. package/dist/url-navigation-state.js +61 -0
  111. package/dist/url-navigation-state.js.map +7 -0
  112. package/dist/{chunk-ILOCSCZL.js → url-navigation.js} +12 -89
  113. package/dist/url-navigation.js.map +7 -0
  114. package/package.json +4 -4
  115. package/dist/chunk-2MV6KU3R.js +0 -352
  116. package/dist/chunk-2MV6KU3R.js.map +0 -1
  117. package/dist/chunk-FB5DRCU7.js.map +0 -1
  118. package/dist/chunk-IG63ONID.js +0 -139
  119. package/dist/chunk-IG63ONID.js.map +0 -1
  120. package/dist/chunk-ILOCSCZL.js.map +0 -1
  121. package/dist/chunk-JFEI2OUZ.js.map +0 -1
  122. package/dist/chunk-NTJONY3N.js +0 -95
  123. package/dist/chunk-NTJONY3N.js.map +0 -1
  124. package/dist/chunk-QWST2TA2.js +0 -22
  125. package/dist/chunk-QWST2TA2.js.map +0 -1
  126. package/dist/chunk-USSLDBDY.js.map +0 -1
  127. package/dist/chunk-VIAJ27YC.js +0 -59
  128. package/dist/chunk-VIAJ27YC.js.map +0 -1
@@ -0,0 +1,35 @@
1
+ // src/cart/cart-sheet.tsx
2
+ import { Overlay, useOverlay } from "@zappie/foundations";
3
+ import { useThemeClass } from "./theme-class.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ function CartSheet({
6
+ id,
7
+ title,
8
+ trigger,
9
+ children
10
+ }) {
11
+ const rootClass = useThemeClass("z-base-cart z-base-editor");
12
+ const overlay = useOverlay("cart_sheet", id);
13
+ return /* @__PURE__ */ jsxs(
14
+ Overlay.Root,
15
+ {
16
+ param: "cart_sheet",
17
+ id,
18
+ presentation: { base: "sheet", lg: "dialog" },
19
+ children: [
20
+ /* @__PURE__ */ jsx(Overlay.Trigger, { className: "z-base-button-secondary", children: trigger }),
21
+ /* @__PURE__ */ jsxs(Overlay.Content, { "data-zappie-theme": "base", className: rootClass, children: [
22
+ /* @__PURE__ */ jsxs("header", { className: "z-base-cart-header", children: [
23
+ /* @__PURE__ */ jsx(Overlay.Title, { children: title }),
24
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Cancel" })
25
+ ] }),
26
+ overlay.isOpen && /* @__PURE__ */ jsx("div", { className: "z-base-cart-body", children })
27
+ ] })
28
+ ]
29
+ }
30
+ );
31
+ }
32
+ export {
33
+ CartSheet
34
+ };
35
+ //# sourceMappingURL=cart-sheet.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/cart-sheet.tsx"],
4
+ "sourcesContent": ["import { Overlay, useOverlay } from \"@zappie/foundations\";\nimport type { ReactNode } from \"react\";\nimport { useThemeClass } from \"./theme-class\";\nexport function CartSheet({\n id,\n title,\n trigger,\n children,\n}: {\n id: string;\n title: string;\n trigger: string;\n children: ReactNode;\n}) {\n const rootClass = useThemeClass(\"z-base-cart z-base-editor\");\n const overlay = useOverlay(\"cart_sheet\", id);\n return (\n <Overlay.Root\n param=\"cart_sheet\"\n id={id}\n presentation={{ base: \"sheet\", lg: \"dialog\" }}\n >\n <Overlay.Trigger className=\"z-base-button-secondary\">\n {trigger}\n </Overlay.Trigger>\n <Overlay.Content data-zappie-theme=\"base\" className={rootClass}>\n <header className=\"z-base-cart-header\">\n <Overlay.Title>{title}</Overlay.Title>\n <Overlay.Close className=\"z-base-button-secondary\">\n Cancel\n </Overlay.Close>\n </header>\n {overlay.isOpen && <div className=\"z-base-cart-body\">{children}</div>}\n </Overlay.Content>\n </Overlay.Root>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,SAAS,kBAAkB;AAEpC,SAAS,qBAAqB;AAoBxB,cAIE,YAJF;AAnBC,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,YAAY,cAAc,2BAA2B;AAC3D,QAAM,UAAU,WAAW,cAAc,EAAE;AAC3C,SACE;AAAA,IAAC,QAAQ;AAAA,IAAR;AAAA,MACC,OAAM;AAAA,MACN;AAAA,MACA,cAAc,EAAE,MAAM,SAAS,IAAI,SAAS;AAAA,MAE5C;AAAA,4BAAC,QAAQ,SAAR,EAAgB,WAAU,2BACxB,mBACH;AAAA,QACA,qBAAC,QAAQ,SAAR,EAAgB,qBAAkB,QAAO,WAAW,WACnD;AAAA,+BAAC,YAAO,WAAU,sBAChB;AAAA,gCAAC,QAAQ,OAAR,EAAe,iBAAM;AAAA,YACtB,oBAAC,QAAQ,OAAR,EAAc,WAAU,2BAA0B,oBAEnD;AAAA,aACF;AAAA,UACC,QAAQ,UAAU,oBAAC,SAAI,WAAU,oBAAoB,UAAS;AAAA,WACjE;AAAA;AAAA;AAAA,EACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,81 @@
1
+ // src/cart/checkout-cta.tsx
2
+ import { isContactPhoneValid } from "@zappie/sdk/checkout";
3
+ import { useCart } from "@zappie/sdk/react";
4
+ import { useState } from "react";
5
+ import { useCheckoutHandoff } from "../checkout.js";
6
+ import { useBaseHostBridge } from "../host-bridge.js";
7
+ import { checkoutButtonState } from "./checkout-state.js";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function CheckoutCta({
10
+ totalsStatus,
11
+ contactPhone
12
+ }) {
13
+ const cart = useCart();
14
+ const bridge = useBaseHostBridge();
15
+ const handoff = useCheckoutHandoff();
16
+ const [busy, setBusy] = useState(false);
17
+ const [error, setError] = useState(null);
18
+ const showContactPhone = Boolean(
19
+ contactPhone && handoff.contactPhone && handoff.customer
20
+ );
21
+ const buttonInput = {
22
+ busy,
23
+ cartState: cart.state,
24
+ totalsStatus,
25
+ fulfilment: cart.fulfilment,
26
+ customer: handoff.customer,
27
+ contactPhoneValid: !showContactPhone || isContactPhoneValid(contactPhone?.value ?? "")
28
+ };
29
+ if (bridge.deliveryDistance) {
30
+ buttonInput.deliveryDistance = bridge.deliveryDistance;
31
+ }
32
+ const button = checkoutButtonState(buttonInput);
33
+ const checkout = async () => {
34
+ if (!button.enabled) {
35
+ return;
36
+ }
37
+ if (button.status === "phone") {
38
+ contactPhone?.touch();
39
+ return;
40
+ }
41
+ setBusy(true);
42
+ setError(null);
43
+ try {
44
+ if (!handoff.customer) {
45
+ await handoff.signIn();
46
+ } else {
47
+ const payload = cart.actions.toCheckoutPayload();
48
+ if (showContactPhone && contactPhone) {
49
+ await handoff.pay(payload, { contactPhone: contactPhone.value });
50
+ } else {
51
+ await handoff.pay(payload);
52
+ }
53
+ }
54
+ } catch (error2) {
55
+ setError(
56
+ error2 instanceof Error ? error2.message : "Unable to continue to checkout"
57
+ );
58
+ } finally {
59
+ setBusy(false);
60
+ }
61
+ };
62
+ return /* @__PURE__ */ jsxs("div", { className: "z-base-checkout", children: [
63
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
64
+ /* @__PURE__ */ jsx(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ className: "z-base-button",
69
+ disabled: !button.enabled,
70
+ onClick: () => {
71
+ void checkout();
72
+ },
73
+ children: button.label
74
+ }
75
+ )
76
+ ] });
77
+ }
78
+ export {
79
+ CheckoutCta
80
+ };
81
+ //# sourceMappingURL=checkout-cta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/checkout-cta.tsx"],
4
+ "sourcesContent": ["import type { TotalsState } from \"@zappie/foundations\";\nimport { isContactPhoneValid } from \"@zappie/sdk/checkout\";\nimport { useCart } from \"@zappie/sdk/react\";\nimport { useState } from \"react\";\nimport { useCheckoutHandoff } from \"../checkout\";\nimport { useBaseHostBridge } from \"../host-bridge\";\nimport { checkoutButtonState } from \"./checkout-state\";\nimport type { ContactPhoneState } from \"./customer-details\";\nexport function CheckoutCta({\n totalsStatus,\n contactPhone,\n}: {\n totalsStatus: TotalsState[\"status\"];\n contactPhone?: ContactPhoneState;\n}) {\n const cart = useCart();\n const bridge = useBaseHostBridge();\n const handoff = useCheckoutHandoff();\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const showContactPhone = Boolean(\n contactPhone && handoff.contactPhone && handoff.customer,\n );\n const buttonInput: Parameters<typeof checkoutButtonState>[0] = {\n busy,\n cartState: cart.state,\n totalsStatus,\n fulfilment: cart.fulfilment,\n customer: handoff.customer,\n contactPhoneValid:\n !showContactPhone || isContactPhoneValid(contactPhone?.value ?? \"\"),\n };\n if (bridge.deliveryDistance) {\n buttonInput.deliveryDistance = bridge.deliveryDistance;\n }\n const button = checkoutButtonState(buttonInput);\n const checkout = async () => {\n if (!button.enabled) {\n return;\n }\n if (button.status === \"phone\") {\n contactPhone?.touch();\n return;\n }\n setBusy(true);\n setError(null);\n try {\n if (!handoff.customer) {\n await handoff.signIn();\n } else {\n const payload = cart.actions.toCheckoutPayload();\n if (showContactPhone && contactPhone) {\n await handoff.pay(payload, { contactPhone: contactPhone.value });\n } else {\n await handoff.pay(payload);\n }\n }\n } catch (error) {\n setError(\n error instanceof Error\n ? error.message\n : \"Unable to continue to checkout\",\n );\n } finally {\n setBusy(false);\n }\n };\n return (\n <div className=\"z-base-checkout\">\n {error && <p role=\"alert\">{error}</p>}\n <button\n type=\"button\"\n className=\"z-base-button\"\n disabled={!button.enabled}\n onClick={() => {\n void checkout();\n }}\n >\n {button.label}\n </button>\n </div>\n );\n}\n"],
5
+ "mappings": ";AACA,SAAS,2BAA2B;AACpC,SAAS,eAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AA8DhC,SACY,KADZ;AA5DG,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AACF,GAGG;AACD,QAAM,OAAO,QAAQ;AACrB,QAAM,SAAS,kBAAkB;AACjC,QAAM,UAAU,mBAAmB;AACnC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,mBAAmB;AAAA,IACvB,gBAAgB,QAAQ,gBAAgB,QAAQ;AAAA,EAClD;AACA,QAAM,cAAyD;AAAA,IAC7D;AAAA,IACA,WAAW,KAAK;AAAA,IAChB;AAAA,IACA,YAAY,KAAK;AAAA,IACjB,UAAU,QAAQ;AAAA,IAClB,mBACE,CAAC,oBAAoB,oBAAoB,cAAc,SAAS,EAAE;AAAA,EACtE;AACA,MAAI,OAAO,kBAAkB;AAC3B,gBAAY,mBAAmB,OAAO;AAAA,EACxC;AACA,QAAM,SAAS,oBAAoB,WAAW;AAC9C,QAAM,WAAW,YAAY;AAC3B,QAAI,CAAC,OAAO,SAAS;AACnB;AAAA,IACF;AACA,QAAI,OAAO,WAAW,SAAS;AAC7B,oBAAc,MAAM;AACpB;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,UAAI,CAAC,QAAQ,UAAU;AACrB,cAAM,QAAQ,OAAO;AAAA,MACvB,OAAO;AACL,cAAM,UAAU,KAAK,QAAQ,kBAAkB;AAC/C,YAAI,oBAAoB,cAAc;AACpC,gBAAM,QAAQ,IAAI,SAAS,EAAE,cAAc,aAAa,MAAM,CAAC;AAAA,QACjE,OAAO;AACL,gBAAM,QAAQ,IAAI,OAAO;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,SAASA,QAAO;AACd;AAAA,QACEA,kBAAiB,QACbA,OAAM,UACN;AAAA,MACN;AAAA,IACF,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AACA,SACE,qBAAC,SAAI,WAAU,mBACZ;AAAA,aAAS,oBAAC,OAAE,MAAK,SAAS,iBAAM;AAAA,IACjC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,UAAU,CAAC,OAAO;AAAA,QAClB,SAAS,MAAM;AACb,eAAK,SAAS;AAAA,QAChB;AAAA,QAEC,iBAAO;AAAA;AAAA,IACV;AAAA,KACF;AAEJ;",
6
+ "names": ["error"]
7
+ }
@@ -0,0 +1,74 @@
1
+ // src/cart/checkout-state.ts
2
+ import {
3
+ payReadiness
4
+ } from "@zappie/sdk/checkout";
5
+ var labels = {
6
+ pay: "Continue to payment",
7
+ sign_in: "Sign in to continue",
8
+ busy: "Please wait\u2026",
9
+ quoting: "Updating total\u2026",
10
+ retry: "Update totals to continue",
11
+ address: "Add a delivery address",
12
+ choose_area: "Choose a delivery area",
13
+ fix_issues: "Review your cart",
14
+ too_far: "Too far for delivery",
15
+ phone: "Check your phone number"
16
+ };
17
+ function toPayReadinessQuoteState(cartState, totalsStatus) {
18
+ if (cartState.status === "quoting") {
19
+ return { status: "loading" };
20
+ }
21
+ if (totalsStatus === "stale" || totalsStatus === "offline") {
22
+ return { status: "error" };
23
+ }
24
+ if (cartState.status === "quoted") {
25
+ return { status: "ready", quote: cartState.quote };
26
+ }
27
+ if (cartState.status === "needs_attention") {
28
+ if (cartState.quote) {
29
+ return { status: "ready", quote: cartState.quote };
30
+ }
31
+ return { status: "error" };
32
+ }
33
+ return { status: "idle" };
34
+ }
35
+ function checkoutButtonState({
36
+ busy,
37
+ cartState,
38
+ totalsStatus,
39
+ fulfilment,
40
+ customer,
41
+ contactPhoneValid = true,
42
+ deliveryDistance
43
+ }) {
44
+ let status;
45
+ if (busy) {
46
+ status = "busy";
47
+ } else if (!customer) {
48
+ status = "sign_in";
49
+ } else if (deliveryDistance?.status === "too_far") {
50
+ status = "too_far";
51
+ } else {
52
+ const addressValid = fulfilment?.type !== "delivery" || Boolean(
53
+ fulfilment.address.line1 || fulfilment.address.placeId || fulfilment.address.coordinates
54
+ );
55
+ status = payReadiness(
56
+ toPayReadinessQuoteState(cartState, totalsStatus),
57
+ contactPhoneValid,
58
+ addressValid
59
+ );
60
+ if (status === "pay" && cartState.status === "needs_attention") {
61
+ status = "fix_issues";
62
+ }
63
+ }
64
+ return {
65
+ status,
66
+ label: labels[status],
67
+ enabled: status === "pay" || status === "sign_in" || status === "phone"
68
+ };
69
+ }
70
+ export {
71
+ checkoutButtonState,
72
+ toPayReadinessQuoteState
73
+ };
74
+ //# sourceMappingURL=checkout-state.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/checkout-state.ts"],
4
+ "sourcesContent": ["import type { TotalsState } from \"@zappie/foundations\";\nimport type { CartFulfilment, CartState } from \"@zappie/sdk\";\nimport {\n payReadiness,\n type PayReadiness,\n type PayReadinessQuoteState,\n} from \"@zappie/sdk/checkout\";\n\nexport type CheckoutButtonStatus = PayReadiness | \"busy\" | \"too_far\";\n\nexport type CheckoutButtonState = {\n status: CheckoutButtonStatus;\n label: string;\n enabled: boolean;\n};\n\nconst labels: Record<CheckoutButtonStatus, string> = {\n pay: \"Continue to payment\",\n sign_in: \"Sign in to continue\",\n busy: \"Please wait\u2026\",\n quoting: \"Updating total\u2026\",\n retry: \"Update totals to continue\",\n address: \"Add a delivery address\",\n choose_area: \"Choose a delivery area\",\n fix_issues: \"Review your cart\",\n too_far: \"Too far for delivery\",\n phone: \"Check your phone number\",\n};\n\nexport function toPayReadinessQuoteState(\n cartState: CartState,\n totalsStatus: TotalsState[\"status\"],\n): PayReadinessQuoteState {\n if (cartState.status === \"quoting\") {\n return { status: \"loading\" };\n }\n if (totalsStatus === \"stale\" || totalsStatus === \"offline\") {\n return { status: \"error\" };\n }\n if (cartState.status === \"quoted\") {\n return { status: \"ready\", quote: cartState.quote };\n }\n if (cartState.status === \"needs_attention\") {\n if (cartState.quote) {\n return { status: \"ready\", quote: cartState.quote };\n }\n return { status: \"error\" };\n }\n return { status: \"idle\" };\n}\n\nexport function checkoutButtonState({\n busy,\n cartState,\n totalsStatus,\n fulfilment,\n customer,\n contactPhoneValid = true,\n deliveryDistance,\n}: {\n busy: boolean;\n cartState: CartState;\n totalsStatus: TotalsState[\"status\"];\n fulfilment: CartFulfilment | null;\n customer: { name?: string } | null;\n contactPhoneValid?: boolean;\n deliveryDistance?: { status: \"unknown\" | \"far\" | \"too_far\" };\n}): CheckoutButtonState {\n let status: CheckoutButtonStatus;\n if (busy) {\n status = \"busy\";\n } else if (!customer) {\n status = \"sign_in\";\n } else if (deliveryDistance?.status === \"too_far\") {\n status = \"too_far\";\n } else {\n const addressValid =\n fulfilment?.type !== \"delivery\" ||\n Boolean(\n fulfilment.address.line1 ||\n fulfilment.address.placeId ||\n fulfilment.address.coordinates,\n );\n status = payReadiness(\n toPayReadinessQuoteState(cartState, totalsStatus),\n contactPhoneValid,\n addressValid,\n );\n // Unresolved warnings (a changed price, a refused promo) still hold payment\n // until the shopper deals with them, although the API would accept the order.\n if (status === \"pay\" && cartState.status === \"needs_attention\") {\n status = \"fix_issues\";\n }\n }\n return {\n status,\n label: labels[status],\n enabled: status === \"pay\" || status === \"sign_in\" || status === \"phone\",\n };\n}\n"],
5
+ "mappings": ";AAEA;AAAA,EACE;AAAA,OAGK;AAUP,IAAM,SAA+C;AAAA,EACnD,KAAK;AAAA,EACL,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,OAAO;AACT;AAEO,SAAS,yBACd,WACA,cACwB;AACxB,MAAI,UAAU,WAAW,WAAW;AAClC,WAAO,EAAE,QAAQ,UAAU;AAAA,EAC7B;AACA,MAAI,iBAAiB,WAAW,iBAAiB,WAAW;AAC1D,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B;AACA,MAAI,UAAU,WAAW,UAAU;AACjC,WAAO,EAAE,QAAQ,SAAS,OAAO,UAAU,MAAM;AAAA,EACnD;AACA,MAAI,UAAU,WAAW,mBAAmB;AAC1C,QAAI,UAAU,OAAO;AACnB,aAAO,EAAE,QAAQ,SAAS,OAAO,UAAU,MAAM;AAAA,IACnD;AACA,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B;AACA,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB;AACF,GAQwB;AACtB,MAAI;AACJ,MAAI,MAAM;AACR,aAAS;AAAA,EACX,WAAW,CAAC,UAAU;AACpB,aAAS;AAAA,EACX,WAAW,kBAAkB,WAAW,WAAW;AACjD,aAAS;AAAA,EACX,OAAO;AACL,UAAM,eACJ,YAAY,SAAS,cACrB;AAAA,MACE,WAAW,QAAQ,SACnB,WAAW,QAAQ,WACnB,WAAW,QAAQ;AAAA,IACrB;AACF,aAAS;AAAA,MACP,yBAAyB,WAAW,YAAY;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AAGA,QAAI,WAAW,SAAS,UAAU,WAAW,mBAAmB;AAC9D,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,OAAO,MAAM;AAAA,IACpB,SAAS,WAAW,SAAS,WAAW,aAAa,WAAW;AAAA,EAClE;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,44 @@
1
+ // src/cart/clear-cart.tsx
2
+ import { Overlay, useOverlay } from "@zappie/foundations";
3
+ import { useCart } from "@zappie/sdk/react";
4
+ import { useThemeClass } from "./theme-class.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ function ClearCart() {
7
+ const rootClass = useThemeClass("z-base-cart z-base-confirm");
8
+ const cart = useCart();
9
+ const confirm = useOverlay("cart_clear", "confirm");
10
+ return /* @__PURE__ */ jsxs(Overlay.Root, { param: "cart_clear", id: "confirm", presentation: "dialog", children: [
11
+ /* @__PURE__ */ jsx(Overlay.Trigger, { className: "z-base-button-secondary", children: "Clear cart" }),
12
+ /* @__PURE__ */ jsxs(
13
+ Overlay.Content,
14
+ {
15
+ "data-zappie-theme": "base",
16
+ role: "alertdialog",
17
+ className: rootClass,
18
+ children: [
19
+ /* @__PURE__ */ jsx(Overlay.Title, { children: "Clear your cart?" }),
20
+ /* @__PURE__ */ jsx("p", { children: "This removes every item in your cart." }),
21
+ /* @__PURE__ */ jsxs("div", { className: "z-base-confirm-actions", children: [
22
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Keep items" }),
23
+ /* @__PURE__ */ jsx(
24
+ "button",
25
+ {
26
+ type: "button",
27
+ className: "z-base-button",
28
+ onClick: () => {
29
+ cart.actions.clear();
30
+ confirm.close();
31
+ },
32
+ children: "Clear cart"
33
+ }
34
+ )
35
+ ] })
36
+ ]
37
+ }
38
+ )
39
+ ] });
40
+ }
41
+ export {
42
+ ClearCart
43
+ };
44
+ //# sourceMappingURL=clear-cart.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/clear-cart.tsx"],
4
+ "sourcesContent": ["import { Overlay, useOverlay } from \"@zappie/foundations\";\nimport { useCart } from \"@zappie/sdk/react\";\nimport { useThemeClass } from \"./theme-class\";\n/** Clearing removes every line, so it asks first, as the legacy cart does. */\nexport function ClearCart() {\n const rootClass = useThemeClass(\"z-base-cart z-base-confirm\");\n const cart = useCart();\n const confirm = useOverlay(\"cart_clear\", \"confirm\");\n return (\n <Overlay.Root param=\"cart_clear\" id=\"confirm\" presentation=\"dialog\">\n <Overlay.Trigger className=\"z-base-button-secondary\">\n Clear cart\n </Overlay.Trigger>\n <Overlay.Content\n data-zappie-theme=\"base\"\n role=\"alertdialog\"\n className={rootClass}\n >\n <Overlay.Title>Clear your cart?</Overlay.Title>\n <p>This removes every item in your cart.</p>\n <div className=\"z-base-confirm-actions\">\n <Overlay.Close className=\"z-base-button-secondary\">\n Keep items\n </Overlay.Close>\n <button\n type=\"button\"\n className=\"z-base-button\"\n onClick={() => {\n cart.actions.clear();\n confirm.close();\n }}\n >\n Clear cart\n </button>\n </div>\n </Overlay.Content>\n </Overlay.Root>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,SAAS,kBAAkB;AACpC,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAQxB,cAUE,YAVF;AANC,SAAS,YAAY;AAC1B,QAAM,YAAY,cAAc,4BAA4B;AAC5D,QAAM,OAAO,QAAQ;AACrB,QAAM,UAAU,WAAW,cAAc,SAAS;AAClD,SACE,qBAAC,QAAQ,MAAR,EAAa,OAAM,cAAa,IAAG,WAAU,cAAa,UACzD;AAAA,wBAAC,QAAQ,SAAR,EAAgB,WAAU,2BAA0B,wBAErD;AAAA,IACA;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACC,qBAAkB;AAAA,QAClB,MAAK;AAAA,QACL,WAAW;AAAA,QAEX;AAAA,8BAAC,QAAQ,OAAR,EAAc,8BAAgB;AAAA,UAC/B,oBAAC,OAAE,mDAAqC;AAAA,UACxC,qBAAC,SAAI,WAAU,0BACb;AAAA,gCAAC,QAAQ,OAAR,EAAc,WAAU,2BAA0B,wBAEnD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,MAAM;AACb,uBAAK,QAAQ,MAAM;AACnB,0BAAQ,MAAM;AAAA,gBAChB;AAAA,gBACD;AAAA;AAAA,YAED;AAAA,aACF;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,70 @@
1
+ // src/cart/customer-details.tsx
2
+ import { isContactPhoneValid } from "@zappie/sdk/checkout";
3
+ import { useId } from "react";
4
+ import { useCheckoutHandoff } from "../checkout.js";
5
+ import { useBaseHostBridge } from "../host-bridge.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ var FIELDS = [
8
+ { field: "firstName", label: "First name", autoComplete: "given-name" },
9
+ { field: "lastName", label: "Last name", autoComplete: "family-name" },
10
+ { field: "email", label: "Email", autoComplete: "email" }
11
+ ];
12
+ function CustomerDetails({
13
+ contactPhone
14
+ } = {}) {
15
+ const { customerDetails } = useBaseHostBridge();
16
+ const handoff = useCheckoutHandoff();
17
+ const showPhone = Boolean(
18
+ contactPhone && handoff.contactPhone && handoff.customer
19
+ );
20
+ const inputId = useId();
21
+ const hintId = useId();
22
+ const errorId = useId();
23
+ const invalid = Boolean(
24
+ contactPhone?.touched && !isContactPhoneValid(contactPhone.value)
25
+ );
26
+ if (!customerDetails && !showPhone) {
27
+ return null;
28
+ }
29
+ return /* @__PURE__ */ jsxs("section", { className: "z-base-fulfilment-panel", "aria-label": "Your details", children: [
30
+ /* @__PURE__ */ jsx("h2", { children: "Your details" }),
31
+ customerDetails && FIELDS.filter(
32
+ ({ field }) => field !== "email" || customerDetails.requiresEmail
33
+ ).map(({ field, label, autoComplete }) => /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
34
+ label,
35
+ /* @__PURE__ */ jsx(
36
+ "input",
37
+ {
38
+ type: field === "email" ? "email" : "text",
39
+ autoComplete,
40
+ required: field !== "lastName",
41
+ value: customerDetails.values[field],
42
+ onChange: (event) => customerDetails.update(field, event.target.value)
43
+ }
44
+ )
45
+ ] }, field)),
46
+ showPhone && contactPhone && /* @__PURE__ */ jsxs("div", { className: "z-base-field", children: [
47
+ /* @__PURE__ */ jsx("label", { htmlFor: inputId, children: "Contact phone (optional)" }),
48
+ /* @__PURE__ */ jsx(
49
+ "input",
50
+ {
51
+ id: inputId,
52
+ type: "tel",
53
+ inputMode: "tel",
54
+ autoComplete: "tel",
55
+ value: contactPhone.value,
56
+ "aria-describedby": invalid ? `${hintId} ${errorId}` : hintId,
57
+ "aria-invalid": invalid,
58
+ onBlur: contactPhone.touch,
59
+ onChange: (event) => contactPhone.update(event.target.value)
60
+ }
61
+ ),
62
+ /* @__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" }),
63
+ invalid && /* @__PURE__ */ jsx("span", { id: errorId, role: "alert", children: "Enter a phone number with 7 to 15 digits" })
64
+ ] })
65
+ ] });
66
+ }
67
+ export {
68
+ CustomerDetails
69
+ };
70
+ //# sourceMappingURL=customer-details.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/customer-details.tsx"],
4
+ "sourcesContent": ["import { isContactPhoneValid } from \"@zappie/sdk/checkout\";\nimport { useId } from \"react\";\nimport { useCheckoutHandoff } from \"../checkout\";\nimport { useBaseHostBridge } from \"../host-bridge\";\nconst FIELDS = [\n { field: \"firstName\", label: \"First name\", autoComplete: \"given-name\" },\n { field: \"lastName\", label: \"Last name\", autoComplete: \"family-name\" },\n { field: \"email\", label: \"Email\", autoComplete: \"email\" },\n] as const;\n\nexport type ContactPhoneState = {\n value: string;\n touched: boolean;\n update(value: string): void;\n touch(): void;\n};\n\n/** The details a business requires before payment, such as a name for the order. */\nexport function CustomerDetails({\n contactPhone,\n}: {\n contactPhone?: ContactPhoneState;\n} = {}) {\n const { customerDetails } = useBaseHostBridge();\n const handoff = useCheckoutHandoff();\n const showPhone = Boolean(\n contactPhone && handoff.contactPhone && handoff.customer,\n );\n const inputId = useId();\n const hintId = useId();\n const errorId = useId();\n const invalid = Boolean(\n contactPhone?.touched && !isContactPhoneValid(contactPhone.value),\n );\n if (!customerDetails && !showPhone) {\n return null;\n }\n return (\n <section className=\"z-base-fulfilment-panel\" aria-label=\"Your details\">\n <h2>Your details</h2>\n {customerDetails &&\n FIELDS.filter(\n ({ field }) => field !== \"email\" || customerDetails.requiresEmail,\n ).map(({ field, label, autoComplete }) => (\n <label key={field} className=\"z-base-field\">\n {label}\n <input\n type={field === \"email\" ? \"email\" : \"text\"}\n autoComplete={autoComplete}\n required={field !== \"lastName\"}\n value={customerDetails.values[field]}\n onChange={(event) =>\n customerDetails.update(field, event.target.value)\n }\n />\n </label>\n ))}\n {showPhone && contactPhone && (\n <div className=\"z-base-field\">\n <label htmlFor={inputId}>Contact phone (optional)</label>\n <input\n id={inputId}\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel\"\n value={contactPhone.value}\n aria-describedby={invalid ? `${hintId} ${errorId}` : hintId}\n aria-invalid={invalid}\n onBlur={contactPhone.touch}\n onChange={(event) => contactPhone.update(event.target.value)}\n />\n <span id={hintId}>\n {handoff.customer?.phoneLast4\n ? `Leave blank to use your Zappie number ending ${handoff.customer.phoneLast4}`\n : \"Leave blank to use your Zappie number\"}\n </span>\n {invalid && (\n <span id={errorId} role=\"alert\">\n Enter a phone number with 7 to 15 digits\n </span>\n )}\n </div>\n )}\n </section>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,2BAA2B;AACpC,SAAS,aAAa;AACtB,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAoC5B,cAKI,YALJ;AAnCN,IAAM,SAAS;AAAA,EACb,EAAE,OAAO,aAAa,OAAO,cAAc,cAAc,aAAa;AAAA,EACtE,EAAE,OAAO,YAAY,OAAO,aAAa,cAAc,cAAc;AAAA,EACrE,EAAE,OAAO,SAAS,OAAO,SAAS,cAAc,QAAQ;AAC1D;AAUO,SAAS,gBAAgB;AAAA,EAC9B;AACF,IAEI,CAAC,GAAG;AACN,QAAM,EAAE,gBAAgB,IAAI,kBAAkB;AAC9C,QAAM,UAAU,mBAAmB;AACnC,QAAM,YAAY;AAAA,IAChB,gBAAgB,QAAQ,gBAAgB,QAAQ;AAAA,EAClD;AACA,QAAM,UAAU,MAAM;AACtB,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,MAAM;AACtB,QAAM,UAAU;AAAA,IACd,cAAc,WAAW,CAAC,oBAAoB,aAAa,KAAK;AAAA,EAClE;AACA,MAAI,CAAC,mBAAmB,CAAC,WAAW;AAClC,WAAO;AAAA,EACT;AACA,SACE,qBAAC,aAAQ,WAAU,2BAA0B,cAAW,gBACtD;AAAA,wBAAC,QAAG,0BAAY;AAAA,IACf,mBACC,OAAO;AAAA,MACL,CAAC,EAAE,MAAM,MAAM,UAAU,WAAW,gBAAgB;AAAA,IACtD,EAAE,IAAI,CAAC,EAAE,OAAO,OAAO,aAAa,MAClC,qBAAC,WAAkB,WAAU,gBAC1B;AAAA;AAAA,MACD;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,UAAU,UAAU,UAAU;AAAA,UACpC;AAAA,UACA,UAAU,UAAU;AAAA,UACpB,OAAO,gBAAgB,OAAO,KAAK;AAAA,UACnC,UAAU,CAAC,UACT,gBAAgB,OAAO,OAAO,MAAM,OAAO,KAAK;AAAA;AAAA,MAEpD;AAAA,SAVU,KAWZ,CACD;AAAA,IACF,aAAa,gBACZ,qBAAC,SAAI,WAAU,gBACb;AAAA,0BAAC,WAAM,SAAS,SAAS,sCAAwB;AAAA,MACjD;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,MAAK;AAAA,UACL,WAAU;AAAA,UACV,cAAa;AAAA,UACb,OAAO,aAAa;AAAA,UACpB,oBAAkB,UAAU,GAAG,MAAM,IAAI,OAAO,KAAK;AAAA,UACrD,gBAAc;AAAA,UACd,QAAQ,aAAa;AAAA,UACrB,UAAU,CAAC,UAAU,aAAa,OAAO,MAAM,OAAO,KAAK;AAAA;AAAA,MAC7D;AAAA,MACA,oBAAC,UAAK,IAAI,QACP,kBAAQ,UAAU,aACf,gDAAgD,QAAQ,SAAS,UAAU,KAC3E,yCACN;AAAA,MACC,WACC,oBAAC,UAAK,IAAI,SAAS,MAAK,SAAQ,sDAEhC;AAAA,OAEJ;AAAA,KAEJ;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,22 @@
1
+ // src/cart/delivery-distance.tsx
2
+ import { useBaseHostBridge } from "../host-bridge.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ function DeliveryDistance() {
5
+ const distance = useBaseHostBridge().deliveryDistance;
6
+ if (!distance?.message) {
7
+ return null;
8
+ }
9
+ return /* @__PURE__ */ jsx(
10
+ "p",
11
+ {
12
+ role: distance.status === "too_far" ? "alert" : "status",
13
+ className: "z-base-notice",
14
+ "data-severity": distance.status === "too_far" ? "error" : "warning",
15
+ children: distance.message
16
+ }
17
+ );
18
+ }
19
+ export {
20
+ DeliveryDistance
21
+ };
22
+ //# sourceMappingURL=delivery-distance.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/delivery-distance.tsx"],
4
+ "sourcesContent": ["import { useBaseHostBridge } from \"../host-bridge\";\n\nexport function DeliveryDistance() {\n const distance = useBaseHostBridge().deliveryDistance;\n if (!distance?.message) {\n return null;\n }\n return (\n <p\n role={distance.status === \"too_far\" ? \"alert\" : \"status\"}\n className=\"z-base-notice\"\n data-severity={distance.status === \"too_far\" ? \"error\" : \"warning\"}\n >\n {distance.message}\n </p>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,yBAAyB;AAQ9B;AANG,SAAS,mBAAmB;AACjC,QAAM,WAAW,kBAAkB,EAAE;AACrC,MAAI,CAAC,UAAU,SAAS;AACtB,WAAO;AAAA,EACT;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,SAAS,WAAW,YAAY,UAAU;AAAA,MAChD,WAAU;AAAA,MACV,iBAAe,SAAS,WAAW,YAAY,UAAU;AAAA,MAExD,mBAAS;AAAA;AAAA,EACZ;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,14 @@
1
+ // src/cart/empty-cart.tsx
2
+ import { Cart, Overlay } from "@zappie/foundations";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ function EmptyCart() {
5
+ return /* @__PURE__ */ jsxs(Cart.Empty, { className: "z-base-cart-empty", children: [
6
+ /* @__PURE__ */ jsx("h2", { children: "Your cart is empty" }),
7
+ /* @__PURE__ */ jsx("p", { children: "Add something from the menu to get started." }),
8
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button", children: "Browse menu" })
9
+ ] });
10
+ }
11
+ export {
12
+ EmptyCart
13
+ };
14
+ //# sourceMappingURL=empty-cart.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/empty-cart.tsx"],
4
+ "sourcesContent": ["import { Cart, Overlay } from \"@zappie/foundations\";\nexport function EmptyCart() {\n return (\n <Cart.Empty className=\"z-base-cart-empty\">\n <h2>Your cart is empty</h2>\n <p>Add something from the menu to get started.</p>\n <Overlay.Close className=\"z-base-button\">Browse menu</Overlay.Close>\n </Cart.Empty>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,MAAM,eAAe;AAG1B,SACE,KADF;AAFG,SAAS,YAAY;AAC1B,SACE,qBAAC,KAAK,OAAL,EAAW,WAAU,qBACpB;AAAA,wBAAC,QAAG,gCAAkB;AAAA,IACtB,oBAAC,OAAE,yDAA2C;AAAA,IAC9C,oBAAC,QAAQ,OAAR,EAAc,WAAU,iBAAgB,yBAAW;AAAA,KACtD;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,83 @@
1
+ // src/cart/fulfilment-panel.tsx
2
+ import { Branch, Fulfilment } from "@zappie/foundations";
3
+ import { useCart, useStore } from "@zappie/sdk/react";
4
+ import { Fragment, useState } from "react";
5
+ import { useAddressLookup } from "../address.js";
6
+ import { useBaseHostBridge } from "../host-bridge.js";
7
+ import { AddressSheet } from "./address-sheet.js";
8
+ import { RegionPicker } from "./region-picker.js";
9
+ import { ScheduleSheet } from "./schedule-sheet.js";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ function FulfilmentPanel() {
12
+ const cart = useCart();
13
+ const store = useStore();
14
+ const bridge = useBaseHostBridge();
15
+ const lookup = useAddressLookup();
16
+ const [error, setError] = useState(null);
17
+ const branch = store.data?.branches.find(
18
+ (branch2) => branch2.id === cart.branchId
19
+ );
20
+ const mode = bridge.fulfilmentMode ?? cart.fulfilment?.type ?? "delivery";
21
+ if (!branch) {
22
+ return null;
23
+ }
24
+ const scheduledFor = cart.fulfilment && "scheduledFor" in cart.fulfilment ? cart.fulfilment.scheduledFor : void 0;
25
+ return /* @__PURE__ */ jsxs("section", { className: "z-base-fulfilment-panel", "aria-label": "Fulfilment", children: [
26
+ /* @__PURE__ */ jsx("h2", { children: "Fulfilment" }),
27
+ /* @__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(
28
+ "button",
29
+ {
30
+ type: "button",
31
+ "aria-pressed": mode === option,
32
+ className: "z-base-button-secondary",
33
+ onClick: () => {
34
+ setError(null);
35
+ try {
36
+ if (!bridge.setFulfilmentMode(
37
+ option
38
+ )) {
39
+ setError(
40
+ "This menu does not allow that fulfilment option."
41
+ );
42
+ }
43
+ } catch (failure) {
44
+ setError(
45
+ failure instanceof Error ? failure.message : "Unable to change fulfilment"
46
+ );
47
+ }
48
+ },
49
+ children: option === "pickup" ? "Pickup" : "Delivery"
50
+ },
51
+ option
52
+ )) }) }),
53
+ /* @__PURE__ */ jsx(Branch.Picker, { branches: [branch], children: ({ selected }) => /* @__PURE__ */ jsxs("p", { children: [
54
+ mode === "pickup" ? "Collect from" : "Ordering from",
55
+ " ",
56
+ selected?.name,
57
+ selected?.address ? ` \u2014 ${selected.address}` : ""
58
+ ] }) }),
59
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
60
+ mode === "delivery" && /* @__PURE__ */ jsxs(Fragment, { children: [
61
+ cart.fulfilment?.type === "delivery" && /* @__PURE__ */ jsxs(Fragment, { children: [
62
+ /* @__PURE__ */ jsx("p", { children: cart.fulfilment.address.line1 }),
63
+ lookup.Map && /* @__PURE__ */ jsx(lookup.Map, { address: cart.fulfilment.address })
64
+ ] }),
65
+ /* @__PURE__ */ jsx(AddressSheet, {}),
66
+ /* @__PURE__ */ jsx(RegionPicker, {})
67
+ ] }),
68
+ scheduledFor && /* @__PURE__ */ jsxs("p", { children: [
69
+ "Scheduled for",
70
+ " ",
71
+ new Intl.DateTimeFormat("en", {
72
+ dateStyle: "medium",
73
+ timeStyle: "short",
74
+ timeZone: branch.timezone ?? store.data?.timezone
75
+ }).format(new Date(scheduledFor))
76
+ ] }),
77
+ branch.fulfilment.scheduling && /* @__PURE__ */ jsx(ScheduleSheet, { branch })
78
+ ] });
79
+ }
80
+ export {
81
+ FulfilmentPanel
82
+ };
83
+ //# sourceMappingURL=fulfilment-panel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/fulfilment-panel.tsx"],
4
+ "sourcesContent": ["import { Branch, Fulfilment } from \"@zappie/foundations\";\nimport { useCart, useStore } from \"@zappie/sdk/react\";\nimport { Fragment, useState } from \"react\";\nimport { useAddressLookup } from \"../address\";\nimport { useBaseHostBridge } from \"../host-bridge\";\nimport { AddressSheet } from \"./address-sheet\";\nimport { RegionPicker } from \"./region-picker\";\nimport { ScheduleSheet } from \"./schedule-sheet\";\nexport function FulfilmentPanel() {\n const cart = useCart();\n const store = useStore();\n const bridge = useBaseHostBridge();\n const lookup = useAddressLookup();\n const [error, setError] = useState<string | null>(null);\n const branch = store.data?.branches.find(\n (branch) => branch.id === cart.branchId,\n );\n const mode = bridge.fulfilmentMode ?? cart.fulfilment?.type ?? \"delivery\";\n if (!branch) {\n return null;\n }\n const scheduledFor =\n cart.fulfilment && \"scheduledFor\" in cart.fulfilment\n ? cart.fulfilment.scheduledFor\n : undefined;\n return (\n <section className=\"z-base-fulfilment-panel\" aria-label=\"Fulfilment\">\n <h2>Fulfilment</h2>\n <Fulfilment.Switch aria-label=\"Order fulfilment\">\n {({ options }) => (\n <div className=\"z-base-line-actions\">\n {options\n .filter((option) => option !== \"dine_in\")\n .map((option) => (\n <button\n type=\"button\"\n key={option}\n aria-pressed={mode === option}\n className=\"z-base-button-secondary\"\n onClick={() => {\n setError(null);\n try {\n if (\n !bridge.setFulfilmentMode(\n option as \"delivery\" | \"pickup\",\n )\n ) {\n setError(\n \"This menu does not allow that fulfilment option.\",\n );\n }\n } catch (failure) {\n setError(\n failure instanceof Error\n ? failure.message\n : \"Unable to change fulfilment\",\n );\n }\n }}\n >\n {option === \"pickup\" ? \"Pickup\" : \"Delivery\"}\n </button>\n ))}\n </div>\n )}\n </Fulfilment.Switch>\n <Branch.Picker branches={[branch]}>\n {({ selected }) => (\n <p>\n {mode === \"pickup\" ? \"Collect from\" : \"Ordering from\"}{\" \"}\n {selected?.name}\n {selected?.address ? ` \u2014 ${selected.address}` : \"\"}\n </p>\n )}\n </Branch.Picker>\n {error && <p role=\"alert\">{error}</p>}\n {mode === \"delivery\" && (\n <Fragment>\n {cart.fulfilment?.type === \"delivery\" && (\n <Fragment>\n <p>{cart.fulfilment.address.line1}</p>\n {lookup.Map && <lookup.Map address={cart.fulfilment.address} />}\n </Fragment>\n )}\n <AddressSheet />\n <RegionPicker />\n </Fragment>\n )}\n {scheduledFor && (\n <p>\n Scheduled for{\" \"}\n {new Intl.DateTimeFormat(\"en\", {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n timeZone: branch.timezone ?? store.data?.timezone,\n }).format(new Date(scheduledFor))}\n </p>\n )}\n {branch.fulfilment.scheduling && <ScheduleSheet branch={branch} />}\n </section>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,QAAQ,kBAAkB;AACnC,SAAS,SAAS,gBAAgB;AAClC,SAAS,UAAU,gBAAgB;AACnC,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAoBxB,cAyCI,YAzCJ;AAnBC,SAAS,kBAAkB;AAChC,QAAM,OAAO,QAAQ;AACrB,QAAM,QAAQ,SAAS;AACvB,QAAM,SAAS,kBAAkB;AACjC,QAAM,SAAS,iBAAiB;AAChC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,SAAS,MAAM,MAAM,SAAS;AAAA,IAClC,CAACA,YAAWA,QAAO,OAAO,KAAK;AAAA,EACjC;AACA,QAAM,OAAO,OAAO,kBAAkB,KAAK,YAAY,QAAQ;AAC/D,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,QAAM,eACJ,KAAK,cAAc,kBAAkB,KAAK,aACtC,KAAK,WAAW,eAChB;AACN,SACE,qBAAC,aAAQ,WAAU,2BAA0B,cAAW,cACtD;AAAA,wBAAC,QAAG,wBAAU;AAAA,IACd,oBAAC,WAAW,QAAX,EAAkB,cAAW,oBAC3B,WAAC,EAAE,QAAQ,MACV,oBAAC,SAAI,WAAU,uBACZ,kBACE,OAAO,CAAC,WAAW,WAAW,SAAS,EACvC,IAAI,CAAC,WACJ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QAEL,gBAAc,SAAS;AAAA,QACvB,WAAU;AAAA,QACV,SAAS,MAAM;AACb,mBAAS,IAAI;AACb,cAAI;AACF,gBACE,CAAC,OAAO;AAAA,cACN;AAAA,YACF,GACA;AACA;AAAA,gBACE;AAAA,cACF;AAAA,YACF;AAAA,UACF,SAAS,SAAS;AAChB;AAAA,cACE,mBAAmB,QACf,QAAQ,UACR;AAAA,YACN;AAAA,UACF;AAAA,QACF;AAAA,QAEC,qBAAW,WAAW,WAAW;AAAA;AAAA,MAxB7B;AAAA,IAyBP,CACD,GACL,GAEJ;AAAA,IACA,oBAAC,OAAO,QAAP,EAAc,UAAU,CAAC,MAAM,GAC7B,WAAC,EAAE,SAAS,MACX,qBAAC,OACE;AAAA,eAAS,WAAW,iBAAiB;AAAA,MAAiB;AAAA,MACtD,UAAU;AAAA,MACV,UAAU,UAAU,WAAM,SAAS,OAAO,KAAK;AAAA,OAClD,GAEJ;AAAA,IACC,SAAS,oBAAC,OAAE,MAAK,SAAS,iBAAM;AAAA,IAChC,SAAS,cACR,qBAAC,YACE;AAAA,WAAK,YAAY,SAAS,cACzB,qBAAC,YACC;AAAA,4BAAC,OAAG,eAAK,WAAW,QAAQ,OAAM;AAAA,QACjC,OAAO,OAAO,oBAAC,OAAO,KAAP,EAAW,SAAS,KAAK,WAAW,SAAS;AAAA,SAC/D;AAAA,MAEF,oBAAC,gBAAa;AAAA,MACd,oBAAC,gBAAa;AAAA,OAChB;AAAA,IAED,gBACC,qBAAC,OAAE;AAAA;AAAA,MACa;AAAA,MACb,IAAI,KAAK,eAAe,MAAM;AAAA,QAC7B,WAAW;AAAA,QACX,WAAW;AAAA,QACX,UAAU,OAAO,YAAY,MAAM,MAAM;AAAA,MAC3C,CAAC,EAAE,OAAO,IAAI,KAAK,YAAY,CAAC;AAAA,OAClC;AAAA,IAED,OAAO,WAAW,cAAc,oBAAC,iBAAc,QAAgB;AAAA,KAClE;AAEJ;",
6
+ "names": ["branch"]
7
+ }
@@ -0,0 +1,35 @@
1
+ // src/cart/line-editor.tsx
2
+ import { Overlay, useOverlay } from "@zappie/foundations";
3
+ import { useZappie } from "@zappie/sdk/react";
4
+ import { ItemConfigurator } from "../item/configurator.js";
5
+ import { useThemeClass } from "./theme-class.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ function LineEditor({ line, item }) {
8
+ const rootClass = useThemeClass("z-base-cart z-base-editor");
9
+ const overlay = useOverlay("cart_edit", line.id);
10
+ const client = useZappie();
11
+ return /* @__PURE__ */ jsxs(Overlay.Content, { "data-zappie-theme": "base", className: rootClass, children: [
12
+ /* @__PURE__ */ jsxs("header", { className: "z-base-cart-header", children: [
13
+ /* @__PURE__ */ jsxs(Overlay.Title, { children: [
14
+ "Edit ",
15
+ line.name
16
+ ] }),
17
+ /* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Cancel" })
18
+ ] }),
19
+ overlay.isOpen && /* @__PURE__ */ jsx("div", { className: "z-base-cart-body", children: /* @__PURE__ */ jsx(
20
+ ItemConfigurator,
21
+ {
22
+ item,
23
+ ...line.menuId !== void 0 ? { menuId: line.menuId } : {},
24
+ line,
25
+ scope: `${client.config.store}:${client.cart.branchId}:${client.cart.fulfilment?.type}`,
26
+ onComplete: overlay.close
27
+ },
28
+ line.id
29
+ ) })
30
+ ] });
31
+ }
32
+ export {
33
+ LineEditor
34
+ };
35
+ //# sourceMappingURL=line-editor.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/line-editor.tsx"],
4
+ "sourcesContent": ["import { Overlay, useOverlay } from \"@zappie/foundations\";\nimport type { CartLine, Item } from \"@zappie/sdk\";\nimport { useZappie } from \"@zappie/sdk/react\";\nimport { ItemConfigurator } from \"../item/configurator\";\nimport { useThemeClass } from \"./theme-class\";\nexport function LineEditor({ line, item }: { line: CartLine; item: Item }) {\n const rootClass = useThemeClass(\"z-base-cart z-base-editor\");\n const overlay = useOverlay(\"cart_edit\", line.id);\n const client = useZappie();\n return (\n <Overlay.Content data-zappie-theme=\"base\" className={rootClass}>\n <header className=\"z-base-cart-header\">\n <Overlay.Title>Edit {line.name}</Overlay.Title>\n <Overlay.Close className=\"z-base-button-secondary\">\n Cancel\n </Overlay.Close>\n </header>\n {overlay.isOpen && (\n <div className=\"z-base-cart-body\">\n <ItemConfigurator\n key={line.id}\n item={item}\n {...(line.menuId !== undefined ? { menuId: line.menuId } : {})}\n line={line}\n scope={`${client.config.store}:${client.cart.branchId}:${client.cart.fulfilment?.type}`}\n onComplete={overlay.close}\n />\n </div>\n )}\n </Overlay.Content>\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,SAAS,kBAAkB;AAEpC,SAAS,iBAAiB;AAC1B,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAQtB,SACA,KADA;AAPD,SAAS,WAAW,EAAE,MAAM,KAAK,GAAmC;AACzE,QAAM,YAAY,cAAc,2BAA2B;AAC3D,QAAM,UAAU,WAAW,aAAa,KAAK,EAAE;AAC/C,QAAM,SAAS,UAAU;AACzB,SACE,qBAAC,QAAQ,SAAR,EAAgB,qBAAkB,QAAO,WAAW,WACnD;AAAA,yBAAC,YAAO,WAAU,sBAChB;AAAA,2BAAC,QAAQ,OAAR,EAAc;AAAA;AAAA,QAAM,KAAK;AAAA,SAAK;AAAA,MAC/B,oBAAC,QAAQ,OAAR,EAAc,WAAU,2BAA0B,oBAEnD;AAAA,OACF;AAAA,IACC,QAAQ,UACP,oBAAC,SAAI,WAAU,oBACb;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACC,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,QAC5D;AAAA,QACA,OAAO,GAAG,OAAO,OAAO,KAAK,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,YAAY,IAAI;AAAA,QACrF,YAAY,QAAQ;AAAA;AAAA,MALf,KAAK;AAAA,IAMZ,GACF;AAAA,KAEJ;AAEJ;",
6
+ "names": []
7
+ }