@cartbase/storefront 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +258 -258
- package/src/cart-drawer/context.tsx +111 -25
- package/src/cart-drawer/index.ts +2 -0
- package/src/checkout/use-checkout-orchestration.ts +12 -0
- package/src/lib/cookie-names.ts +14 -0
package/package.json
CHANGED
|
@@ -1,258 +1,258 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@cartbase/storefront",
|
|
3
|
-
"version": "0.18.
|
|
4
|
-
"description": "Storefront SDK + UI component library for Cartbase stores: typed API client, checkout orchestration, cart drawer, product/catalog components, tracking. Source-shipped TypeScript — add it to transpilePackages.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/Cartbase/cartbase.git",
|
|
9
|
-
"directory": "packages/storefront"
|
|
10
|
-
},
|
|
11
|
-
"type": "module",
|
|
12
|
-
"sideEffects": false,
|
|
13
|
-
"files": [
|
|
14
|
-
"src",
|
|
15
|
-
"theme",
|
|
16
|
-
"README.md"
|
|
17
|
-
],
|
|
18
|
-
"exports": {
|
|
19
|
-
".": "./src/index.ts",
|
|
20
|
-
"./api": "./src/api/index.ts",
|
|
21
|
-
"./api/http": "./src/api/http.ts",
|
|
22
|
-
"./api/types": "./src/api/types.ts",
|
|
23
|
-
"./api/products": "./src/api/products.ts",
|
|
24
|
-
"./api/collections": "./src/api/collections.ts",
|
|
25
|
-
"./api/categories": "./src/api/categories.ts",
|
|
26
|
-
"./api/regions": "./src/api/regions.ts",
|
|
27
|
-
"./api/store": "./src/api/store.ts",
|
|
28
|
-
"./api/carts": "./src/api/carts.ts",
|
|
29
|
-
"./api/gift-cards": "./src/api/gift-cards.ts",
|
|
30
|
-
"./api/checkout": "./src/api/checkout.ts",
|
|
31
|
-
"./api/orders": "./src/api/orders.ts",
|
|
32
|
-
"./api/customers": "./src/api/customers.ts",
|
|
33
|
-
"./api/auth": "./src/api/auth.ts",
|
|
34
|
-
"./api/content": "./src/api/content.ts",
|
|
35
|
-
"./api/menus": "./src/api/menus.ts",
|
|
36
|
-
"./api/metaobjects": "./src/api/metaobjects.ts",
|
|
37
|
-
"./api/reviews": "./src/api/reviews.ts",
|
|
38
|
-
"./api/search": "./src/api/search.ts",
|
|
39
|
-
"./api/integrations": "./src/api/integrations.ts",
|
|
40
|
-
"./api/consent": "./src/api/consent.ts",
|
|
41
|
-
"./api/redirects": "./src/api/redirects.ts",
|
|
42
|
-
"./theme": "./theme/index.css",
|
|
43
|
-
"./theme/tokens.css": "./theme/tokens.css",
|
|
44
|
-
"./theme/theme.css": "./theme/theme.css",
|
|
45
|
-
"./lib/utils": "./src/lib/utils.ts",
|
|
46
|
-
"./lib/money": "./src/lib/money.ts",
|
|
47
|
-
"./lib/cart-helpers": "./src/lib/cart-helpers.ts",
|
|
48
|
-
"./lib/get-product-price": "./src/lib/get-product-price.ts",
|
|
49
|
-
"./lib/get-percentage-diff": "./src/lib/get-percentage-diff.ts",
|
|
50
|
-
"./lib/product": "./src/lib/product.ts",
|
|
51
|
-
"./lib/sort-products": "./src/lib/sort-products.ts",
|
|
52
|
-
"./lib/price": "./src/lib/price.tsx",
|
|
53
|
-
"./lib/payment-constants": "./src/lib/payment-constants.ts",
|
|
54
|
-
"./lib/country-name": "./src/lib/country-name.ts",
|
|
55
|
-
"./lib/store-api-error": "./src/lib/store-api-error.ts",
|
|
56
|
-
"./lib/hooks/use-intersection": "./src/lib/hooks/use-intersection.ts",
|
|
57
|
-
"./lib/hooks/use-toggle-state": "./src/lib/hooks/use-toggle-state.ts",
|
|
58
|
-
"./lib/cookie-names": "./src/lib/cookie-names.ts",
|
|
59
|
-
"./lib/media-image": "./src/lib/media-image.tsx",
|
|
60
|
-
"./lib/platform": "./src/lib/platform.ts",
|
|
61
|
-
"./lib/visitor": "./src/lib/visitor.ts",
|
|
62
|
-
"./platform": "./src/platform/index.ts",
|
|
63
|
-
"./platform/identity": "./src/platform/identity.ts",
|
|
64
|
-
"./platform/metadata": "./src/platform/metadata.ts",
|
|
65
|
-
"./platform/platform-init": "./src/platform/platform-init.tsx",
|
|
66
|
-
"./primitives/field": "./src/primitives/field.tsx",
|
|
67
|
-
"./primitives/select-field": "./src/primitives/select-field.tsx",
|
|
68
|
-
"./primitives/ui/accordion": "./src/primitives/ui/accordion.tsx",
|
|
69
|
-
"./primitives/ui/button": "./src/primitives/ui/button.tsx",
|
|
70
|
-
"./primitives/ui/collapsible": "./src/primitives/ui/collapsible.tsx",
|
|
71
|
-
"./primitives/ui/dialog": "./src/primitives/ui/dialog.tsx",
|
|
72
|
-
"./primitives/ui/input": "./src/primitives/ui/input.tsx",
|
|
73
|
-
"./primitives/ui/label": "./src/primitives/ui/label.tsx",
|
|
74
|
-
"./primitives/ui/popover": "./src/primitives/ui/popover.tsx",
|
|
75
|
-
"./primitives/ui/select": "./src/primitives/ui/select.tsx",
|
|
76
|
-
"./primitives/ui/sheet": "./src/primitives/ui/sheet.tsx",
|
|
77
|
-
"./primitives/ui/tabs": "./src/primitives/ui/tabs.tsx",
|
|
78
|
-
"./tracking": "./src/tracking/index.ts",
|
|
79
|
-
"./tracking/types": "./src/tracking/types.ts",
|
|
80
|
-
"./tracking/consent": "./src/tracking/consent.ts",
|
|
81
|
-
"./tracking/consent-init": "./src/tracking/consent-init.tsx",
|
|
82
|
-
"./tracking/consent-banner": "./src/tracking/consent-banner.tsx",
|
|
83
|
-
"./tracking/meta-pixel": "./src/tracking/meta-pixel.tsx",
|
|
84
|
-
"./tracking/ga4": "./src/tracking/ga4.tsx",
|
|
85
|
-
"./tracking/tiktok-pixel": "./src/tracking/tiktok-pixel.tsx",
|
|
86
|
-
"./tracking/ttq": "./src/tracking/ttq.ts",
|
|
87
|
-
"./tracking/events": "./src/tracking/events.ts",
|
|
88
|
-
"./tracking/storefront-tags": "./src/tracking/storefront-tags.tsx",
|
|
89
|
-
"./tracking/track-init": "./src/tracking/track-init.tsx",
|
|
90
|
-
"./tracking/track-order-purchase": "./src/tracking/track-order-purchase.tsx",
|
|
91
|
-
"./tracking/gtm": "./src/tracking/gtm.tsx",
|
|
92
|
-
"./tracking/inline-script": "./src/tracking/inline-script.ts",
|
|
93
|
-
"./tracking/google-ads": "./src/tracking/google-ads.ts",
|
|
94
|
-
"./tracking/rybbit": "./src/tracking/rybbit.tsx",
|
|
95
|
-
"./tracking/rybbit-events": "./src/tracking/rybbit-events.ts",
|
|
96
|
-
"./tracking/fbq": "./src/tracking/fbq.ts",
|
|
97
|
-
"./tracking/gtag": "./src/tracking/gtag.ts",
|
|
98
|
-
"./tracking/attribution": "./src/tracking/attribution.ts",
|
|
99
|
-
"./tracking/get-tracking-config": "./src/tracking/get-tracking-config.ts",
|
|
100
|
-
"./tracking/use-tracking-config": "./src/tracking/use-tracking-config.ts",
|
|
101
|
-
"./tracking/get-tracking-attribution": "./src/tracking/get-tracking-attribution.ts",
|
|
102
|
-
"./tracking/use-engagement-time": "./src/tracking/use-engagement-time.ts",
|
|
103
|
-
"./tracking/page-views": "./src/tracking/page-views.tsx",
|
|
104
|
-
"./tracking/live-heartbeat": "./src/tracking/live-heartbeat.tsx",
|
|
105
|
-
"./checkout": "./src/checkout/index.ts",
|
|
106
|
-
"./checkout/context": "./src/checkout/context.tsx",
|
|
107
|
-
"./checkout/labels": "./src/checkout/labels.ts",
|
|
108
|
-
"./checkout/error-message": "./src/checkout/error-message.tsx",
|
|
109
|
-
"./checkout/stripe-wrapper": "./src/checkout/stripe-wrapper.tsx",
|
|
110
|
-
"./checkout/payment-wrapper": "./src/checkout/payment-wrapper.tsx",
|
|
111
|
-
"./checkout/payment-button": "./src/checkout/payment-button.tsx",
|
|
112
|
-
"./checkout/econt-office-selector": "./src/checkout/econt-office-selector.tsx",
|
|
113
|
-
"./checkout/boxnow-locker-selector": "./src/checkout/boxnow-locker-selector.tsx",
|
|
114
|
-
"./checkout/address-select": "./src/checkout/address-select.tsx",
|
|
115
|
-
"./checkout/company-details": "./src/checkout/company-details.tsx",
|
|
116
|
-
"./checkout/discount-section": "./src/checkout/discount-section.tsx",
|
|
117
|
-
"./checkout/gift-card-section": "./src/checkout/gift-card-section.tsx",
|
|
118
|
-
"./checkout/line-item-card": "./src/checkout/line-item-card.tsx",
|
|
119
|
-
"./checkout/order-summary": "./src/checkout/order-summary.tsx",
|
|
120
|
-
"./checkout/address-form": "./src/checkout/address-form.tsx",
|
|
121
|
-
"./checkout/shipping-method-list": "./src/checkout/shipping-method-list.tsx",
|
|
122
|
-
"./checkout/payment-method-list": "./src/checkout/payment-method-list.tsx",
|
|
123
|
-
"./checkout/checkout-client": "./src/checkout/checkout-client.tsx",
|
|
124
|
-
"./checkout/use-checkout-orchestration": "./src/checkout/use-checkout-orchestration.ts",
|
|
125
|
-
"./checkout/payment-error-copy": "./src/checkout/payment-error-copy.ts",
|
|
126
|
-
"./checkout/address-error-copy": "./src/checkout/address-error-copy.ts",
|
|
127
|
-
"./checkout/promotion-error-copy": "./src/checkout/promotion-error-copy.ts",
|
|
128
|
-
"./cart-drawer": "./src/cart-drawer/index.ts",
|
|
129
|
-
"./cart-drawer/context": "./src/cart-drawer/context.tsx",
|
|
130
|
-
"./cart-drawer/mutation-queue": "./src/cart-drawer/mutation-queue.ts",
|
|
131
|
-
"./cart-drawer/labels": "./src/cart-drawer/labels.ts",
|
|
132
|
-
"./cart-drawer/cart-drawer": "./src/cart-drawer/cart-drawer.tsx",
|
|
133
|
-
"./cart-drawer/header": "./src/cart-drawer/header.tsx",
|
|
134
|
-
"./cart-drawer/promo-banner": "./src/cart-drawer/promo-banner.tsx",
|
|
135
|
-
"./cart-drawer/tiered-progress": "./src/cart-drawer/tiered-progress.tsx",
|
|
136
|
-
"./cart-drawer/item": "./src/cart-drawer/item/index.tsx",
|
|
137
|
-
"./cart-drawer/item/quantity": "./src/cart-drawer/item/quantity.tsx",
|
|
138
|
-
"./cart-drawer/item/variant": "./src/cart-drawer/item/variant.tsx",
|
|
139
|
-
"./cart-drawer/item/upsell": "./src/cart-drawer/item/upsell.tsx",
|
|
140
|
-
"./cart-drawer/free-gift": "./src/cart-drawer/free-gift.tsx",
|
|
141
|
-
"./cart-drawer/gift-wrap": "./src/cart-drawer/gift-wrap.tsx",
|
|
142
|
-
"./cart-drawer/notes": "./src/cart-drawer/notes.tsx",
|
|
143
|
-
"./cart-drawer/rewards-points": "./src/cart-drawer/rewards-points.tsx",
|
|
144
|
-
"./cart-drawer/cross-sell-sidebar": "./src/cart-drawer/cross-sell-sidebar.tsx",
|
|
145
|
-
"./cart-drawer/cross-sell-carousel": "./src/cart-drawer/cross-sell-carousel.tsx",
|
|
146
|
-
"./cart-drawer/summary-breakdown": "./src/cart-drawer/summary-breakdown.tsx",
|
|
147
|
-
"./cart-drawer/sticky-footer": "./src/cart-drawer/sticky-footer.tsx",
|
|
148
|
-
"./cart-drawer/payment-badges": "./src/cart-drawer/payment-badges.tsx",
|
|
149
|
-
"./cart-drawer/continue-shopping": "./src/cart-drawer/continue-shopping.tsx",
|
|
150
|
-
"./cart-drawer/empty": "./src/cart-drawer/empty.tsx",
|
|
151
|
-
"./cart-drawer/template": "./src/cart-drawer/template.tsx",
|
|
152
|
-
"./products": "./src/products/index.ts",
|
|
153
|
-
"./products/context": "./src/products/context.tsx",
|
|
154
|
-
"./products/labels": "./src/products/labels.ts",
|
|
155
|
-
"./products/thumbnail": "./src/products/thumbnail.tsx",
|
|
156
|
-
"./products/preview-price": "./src/products/preview-price.tsx",
|
|
157
|
-
"./products/product-price": "./src/products/product-price.tsx",
|
|
158
|
-
"./products/option-select": "./src/products/option-select.tsx",
|
|
159
|
-
"./products/image-gallery": "./src/products/image-gallery.tsx",
|
|
160
|
-
"./products/variant-url": "./src/products/variant-url.ts",
|
|
161
|
-
"./products/sets": "./src/products/sets.ts",
|
|
162
|
-
"./products/use-product-actions": "./src/products/use-product-actions.ts",
|
|
163
|
-
"./products/product-actions": "./src/products/product-actions.tsx",
|
|
164
|
-
"./products/mobile-actions": "./src/products/mobile-actions.tsx",
|
|
165
|
-
"./products/product-tabs": "./src/products/product-tabs.tsx",
|
|
166
|
-
"./products/product-specs": "./src/products/product-specs.tsx",
|
|
167
|
-
"./products/product-promises": "./src/products/product-promises.tsx",
|
|
168
|
-
"./products/product-info": "./src/products/product-info.tsx",
|
|
169
|
-
"./products/product-preview": "./src/products/product-preview.tsx",
|
|
170
|
-
"./products/related-products": "./src/products/related-products.tsx",
|
|
171
|
-
"./products/product-actions-wrapper": "./src/products/product-actions-wrapper.tsx",
|
|
172
|
-
"./products/product-template": "./src/products/product-template.tsx",
|
|
173
|
-
"./store": "./src/store/index.ts",
|
|
174
|
-
"./store/labels": "./src/store/labels.ts",
|
|
175
|
-
"./store/pagination": "./src/store/pagination.tsx",
|
|
176
|
-
"./store/sort-select": "./src/store/sort-select.tsx",
|
|
177
|
-
"./store/paginated-products": "./src/store/paginated-products.tsx",
|
|
178
|
-
"./store/skeleton-product-grid": "./src/store/skeleton-product-grid.tsx",
|
|
179
|
-
"./store/store-template": "./src/store/store-template.tsx",
|
|
180
|
-
"./store/collection-template": "./src/store/collection-template.tsx",
|
|
181
|
-
"./store/category-template": "./src/store/category-template.tsx",
|
|
182
|
-
"./store/search-template": "./src/store/search-template.tsx",
|
|
183
|
-
"./order": "./src/order/index.ts",
|
|
184
|
-
"./order/context": "./src/order/context.tsx",
|
|
185
|
-
"./order/labels": "./src/order/labels.ts",
|
|
186
|
-
"./order/order-confirmation-header": "./src/order/order-confirmation-header.tsx",
|
|
187
|
-
"./order/order-item": "./src/order/order-item.tsx",
|
|
188
|
-
"./order/order-items-list": "./src/order/order-items-list.tsx",
|
|
189
|
-
"./order/order-totals": "./src/order/order-totals.tsx",
|
|
190
|
-
"./order/order-address-card": "./src/order/order-address-card.tsx",
|
|
191
|
-
"./order/order-delivery-card": "./src/order/order-delivery-card.tsx",
|
|
192
|
-
"./order/order-payment-card": "./src/order/order-payment-card.tsx",
|
|
193
|
-
"./order/order-timeline": "./src/order/order-timeline.tsx",
|
|
194
|
-
"./order/order-help-section": "./src/order/order-help-section.tsx",
|
|
195
|
-
"./order/order-completed-template": "./src/order/order-completed-template.tsx",
|
|
196
|
-
"./common": "./src/common/index.ts",
|
|
197
|
-
"./common/localized-link": "./src/common/localized-link.tsx",
|
|
198
|
-
"./common/cart-button": "./src/common/cart-button.tsx",
|
|
199
|
-
"./common/cart-button-client": "./src/common/cart-button-client.tsx",
|
|
200
|
-
"./common/delete-button": "./src/common/delete-button.tsx",
|
|
201
|
-
"./common/country-flag": "./src/common/country-flag.tsx",
|
|
202
|
-
"./common/market-select": "./src/common/market-select.tsx",
|
|
203
|
-
"./common/country-select": "./src/common/country-select.tsx",
|
|
204
|
-
"./common/language-select": "./src/common/language-select.tsx",
|
|
205
|
-
"./common/skeleton": "./src/common/skeleton.tsx",
|
|
206
|
-
"./reviews-ui": "./src/reviews-ui/index.ts",
|
|
207
|
-
"./locales": "./src/locales/index.ts",
|
|
208
|
-
"./locales/en": "./src/locales/en.ts",
|
|
209
|
-
"./locales/es": "./src/locales/es.ts",
|
|
210
|
-
"./locales/bg": "./src/locales/bg.ts"
|
|
211
|
-
},
|
|
212
|
-
"dependencies": {
|
|
213
|
-
"@radix-ui/react-accordion": "^1.2.12",
|
|
214
|
-
"@radix-ui/react-collapsible": "^1.1.12",
|
|
215
|
-
"@radix-ui/react-dialog": "^1.1.15",
|
|
216
|
-
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
217
|
-
"@radix-ui/react-label": "^2.1.8",
|
|
218
|
-
"@radix-ui/react-popover": "^1.1.15",
|
|
219
|
-
"@radix-ui/react-select": "^2.2.6",
|
|
220
|
-
"@radix-ui/react-slot": "^1.2.4",
|
|
221
|
-
"@radix-ui/react-tabs": "^1.1.13",
|
|
222
|
-
"@stripe/react-stripe-js": "^6.1.0",
|
|
223
|
-
"@stripe/stripe-js": "^9.1.0",
|
|
224
|
-
"class-variance-authority": "^0.7.1",
|
|
225
|
-
"clsx": "^2.1.1",
|
|
226
|
-
"flag-icons": "^7.5.0",
|
|
227
|
-
"lucide-react": "^1.8.0",
|
|
228
|
-
"tailwind-merge": "^3.5.0"
|
|
229
|
-
},
|
|
230
|
-
"scripts": {
|
|
231
|
-
"typecheck": "tsc --noEmit"
|
|
232
|
-
},
|
|
233
|
-
"peerDependencies": {
|
|
234
|
-
"next": "^16.0.0",
|
|
235
|
-
"react": "^19.0.0",
|
|
236
|
-
"react-dom": "^19.0.0"
|
|
237
|
-
},
|
|
238
|
-
"peerDependenciesMeta": {
|
|
239
|
-
"next": {
|
|
240
|
-
"optional": true
|
|
241
|
-
},
|
|
242
|
-
"react": {
|
|
243
|
-
"optional": true
|
|
244
|
-
},
|
|
245
|
-
"react-dom": {
|
|
246
|
-
"optional": true
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
"devDependencies": {
|
|
250
|
-
"@types/node": "^20",
|
|
251
|
-
"@types/react": "^19",
|
|
252
|
-
"@types/react-dom": "^19",
|
|
253
|
-
"typescript": "^5"
|
|
254
|
-
},
|
|
255
|
-
"engines": {
|
|
256
|
-
"node": ">=20"
|
|
257
|
-
}
|
|
258
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@cartbase/storefront",
|
|
3
|
+
"version": "0.18.1",
|
|
4
|
+
"description": "Storefront SDK + UI component library for Cartbase stores: typed API client, checkout orchestration, cart drawer, product/catalog components, tracking. Source-shipped TypeScript — add it to transpilePackages.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Cartbase/cartbase.git",
|
|
9
|
+
"directory": "packages/storefront"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"theme",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./src/index.ts",
|
|
20
|
+
"./api": "./src/api/index.ts",
|
|
21
|
+
"./api/http": "./src/api/http.ts",
|
|
22
|
+
"./api/types": "./src/api/types.ts",
|
|
23
|
+
"./api/products": "./src/api/products.ts",
|
|
24
|
+
"./api/collections": "./src/api/collections.ts",
|
|
25
|
+
"./api/categories": "./src/api/categories.ts",
|
|
26
|
+
"./api/regions": "./src/api/regions.ts",
|
|
27
|
+
"./api/store": "./src/api/store.ts",
|
|
28
|
+
"./api/carts": "./src/api/carts.ts",
|
|
29
|
+
"./api/gift-cards": "./src/api/gift-cards.ts",
|
|
30
|
+
"./api/checkout": "./src/api/checkout.ts",
|
|
31
|
+
"./api/orders": "./src/api/orders.ts",
|
|
32
|
+
"./api/customers": "./src/api/customers.ts",
|
|
33
|
+
"./api/auth": "./src/api/auth.ts",
|
|
34
|
+
"./api/content": "./src/api/content.ts",
|
|
35
|
+
"./api/menus": "./src/api/menus.ts",
|
|
36
|
+
"./api/metaobjects": "./src/api/metaobjects.ts",
|
|
37
|
+
"./api/reviews": "./src/api/reviews.ts",
|
|
38
|
+
"./api/search": "./src/api/search.ts",
|
|
39
|
+
"./api/integrations": "./src/api/integrations.ts",
|
|
40
|
+
"./api/consent": "./src/api/consent.ts",
|
|
41
|
+
"./api/redirects": "./src/api/redirects.ts",
|
|
42
|
+
"./theme": "./theme/index.css",
|
|
43
|
+
"./theme/tokens.css": "./theme/tokens.css",
|
|
44
|
+
"./theme/theme.css": "./theme/theme.css",
|
|
45
|
+
"./lib/utils": "./src/lib/utils.ts",
|
|
46
|
+
"./lib/money": "./src/lib/money.ts",
|
|
47
|
+
"./lib/cart-helpers": "./src/lib/cart-helpers.ts",
|
|
48
|
+
"./lib/get-product-price": "./src/lib/get-product-price.ts",
|
|
49
|
+
"./lib/get-percentage-diff": "./src/lib/get-percentage-diff.ts",
|
|
50
|
+
"./lib/product": "./src/lib/product.ts",
|
|
51
|
+
"./lib/sort-products": "./src/lib/sort-products.ts",
|
|
52
|
+
"./lib/price": "./src/lib/price.tsx",
|
|
53
|
+
"./lib/payment-constants": "./src/lib/payment-constants.ts",
|
|
54
|
+
"./lib/country-name": "./src/lib/country-name.ts",
|
|
55
|
+
"./lib/store-api-error": "./src/lib/store-api-error.ts",
|
|
56
|
+
"./lib/hooks/use-intersection": "./src/lib/hooks/use-intersection.ts",
|
|
57
|
+
"./lib/hooks/use-toggle-state": "./src/lib/hooks/use-toggle-state.ts",
|
|
58
|
+
"./lib/cookie-names": "./src/lib/cookie-names.ts",
|
|
59
|
+
"./lib/media-image": "./src/lib/media-image.tsx",
|
|
60
|
+
"./lib/platform": "./src/lib/platform.ts",
|
|
61
|
+
"./lib/visitor": "./src/lib/visitor.ts",
|
|
62
|
+
"./platform": "./src/platform/index.ts",
|
|
63
|
+
"./platform/identity": "./src/platform/identity.ts",
|
|
64
|
+
"./platform/metadata": "./src/platform/metadata.ts",
|
|
65
|
+
"./platform/platform-init": "./src/platform/platform-init.tsx",
|
|
66
|
+
"./primitives/field": "./src/primitives/field.tsx",
|
|
67
|
+
"./primitives/select-field": "./src/primitives/select-field.tsx",
|
|
68
|
+
"./primitives/ui/accordion": "./src/primitives/ui/accordion.tsx",
|
|
69
|
+
"./primitives/ui/button": "./src/primitives/ui/button.tsx",
|
|
70
|
+
"./primitives/ui/collapsible": "./src/primitives/ui/collapsible.tsx",
|
|
71
|
+
"./primitives/ui/dialog": "./src/primitives/ui/dialog.tsx",
|
|
72
|
+
"./primitives/ui/input": "./src/primitives/ui/input.tsx",
|
|
73
|
+
"./primitives/ui/label": "./src/primitives/ui/label.tsx",
|
|
74
|
+
"./primitives/ui/popover": "./src/primitives/ui/popover.tsx",
|
|
75
|
+
"./primitives/ui/select": "./src/primitives/ui/select.tsx",
|
|
76
|
+
"./primitives/ui/sheet": "./src/primitives/ui/sheet.tsx",
|
|
77
|
+
"./primitives/ui/tabs": "./src/primitives/ui/tabs.tsx",
|
|
78
|
+
"./tracking": "./src/tracking/index.ts",
|
|
79
|
+
"./tracking/types": "./src/tracking/types.ts",
|
|
80
|
+
"./tracking/consent": "./src/tracking/consent.ts",
|
|
81
|
+
"./tracking/consent-init": "./src/tracking/consent-init.tsx",
|
|
82
|
+
"./tracking/consent-banner": "./src/tracking/consent-banner.tsx",
|
|
83
|
+
"./tracking/meta-pixel": "./src/tracking/meta-pixel.tsx",
|
|
84
|
+
"./tracking/ga4": "./src/tracking/ga4.tsx",
|
|
85
|
+
"./tracking/tiktok-pixel": "./src/tracking/tiktok-pixel.tsx",
|
|
86
|
+
"./tracking/ttq": "./src/tracking/ttq.ts",
|
|
87
|
+
"./tracking/events": "./src/tracking/events.ts",
|
|
88
|
+
"./tracking/storefront-tags": "./src/tracking/storefront-tags.tsx",
|
|
89
|
+
"./tracking/track-init": "./src/tracking/track-init.tsx",
|
|
90
|
+
"./tracking/track-order-purchase": "./src/tracking/track-order-purchase.tsx",
|
|
91
|
+
"./tracking/gtm": "./src/tracking/gtm.tsx",
|
|
92
|
+
"./tracking/inline-script": "./src/tracking/inline-script.ts",
|
|
93
|
+
"./tracking/google-ads": "./src/tracking/google-ads.ts",
|
|
94
|
+
"./tracking/rybbit": "./src/tracking/rybbit.tsx",
|
|
95
|
+
"./tracking/rybbit-events": "./src/tracking/rybbit-events.ts",
|
|
96
|
+
"./tracking/fbq": "./src/tracking/fbq.ts",
|
|
97
|
+
"./tracking/gtag": "./src/tracking/gtag.ts",
|
|
98
|
+
"./tracking/attribution": "./src/tracking/attribution.ts",
|
|
99
|
+
"./tracking/get-tracking-config": "./src/tracking/get-tracking-config.ts",
|
|
100
|
+
"./tracking/use-tracking-config": "./src/tracking/use-tracking-config.ts",
|
|
101
|
+
"./tracking/get-tracking-attribution": "./src/tracking/get-tracking-attribution.ts",
|
|
102
|
+
"./tracking/use-engagement-time": "./src/tracking/use-engagement-time.ts",
|
|
103
|
+
"./tracking/page-views": "./src/tracking/page-views.tsx",
|
|
104
|
+
"./tracking/live-heartbeat": "./src/tracking/live-heartbeat.tsx",
|
|
105
|
+
"./checkout": "./src/checkout/index.ts",
|
|
106
|
+
"./checkout/context": "./src/checkout/context.tsx",
|
|
107
|
+
"./checkout/labels": "./src/checkout/labels.ts",
|
|
108
|
+
"./checkout/error-message": "./src/checkout/error-message.tsx",
|
|
109
|
+
"./checkout/stripe-wrapper": "./src/checkout/stripe-wrapper.tsx",
|
|
110
|
+
"./checkout/payment-wrapper": "./src/checkout/payment-wrapper.tsx",
|
|
111
|
+
"./checkout/payment-button": "./src/checkout/payment-button.tsx",
|
|
112
|
+
"./checkout/econt-office-selector": "./src/checkout/econt-office-selector.tsx",
|
|
113
|
+
"./checkout/boxnow-locker-selector": "./src/checkout/boxnow-locker-selector.tsx",
|
|
114
|
+
"./checkout/address-select": "./src/checkout/address-select.tsx",
|
|
115
|
+
"./checkout/company-details": "./src/checkout/company-details.tsx",
|
|
116
|
+
"./checkout/discount-section": "./src/checkout/discount-section.tsx",
|
|
117
|
+
"./checkout/gift-card-section": "./src/checkout/gift-card-section.tsx",
|
|
118
|
+
"./checkout/line-item-card": "./src/checkout/line-item-card.tsx",
|
|
119
|
+
"./checkout/order-summary": "./src/checkout/order-summary.tsx",
|
|
120
|
+
"./checkout/address-form": "./src/checkout/address-form.tsx",
|
|
121
|
+
"./checkout/shipping-method-list": "./src/checkout/shipping-method-list.tsx",
|
|
122
|
+
"./checkout/payment-method-list": "./src/checkout/payment-method-list.tsx",
|
|
123
|
+
"./checkout/checkout-client": "./src/checkout/checkout-client.tsx",
|
|
124
|
+
"./checkout/use-checkout-orchestration": "./src/checkout/use-checkout-orchestration.ts",
|
|
125
|
+
"./checkout/payment-error-copy": "./src/checkout/payment-error-copy.ts",
|
|
126
|
+
"./checkout/address-error-copy": "./src/checkout/address-error-copy.ts",
|
|
127
|
+
"./checkout/promotion-error-copy": "./src/checkout/promotion-error-copy.ts",
|
|
128
|
+
"./cart-drawer": "./src/cart-drawer/index.ts",
|
|
129
|
+
"./cart-drawer/context": "./src/cart-drawer/context.tsx",
|
|
130
|
+
"./cart-drawer/mutation-queue": "./src/cart-drawer/mutation-queue.ts",
|
|
131
|
+
"./cart-drawer/labels": "./src/cart-drawer/labels.ts",
|
|
132
|
+
"./cart-drawer/cart-drawer": "./src/cart-drawer/cart-drawer.tsx",
|
|
133
|
+
"./cart-drawer/header": "./src/cart-drawer/header.tsx",
|
|
134
|
+
"./cart-drawer/promo-banner": "./src/cart-drawer/promo-banner.tsx",
|
|
135
|
+
"./cart-drawer/tiered-progress": "./src/cart-drawer/tiered-progress.tsx",
|
|
136
|
+
"./cart-drawer/item": "./src/cart-drawer/item/index.tsx",
|
|
137
|
+
"./cart-drawer/item/quantity": "./src/cart-drawer/item/quantity.tsx",
|
|
138
|
+
"./cart-drawer/item/variant": "./src/cart-drawer/item/variant.tsx",
|
|
139
|
+
"./cart-drawer/item/upsell": "./src/cart-drawer/item/upsell.tsx",
|
|
140
|
+
"./cart-drawer/free-gift": "./src/cart-drawer/free-gift.tsx",
|
|
141
|
+
"./cart-drawer/gift-wrap": "./src/cart-drawer/gift-wrap.tsx",
|
|
142
|
+
"./cart-drawer/notes": "./src/cart-drawer/notes.tsx",
|
|
143
|
+
"./cart-drawer/rewards-points": "./src/cart-drawer/rewards-points.tsx",
|
|
144
|
+
"./cart-drawer/cross-sell-sidebar": "./src/cart-drawer/cross-sell-sidebar.tsx",
|
|
145
|
+
"./cart-drawer/cross-sell-carousel": "./src/cart-drawer/cross-sell-carousel.tsx",
|
|
146
|
+
"./cart-drawer/summary-breakdown": "./src/cart-drawer/summary-breakdown.tsx",
|
|
147
|
+
"./cart-drawer/sticky-footer": "./src/cart-drawer/sticky-footer.tsx",
|
|
148
|
+
"./cart-drawer/payment-badges": "./src/cart-drawer/payment-badges.tsx",
|
|
149
|
+
"./cart-drawer/continue-shopping": "./src/cart-drawer/continue-shopping.tsx",
|
|
150
|
+
"./cart-drawer/empty": "./src/cart-drawer/empty.tsx",
|
|
151
|
+
"./cart-drawer/template": "./src/cart-drawer/template.tsx",
|
|
152
|
+
"./products": "./src/products/index.ts",
|
|
153
|
+
"./products/context": "./src/products/context.tsx",
|
|
154
|
+
"./products/labels": "./src/products/labels.ts",
|
|
155
|
+
"./products/thumbnail": "./src/products/thumbnail.tsx",
|
|
156
|
+
"./products/preview-price": "./src/products/preview-price.tsx",
|
|
157
|
+
"./products/product-price": "./src/products/product-price.tsx",
|
|
158
|
+
"./products/option-select": "./src/products/option-select.tsx",
|
|
159
|
+
"./products/image-gallery": "./src/products/image-gallery.tsx",
|
|
160
|
+
"./products/variant-url": "./src/products/variant-url.ts",
|
|
161
|
+
"./products/sets": "./src/products/sets.ts",
|
|
162
|
+
"./products/use-product-actions": "./src/products/use-product-actions.ts",
|
|
163
|
+
"./products/product-actions": "./src/products/product-actions.tsx",
|
|
164
|
+
"./products/mobile-actions": "./src/products/mobile-actions.tsx",
|
|
165
|
+
"./products/product-tabs": "./src/products/product-tabs.tsx",
|
|
166
|
+
"./products/product-specs": "./src/products/product-specs.tsx",
|
|
167
|
+
"./products/product-promises": "./src/products/product-promises.tsx",
|
|
168
|
+
"./products/product-info": "./src/products/product-info.tsx",
|
|
169
|
+
"./products/product-preview": "./src/products/product-preview.tsx",
|
|
170
|
+
"./products/related-products": "./src/products/related-products.tsx",
|
|
171
|
+
"./products/product-actions-wrapper": "./src/products/product-actions-wrapper.tsx",
|
|
172
|
+
"./products/product-template": "./src/products/product-template.tsx",
|
|
173
|
+
"./store": "./src/store/index.ts",
|
|
174
|
+
"./store/labels": "./src/store/labels.ts",
|
|
175
|
+
"./store/pagination": "./src/store/pagination.tsx",
|
|
176
|
+
"./store/sort-select": "./src/store/sort-select.tsx",
|
|
177
|
+
"./store/paginated-products": "./src/store/paginated-products.tsx",
|
|
178
|
+
"./store/skeleton-product-grid": "./src/store/skeleton-product-grid.tsx",
|
|
179
|
+
"./store/store-template": "./src/store/store-template.tsx",
|
|
180
|
+
"./store/collection-template": "./src/store/collection-template.tsx",
|
|
181
|
+
"./store/category-template": "./src/store/category-template.tsx",
|
|
182
|
+
"./store/search-template": "./src/store/search-template.tsx",
|
|
183
|
+
"./order": "./src/order/index.ts",
|
|
184
|
+
"./order/context": "./src/order/context.tsx",
|
|
185
|
+
"./order/labels": "./src/order/labels.ts",
|
|
186
|
+
"./order/order-confirmation-header": "./src/order/order-confirmation-header.tsx",
|
|
187
|
+
"./order/order-item": "./src/order/order-item.tsx",
|
|
188
|
+
"./order/order-items-list": "./src/order/order-items-list.tsx",
|
|
189
|
+
"./order/order-totals": "./src/order/order-totals.tsx",
|
|
190
|
+
"./order/order-address-card": "./src/order/order-address-card.tsx",
|
|
191
|
+
"./order/order-delivery-card": "./src/order/order-delivery-card.tsx",
|
|
192
|
+
"./order/order-payment-card": "./src/order/order-payment-card.tsx",
|
|
193
|
+
"./order/order-timeline": "./src/order/order-timeline.tsx",
|
|
194
|
+
"./order/order-help-section": "./src/order/order-help-section.tsx",
|
|
195
|
+
"./order/order-completed-template": "./src/order/order-completed-template.tsx",
|
|
196
|
+
"./common": "./src/common/index.ts",
|
|
197
|
+
"./common/localized-link": "./src/common/localized-link.tsx",
|
|
198
|
+
"./common/cart-button": "./src/common/cart-button.tsx",
|
|
199
|
+
"./common/cart-button-client": "./src/common/cart-button-client.tsx",
|
|
200
|
+
"./common/delete-button": "./src/common/delete-button.tsx",
|
|
201
|
+
"./common/country-flag": "./src/common/country-flag.tsx",
|
|
202
|
+
"./common/market-select": "./src/common/market-select.tsx",
|
|
203
|
+
"./common/country-select": "./src/common/country-select.tsx",
|
|
204
|
+
"./common/language-select": "./src/common/language-select.tsx",
|
|
205
|
+
"./common/skeleton": "./src/common/skeleton.tsx",
|
|
206
|
+
"./reviews-ui": "./src/reviews-ui/index.ts",
|
|
207
|
+
"./locales": "./src/locales/index.ts",
|
|
208
|
+
"./locales/en": "./src/locales/en.ts",
|
|
209
|
+
"./locales/es": "./src/locales/es.ts",
|
|
210
|
+
"./locales/bg": "./src/locales/bg.ts"
|
|
211
|
+
},
|
|
212
|
+
"dependencies": {
|
|
213
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
214
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
215
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
216
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
217
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
218
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
219
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
220
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
221
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
222
|
+
"@stripe/react-stripe-js": "^6.1.0",
|
|
223
|
+
"@stripe/stripe-js": "^9.1.0",
|
|
224
|
+
"class-variance-authority": "^0.7.1",
|
|
225
|
+
"clsx": "^2.1.1",
|
|
226
|
+
"flag-icons": "^7.5.0",
|
|
227
|
+
"lucide-react": "^1.8.0",
|
|
228
|
+
"tailwind-merge": "^3.5.0"
|
|
229
|
+
},
|
|
230
|
+
"scripts": {
|
|
231
|
+
"typecheck": "tsc --noEmit"
|
|
232
|
+
},
|
|
233
|
+
"peerDependencies": {
|
|
234
|
+
"next": "^16.0.0",
|
|
235
|
+
"react": "^19.0.0",
|
|
236
|
+
"react-dom": "^19.0.0"
|
|
237
|
+
},
|
|
238
|
+
"peerDependenciesMeta": {
|
|
239
|
+
"next": {
|
|
240
|
+
"optional": true
|
|
241
|
+
},
|
|
242
|
+
"react": {
|
|
243
|
+
"optional": true
|
|
244
|
+
},
|
|
245
|
+
"react-dom": {
|
|
246
|
+
"optional": true
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
"devDependencies": {
|
|
250
|
+
"@types/node": "^20",
|
|
251
|
+
"@types/react": "^19",
|
|
252
|
+
"@types/react-dom": "^19",
|
|
253
|
+
"typescript": "^5"
|
|
254
|
+
},
|
|
255
|
+
"engines": {
|
|
256
|
+
"node": ">=20"
|
|
257
|
+
}
|
|
258
|
+
}
|
|
@@ -134,6 +134,20 @@ export type CartMutationResult =
|
|
|
134
134
|
/** The id prefix of a line the platform has not confirmed yet. */
|
|
135
135
|
const PENDING_PREFIX = "optimistic-"
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* A cart that can still be shopped. A completed cart is an order now: the
|
|
139
|
+
* platform still answers it, lines and all, but refuses every change to it.
|
|
140
|
+
*/
|
|
141
|
+
export function isLiveCart(cart: Cart | null | undefined): cart is Cart {
|
|
142
|
+
return Boolean(cart && !cart.completed_at)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** The platform's answer that the cart a change was aimed at is over (ordered, or gone). */
|
|
146
|
+
export function isEndedCartError(err: unknown): boolean {
|
|
147
|
+
const code = (err as { code?: unknown } | null)?.code
|
|
148
|
+
return code === "cart_completed" || code === "cart_not_found"
|
|
149
|
+
}
|
|
150
|
+
|
|
137
151
|
/**
|
|
138
152
|
* A line the platform has not confirmed yet: it was added a moment ago and
|
|
139
153
|
* carries a placeholder id. Its quantity and removal work already (the
|
|
@@ -196,6 +210,12 @@ type CartDrawerContextValue = {
|
|
|
196
210
|
removeItem: (lineId: string) => Promise<boolean>
|
|
197
211
|
/** Re-read the decorated cart (totals/gift-card tender are live per read). */
|
|
198
212
|
refresh: () => Promise<void>
|
|
213
|
+
/**
|
|
214
|
+
* The cart is over (the order was placed): the drawer empties and the
|
|
215
|
+
* store's `onCartEnd` clears its cookie. The checkout calls it; the next
|
|
216
|
+
* add starts a new cart.
|
|
217
|
+
*/
|
|
218
|
+
forget: () => Promise<void>
|
|
199
219
|
/** True when the provider was given a client, so the methods above reach the platform. */
|
|
200
220
|
canMutate: boolean
|
|
201
221
|
labels: CartDrawerLabels
|
|
@@ -215,6 +235,7 @@ const CartDrawerContext = createContext<CartDrawerContextValue>({
|
|
|
215
235
|
updateQuantity: async () => false,
|
|
216
236
|
removeItem: async () => false,
|
|
217
237
|
refresh: async () => {},
|
|
238
|
+
forget: async () => {},
|
|
218
239
|
canMutate: false,
|
|
219
240
|
labels: defaultCartDrawerLabels,
|
|
220
241
|
hrefs: defaultHrefs,
|
|
@@ -351,6 +372,7 @@ export function CartDrawerProvider({
|
|
|
351
372
|
client,
|
|
352
373
|
cartId,
|
|
353
374
|
onCartChange,
|
|
375
|
+
onCartEnd,
|
|
354
376
|
onOptimisticError,
|
|
355
377
|
labels: labelOverrides,
|
|
356
378
|
hrefs: hrefOverrides,
|
|
@@ -374,6 +396,13 @@ export function CartDrawerProvider({
|
|
|
374
396
|
* here so the cart survives reloads.
|
|
375
397
|
*/
|
|
376
398
|
onCartChange?: (cart: Cart) => void
|
|
399
|
+
/**
|
|
400
|
+
* Fires when the cart is over: the order was placed, or the platform
|
|
401
|
+
* answered that the stored cart is completed or gone. Clear the stored
|
|
402
|
+
* cart id (the cookie) here; the next add creates a new cart and
|
|
403
|
+
* `onCartChange` stores its id.
|
|
404
|
+
*/
|
|
405
|
+
onCartEnd?: () => void
|
|
377
406
|
/** Ops funnel for every failed optimistic mutation (see module JSDoc). */
|
|
378
407
|
onOptimisticError?: (failure: OptimisticCartError) => void
|
|
379
408
|
/**
|
|
@@ -392,27 +421,55 @@ export function CartDrawerProvider({
|
|
|
392
421
|
// it reads when a change's turn comes (state lags a render behind).
|
|
393
422
|
const queue = useRef<CartMutationQueue | null>(null)
|
|
394
423
|
if (!queue.current) queue.current = createCartMutationQueue()
|
|
395
|
-
|
|
424
|
+
// A completed cart is an order: the drawer never holds one.
|
|
425
|
+
const latest = useRef<Cart | null>(isLiveCart(cart) ? cart : null)
|
|
426
|
+
|
|
427
|
+
// The store's hooks, read through refs so an inline handler never re-runs an effect.
|
|
428
|
+
const cartEnded = useRef(onCartEnd)
|
|
429
|
+
cartEnded.current = onCartEnd
|
|
396
430
|
|
|
397
431
|
// Confirmed snapshot: seeded from the prop, replaced by every SDK
|
|
398
432
|
// mutation response and by prop updates from server refreshes.
|
|
399
|
-
const [serverCart, setServerCart] = useState<Cart | null>(
|
|
433
|
+
const [serverCart, setServerCart] = useState<Cart | null>(latest.current)
|
|
434
|
+
|
|
435
|
+
/** The cart is over: the drawer empties and the store forgets the id. */
|
|
436
|
+
const end = useCallback(() => {
|
|
437
|
+
latest.current = null
|
|
438
|
+
startTransition(() => setServerCart(null))
|
|
439
|
+
try {
|
|
440
|
+
cartEnded.current?.()
|
|
441
|
+
} catch {
|
|
442
|
+
// A store's handler must never break the drawer.
|
|
443
|
+
}
|
|
444
|
+
}, [])
|
|
445
|
+
|
|
400
446
|
useEffect(() => {
|
|
401
447
|
if (cart === undefined) return
|
|
402
448
|
// A refresh carrying the cart as it was must not overwrite an answer
|
|
403
449
|
// still on its way; the queue's own answers are newer.
|
|
404
450
|
if (queue.current?.busy()) return
|
|
451
|
+
if (cart && !isLiveCart(cart)) {
|
|
452
|
+
end()
|
|
453
|
+
return
|
|
454
|
+
}
|
|
405
455
|
latest.current = cart
|
|
406
456
|
setServerCart(cart)
|
|
407
|
-
}, [cart])
|
|
457
|
+
}, [cart, end])
|
|
408
458
|
|
|
409
459
|
// A confirmed cart becomes the snapshot inside a transition, so it lands
|
|
410
460
|
// together with the end of the change that asked for it and a pending
|
|
411
|
-
// line is never shown twice.
|
|
412
|
-
const adopt = useCallback(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
461
|
+
// line is never shown twice. A completed one ends the cart instead.
|
|
462
|
+
const adopt = useCallback(
|
|
463
|
+
(next: Cart) => {
|
|
464
|
+
if (!isLiveCart(next)) {
|
|
465
|
+
end()
|
|
466
|
+
return
|
|
467
|
+
}
|
|
468
|
+
latest.current = next
|
|
469
|
+
startTransition(() => setServerCart(next))
|
|
470
|
+
},
|
|
471
|
+
[end]
|
|
472
|
+
)
|
|
416
473
|
|
|
417
474
|
// Client+cartId mode: read the cart on mount, through the queue, so an
|
|
418
475
|
// add made before the read answers goes to this cart, not a new one.
|
|
@@ -423,15 +480,16 @@ export function CartDrawerProvider({
|
|
|
423
480
|
try {
|
|
424
481
|
const res = await sdkRetrieveCart(client, cartId)
|
|
425
482
|
if (!cancelled) adopt(res.cart)
|
|
426
|
-
} catch {
|
|
427
|
-
//
|
|
428
|
-
//
|
|
483
|
+
} catch (err) {
|
|
484
|
+
// A stored id the platform no longer knows: forget it. Any other
|
|
485
|
+
// failure (a network blip) keeps the id for the next visit.
|
|
486
|
+
if (!cancelled && isEndedCartError(err)) end()
|
|
429
487
|
}
|
|
430
488
|
})
|
|
431
489
|
return () => {
|
|
432
490
|
cancelled = true
|
|
433
491
|
}
|
|
434
|
-
}, [cart, client, cartId, adopt])
|
|
492
|
+
}, [cart, client, cartId, adopt, end])
|
|
435
493
|
|
|
436
494
|
const [optimisticCart, dispatchOptimistic] = useOptimistic(
|
|
437
495
|
serverCart,
|
|
@@ -532,7 +590,8 @@ export function CartDrawerProvider({
|
|
|
532
590
|
const confirm = useCallback(
|
|
533
591
|
(next: Cart) => {
|
|
534
592
|
adopt(next)
|
|
535
|
-
|
|
593
|
+
// A completed cart has ended the cart; its id is never stored again.
|
|
594
|
+
if (isLiveCart(next)) onCartChange?.(next)
|
|
536
595
|
},
|
|
537
596
|
[adopt, onCartChange]
|
|
538
597
|
)
|
|
@@ -561,13 +620,26 @@ export function CartDrawerProvider({
|
|
|
561
620
|
...display,
|
|
562
621
|
}
|
|
563
622
|
const work = queue.current!.run(async (): Promise<CartMutationResult> => {
|
|
623
|
+
// First add with no cart: create one with the item in a single
|
|
624
|
+
// call. region_id falls back to the store default server-side.
|
|
625
|
+
const create = () => sdkCreateCart(client, { items: [{ variant_id: variantId, quantity }] })
|
|
564
626
|
try {
|
|
565
627
|
const cartId = latest.current?.id
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
628
|
+
let res
|
|
629
|
+
if (!cartId) {
|
|
630
|
+
res = await create()
|
|
631
|
+
} else {
|
|
632
|
+
try {
|
|
633
|
+
res = await sdkAddLineItem(client, cartId, { variant_id: variantId, quantity })
|
|
634
|
+
} catch (error) {
|
|
635
|
+
// The stored cart is over (ordered in another tab, or gone):
|
|
636
|
+
// Medusa's starter treats it as no cart, so a new one starts
|
|
637
|
+
// with this item.
|
|
638
|
+
if (!isEndedCartError(error)) throw error
|
|
639
|
+
end()
|
|
640
|
+
res = await create()
|
|
641
|
+
}
|
|
642
|
+
}
|
|
571
643
|
confirm(res.cart)
|
|
572
644
|
return { ok: true, cart: res.cart }
|
|
573
645
|
} catch (error) {
|
|
@@ -577,7 +649,7 @@ export function CartDrawerProvider({
|
|
|
577
649
|
})
|
|
578
650
|
return showWhile(action, work)
|
|
579
651
|
},
|
|
580
|
-
[client, confirm, report, showWhile]
|
|
652
|
+
[client, confirm, report, showWhile, end]
|
|
581
653
|
)
|
|
582
654
|
|
|
583
655
|
const addItem = useCallback(
|
|
@@ -599,7 +671,8 @@ export function CartDrawerProvider({
|
|
|
599
671
|
confirm(res.cart)
|
|
600
672
|
return true
|
|
601
673
|
} catch (err) {
|
|
602
|
-
|
|
674
|
+
if (isEndedCartError(err)) end()
|
|
675
|
+
else report({ type: "update_quantity", lineId, quantity: latestQuantity }, err)
|
|
603
676
|
return false
|
|
604
677
|
}
|
|
605
678
|
})
|
|
@@ -608,7 +681,7 @@ export function CartDrawerProvider({
|
|
|
608
681
|
work.then((sent) => sent === true)
|
|
609
682
|
)
|
|
610
683
|
},
|
|
611
|
-
[client, lineNow, confirm, report, showWhile]
|
|
684
|
+
[client, lineNow, confirm, report, showWhile, end]
|
|
612
685
|
)
|
|
613
686
|
|
|
614
687
|
const removeItem = useCallback(
|
|
@@ -627,13 +700,17 @@ export function CartDrawerProvider({
|
|
|
627
700
|
confirm(res.cart)
|
|
628
701
|
return true
|
|
629
702
|
} catch (err) {
|
|
703
|
+
if (isEndedCartError(err)) {
|
|
704
|
+
end()
|
|
705
|
+
return true
|
|
706
|
+
}
|
|
630
707
|
report(action, err)
|
|
631
708
|
return false
|
|
632
709
|
}
|
|
633
710
|
})
|
|
634
711
|
return showWhile(action, work)
|
|
635
712
|
},
|
|
636
|
-
[client, lineNow, confirm, report, showWhile]
|
|
713
|
+
[client, lineNow, confirm, report, showWhile, end]
|
|
637
714
|
)
|
|
638
715
|
|
|
639
716
|
const refresh = useCallback(
|
|
@@ -645,12 +722,20 @@ export function CartDrawerProvider({
|
|
|
645
722
|
try {
|
|
646
723
|
const res = await sdkRetrieveCart(client, id)
|
|
647
724
|
confirm(res.cart)
|
|
648
|
-
} catch {
|
|
649
|
-
//
|
|
725
|
+
} catch (err) {
|
|
726
|
+
// A cart the platform no longer knows ends; a transient failure
|
|
727
|
+
// keeps the last snapshot.
|
|
728
|
+
if (isEndedCartError(err)) end()
|
|
650
729
|
}
|
|
651
730
|
})
|
|
652
731
|
},
|
|
653
|
-
[client, confirm]
|
|
732
|
+
[client, confirm, end]
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
/** The order was placed: empty the drawer and let the store forget the id. */
|
|
736
|
+
const forget = useCallback(
|
|
737
|
+
(): Promise<void> => queue.current!.run(async () => end()),
|
|
738
|
+
[end]
|
|
654
739
|
)
|
|
655
740
|
|
|
656
741
|
// The mounted language is the default (2026-09-14): a store that mounts
|
|
@@ -681,6 +766,7 @@ export function CartDrawerProvider({
|
|
|
681
766
|
updateQuantity,
|
|
682
767
|
removeItem,
|
|
683
768
|
refresh,
|
|
769
|
+
forget,
|
|
684
770
|
canMutate: Boolean(client),
|
|
685
771
|
labels,
|
|
686
772
|
hrefs,
|
package/src/cart-drawer/index.ts
CHANGED
|
@@ -41,6 +41,8 @@ import {
|
|
|
41
41
|
type UpdateCustomerInput,
|
|
42
42
|
} from "../api/customers"
|
|
43
43
|
import { isStripeLike } from "../lib/payment-constants"
|
|
44
|
+
import { clearCartCookie } from "../lib/cookie-names"
|
|
45
|
+
import { useCartDrawer } from "../cart-drawer/context"
|
|
44
46
|
import compareAddresses from "./compare-addresses"
|
|
45
47
|
import { translateAddressError } from "./address-error-copy"
|
|
46
48
|
import { translatePaymentError } from "./payment-error-copy"
|
|
@@ -303,6 +305,9 @@ export function useCheckoutOrchestration({
|
|
|
303
305
|
const contextOrderConfirmedPath = useOrderConfirmedPath()
|
|
304
306
|
const orderConfirmedPath =
|
|
305
307
|
orderConfirmedPathProp ?? contextOrderConfirmedPath
|
|
308
|
+
// The mounted cart drawer, emptied when the order is placed (a no-op
|
|
309
|
+
// when the store mounts none).
|
|
310
|
+
const { forget: forgetCart } = useCartDrawer()
|
|
306
311
|
|
|
307
312
|
// ── Completed-cart detection ────────────────────────────────────────
|
|
308
313
|
// Surfaced as a flag so the page-level server component can redirect
|
|
@@ -1041,6 +1046,12 @@ export function useCheckoutOrchestration({
|
|
|
1041
1046
|
|
|
1042
1047
|
const { order } = await completeCart(client, cart.id)
|
|
1043
1048
|
|
|
1049
|
+
// The cart is an order now (Medusa's placeOrder: removeCartId()): the
|
|
1050
|
+
// stored id goes and the drawer empties, so the next add starts a new
|
|
1051
|
+
// cart instead of being refused by the completed one.
|
|
1052
|
+
clearCartCookie()
|
|
1053
|
+
await forgetCart()
|
|
1054
|
+
|
|
1044
1055
|
if (onOrderPlaced) {
|
|
1045
1056
|
onOrderPlaced(order)
|
|
1046
1057
|
} else if (typeof window !== "undefined") {
|
|
@@ -1057,6 +1068,7 @@ export function useCheckoutOrchestration({
|
|
|
1057
1068
|
client,
|
|
1058
1069
|
cart.id,
|
|
1059
1070
|
cart.metadata,
|
|
1071
|
+
forgetCart,
|
|
1060
1072
|
onOrderPlaced,
|
|
1061
1073
|
orderConfirmedPath,
|
|
1062
1074
|
resolveTrackingMetadata,
|
package/src/lib/cookie-names.ts
CHANGED
|
@@ -40,6 +40,20 @@ export function readCartCookie(
|
|
|
40
40
|
return get(CART_COOKIE) ?? get(LEGACY_CART_COOKIE)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Forget the stored cart in the browser, under both names: Medusa's
|
|
45
|
+
* `removeCartId()`. The package's checkout calls it when the order is
|
|
46
|
+
* placed, and a store hands it to `CartDrawerProvider`'s `onCartEnd` so a
|
|
47
|
+
* cart that turned out to be completed or gone is forgotten too. A no-op
|
|
48
|
+
* on the server.
|
|
49
|
+
*/
|
|
50
|
+
export function clearCartCookie(): void {
|
|
51
|
+
if (typeof document === "undefined") return
|
|
52
|
+
for (const name of [CART_COOKIE, LEGACY_CART_COOKIE]) {
|
|
53
|
+
document.cookie = `${name}=;path=/;max-age=0;samesite=lax`
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
43
57
|
/**
|
|
44
58
|
* THE VISITOR ID — our own per-browser id and the join key between browsing
|
|
45
59
|
* and money (ecommerce-analytics §3.1). It is OURS deliberately: the
|