@zappie/theme-base 0.1.0 → 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.
- package/CHANGELOG.md +39 -0
- package/README.md +26 -53
- package/dist/address.js +99 -2
- package/dist/address.js.map +7 -1
- package/dist/cart/address-sheet.js +143 -0
- package/dist/cart/address-sheet.js.map +7 -0
- package/dist/cart/cart-issues.js +72 -0
- package/dist/cart/cart-issues.js.map +7 -0
- package/dist/cart/cart-line-groups.js +34 -0
- package/dist/cart/cart-line-groups.js.map +7 -0
- package/dist/{chunk-FB5DRCU7.js → cart/cart-line.js} +9 -70
- package/dist/cart/cart-line.js.map +7 -0
- package/dist/cart/cart-lines.js +27 -0
- package/dist/cart/cart-lines.js.map +7 -0
- package/dist/cart/cart-schedule.js +24 -0
- package/dist/cart/cart-schedule.js.map +7 -0
- package/dist/cart/cart-sheet.js +35 -0
- package/dist/cart/cart-sheet.js.map +7 -0
- package/dist/cart/checkout-cta.js +81 -0
- package/dist/cart/checkout-cta.js.map +7 -0
- package/dist/cart/checkout-state.js +74 -0
- package/dist/cart/checkout-state.js.map +7 -0
- package/dist/cart/clear-cart.js +44 -0
- package/dist/cart/clear-cart.js.map +7 -0
- package/dist/cart/customer-details.js +70 -0
- package/dist/cart/customer-details.js.map +7 -0
- package/dist/cart/delivery-distance.js +22 -0
- package/dist/cart/delivery-distance.js.map +7 -0
- package/dist/cart/empty-cart.js +14 -0
- package/dist/cart/empty-cart.js.map +7 -0
- package/dist/cart/fulfilment-panel.js +83 -0
- package/dist/cart/fulfilment-panel.js.map +7 -0
- package/dist/cart/line-editor.js +35 -0
- package/dist/cart/line-editor.js.map +7 -0
- package/dist/cart/line-options.js +96 -0
- package/dist/cart/line-options.js.map +7 -0
- package/dist/cart/loading.js +17 -0
- package/dist/cart/loading.js.map +7 -0
- package/dist/cart/promo-sheet.js +103 -0
- package/dist/cart/promo-sheet.js.map +7 -0
- package/dist/cart/region-picker.js +40 -0
- package/dist/cart/region-picker.js.map +7 -0
- package/dist/cart/rewards-sheet.js +86 -0
- package/dist/cart/rewards-sheet.js.map +7 -0
- package/dist/cart/schedule-sheet.js +87 -0
- package/dist/cart/schedule-sheet.js.map +7 -0
- package/dist/{chunk-JFEI2OUZ.js → cart/theme-class.js} +7 -5
- package/dist/cart/theme-class.js.map +7 -0
- package/dist/cart/totals.js +81 -0
- package/dist/cart/totals.js.map +7 -0
- package/dist/cart/use-address-selection.js +130 -0
- package/dist/cart/use-address-selection.js.map +7 -0
- package/dist/cart.js +21 -1069
- package/dist/cart.js.map +7 -1
- package/dist/catalogue/catalogue-cart.js +25 -0
- package/dist/catalogue/catalogue-cart.js.map +7 -0
- package/dist/catalogue/catalogue-header.js +88 -0
- package/dist/catalogue/catalogue-header.js.map +7 -0
- package/dist/catalogue/catalogue-pages.js +68 -0
- package/dist/catalogue/catalogue-pages.js.map +7 -0
- package/dist/catalogue/catalogue-search.js +89 -0
- package/dist/catalogue/catalogue-search.js.map +7 -0
- package/dist/catalogue/category-navigation.js +98 -0
- package/dist/catalogue/category-navigation.js.map +7 -0
- package/dist/catalogue/category-section.js +113 -0
- package/dist/catalogue/category-section.js.map +7 -0
- package/dist/catalogue/info-banners.js +148 -0
- package/dist/catalogue/info-banners.js.map +7 -0
- package/dist/catalogue/item-tile.js +55 -0
- package/dist/catalogue/item-tile.js.map +7 -0
- package/dist/catalogue/loader.js +136 -0
- package/dist/catalogue/loader.js.map +7 -0
- package/dist/{chunk-USSLDBDY.js → catalogue/presentation.js} +12 -9
- package/dist/catalogue/presentation.js.map +7 -0
- package/dist/catalogue/saved-catalogue-sync.js +115 -0
- package/dist/catalogue/saved-catalogue-sync.js.map +7 -0
- package/dist/catalogue/types.js +1 -0
- package/dist/catalogue/types.js.map +7 -0
- package/dist/catalogue/use-catalogue-data.js +88 -0
- package/dist/catalogue/use-catalogue-data.js.map +7 -0
- package/dist/catalogue/use-category-scroll.js +115 -0
- package/dist/catalogue/use-category-scroll.js.map +7 -0
- package/dist/catalogue/use-item-opener.js +46 -0
- package/dist/catalogue/use-item-opener.js.map +7 -0
- package/dist/catalogue/use-search-source.js +132 -0
- package/dist/catalogue/use-search-source.js.map +7 -0
- package/dist/catalogue.js +26 -1216
- package/dist/catalogue.js.map +7 -1
- package/dist/checkout.js +149 -2
- package/dist/checkout.js.map +7 -1
- package/dist/host-bridge.js +22 -2
- package/dist/host-bridge.js.map +7 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +7 -1
- package/dist/item/configurator-commit.js +15 -0
- package/dist/item/configurator-commit.js.map +7 -0
- package/dist/item/configurator-draft.js +63 -0
- package/dist/item/configurator-draft.js.map +7 -0
- package/dist/item/configurator.js +135 -0
- package/dist/item/configurator.js.map +7 -0
- package/dist/item/note.js +65 -0
- package/dist/item/note.js.map +7 -0
- package/dist/item/variant-status.js +23 -0
- package/dist/item/variant-status.js.map +7 -0
- package/dist/item-frame.js +60 -3
- package/dist/item-frame.js.map +7 -1
- package/dist/item.js +11 -11
- package/dist/item.js.map +7 -1
- package/dist/navigation.js +39 -2
- package/dist/navigation.js.map +7 -1
- package/dist/url-navigation-state.js +61 -0
- package/dist/url-navigation-state.js.map +7 -0
- package/dist/{chunk-ILOCSCZL.js → url-navigation.js} +12 -89
- package/dist/url-navigation.js.map +7 -0
- package/package.json +8 -7
- package/dist/chunk-2MV6KU3R.js +0 -352
- package/dist/chunk-2MV6KU3R.js.map +0 -1
- package/dist/chunk-FB5DRCU7.js.map +0 -1
- package/dist/chunk-IG63ONID.js +0 -139
- package/dist/chunk-IG63ONID.js.map +0 -1
- package/dist/chunk-ILOCSCZL.js.map +0 -1
- package/dist/chunk-JFEI2OUZ.js.map +0 -1
- package/dist/chunk-NTJONY3N.js +0 -95
- package/dist/chunk-NTJONY3N.js.map +0 -1
- package/dist/chunk-QWST2TA2.js +0 -22
- package/dist/chunk-QWST2TA2.js.map +0 -1
- package/dist/chunk-USSLDBDY.js.map +0 -1
- package/dist/chunk-VIAJ27YC.js +0 -59
- package/dist/chunk-VIAJ27YC.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @zappie/theme-base
|
|
2
|
+
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d3c5f98: Keep each runtime module separate so your app can split package code across routes. Check and verify accept compatible package updates without pinning you to one patch version.
|
|
8
|
+
- Updated dependencies [d3c5f98]
|
|
9
|
+
- @zappie/sdk@0.1.2
|
|
10
|
+
- @zappie/foundations@0.1.2
|
|
11
|
+
|
|
12
|
+
## 0.1.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 1e6f420: Each package now has a README written for people installing it from npm: what it does, how to install and use it, its entry points, and links to docs.zappie.ai. `@zappie/kit` gains its first README.
|
|
17
|
+
- Updated dependencies [38f23ac]
|
|
18
|
+
- Updated dependencies [1e6f420]
|
|
19
|
+
- @zappie/sdk@0.1.1
|
|
20
|
+
- @zappie/foundations@0.1.1
|
|
21
|
+
- @zappie/tokens@0.1.1
|
|
22
|
+
|
|
23
|
+
## 0.1.0
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- - `@zappie/tokens`: Publish the semantic storefront token contract, CSS aliases, validation and compilation tools.
|
|
28
|
+
- `@zappie/sdk`: Publish the framework-agnostic storefront client and its React, server, checkout, customer, places, visits and URL entries.
|
|
29
|
+
- `@zappie/foundations`: Publish accessible, unstyled React primitives for storefront catalogue, item, fulfilment and cart experiences.
|
|
30
|
+
- `@zappie/theme-base`: Publish the reusable base storefront theme and its catalogue, item and cart surfaces.
|
|
31
|
+
- `@zappie/kit`: Publish the built component registry consumed by the Zappie CLI.
|
|
32
|
+
- `zappie`: Publish the component CLI with `add`, `list` and `diff`.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies
|
|
37
|
+
- @zappie/tokens@0.1.0
|
|
38
|
+
- @zappie/sdk@0.1.0
|
|
39
|
+
- @zappie/foundations@0.1.0
|
package/README.md
CHANGED
|
@@ -1,65 +1,38 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @zappie/theme-base
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
changes, editing, removal, issue fixes, server-quoted totals and the existing
|
|
5
|
-
host payment flow. Empty and loading states use the same foundations overlay.
|
|
3
|
+
The base storefront theme that Zappie's own storefront app renders: the catalogue, item sheets, cart and checkout steps. It's built only from Zappie's public packages, `@zappie/sdk`, `@zappie/foundations` and `@zappie/tokens`, so it also shows how far those packages go on their own.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
```sh
|
|
6
|
+
npm install @zappie/theme-base
|
|
7
|
+
```
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
reconciles complete snapshots into the SDK and mirrors subsequent SDK edits
|
|
13
|
-
back into the same legacy storage bucket. Line identities, choices, notes and
|
|
14
|
-
unavailable-item issues survive. A private SDK import seam makes this atomic;
|
|
15
|
-
no backend API or public cart method changes. Scope changes detach the bridge.
|
|
9
|
+
React 19.2 is a peer dependency.
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
payment, sign-in, customer details and address suggestions. The host checks a
|
|
19
|
-
current quote and synchronized basket, closes the cart through foundations,
|
|
20
|
-
waits for the URL change and cart unmount, and only then starts the existing
|
|
21
|
-
payment flow. Sign-in similarly releases the foundations modal before invoking
|
|
22
|
-
the host auth callback, which restores the cart after authentication.
|
|
23
|
-
Address lookup uses the existing host Places endpoint. Fulfilment must match
|
|
24
|
-
the current host branch and pickup/delivery bucket before checkout.
|
|
11
|
+
## Who it's for
|
|
25
12
|
|
|
26
|
-
|
|
27
|
-
`?template=base-next&modal_id=review-menu`. Below 1024px the cart is a full-height
|
|
28
|
-
swipeable drawer; from 1024px it is a centred dialog. Deep-link close retains
|
|
29
|
-
the store URL. All other storefront templates retain their existing cart.
|
|
13
|
+
Zappie's storefront app mounts this theme and supplies payment, sign-in, rewards and delivery regions through `@zappie/theme-base/host-bridge`. That bridge is a temporary contract with Zappie's own app. It will be replaced, so it isn't a stable way to run the theme in your own project.
|
|
30
14
|
|
|
31
|
-
`
|
|
32
|
-
CSS with `pnpm base-next:tokens`. Explicit `.dark` / `data-theme="dark"` choices
|
|
33
|
-
use dark tokens; the default ignores the operating-system preference.
|
|
15
|
+
Building your own storefront or template? Start from `@zappie/sdk`, `@zappie/foundations` and the kit's copy-in components (`npx zappie add <name>`). Use this theme as a reference for how the parts fit together.
|
|
34
16
|
|
|
35
|
-
|
|
36
|
-
manifest and SEO. This package imports only public commerce packages. The
|
|
37
|
-
host-side seam owns its provider and legacy template contract.
|
|
17
|
+
## Entry points
|
|
38
18
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
19
|
+
| Import | For |
|
|
20
|
+
| ------------------------------------------------------ | --------------------------------------------------- |
|
|
21
|
+
| `@zappie/theme-base/catalogue`, `/item`, `/item-frame` | The menu and item views |
|
|
22
|
+
| `@zappie/theme-base/cart` and `/checkout` | The cart and checkout steps |
|
|
23
|
+
| `@zappie/theme-base/address` and `/navigation` | Address entry and in-page navigation |
|
|
24
|
+
| `@zappie/theme-base/styles.css` | The theme's styles, scoped to its own root |
|
|
25
|
+
| `@zappie/theme-base/host-bridge` | The temporary contract with Zappie's storefront app |
|
|
43
26
|
|
|
44
|
-
|
|
45
|
-
pre-migration baseline. Counts cover the explicit PRD legacy paths and all
|
|
46
|
-
non-test cart source. CSS totals include compiled tokens; legacy shared CSS
|
|
47
|
-
cannot be attributed to cart alone. These incremental metrics are not a claim of
|
|
48
|
-
full cart parity or a completed Stage A reduction.
|
|
27
|
+
## Docs
|
|
49
28
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
its own router implementation or the framework-independent
|
|
53
|
-
`createUrlNavigation()` default. Item links and URL state come from that
|
|
54
|
-
navigation context. `initialMenu` contains menus/categories and no items;
|
|
55
|
-
the supplied policy chooses eager or progressive reads. `orderAction` supplies
|
|
56
|
-
the Place/Schedule/View label. Search's controlled source performs bounded
|
|
57
|
-
reads, and themeClass reaches mobile overlay portals.
|
|
29
|
+
- [Open Storefronts](https://docs.zappie.ai/open-storefronts)
|
|
30
|
+
- [Build a storefront](https://docs.zappie.ai/guides/build-a-storefront)
|
|
58
31
|
|
|
59
|
-
##
|
|
32
|
+
## Status
|
|
60
33
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
34
|
+
The theme is at `0.x`. It changes with Zappie's storefront app, and any release can change its entry points. Each change is listed in `CHANGELOG.md`.
|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
MIT
|
package/dist/address.js
CHANGED
|
@@ -1,4 +1,101 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
// src/address.tsx
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
useContext
|
|
7
|
+
} from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
function deliveryAddress(place, source) {
|
|
10
|
+
const result = {
|
|
11
|
+
line1: place.line1,
|
|
12
|
+
placeId: place.place_id,
|
|
13
|
+
coordinates: { lat: place.lat, lng: place.lng }
|
|
14
|
+
};
|
|
15
|
+
if (place.city !== void 0) {
|
|
16
|
+
result.city = place.city;
|
|
17
|
+
}
|
|
18
|
+
if (source?.line2 !== void 0) {
|
|
19
|
+
result.line2 = source.line2;
|
|
20
|
+
}
|
|
21
|
+
if (source?.instructions !== void 0) {
|
|
22
|
+
result.instructions = source.instructions;
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
var Context = createContext(null);
|
|
27
|
+
function AddressLookupProvider({
|
|
28
|
+
lookup,
|
|
29
|
+
children
|
|
30
|
+
}) {
|
|
31
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value: lookup, children });
|
|
32
|
+
}
|
|
33
|
+
function useAddressLookup() {
|
|
34
|
+
const lookup = useContext(Context);
|
|
35
|
+
if (!lookup) {
|
|
36
|
+
throw new Error("useAddressLookup requires AddressLookupProvider");
|
|
37
|
+
}
|
|
38
|
+
return lookup;
|
|
39
|
+
}
|
|
40
|
+
function createSdkAddressLookup({
|
|
41
|
+
places,
|
|
42
|
+
branchId
|
|
43
|
+
}) {
|
|
44
|
+
let sessionToken = crypto.randomUUID();
|
|
45
|
+
const Map = ({ address }) => {
|
|
46
|
+
if (!address.coordinates) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return (
|
|
50
|
+
// The theme can't use next/image; the map's size is fixed by the API.
|
|
51
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
52
|
+
/* @__PURE__ */ jsx(
|
|
53
|
+
"img",
|
|
54
|
+
{
|
|
55
|
+
className: "z-base-address-map",
|
|
56
|
+
src: places.staticMapUrl(
|
|
57
|
+
address.coordinates.lat,
|
|
58
|
+
address.coordinates.lng,
|
|
59
|
+
branchId
|
|
60
|
+
),
|
|
61
|
+
alt: `Map of ${address.line1}`,
|
|
62
|
+
width: 640,
|
|
63
|
+
height: 320,
|
|
64
|
+
loading: "lazy"
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
async suggest(query) {
|
|
71
|
+
const suggestions = await places.autocomplete(query, sessionToken);
|
|
72
|
+
return suggestions.map((suggestion) => ({
|
|
73
|
+
placeId: suggestion.place_id,
|
|
74
|
+
address: suggestion.secondary ? `${suggestion.text}, ${suggestion.secondary}` : suggestion.text,
|
|
75
|
+
sessionToken
|
|
76
|
+
}));
|
|
77
|
+
},
|
|
78
|
+
async resolve(address, token) {
|
|
79
|
+
if (!address.placeId) {
|
|
80
|
+
throw new Error("Choose a suggested delivery address");
|
|
81
|
+
}
|
|
82
|
+
const place = await places.place(address.placeId, {
|
|
83
|
+
branchId,
|
|
84
|
+
sessionToken: token ?? sessionToken
|
|
85
|
+
});
|
|
86
|
+
sessionToken = crypto.randomUUID();
|
|
87
|
+
return deliveryAddress(place, address);
|
|
88
|
+
},
|
|
89
|
+
async reverse({ lat, lng }) {
|
|
90
|
+
const place = await places.reverse(lat, lng);
|
|
91
|
+
return deliveryAddress(place);
|
|
92
|
+
},
|
|
93
|
+
Map
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
AddressLookupProvider,
|
|
98
|
+
createSdkAddressLookup,
|
|
99
|
+
useAddressLookup
|
|
100
|
+
};
|
|
3
101
|
//# sourceMappingURL=address.js.map
|
|
4
|
-
//# sourceMappingURL=address.js.map
|
package/dist/address.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/address.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport type { DeliveryAddress } from \"@zappie/sdk\";\nimport type { Place, PlacesClient } from \"@zappie/sdk/places\";\nimport {\n createContext,\n useContext,\n type ComponentType,\n type ReactNode,\n} from \"react\";\n\nexport type AddressSuggestion = {\n placeId: string;\n address: string;\n sessionToken?: string;\n};\n\nexport type AddressLookup = {\n suggest(query: string): Promise<AddressSuggestion[]>;\n reverse?(coordinates: { lat: number; lng: number }): Promise<DeliveryAddress>;\n resolve?(\n address: DeliveryAddress,\n sessionToken?: string,\n ): Promise<DeliveryAddress>;\n Map?: ComponentType<{ address: DeliveryAddress }>;\n};\n\nfunction deliveryAddress(\n place: Place,\n source?: DeliveryAddress,\n): DeliveryAddress {\n const result: DeliveryAddress = {\n line1: place.line1,\n placeId: place.place_id,\n coordinates: { lat: place.lat, lng: place.lng },\n };\n if (place.city !== undefined) {\n result.city = place.city;\n }\n if (source?.line2 !== undefined) {\n result.line2 = source.line2;\n }\n if (source?.instructions !== undefined) {\n result.instructions = source.instructions;\n }\n return result;\n}\n\nconst Context = createContext<AddressLookup | null>(null);\n\nexport function AddressLookupProvider({\n lookup,\n children,\n}: {\n lookup: AddressLookup;\n children: ReactNode;\n}) {\n return <Context.Provider value={lookup}>{children}</Context.Provider>;\n}\n\nexport function useAddressLookup() {\n const lookup = useContext(Context);\n if (!lookup) {\n throw new Error(\"useAddressLookup requires AddressLookupProvider\");\n }\n return lookup;\n}\n\nexport function createSdkAddressLookup({\n places,\n branchId,\n}: {\n places: PlacesClient;\n branchId: string;\n}): AddressLookup {\n let sessionToken = crypto.randomUUID();\n const Map = ({ address }: { address: DeliveryAddress }) => {\n if (!address.coordinates) {\n return null;\n }\n return (\n // The theme can't use next/image; the map's size is fixed by the API.\n // eslint-disable-next-line @next/next/no-img-element\n <img\n className=\"z-base-address-map\"\n src={places.staticMapUrl(\n address.coordinates.lat,\n address.coordinates.lng,\n branchId,\n )}\n alt={`Map of ${address.line1}`}\n width={640}\n height={320}\n loading=\"lazy\"\n />\n );\n };\n return {\n async suggest(query) {\n const suggestions = await places.autocomplete(query, sessionToken);\n return suggestions.map((suggestion) => ({\n placeId: suggestion.place_id,\n address: suggestion.secondary\n ? `${suggestion.text}, ${suggestion.secondary}`\n : suggestion.text,\n sessionToken,\n }));\n },\n async resolve(address, token) {\n if (!address.placeId) {\n throw new Error(\"Choose a suggested delivery address\");\n }\n const place = await places.place(address.placeId, {\n branchId,\n sessionToken: token ?? sessionToken,\n });\n sessionToken = crypto.randomUUID();\n return deliveryAddress(place, address);\n },\n async reverse({ lat, lng }) {\n const place = await places.reverse(lat, lng);\n return deliveryAddress(place);\n },\n Map,\n };\n}\n"],
|
|
5
|
+
"mappings": ";;;AAIA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAgDE;AA9BT,SAAS,gBACP,OACA,QACiB;AACjB,QAAM,SAA0B;AAAA,IAC9B,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,IACf,aAAa,EAAE,KAAK,MAAM,KAAK,KAAK,MAAM,IAAI;AAAA,EAChD;AACA,MAAI,MAAM,SAAS,QAAW;AAC5B,WAAO,OAAO,MAAM;AAAA,EACtB;AACA,MAAI,QAAQ,UAAU,QAAW;AAC/B,WAAO,QAAQ,OAAO;AAAA,EACxB;AACA,MAAI,QAAQ,iBAAiB,QAAW;AACtC,WAAO,eAAe,OAAO;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,IAAM,UAAU,cAAoC,IAAI;AAEjD,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AACF,GAGG;AACD,SAAO,oBAAC,QAAQ,UAAR,EAAiB,OAAO,QAAS,UAAS;AACpD;AAEO,SAAS,mBAAmB;AACjC,QAAM,SAAS,WAAW,OAAO;AACjC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA;AACF,GAGkB;AAChB,MAAI,eAAe,OAAO,WAAW;AACrC,QAAM,MAAM,CAAC,EAAE,QAAQ,MAAoC;AACzD,QAAI,CAAC,QAAQ,aAAa;AACxB,aAAO;AAAA,IACT;AACA;AAAA;AAAA;AAAA,MAGE;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,KAAK,OAAO;AAAA,YACV,QAAQ,YAAY;AAAA,YACpB,QAAQ,YAAY;AAAA,YACpB;AAAA,UACF;AAAA,UACA,KAAK,UAAU,QAAQ,KAAK;AAAA,UAC5B,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,SAAQ;AAAA;AAAA,MACV;AAAA;AAAA,EAEJ;AACA,SAAO;AAAA,IACL,MAAM,QAAQ,OAAO;AACnB,YAAM,cAAc,MAAM,OAAO,aAAa,OAAO,YAAY;AACjE,aAAO,YAAY,IAAI,CAAC,gBAAgB;AAAA,QACtC,SAAS,WAAW;AAAA,QACpB,SAAS,WAAW,YAChB,GAAG,WAAW,IAAI,KAAK,WAAW,SAAS,KAC3C,WAAW;AAAA,QACf;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,IACA,MAAM,QAAQ,SAAS,OAAO;AAC5B,UAAI,CAAC,QAAQ,SAAS;AACpB,cAAM,IAAI,MAAM,qCAAqC;AAAA,MACvD;AACA,YAAM,QAAQ,MAAM,OAAO,MAAM,QAAQ,SAAS;AAAA,QAChD;AAAA,QACA,cAAc,SAAS;AAAA,MACzB,CAAC;AACD,qBAAe,OAAO,WAAW;AACjC,aAAO,gBAAgB,OAAO,OAAO;AAAA,IACvC;AAAA,IACA,MAAM,QAAQ,EAAE,KAAK,IAAI,GAAG;AAC1B,YAAM,QAAQ,MAAM,OAAO,QAAQ,KAAK,GAAG;AAC3C,aAAO,gBAAgB,KAAK;AAAA,IAC9B;AAAA,IACA;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// src/cart/address-sheet.tsx
|
|
2
|
+
import { Address, useOverlay } from "@zappie/foundations";
|
|
3
|
+
import { useCart } 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 { CartSheet } from "./cart-sheet.js";
|
|
8
|
+
import { useAddressSelection } from "./use-address-selection.js";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
function AddressForm() {
|
|
11
|
+
const cart = useCart();
|
|
12
|
+
const lookup = useAddressLookup();
|
|
13
|
+
const bridge = useBaseHostBridge();
|
|
14
|
+
const overlay = useOverlay("cart_sheet", "address");
|
|
15
|
+
const current = cart.fulfilment?.type === "delivery" ? cart.fulfilment.address : void 0;
|
|
16
|
+
const {
|
|
17
|
+
selected,
|
|
18
|
+
query,
|
|
19
|
+
busy,
|
|
20
|
+
error: lookupError,
|
|
21
|
+
suggestions,
|
|
22
|
+
changeQuery,
|
|
23
|
+
select,
|
|
24
|
+
findCurrentLocation,
|
|
25
|
+
locating
|
|
26
|
+
} = useAddressSelection(current);
|
|
27
|
+
const [instructions, setInstructions] = useState(current?.instructions ?? "");
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
const save = () => {
|
|
30
|
+
if (!selected || !cart.branchId || busy) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setError(null);
|
|
34
|
+
try {
|
|
35
|
+
const fulfilment = {
|
|
36
|
+
type: "delivery",
|
|
37
|
+
branchId: cart.branchId,
|
|
38
|
+
address: { ...selected, instructions },
|
|
39
|
+
...cart.fulfilment && "scheduledFor" in cart.fulfilment ? { scheduledFor: cart.fulfilment.scheduledFor } : {}
|
|
40
|
+
};
|
|
41
|
+
cart.actions.setFulfilment(fulfilment);
|
|
42
|
+
bridge.saveFulfilment?.(fulfilment);
|
|
43
|
+
overlay.close();
|
|
44
|
+
} catch (failure) {
|
|
45
|
+
setError(
|
|
46
|
+
failure instanceof Error ? failure.message : "Unable to save this address"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
51
|
+
lookup.reverse && typeof navigator !== "undefined" && navigator.geolocation && /* @__PURE__ */ jsx(
|
|
52
|
+
"button",
|
|
53
|
+
{
|
|
54
|
+
type: "button",
|
|
55
|
+
className: "z-base-button-secondary",
|
|
56
|
+
disabled: busy,
|
|
57
|
+
onClick: findCurrentLocation,
|
|
58
|
+
children: locating ? "Finding your location\u2026" : "Use my current location"
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ jsx(
|
|
62
|
+
Address.Picker,
|
|
63
|
+
{
|
|
64
|
+
query,
|
|
65
|
+
onQueryChange: changeQuery,
|
|
66
|
+
getSuggestions: suggestions,
|
|
67
|
+
onSelect: (value) => {
|
|
68
|
+
if ("address" in value) {
|
|
69
|
+
void select(value.address);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
children: ({ suggestions: suggestions2, status, isOpen }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
73
|
+
/* @__PURE__ */ jsxs("label", { className: "z-base-field", htmlFor: "z-base-delivery-address", children: [
|
|
74
|
+
"Delivery address",
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
Address.Input,
|
|
77
|
+
{
|
|
78
|
+
className: "z-base-input",
|
|
79
|
+
id: "z-base-delivery-address",
|
|
80
|
+
"aria-label": "Delivery address"
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
] }),
|
|
84
|
+
status === "loading" && /* @__PURE__ */ jsx("p", { role: "status", children: "Finding addresses\u2026" }),
|
|
85
|
+
status === "error" && /* @__PURE__ */ jsx("p", { role: "alert", children: "Unable to find addresses. Try again." }),
|
|
86
|
+
isOpen && /* @__PURE__ */ jsx(Address.Suggestions, { className: "z-base-suggestions", children: suggestions2.map((value, index) => /* @__PURE__ */ jsx(
|
|
87
|
+
Address.Suggestion,
|
|
88
|
+
{
|
|
89
|
+
index,
|
|
90
|
+
className: "z-base-choice",
|
|
91
|
+
children: value.label
|
|
92
|
+
},
|
|
93
|
+
value.id
|
|
94
|
+
)) }),
|
|
95
|
+
isOpen && status === "ready" && query && suggestions2.length === 0 && /* @__PURE__ */ jsx("p", { children: "No matching addresses." })
|
|
96
|
+
] })
|
|
97
|
+
}
|
|
98
|
+
),
|
|
99
|
+
/* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
|
|
100
|
+
"Delivery instructions",
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
"textarea",
|
|
103
|
+
{
|
|
104
|
+
className: "z-base-input",
|
|
105
|
+
maxLength: 500,
|
|
106
|
+
value: instructions,
|
|
107
|
+
onChange: (event) => setInstructions(event.target.value)
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
] }),
|
|
111
|
+
selected && lookup.Map && /* @__PURE__ */ jsx(lookup.Map, { address: selected }),
|
|
112
|
+
lookupError && /* @__PURE__ */ jsx("p", { role: "alert", children: lookupError }),
|
|
113
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
|
|
114
|
+
/* @__PURE__ */ jsx(
|
|
115
|
+
"button",
|
|
116
|
+
{
|
|
117
|
+
type: "button",
|
|
118
|
+
className: "z-base-button",
|
|
119
|
+
disabled: !selected || busy,
|
|
120
|
+
onClick: () => {
|
|
121
|
+
void save();
|
|
122
|
+
},
|
|
123
|
+
children: busy ? "Locating address\u2026" : "Save address"
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
] });
|
|
127
|
+
}
|
|
128
|
+
function AddressSheet() {
|
|
129
|
+
const cart = useCart();
|
|
130
|
+
return /* @__PURE__ */ jsx(
|
|
131
|
+
CartSheet,
|
|
132
|
+
{
|
|
133
|
+
id: "address",
|
|
134
|
+
title: "Delivery address",
|
|
135
|
+
trigger: cart.fulfilment?.type === "delivery" ? "Change address" : "Add delivery address",
|
|
136
|
+
children: /* @__PURE__ */ jsx(AddressForm, {})
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
AddressSheet
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=address-sheet.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/cart/address-sheet.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Address, useOverlay } from \"@zappie/foundations\";\nimport { useCart } from \"@zappie/sdk/react\";\nimport { Fragment, useState } from \"react\";\nimport { useAddressLookup } from \"../address\";\nimport { useBaseHostBridge } from \"../host-bridge\";\nimport { CartSheet } from \"./cart-sheet\";\nimport { useAddressSelection } from \"./use-address-selection\";\nfunction AddressForm() {\n const cart = useCart();\n const lookup = useAddressLookup();\n const bridge = useBaseHostBridge();\n const overlay = useOverlay(\"cart_sheet\", \"address\");\n const current =\n cart.fulfilment?.type === \"delivery\" ? cart.fulfilment.address : undefined;\n const {\n selected,\n query,\n busy,\n error: lookupError,\n suggestions,\n changeQuery,\n select,\n findCurrentLocation,\n locating,\n } = useAddressSelection(current);\n const [instructions, setInstructions] = useState(current?.instructions ?? \"\");\n const [error, setError] = useState<string | null>(null);\n const save = () => {\n if (!selected || !cart.branchId || busy) {\n return;\n }\n setError(null);\n try {\n const fulfilment = {\n type: \"delivery\" as const,\n branchId: cart.branchId,\n address: { ...selected, instructions },\n ...(cart.fulfilment && \"scheduledFor\" in cart.fulfilment\n ? { scheduledFor: cart.fulfilment.scheduledFor }\n : {}),\n };\n cart.actions.setFulfilment(fulfilment);\n bridge.saveFulfilment?.(fulfilment);\n overlay.close();\n } catch (failure) {\n setError(\n failure instanceof Error\n ? failure.message\n : \"Unable to save this address\",\n );\n }\n };\n return (\n <Fragment>\n {lookup.reverse &&\n typeof navigator !== \"undefined\" &&\n navigator.geolocation && (\n <button\n type=\"button\"\n className=\"z-base-button-secondary\"\n disabled={busy}\n onClick={findCurrentLocation}\n >\n {locating ? \"Finding your location\u2026\" : \"Use my current location\"}\n </button>\n )}\n <Address.Picker\n query={query}\n onQueryChange={changeQuery}\n getSuggestions={suggestions}\n onSelect={(value) => {\n if (\"address\" in value) {\n void select(value.address);\n }\n }}\n >\n {({ suggestions, status, isOpen }) => (\n <Fragment>\n <label className=\"z-base-field\" htmlFor=\"z-base-delivery-address\">\n Delivery address\n <Address.Input\n className=\"z-base-input\"\n id=\"z-base-delivery-address\"\n aria-label=\"Delivery address\"\n />\n </label>\n {status === \"loading\" && <p role=\"status\">Finding addresses\u2026</p>}\n {status === \"error\" && (\n <p role=\"alert\">Unable to find addresses. Try again.</p>\n )}\n {isOpen && (\n <Address.Suggestions className=\"z-base-suggestions\">\n {suggestions.map((value, index) => (\n <Address.Suggestion\n key={value.id}\n index={index}\n className=\"z-base-choice\"\n >\n {value.label}\n </Address.Suggestion>\n ))}\n </Address.Suggestions>\n )}\n {isOpen &&\n status === \"ready\" &&\n query &&\n suggestions.length === 0 && <p>No matching addresses.</p>}\n </Fragment>\n )}\n </Address.Picker>\n <label className=\"z-base-field\">\n Delivery instructions\n <textarea\n className=\"z-base-input\"\n maxLength={500}\n value={instructions}\n onChange={(event) => setInstructions(event.target.value)}\n />\n </label>\n {selected && lookup.Map && <lookup.Map address={selected} />}\n {lookupError && <p role=\"alert\">{lookupError}</p>}\n {error && <p role=\"alert\">{error}</p>}\n <button\n type=\"button\"\n className=\"z-base-button\"\n disabled={!selected || busy}\n onClick={() => {\n void save();\n }}\n >\n {busy ? \"Locating address\u2026\" : \"Save address\"}\n </button>\n </Fragment>\n );\n}\nexport function AddressSheet() {\n const cart = useCart();\n return (\n <CartSheet\n id=\"address\"\n title=\"Delivery address\"\n trigger={\n cart.fulfilment?.type === \"delivery\"\n ? \"Change address\"\n : \"Add delivery address\"\n }\n >\n <AddressForm />\n </CartSheet>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["suggestions"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/cart/cart-issues.tsx
|
|
2
|
+
import { Cart, useOverlay } from "@zappie/foundations";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
var labels = {
|
|
6
|
+
remove_line: "Remove item",
|
|
7
|
+
accept_price: "Accept new price",
|
|
8
|
+
remove_promo: "Remove promo",
|
|
9
|
+
set_quantity: "Update quantity",
|
|
10
|
+
choose_option: "Choose options",
|
|
11
|
+
choose_other_option: "Change options",
|
|
12
|
+
change_address: "Change delivery address",
|
|
13
|
+
schedule: "Choose order time"
|
|
14
|
+
};
|
|
15
|
+
function Issue({
|
|
16
|
+
issue,
|
|
17
|
+
applyFix
|
|
18
|
+
}) {
|
|
19
|
+
const editor = useOverlay("cart_edit", issue.lineId ?? "");
|
|
20
|
+
const address = useOverlay("cart_sheet", "address");
|
|
21
|
+
const schedule = useOverlay("cart_sheet", "schedule");
|
|
22
|
+
const [error, setError] = useState(null);
|
|
23
|
+
const fix = (value) => {
|
|
24
|
+
setError(null);
|
|
25
|
+
try {
|
|
26
|
+
if (value.action === "choose_option" || value.action === "choose_other_option") {
|
|
27
|
+
editor.open();
|
|
28
|
+
} else if (value.action === "change_address") {
|
|
29
|
+
address.open();
|
|
30
|
+
} else if (value.action === "schedule") {
|
|
31
|
+
schedule.open();
|
|
32
|
+
} else {
|
|
33
|
+
applyFix(issue, value);
|
|
34
|
+
}
|
|
35
|
+
} catch (error2) {
|
|
36
|
+
setError(
|
|
37
|
+
error2 instanceof Error ? error2.message : "Unable to apply this change"
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
42
|
+
/* @__PURE__ */ jsx("p", { children: issue.message }),
|
|
43
|
+
issue.fixes.filter((value) => labels[value.action]).map((value, index) => /* @__PURE__ */ jsx(
|
|
44
|
+
"button",
|
|
45
|
+
{
|
|
46
|
+
type: "button",
|
|
47
|
+
className: "z-base-button-secondary",
|
|
48
|
+
onClick: () => fix(value),
|
|
49
|
+
children: value.action === "set_quantity" ? `Set quantity to ${value.quantity}` : labels[value.action]
|
|
50
|
+
},
|
|
51
|
+
index
|
|
52
|
+
)),
|
|
53
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", children: error })
|
|
54
|
+
] });
|
|
55
|
+
}
|
|
56
|
+
function CartIssues() {
|
|
57
|
+
return /* @__PURE__ */ jsx(Cart.Issues, { children: ({ issues, applyFix }) => issues.length > 0 && /* @__PURE__ */ jsxs("section", { className: "z-base-issues", "aria-label": "Cart issues", children: [
|
|
58
|
+
/* @__PURE__ */ jsx("h2", { children: "Review your cart" }),
|
|
59
|
+
/* @__PURE__ */ jsx("ul", { children: issues.map((issue, index) => /* @__PURE__ */ jsx(
|
|
60
|
+
Issue,
|
|
61
|
+
{
|
|
62
|
+
issue,
|
|
63
|
+
applyFix
|
|
64
|
+
},
|
|
65
|
+
`${issue.lineId}:${issue.code}:${index}`
|
|
66
|
+
)) })
|
|
67
|
+
] }) });
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
CartIssues
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=cart-issues.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/cart/cart-issues.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Cart, useOverlay } from \"@zappie/foundations\";\nimport type { CartFix, CartIssue } from \"@zappie/sdk\";\nimport { useState } from \"react\";\nconst labels: Partial<Record<CartFix[\"action\"], string>> = {\n remove_line: \"Remove item\",\n accept_price: \"Accept new price\",\n remove_promo: \"Remove promo\",\n set_quantity: \"Update quantity\",\n choose_option: \"Choose options\",\n choose_other_option: \"Change options\",\n change_address: \"Change delivery address\",\n schedule: \"Choose order time\",\n};\nfunction Issue({\n issue,\n applyFix,\n}: {\n issue: CartIssue;\n applyFix: (issue: CartIssue, fix: CartFix) => void;\n}) {\n const editor = useOverlay(\"cart_edit\", issue.lineId ?? \"\");\n const address = useOverlay(\"cart_sheet\", \"address\");\n const schedule = useOverlay(\"cart_sheet\", \"schedule\");\n const [error, setError] = useState<string | null>(null);\n const fix = (value: CartFix) => {\n setError(null);\n try {\n if (\n value.action === \"choose_option\" ||\n value.action === \"choose_other_option\"\n ) {\n editor.open();\n } else if (value.action === \"change_address\") {\n address.open();\n } else if (value.action === \"schedule\") {\n schedule.open();\n } else {\n applyFix(issue, value);\n }\n } catch (error) {\n setError(\n error instanceof Error ? error.message : \"Unable to apply this change\",\n );\n }\n };\n return (\n <li>\n <p>{issue.message}</p>\n {issue.fixes\n .filter((value) => labels[value.action])\n .map((value, index) => (\n <button\n key={index}\n type=\"button\"\n className=\"z-base-button-secondary\"\n onClick={() => fix(value)}\n >\n {value.action === \"set_quantity\"\n ? `Set quantity to ${value.quantity}`\n : labels[value.action]}\n </button>\n ))}\n {error && <p role=\"alert\">{error}</p>}\n </li>\n );\n}\nexport function CartIssues() {\n return (\n <Cart.Issues>\n {({ issues, applyFix }) =>\n issues.length > 0 && (\n <section className=\"z-base-issues\" aria-label=\"Cart issues\">\n <h2>Review your cart</h2>\n <ul>\n {issues.map((issue, index) => (\n <Issue\n key={`${issue.lineId}:${issue.code}:${index}`}\n issue={issue}\n applyFix={applyFix}\n />\n ))}\n </ul>\n </section>\n )\n }\n </Cart.Issues>\n );\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,MAAM,kBAAkB;AAEjC,SAAS,gBAAgB;AA4CrB,SACE,KADF;AA3CJ,IAAM,SAAqD;AAAA,EACzD,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA,EACd,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,UAAU;AACZ;AACA,SAAS,MAAM;AAAA,EACb;AAAA,EACA;AACF,GAGG;AACD,QAAM,SAAS,WAAW,aAAa,MAAM,UAAU,EAAE;AACzD,QAAM,UAAU,WAAW,cAAc,SAAS;AAClD,QAAM,WAAW,WAAW,cAAc,UAAU;AACpD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,MAAM,CAAC,UAAmB;AAC9B,aAAS,IAAI;AACb,QAAI;AACF,UACE,MAAM,WAAW,mBACjB,MAAM,WAAW,uBACjB;AACA,eAAO,KAAK;AAAA,MACd,WAAW,MAAM,WAAW,kBAAkB;AAC5C,gBAAQ,KAAK;AAAA,MACf,WAAW,MAAM,WAAW,YAAY;AACtC,iBAAS,KAAK;AAAA,MAChB,OAAO;AACL,iBAAS,OAAO,KAAK;AAAA,MACvB;AAAA,IACF,SAASA,QAAO;AACd;AAAA,QACEA,kBAAiB,QAAQA,OAAM,UAAU;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACA,SACE,qBAAC,QACC;AAAA,wBAAC,OAAG,gBAAM,SAAQ;AAAA,IACjB,MAAM,MACJ,OAAO,CAAC,UAAU,OAAO,MAAM,MAAM,CAAC,EACtC,IAAI,CAAC,OAAO,UACX;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,IAAI,KAAK;AAAA,QAEvB,gBAAM,WAAW,iBACd,mBAAmB,MAAM,QAAQ,KACjC,OAAO,MAAM,MAAM;AAAA;AAAA,MAPlB;AAAA,IAQP,CACD;AAAA,IACF,SAAS,oBAAC,OAAE,MAAK,SAAS,iBAAM;AAAA,KACnC;AAEJ;AACO,SAAS,aAAa;AAC3B,SACE,oBAAC,KAAK,QAAL,EACE,WAAC,EAAE,QAAQ,SAAS,MACnB,OAAO,SAAS,KACd,qBAAC,aAAQ,WAAU,iBAAgB,cAAW,eAC5C;AAAA,wBAAC,QAAG,8BAAgB;AAAA,IACpB,oBAAC,QACE,iBAAO,IAAI,CAAC,OAAO,UAClB;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA;AAAA;AAAA,MAFK,GAAG,MAAM,MAAM,IAAI,MAAM,IAAI,IAAI,KAAK;AAAA,IAG7C,CACD,GACH;AAAA,KACF,GAGN;AAEJ;",
|
|
6
|
+
"names": ["error"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/cart/cart-line-groups.ts
|
|
2
|
+
function groupCartLinesByMenu(lines, catalogue) {
|
|
3
|
+
const names = new Map(
|
|
4
|
+
(catalogue?.menus ?? []).map((menu) => [menu.id, menu.name])
|
|
5
|
+
);
|
|
6
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const line of lines) {
|
|
8
|
+
const menuId = line.menuId ?? "unknown";
|
|
9
|
+
const group = groups.get(menuId);
|
|
10
|
+
if (group) {
|
|
11
|
+
group.lines.push(line);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const menuName = names.get(menuId);
|
|
15
|
+
groups.set(menuId, {
|
|
16
|
+
menuId,
|
|
17
|
+
...menuName !== void 0 ? { menuName } : {},
|
|
18
|
+
lines: [line]
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const ordered = [];
|
|
22
|
+
for (const menu of catalogue?.menus ?? []) {
|
|
23
|
+
const group = groups.get(menu.id);
|
|
24
|
+
if (group) {
|
|
25
|
+
ordered.push(group);
|
|
26
|
+
groups.delete(menu.id);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return [...ordered, ...groups.values()];
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
groupCartLinesByMenu
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=cart-line-groups.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/cart/cart-line-groups.ts"],
|
|
4
|
+
"sourcesContent": ["import type { CartLine, Menu } from \"@zappie/sdk\";\n\nexport type CartLineGroup = {\n menuId: string;\n menuName?: string;\n lines: CartLine[];\n};\n\nexport function groupCartLinesByMenu(\n lines: readonly CartLine[],\n catalogue?: Menu,\n): CartLineGroup[] {\n const names = new Map(\n (catalogue?.menus ?? []).map((menu) => [menu.id, menu.name]),\n );\n const groups = new Map<string, CartLineGroup>();\n for (const line of lines) {\n const menuId = line.menuId ?? \"unknown\";\n const group = groups.get(menuId);\n if (group) {\n group.lines.push(line);\n continue;\n }\n const menuName = names.get(menuId);\n groups.set(menuId, {\n menuId,\n ...(menuName !== undefined ? { menuName } : {}),\n lines: [line],\n });\n }\n const ordered: CartLineGroup[] = [];\n for (const menu of catalogue?.menus ?? []) {\n const group = groups.get(menu.id);\n if (group) {\n ordered.push(group);\n groups.delete(menu.id);\n }\n }\n return [...ordered, ...groups.values()];\n}\n"],
|
|
5
|
+
"mappings": ";AAQO,SAAS,qBACd,OACA,WACiB;AACjB,QAAM,QAAQ,IAAI;AAAA,KACf,WAAW,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC;AAAA,EAC7D;AACA,QAAM,SAAS,oBAAI,IAA2B;AAC9C,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,QAAQ,OAAO,IAAI,MAAM;AAC/B,QAAI,OAAO;AACT,YAAM,MAAM,KAAK,IAAI;AACrB;AAAA,IACF;AACA,UAAM,WAAW,MAAM,IAAI,MAAM;AACjC,WAAO,IAAI,QAAQ;AAAA,MACjB;AAAA,MACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C,OAAO,CAAC,IAAI;AAAA,IACd,CAAC;AAAA,EACH;AACA,QAAM,UAA2B,CAAC;AAClC,aAAW,QAAQ,WAAW,SAAS,CAAC,GAAG;AACzC,UAAM,QAAQ,OAAO,IAAI,KAAK,EAAE;AAChC,QAAI,OAAO;AACT,cAAQ,KAAK,KAAK;AAClB,aAAO,OAAO,KAAK,EAAE;AAAA,IACvB;AAAA,EACF;AACA,SAAO,CAAC,GAAG,SAAS,GAAG,OAAO,OAAO,CAAC;AACxC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,69 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
function ClearCart() {
|
|
8
|
-
const rootClass = useThemeClass("z-base-cart z-base-confirm");
|
|
9
|
-
const cart = useCart();
|
|
10
|
-
const confirm = useOverlay("cart_clear", "confirm");
|
|
11
|
-
return /* @__PURE__ */ jsxs(Overlay.Root, { param: "cart_clear", id: "confirm", presentation: "dialog", children: [
|
|
12
|
-
/* @__PURE__ */ jsx(Overlay.Trigger, { className: "z-base-button-secondary", children: "Clear cart" }),
|
|
13
|
-
/* @__PURE__ */ jsxs(
|
|
14
|
-
Overlay.Content,
|
|
15
|
-
{
|
|
16
|
-
"data-zappie-theme": "base",
|
|
17
|
-
role: "alertdialog",
|
|
18
|
-
className: rootClass,
|
|
19
|
-
children: [
|
|
20
|
-
/* @__PURE__ */ jsx(Overlay.Title, { children: "Clear your cart?" }),
|
|
21
|
-
/* @__PURE__ */ jsx("p", { children: "This removes every item in your cart." }),
|
|
22
|
-
/* @__PURE__ */ jsxs("div", { className: "z-base-confirm-actions", children: [
|
|
23
|
-
/* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Keep items" }),
|
|
24
|
-
/* @__PURE__ */ jsx(
|
|
25
|
-
"button",
|
|
26
|
-
{
|
|
27
|
-
type: "button",
|
|
28
|
-
className: "z-base-button",
|
|
29
|
-
onClick: () => {
|
|
30
|
-
cart.actions.clear();
|
|
31
|
-
confirm.close();
|
|
32
|
-
},
|
|
33
|
-
children: "Clear cart"
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
] })
|
|
37
|
-
]
|
|
38
|
-
}
|
|
39
|
-
)
|
|
40
|
-
] });
|
|
41
|
-
}
|
|
42
|
-
function LineEditor({ line, item }) {
|
|
43
|
-
const rootClass = useThemeClass("z-base-cart z-base-editor");
|
|
44
|
-
const overlay = useOverlay("cart_edit", line.id);
|
|
45
|
-
const client = useZappie();
|
|
46
|
-
return /* @__PURE__ */ jsxs(Overlay.Content, { "data-zappie-theme": "base", className: rootClass, children: [
|
|
47
|
-
/* @__PURE__ */ jsxs("header", { className: "z-base-cart-header", children: [
|
|
48
|
-
/* @__PURE__ */ jsxs(Overlay.Title, { children: [
|
|
49
|
-
"Edit ",
|
|
50
|
-
line.name
|
|
51
|
-
] }),
|
|
52
|
-
/* @__PURE__ */ jsx(Overlay.Close, { className: "z-base-button-secondary", children: "Cancel" })
|
|
53
|
-
] }),
|
|
54
|
-
overlay.isOpen && /* @__PURE__ */ jsx("div", { className: "z-base-cart-body", children: /* @__PURE__ */ jsx(
|
|
55
|
-
ItemConfigurator,
|
|
56
|
-
{
|
|
57
|
-
item,
|
|
58
|
-
...line.menuId !== void 0 ? { menuId: line.menuId } : {},
|
|
59
|
-
line,
|
|
60
|
-
scope: `${client.config.store}:${client.cart.branchId}:${client.cart.fulfilment?.type}`,
|
|
61
|
-
onComplete: overlay.close
|
|
62
|
-
},
|
|
63
|
-
line.id
|
|
64
|
-
) })
|
|
65
|
-
] });
|
|
66
|
-
}
|
|
1
|
+
// src/cart/cart-line.tsx
|
|
2
|
+
import { Cart, Money, Overlay, Quantity } from "@zappie/foundations";
|
|
3
|
+
import { useCart } from "@zappie/sdk/react";
|
|
4
|
+
import { LineEditor } from "./line-editor.js";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
67
6
|
function CartLine({ line }) {
|
|
68
7
|
const cart = useCart();
|
|
69
8
|
const invalid = cart.issues.some(
|
|
@@ -140,7 +79,7 @@ function CartLine({ line }) {
|
|
|
140
79
|
] })
|
|
141
80
|
] }) });
|
|
142
81
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
//# sourceMappingURL=
|
|
82
|
+
export {
|
|
83
|
+
CartLine
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=cart-line.js.map
|