@shopify/hydrogen 1.3.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esnext/components/CartProvider/CartActions.client.d.ts +60 -0
- package/dist/esnext/components/CartProvider/CartActions.client.js +232 -0
- package/dist/esnext/components/CartProvider/CartProviderV2.client.d.ts +44 -0
- package/dist/esnext/components/CartProvider/CartProviderV2.client.js +232 -0
- package/dist/esnext/components/CartProvider/hooks.client.js +1 -1
- package/dist/esnext/components/CartProvider/types.d.ts +149 -0
- package/dist/esnext/components/CartProvider/useCartAPIStateMachine.client.d.ts +16 -0
- package/dist/esnext/components/CartProvider/useCartAPIStateMachine.client.js +231 -0
- package/dist/esnext/entry-client.js +26 -8
- package/dist/esnext/experimental.d.ts +1 -0
- package/dist/esnext/experimental.js +1 -0
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.d.ts +3 -2
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.js +1 -0
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.d.ts +3 -3
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +1 -0
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +21 -6
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +5 -2
- package/dist/esnext/foundation/useShop/use-shop.d.ts +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +1 -0
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +0 -8
- package/dist/esnext/hooks/useDelay/useDelay.d.ts +1 -0
- package/dist/esnext/hooks/useDelay/useDelay.js +17 -0
- package/dist/esnext/hooks/useShopQuery/hooks.js +4 -2
- package/dist/esnext/index.d.ts +1 -0
- package/dist/esnext/index.js +1 -0
- package/dist/esnext/shared-types.d.ts +2 -1
- package/dist/esnext/utilities/apiRoutes.js +4 -2
- package/dist/esnext/utilities/object.d.ts +1 -1
- package/dist/esnext/utilities/storefrontApi.d.ts +4 -2
- package/dist/esnext/utilities/storefrontApi.js +27 -6
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +1 -0
- package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +0 -8
- package/dist/node/shared-types.d.ts +2 -1
- package/package.json +3 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { AttributeInput, CartBuyerIdentityInput, CartInput, CartLineInput, CartLineUpdateInput } from '../../storefront-api-types.js';
|
|
2
|
+
import { CartAttributesUpdateMutation } from './graphql/CartAttributesUpdateMutation.js';
|
|
3
|
+
import { CartBuyerIdentityUpdateMutation } from './graphql/CartBuyerIdentityUpdateMutation.js';
|
|
4
|
+
import { CartCreateMutation } from './graphql/CartCreateMutation.js';
|
|
5
|
+
import { CartDiscountCodesUpdateMutation, CartDiscountCodesUpdateMutationVariables } from './graphql/CartDiscountCodesUpdateMutation.js';
|
|
6
|
+
import { CartLineAddMutation } from './graphql/CartLineAddMutation.js';
|
|
7
|
+
import { CartLineRemoveMutation } from './graphql/CartLineRemoveMutation.js';
|
|
8
|
+
import { CartLineUpdateMutation } from './graphql/CartLineUpdateMutation.js';
|
|
9
|
+
import { CartNoteUpdateMutation, CartNoteUpdateMutationVariables } from './graphql/CartNoteUpdateMutation.js';
|
|
10
|
+
import { CartQueryQuery } from './graphql/CartQuery.js';
|
|
11
|
+
/**
|
|
12
|
+
* The `useCartActions` hook returns helper graphql functions for Storefront Cart API
|
|
13
|
+
*
|
|
14
|
+
* See [cart API graphql mutations](https://shopify.dev/api/storefront/2022-07/objects/Cart)
|
|
15
|
+
*/
|
|
16
|
+
export declare function useCartActions({ numCartLines, cartFragment, }: {
|
|
17
|
+
/** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */
|
|
18
|
+
numCartLines?: number;
|
|
19
|
+
/** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */
|
|
20
|
+
cartFragment?: string;
|
|
21
|
+
}): {
|
|
22
|
+
cartFetch: (cartId: string) => Promise<{
|
|
23
|
+
data: CartQueryQuery | undefined;
|
|
24
|
+
errors: any;
|
|
25
|
+
}>;
|
|
26
|
+
cartCreate: (cart: CartInput) => Promise<{
|
|
27
|
+
data: CartCreateMutation | undefined;
|
|
28
|
+
errors: any;
|
|
29
|
+
}>;
|
|
30
|
+
cartLineAdd: (cartId: string, lines: CartLineInput[]) => Promise<{
|
|
31
|
+
data: CartLineAddMutation | undefined;
|
|
32
|
+
errors: any;
|
|
33
|
+
}>;
|
|
34
|
+
cartLineUpdate: (cartId: string, lines: CartLineUpdateInput[]) => Promise<{
|
|
35
|
+
data: CartLineUpdateMutation | undefined;
|
|
36
|
+
errors: any;
|
|
37
|
+
}>;
|
|
38
|
+
cartLineRemove: (cartId: string, lines: string[]) => Promise<{
|
|
39
|
+
data: CartLineRemoveMutation | undefined;
|
|
40
|
+
errors: any;
|
|
41
|
+
}>;
|
|
42
|
+
noteUpdate: (cartId: string, note: CartNoteUpdateMutationVariables['note']) => Promise<{
|
|
43
|
+
data: CartNoteUpdateMutation | undefined;
|
|
44
|
+
errors: any;
|
|
45
|
+
}>;
|
|
46
|
+
buyerIdentityUpdate: (cartId: string, buyerIdentity: CartBuyerIdentityInput) => Promise<{
|
|
47
|
+
data: CartBuyerIdentityUpdateMutation | undefined;
|
|
48
|
+
errors: any;
|
|
49
|
+
}>;
|
|
50
|
+
cartAttributesUpdate: (cartId: string, attributes: AttributeInput[]) => Promise<{
|
|
51
|
+
data: CartAttributesUpdateMutation | undefined;
|
|
52
|
+
errors: any;
|
|
53
|
+
}>;
|
|
54
|
+
discountCodesUpdate: (cartId: string, discountCodes: CartDiscountCodesUpdateMutationVariables['discountCodes']) => Promise<{
|
|
55
|
+
data: CartDiscountCodesUpdateMutation | undefined;
|
|
56
|
+
errors: any;
|
|
57
|
+
}>;
|
|
58
|
+
cartFragment: string;
|
|
59
|
+
};
|
|
60
|
+
export declare const defaultCartFragment = "\nfragment CartFragment on Cart {\n id\n checkoutUrl\n totalQuantity\n buyerIdentity {\n countryCode\n customer {\n id\n email\n firstName\n lastName\n displayName\n }\n email\n phone\n }\n lines(first: $numCartLines) {\n edges {\n node {\n id\n quantity\n attributes {\n key\n value\n }\n cost {\n totalAmount {\n amount\n currencyCode\n }\n compareAtAmountPerQuantity {\n amount\n currencyCode\n }\n }\n merchandise {\n ... on ProductVariant {\n id\n availableForSale\n compareAtPriceV2 {\n ...MoneyFragment\n }\n priceV2 {\n ...MoneyFragment\n }\n requiresShipping\n title\n image {\n ...ImageFragment\n }\n product {\n handle\n title\n }\n selectedOptions {\n name\n value\n }\n }\n }\n }\n }\n }\n cost {\n subtotalAmount {\n ...MoneyFragment\n }\n totalAmount {\n ...MoneyFragment\n }\n totalDutyAmount {\n ...MoneyFragment\n }\n totalTaxAmount {\n ...MoneyFragment\n }\n }\n note\n attributes {\n key\n value\n }\n discountCodes {\n code\n }\n}\n\nfragment MoneyFragment on MoneyV2 {\n currencyCode\n amount\n}\nfragment ImageFragment on Image {\n id\n url\n altText\n width\n height\n}\n";
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { CountryCode, } from '../../storefront-api-types.js';
|
|
3
|
+
import { CartAttributesUpdate, CartBuyerIdentityUpdate, CartCreate, CartDiscountCodesUpdate, CartLineAdd, CartLineRemove, CartLineUpdate, CartNoteUpdate, CartQuery, } from './cart-queries.js';
|
|
4
|
+
import { useCartFetch } from './hooks.client.js';
|
|
5
|
+
/**
|
|
6
|
+
* The `useCartActions` hook returns helper graphql functions for Storefront Cart API
|
|
7
|
+
*
|
|
8
|
+
* See [cart API graphql mutations](https://shopify.dev/api/storefront/2022-07/objects/Cart)
|
|
9
|
+
*/
|
|
10
|
+
export function useCartActions({ numCartLines, cartFragment = defaultCartFragment, }) {
|
|
11
|
+
const fetchCart = useCartFetch();
|
|
12
|
+
const cartFetch = useCallback((cartId) => {
|
|
13
|
+
return fetchCart({
|
|
14
|
+
query: CartQuery(cartFragment),
|
|
15
|
+
variables: {
|
|
16
|
+
id: cartId,
|
|
17
|
+
numCartLines,
|
|
18
|
+
country: CountryCode.Us,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}, [fetchCart, cartFragment, numCartLines]);
|
|
22
|
+
const cartCreate = useCallback((cart) => {
|
|
23
|
+
return fetchCart({
|
|
24
|
+
query: CartCreate(cartFragment),
|
|
25
|
+
variables: {
|
|
26
|
+
input: cart,
|
|
27
|
+
numCartLines,
|
|
28
|
+
country: CountryCode.Us,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
32
|
+
const cartLineAdd = useCallback((cartId, lines) => {
|
|
33
|
+
return fetchCart({
|
|
34
|
+
query: CartLineAdd(cartFragment),
|
|
35
|
+
variables: {
|
|
36
|
+
cartId,
|
|
37
|
+
lines,
|
|
38
|
+
numCartLines,
|
|
39
|
+
country: CountryCode.Us,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
43
|
+
const cartLineUpdate = useCallback((cartId, lines) => {
|
|
44
|
+
return fetchCart({
|
|
45
|
+
query: CartLineUpdate(cartFragment),
|
|
46
|
+
variables: {
|
|
47
|
+
cartId,
|
|
48
|
+
lines,
|
|
49
|
+
numCartLines,
|
|
50
|
+
country: CountryCode.Us,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
54
|
+
const cartLineRemove = useCallback((cartId, lines) => {
|
|
55
|
+
return fetchCart({
|
|
56
|
+
query: CartLineRemove(cartFragment),
|
|
57
|
+
variables: {
|
|
58
|
+
cartId,
|
|
59
|
+
lines,
|
|
60
|
+
numCartLines,
|
|
61
|
+
country: CountryCode.Us,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
65
|
+
const noteUpdate = useCallback((cartId, note) => {
|
|
66
|
+
return fetchCart({
|
|
67
|
+
query: CartNoteUpdate(cartFragment),
|
|
68
|
+
variables: {
|
|
69
|
+
cartId,
|
|
70
|
+
note,
|
|
71
|
+
numCartLines,
|
|
72
|
+
country: CountryCode.Us,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}, [fetchCart, cartFragment, numCartLines]);
|
|
76
|
+
const buyerIdentityUpdate = useCallback((cartId, buyerIdentity) => {
|
|
77
|
+
return fetchCart({
|
|
78
|
+
query: CartBuyerIdentityUpdate(cartFragment),
|
|
79
|
+
variables: {
|
|
80
|
+
cartId,
|
|
81
|
+
buyerIdentity,
|
|
82
|
+
numCartLines,
|
|
83
|
+
country: CountryCode.Us,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
87
|
+
const cartAttributesUpdate = useCallback((cartId, attributes) => {
|
|
88
|
+
return fetchCart({
|
|
89
|
+
query: CartAttributesUpdate(cartFragment),
|
|
90
|
+
variables: {
|
|
91
|
+
cartId,
|
|
92
|
+
attributes,
|
|
93
|
+
numCartLines,
|
|
94
|
+
country: CountryCode.Us,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
98
|
+
const discountCodesUpdate = useCallback((cartId, discountCodes) => {
|
|
99
|
+
return fetchCart({
|
|
100
|
+
query: CartDiscountCodesUpdate(cartFragment),
|
|
101
|
+
variables: {
|
|
102
|
+
cartId,
|
|
103
|
+
discountCodes,
|
|
104
|
+
numCartLines,
|
|
105
|
+
country: CountryCode.Us,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}, [cartFragment, fetchCart, numCartLines]);
|
|
109
|
+
return useMemo(() => ({
|
|
110
|
+
cartFetch,
|
|
111
|
+
cartCreate,
|
|
112
|
+
cartLineAdd,
|
|
113
|
+
cartLineUpdate,
|
|
114
|
+
cartLineRemove,
|
|
115
|
+
noteUpdate,
|
|
116
|
+
buyerIdentityUpdate,
|
|
117
|
+
cartAttributesUpdate,
|
|
118
|
+
discountCodesUpdate,
|
|
119
|
+
cartFragment,
|
|
120
|
+
}), [
|
|
121
|
+
cartFetch,
|
|
122
|
+
cartCreate,
|
|
123
|
+
cartLineAdd,
|
|
124
|
+
cartLineUpdate,
|
|
125
|
+
cartLineRemove,
|
|
126
|
+
noteUpdate,
|
|
127
|
+
buyerIdentityUpdate,
|
|
128
|
+
cartAttributesUpdate,
|
|
129
|
+
discountCodesUpdate,
|
|
130
|
+
cartFragment,
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
133
|
+
export const defaultCartFragment = `
|
|
134
|
+
fragment CartFragment on Cart {
|
|
135
|
+
id
|
|
136
|
+
checkoutUrl
|
|
137
|
+
totalQuantity
|
|
138
|
+
buyerIdentity {
|
|
139
|
+
countryCode
|
|
140
|
+
customer {
|
|
141
|
+
id
|
|
142
|
+
email
|
|
143
|
+
firstName
|
|
144
|
+
lastName
|
|
145
|
+
displayName
|
|
146
|
+
}
|
|
147
|
+
email
|
|
148
|
+
phone
|
|
149
|
+
}
|
|
150
|
+
lines(first: $numCartLines) {
|
|
151
|
+
edges {
|
|
152
|
+
node {
|
|
153
|
+
id
|
|
154
|
+
quantity
|
|
155
|
+
attributes {
|
|
156
|
+
key
|
|
157
|
+
value
|
|
158
|
+
}
|
|
159
|
+
cost {
|
|
160
|
+
totalAmount {
|
|
161
|
+
amount
|
|
162
|
+
currencyCode
|
|
163
|
+
}
|
|
164
|
+
compareAtAmountPerQuantity {
|
|
165
|
+
amount
|
|
166
|
+
currencyCode
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
merchandise {
|
|
170
|
+
... on ProductVariant {
|
|
171
|
+
id
|
|
172
|
+
availableForSale
|
|
173
|
+
compareAtPriceV2 {
|
|
174
|
+
...MoneyFragment
|
|
175
|
+
}
|
|
176
|
+
priceV2 {
|
|
177
|
+
...MoneyFragment
|
|
178
|
+
}
|
|
179
|
+
requiresShipping
|
|
180
|
+
title
|
|
181
|
+
image {
|
|
182
|
+
...ImageFragment
|
|
183
|
+
}
|
|
184
|
+
product {
|
|
185
|
+
handle
|
|
186
|
+
title
|
|
187
|
+
}
|
|
188
|
+
selectedOptions {
|
|
189
|
+
name
|
|
190
|
+
value
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
cost {
|
|
198
|
+
subtotalAmount {
|
|
199
|
+
...MoneyFragment
|
|
200
|
+
}
|
|
201
|
+
totalAmount {
|
|
202
|
+
...MoneyFragment
|
|
203
|
+
}
|
|
204
|
+
totalDutyAmount {
|
|
205
|
+
...MoneyFragment
|
|
206
|
+
}
|
|
207
|
+
totalTaxAmount {
|
|
208
|
+
...MoneyFragment
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
note
|
|
212
|
+
attributes {
|
|
213
|
+
key
|
|
214
|
+
value
|
|
215
|
+
}
|
|
216
|
+
discountCodes {
|
|
217
|
+
code
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
fragment MoneyFragment on MoneyV2 {
|
|
222
|
+
currencyCode
|
|
223
|
+
amount
|
|
224
|
+
}
|
|
225
|
+
fragment ImageFragment on Image {
|
|
226
|
+
id
|
|
227
|
+
url
|
|
228
|
+
altText
|
|
229
|
+
width
|
|
230
|
+
height
|
|
231
|
+
}
|
|
232
|
+
`;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CartFragmentFragment } from './graphql/CartFragment.js';
|
|
3
|
+
export declare function CartProviderV2({ children, numCartLines, onCreate, onLineAdd, onLineRemove, onLineUpdate, onNoteUpdate, onBuyerIdentityUpdate, onAttributesUpdate, onDiscountCodesUpdate, onCreateComplete, onLineAddComplete, onLineRemoveComplete, onLineUpdateComplete, onNoteUpdateComplete, onBuyerIdentityUpdateComplete, onAttributesUpdateComplete, onDiscountCodesUpdateComplete, data, cartFragment, }: {
|
|
4
|
+
/** Any `ReactNode` elements. */
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
/** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */
|
|
7
|
+
numCartLines?: number;
|
|
8
|
+
/** A callback that is invoked when the process to create a cart begins, but before the cart is created in the Storefront API. */
|
|
9
|
+
onCreate?: () => void;
|
|
10
|
+
/** A callback that is invoked when the process to add a line item to the cart begins, but before the line item is added to the Storefront API. */
|
|
11
|
+
onLineAdd?: () => void;
|
|
12
|
+
/** A callback that is invoked when the process to remove a line item to the cart begins, but before the line item is removed from the Storefront API. */
|
|
13
|
+
onLineRemove?: () => void;
|
|
14
|
+
/** A callback that is invoked when the process to update a line item in the cart begins, but before the line item is updated in the Storefront API. */
|
|
15
|
+
onLineUpdate?: () => void;
|
|
16
|
+
/** A callback that is invoked when the process to add or update a note in the cart begins, but before the note is added or updated in the Storefront API. */
|
|
17
|
+
onNoteUpdate?: () => void;
|
|
18
|
+
/** A callback that is invoked when the process to update the buyer identity begins, but before the buyer identity is updated in the Storefront API. */
|
|
19
|
+
onBuyerIdentityUpdate?: () => void;
|
|
20
|
+
/** A callback that is invoked when the process to update the cart attributes begins, but before the attributes are updated in the Storefront API. */
|
|
21
|
+
onAttributesUpdate?: () => void;
|
|
22
|
+
/** A callback that is invoked when the process to update the cart discount codes begins, but before the discount codes are updated in the Storefront API. */
|
|
23
|
+
onDiscountCodesUpdate?: () => void;
|
|
24
|
+
/** A callback that is invoked when the process to create a cart completes */
|
|
25
|
+
onCreateComplete?: () => void;
|
|
26
|
+
/** A callback that is invoked when the process to add a line item to the cart completes */
|
|
27
|
+
onLineAddComplete?: () => void;
|
|
28
|
+
/** A callback that is invoked when the process to remove a line item to the cart completes */
|
|
29
|
+
onLineRemoveComplete?: () => void;
|
|
30
|
+
/** A callback that is invoked when the process to update a line item in the cart completes */
|
|
31
|
+
onLineUpdateComplete?: () => void;
|
|
32
|
+
/** A callback that is invoked when the process to add or update a note in the cart completes */
|
|
33
|
+
onNoteUpdateComplete?: () => void;
|
|
34
|
+
/** A callback that is invoked when the process to update the buyer identity completes */
|
|
35
|
+
onBuyerIdentityUpdateComplete?: () => void;
|
|
36
|
+
/** A callback that is invoked when the process to update the cart attributes completes */
|
|
37
|
+
onAttributesUpdateComplete?: () => void;
|
|
38
|
+
/** A callback that is invoked when the process to update the cart discount codes completes */
|
|
39
|
+
onDiscountCodesUpdateComplete?: () => void;
|
|
40
|
+
/** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart). */
|
|
41
|
+
data?: CartFragmentFragment;
|
|
42
|
+
/** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */
|
|
43
|
+
cartFragment?: string;
|
|
44
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { CartContext } from './context.js';
|
|
3
|
+
import { useCartActions } from './CartActions.client.js';
|
|
4
|
+
import { useCartAPIStateMachine } from './useCartAPIStateMachine.client.js';
|
|
5
|
+
import { CART_ID_STORAGE_KEY } from './constants.js';
|
|
6
|
+
export function CartProviderV2({ children, numCartLines, onCreate, onLineAdd, onLineRemove, onLineUpdate, onNoteUpdate, onBuyerIdentityUpdate, onAttributesUpdate, onDiscountCodesUpdate, onCreateComplete, onLineAddComplete, onLineRemoveComplete, onLineUpdateComplete, onNoteUpdateComplete, onBuyerIdentityUpdateComplete, onAttributesUpdateComplete, onDiscountCodesUpdateComplete, data: cart, cartFragment, }) {
|
|
7
|
+
const { cartFragment: usedCartFragment } = useCartActions({
|
|
8
|
+
numCartLines,
|
|
9
|
+
cartFragment,
|
|
10
|
+
});
|
|
11
|
+
const [cartState, cartSend] = useCartAPIStateMachine({
|
|
12
|
+
numCartLines,
|
|
13
|
+
cartFragment,
|
|
14
|
+
onCartActionEntry(context, event) {
|
|
15
|
+
switch (event.type) {
|
|
16
|
+
case 'CART_CREATE':
|
|
17
|
+
return onCreate?.();
|
|
18
|
+
case 'CARTLINE_ADD':
|
|
19
|
+
return onLineAdd?.();
|
|
20
|
+
case 'CARTLINE_REMOVE':
|
|
21
|
+
return onLineRemove?.();
|
|
22
|
+
case 'CARTLINE_UPDATE':
|
|
23
|
+
return onLineUpdate?.();
|
|
24
|
+
case 'NOTE_UPDATE':
|
|
25
|
+
return onNoteUpdate?.();
|
|
26
|
+
case 'BUYER_IDENTITY_UPDATE':
|
|
27
|
+
return onBuyerIdentityUpdate?.();
|
|
28
|
+
case 'CART_ATTRIBUTES_UPDATE':
|
|
29
|
+
return onAttributesUpdate?.();
|
|
30
|
+
case 'DISCOUNT_CODES_UPDATE':
|
|
31
|
+
return onDiscountCodesUpdate?.();
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
onCartActionComplete(context, event) {
|
|
35
|
+
switch (event.type) {
|
|
36
|
+
case 'RESOLVE':
|
|
37
|
+
switch (event.payload.cartActionEvent.type) {
|
|
38
|
+
case 'CART_CREATE':
|
|
39
|
+
return onCreateComplete?.();
|
|
40
|
+
case 'CARTLINE_ADD':
|
|
41
|
+
return onLineAddComplete?.();
|
|
42
|
+
case 'CARTLINE_REMOVE':
|
|
43
|
+
return onLineRemoveComplete?.();
|
|
44
|
+
case 'CARTLINE_UPDATE':
|
|
45
|
+
return onLineUpdateComplete?.();
|
|
46
|
+
case 'NOTE_UPDATE':
|
|
47
|
+
return onNoteUpdateComplete?.();
|
|
48
|
+
case 'BUYER_IDENTITY_UPDATE':
|
|
49
|
+
return onBuyerIdentityUpdateComplete?.();
|
|
50
|
+
case 'CART_ATTRIBUTES_UPDATE':
|
|
51
|
+
return onAttributesUpdateComplete?.();
|
|
52
|
+
case 'DISCOUNT_CODES_UPDATE':
|
|
53
|
+
return onDiscountCodesUpdateComplete?.();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
const [cartReady, setCartReady] = useState(false);
|
|
59
|
+
const cartCompleted = cartState.matches('cartCompleted');
|
|
60
|
+
// send cart events when ready
|
|
61
|
+
const onCartReadySend = useCallback((cartEvent) => {
|
|
62
|
+
if (!cartReady) {
|
|
63
|
+
return console.warn("Cart isn't ready yet");
|
|
64
|
+
}
|
|
65
|
+
cartSend(cartEvent);
|
|
66
|
+
}, [cartReady, cartSend]);
|
|
67
|
+
// save cart id to local storage
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (cartState?.context?.cart?.id && storageAvailable('localStorage')) {
|
|
70
|
+
try {
|
|
71
|
+
window.localStorage.setItem(CART_ID_STORAGE_KEY, cartState.context.cart?.id);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.warn('Failed to save cartId to localStorage', error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}, [cartState?.context?.cart?.id]);
|
|
78
|
+
// delete cart from local storage if cart fetched has been completed
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (cartCompleted && storageAvailable('localStorage')) {
|
|
81
|
+
try {
|
|
82
|
+
window.localStorage.removeItem(CART_ID_STORAGE_KEY);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.warn('Failed to delete cartId from localStorage', error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}, [cartCompleted]);
|
|
89
|
+
// fetch cart from local storage if cart id present and set cart as ready for use
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (!cartReady && storageAvailable('localStorage')) {
|
|
92
|
+
try {
|
|
93
|
+
const cartId = window.localStorage.getItem(CART_ID_STORAGE_KEY);
|
|
94
|
+
if (cartId) {
|
|
95
|
+
cartSend({ type: 'CART_FETCH', payload: { cartId } });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.warn('error fetching cartId');
|
|
100
|
+
console.warn(error);
|
|
101
|
+
}
|
|
102
|
+
setCartReady(true);
|
|
103
|
+
}
|
|
104
|
+
}, [cartReady, cartSend]);
|
|
105
|
+
const cartContextValue = useMemo(() => {
|
|
106
|
+
return {
|
|
107
|
+
...(cartState?.context?.cart ?? { lines: [], attributes: [] }),
|
|
108
|
+
status: transposeStatus(cartState.value),
|
|
109
|
+
error: cartState?.context?.errors,
|
|
110
|
+
totalQuantity: cartState?.context?.cart?.totalQuantity ?? 0,
|
|
111
|
+
cartCreate(cartInput) {
|
|
112
|
+
onCartReadySend({
|
|
113
|
+
type: 'CART_CREATE',
|
|
114
|
+
payload: cartInput,
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
linesAdd(lines) {
|
|
118
|
+
onCartReadySend({
|
|
119
|
+
type: 'CARTLINE_ADD',
|
|
120
|
+
payload: { lines },
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
linesRemove(lines) {
|
|
124
|
+
onCartReadySend({
|
|
125
|
+
type: 'CARTLINE_REMOVE',
|
|
126
|
+
payload: {
|
|
127
|
+
lines,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
linesUpdate(lines) {
|
|
132
|
+
onCartReadySend({
|
|
133
|
+
type: 'CARTLINE_UPDATE',
|
|
134
|
+
payload: {
|
|
135
|
+
lines,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
noteUpdate(note) {
|
|
140
|
+
onCartReadySend({
|
|
141
|
+
type: 'NOTE_UPDATE',
|
|
142
|
+
payload: {
|
|
143
|
+
note,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
buyerIdentityUpdate(buyerIdentity) {
|
|
148
|
+
onCartReadySend({
|
|
149
|
+
type: 'BUYER_IDENTITY_UPDATE',
|
|
150
|
+
payload: {
|
|
151
|
+
buyerIdentity,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
cartAttributesUpdate(attributes) {
|
|
156
|
+
onCartReadySend({
|
|
157
|
+
type: 'CART_ATTRIBUTES_UPDATE',
|
|
158
|
+
payload: {
|
|
159
|
+
attributes,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
discountCodesUpdate(discountCodes) {
|
|
164
|
+
onCartReadySend({
|
|
165
|
+
type: 'DISCOUNT_CODES_UPDATE',
|
|
166
|
+
payload: {
|
|
167
|
+
discountCodes,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
cartFragment: usedCartFragment,
|
|
172
|
+
};
|
|
173
|
+
}, [
|
|
174
|
+
cartState?.context?.cart,
|
|
175
|
+
cartState?.context?.errors,
|
|
176
|
+
cartState.value,
|
|
177
|
+
onCartReadySend,
|
|
178
|
+
usedCartFragment,
|
|
179
|
+
]);
|
|
180
|
+
return (React.createElement(CartContext.Provider, { value: cartContextValue }, children));
|
|
181
|
+
}
|
|
182
|
+
function transposeStatus(status) {
|
|
183
|
+
switch (status) {
|
|
184
|
+
case 'uninitialized':
|
|
185
|
+
return 'uninitialized';
|
|
186
|
+
case 'idle':
|
|
187
|
+
case 'cartCompleted':
|
|
188
|
+
case 'error':
|
|
189
|
+
case 'initializationError':
|
|
190
|
+
return 'idle';
|
|
191
|
+
case 'cartFetching':
|
|
192
|
+
return 'fetching';
|
|
193
|
+
case 'cartCreating':
|
|
194
|
+
return 'creating';
|
|
195
|
+
case 'cartLineAdding':
|
|
196
|
+
case 'cartLineRemoving':
|
|
197
|
+
case 'cartLineUpdating':
|
|
198
|
+
case 'noteUpdating':
|
|
199
|
+
case 'buyerIdentityUpdating':
|
|
200
|
+
case 'cartAttributesUpdating':
|
|
201
|
+
case 'discountCodesUpdating':
|
|
202
|
+
return 'updating';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** Check for storage availability funciton obtained from
|
|
206
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
|
|
207
|
+
*/
|
|
208
|
+
function storageAvailable(type) {
|
|
209
|
+
let storage;
|
|
210
|
+
try {
|
|
211
|
+
storage = window[type];
|
|
212
|
+
const x = '__storage_test__';
|
|
213
|
+
storage.setItem(x, x);
|
|
214
|
+
storage.removeItem(x);
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
return (e instanceof DOMException &&
|
|
219
|
+
// everything except Firefox
|
|
220
|
+
(e.code === 22 ||
|
|
221
|
+
// Firefox
|
|
222
|
+
e.code === 1014 ||
|
|
223
|
+
// test name field too, because code might not be present
|
|
224
|
+
// everything except Firefox
|
|
225
|
+
e.name === 'QuotaExceededError' ||
|
|
226
|
+
// Firefox
|
|
227
|
+
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
|
|
228
|
+
// acknowledge QuotaExceededError only if there's something already stored
|
|
229
|
+
storage &&
|
|
230
|
+
storage.length !== 0);
|
|
231
|
+
}
|
|
232
|
+
}
|