@graphcommerce/magento-cart 3.0.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/Api/CartItemCountChanged.gql.ts +4 -0
- package/Api/CartItemCountChanged.graphql +9 -0
- package/CHANGELOG.md +324 -0
- package/README.md +102 -0
- package/components/AddToCartButton/AddToCartButton.tsx +127 -0
- package/components/ApolloCartError/ApolloCartErrorAlert.tsx +36 -0
- package/components/ApolloCartError/ApolloCartErrorFullPage.tsx +1 -0
- package/components/CartFab/CartFab.gql.ts +12 -0
- package/components/CartFab/CartFab.graphql +6 -0
- package/components/CartFab/CartFab.tsx +67 -0
- package/components/CartFab/CartTotalQuantity.gql.ts +4 -0
- package/components/CartFab/CartTotalQuantity.graphql +3 -0
- package/components/CartItemSummary/GetCartItemSummary.gql.ts +12 -0
- package/components/CartItemSummary/GetCartItemSummary.graphql +6 -0
- package/components/CartItemSummary/index.tsx +133 -0
- package/components/CartStartCheckout/CartStartCheckout.gql.ts +4 -0
- package/components/CartStartCheckout/CartStartCheckout.graphql +7 -0
- package/components/CartStartCheckout/CartStartCheckout.tsx +63 -0
- package/components/CartSummary/CartSummary.gql.ts +4 -0
- package/components/CartSummary/CartSummary.graphql +15 -0
- package/components/CartSummary/GetCartSummary.gql.ts +12 -0
- package/components/CartSummary/GetCartSummary.graphql +5 -0
- package/components/CartSummary/index.tsx +139 -0
- package/components/CartTotals/CartTotals.gql.ts +4 -0
- package/components/CartTotals/CartTotals.graphql +51 -0
- package/components/CartTotals/CartTotals.tsx +187 -0
- package/components/CartTotals/GetCartTotals.gql.ts +12 -0
- package/components/CartTotals/GetCartTotals.graphql +5 -0
- package/components/EmptyCart/EmptyCart.tsx +56 -0
- package/components/index.ts +24 -0
- package/hooks/CreateEmptyCart.gql.ts +10 -0
- package/hooks/CreateEmptyCart.graphql +3 -0
- package/hooks/CurrentCartId.gql.ts +10 -0
- package/hooks/CurrentCartId.graphql +6 -0
- package/hooks/CurrentCartId.graphqls +11 -0
- package/hooks/CustomerCart.gql.ts +10 -0
- package/hooks/CustomerCart.graphql +7 -0
- package/hooks/UseCartRedirect.gql.ts +12 -0
- package/hooks/UseCartRedirect.graphql +5 -0
- package/hooks/UseMergeCustomerCart.gql.ts +13 -0
- package/hooks/UseMergeCustomerCart.graphql +6 -0
- package/hooks/index.ts +8 -0
- package/hooks/useAssignCurrentCartId.ts +18 -0
- package/hooks/useCartIdCreate.ts +22 -0
- package/hooks/useCartQuery.ts +37 -0
- package/hooks/useClearCurrentCartId.ts +18 -0
- package/hooks/useCurrentCartId.ts +6 -0
- package/hooks/useDisplayInclTax.ts +7 -0
- package/hooks/useFormGqlMutationCart.ts +28 -0
- package/hooks/useMergeCustomerCart.ts +49 -0
- package/index.ts +4 -0
- package/next-env.d.ts +4 -0
- package/package.json +42 -0
- package/tsconfig.json +5 -0
- package/typePolicies.ts +56 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Divider, makeStyles, Theme } from '@material-ui/core'
|
|
2
|
+
import { Money, MoneyProps } from '@graphcommerce/magento-store'
|
|
3
|
+
import { AnimatedRow, UseStyles } from '@graphcommerce/next-ui'
|
|
4
|
+
import clsx from 'clsx'
|
|
5
|
+
import { AnimatePresence } from 'framer-motion'
|
|
6
|
+
import React from 'react'
|
|
7
|
+
import { useCartQuery, useDisplayInclTax } from '../../hooks'
|
|
8
|
+
import { GetCartTotalsDocument } from './GetCartTotals.gql'
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles(
|
|
11
|
+
(theme: Theme) => ({
|
|
12
|
+
costsContainer: {
|
|
13
|
+
borderRadius: 4,
|
|
14
|
+
background: '#FFFADD',
|
|
15
|
+
padding: `${theme.spacings.xs} ${theme.spacings.sm}`,
|
|
16
|
+
},
|
|
17
|
+
containerMarginTop: {
|
|
18
|
+
marginTop: theme.spacings.md,
|
|
19
|
+
},
|
|
20
|
+
costsDivider: {
|
|
21
|
+
margin: `1em 0`,
|
|
22
|
+
},
|
|
23
|
+
costsRow: {
|
|
24
|
+
display: 'flex',
|
|
25
|
+
justifyContent: 'space-between',
|
|
26
|
+
...theme.typography.subtitle1,
|
|
27
|
+
},
|
|
28
|
+
costsGrandTotal: {
|
|
29
|
+
fontWeight: theme.typography.fontWeightBold,
|
|
30
|
+
color: theme.palette.primary.main,
|
|
31
|
+
},
|
|
32
|
+
costsDiscount: {
|
|
33
|
+
fontWeight: theme.typography.fontWeightBold,
|
|
34
|
+
},
|
|
35
|
+
costsDiscountSub: {
|
|
36
|
+
fontWeight: theme.typography.fontWeightBold,
|
|
37
|
+
},
|
|
38
|
+
costsTax: {
|
|
39
|
+
color: theme.palette.primary.mutedText,
|
|
40
|
+
paddingTop: 0,
|
|
41
|
+
},
|
|
42
|
+
money: {
|
|
43
|
+
whiteSpace: 'nowrap',
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
{ name: 'CartTotals' },
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export type CartTotalsProps = { containerMargin?: boolean } & UseStyles<typeof useStyles>
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* ⚠️ WARNING: The current CartTotals rely heavily on how Magento is configured. It kinda works for
|
|
53
|
+
* the demo, but we need additional fields from the API to get this working as expected:
|
|
54
|
+
*
|
|
55
|
+
* @see https://github.com/magento/magento2/issues/33848
|
|
56
|
+
* @see https://github.com/magento/magento2/issues?q=is%3Aopen+is%3Aissue+label%3A%22Project%3A+GraphQL%22+tax
|
|
57
|
+
*/
|
|
58
|
+
export default function CartTotals(props: CartTotalsProps) {
|
|
59
|
+
const { data } = useCartQuery(GetCartTotalsDocument, { allowUrl: true })
|
|
60
|
+
const classes = useStyles(props)
|
|
61
|
+
const inclTax = useDisplayInclTax()
|
|
62
|
+
|
|
63
|
+
if (!data?.cart) return null
|
|
64
|
+
|
|
65
|
+
const { containerMargin } = props
|
|
66
|
+
const { shipping_addresses, prices } = data.cart
|
|
67
|
+
const shippingMethod = shipping_addresses?.[0]?.selected_shipping_method
|
|
68
|
+
const shippingMethodPrices = shipping_addresses?.[0]?.available_shipping_methods?.find(
|
|
69
|
+
(avail) =>
|
|
70
|
+
(shippingMethod?.amount.value ?? 0) > 0 &&
|
|
71
|
+
avail?.carrier_code === shippingMethod?.carrier_code &&
|
|
72
|
+
avail?.method_code === shippingMethod?.method_code,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<AnimatedRow
|
|
77
|
+
className={clsx(
|
|
78
|
+
containerMargin ? classes.containerMarginTop : undefined,
|
|
79
|
+
classes.costsContainer,
|
|
80
|
+
)}
|
|
81
|
+
key='total-costs'
|
|
82
|
+
>
|
|
83
|
+
<AnimatePresence initial={false}>
|
|
84
|
+
{prices?.subtotal_including_tax && (
|
|
85
|
+
<AnimatedRow className={classes.costsRow} key='subtotal'>
|
|
86
|
+
<div>Products</div>
|
|
87
|
+
<div className={classes.money}>
|
|
88
|
+
<Money
|
|
89
|
+
{...(inclTax ? prices.subtotal_including_tax : prices.subtotal_excluding_tax)}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
</AnimatedRow>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
{/* {prices?.discounts && prices.discounts.length > 1 && (
|
|
96
|
+
<AnimatedRow className={clsx(classes.costsRow, classes.costsDiscount)} key='discount'>
|
|
97
|
+
<div>Product discount</div>
|
|
98
|
+
<div className={classes.money}>
|
|
99
|
+
<Money
|
|
100
|
+
currency={prices.subtotal_with_discount_excluding_tax?.currency}
|
|
101
|
+
value={
|
|
102
|
+
(prices.subtotal_excluding_tax?.value ?? 0) * -1 -
|
|
103
|
+
(prices.subtotal_with_discount_excluding_tax?.value ?? 0) * -1
|
|
104
|
+
}
|
|
105
|
+
/>
|
|
106
|
+
</div>
|
|
107
|
+
</AnimatedRow>
|
|
108
|
+
)} */}
|
|
109
|
+
|
|
110
|
+
{prices?.discounts?.map((discount) => {
|
|
111
|
+
const value = inclTax
|
|
112
|
+
? (discount?.amount.value ?? 0) * -1
|
|
113
|
+
: (discount?.amount.value ?? 0) *
|
|
114
|
+
((prices.subtotal_excluding_tax?.value ?? 1) /
|
|
115
|
+
(prices.subtotal_including_tax?.value ?? 1)) *
|
|
116
|
+
-1
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<AnimatedRow
|
|
120
|
+
className={clsx(classes.costsRow, classes.costsDiscountSub)}
|
|
121
|
+
key={discount?.label}
|
|
122
|
+
>
|
|
123
|
+
<div>{discount?.label}</div>
|
|
124
|
+
<div className={classes.money}>
|
|
125
|
+
{discount?.amount && <Money {...discount} value={value} />}
|
|
126
|
+
</div>
|
|
127
|
+
</AnimatedRow>
|
|
128
|
+
)
|
|
129
|
+
})}
|
|
130
|
+
|
|
131
|
+
{shippingMethod && (
|
|
132
|
+
<AnimatedRow className={classes.costsRow} key='shippingMethod'>
|
|
133
|
+
<div>
|
|
134
|
+
Shipping ({shippingMethod.carrier_title} {shippingMethod.method_title})
|
|
135
|
+
</div>
|
|
136
|
+
<div className={classes.money}>
|
|
137
|
+
<Money
|
|
138
|
+
{...(inclTax
|
|
139
|
+
? shippingMethodPrices?.price_incl_tax
|
|
140
|
+
: shippingMethodPrices?.price_excl_tax)}
|
|
141
|
+
/>
|
|
142
|
+
</div>
|
|
143
|
+
</AnimatedRow>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{!inclTax &&
|
|
147
|
+
prices?.applied_taxes?.map((tax) => (
|
|
148
|
+
<AnimatedRow className={clsx(classes.costsRow)} key={`excl${tax?.label}`}>
|
|
149
|
+
<div>{tax?.label}</div>
|
|
150
|
+
<div className={classes.money}>
|
|
151
|
+
<Money {...tax?.amount} />
|
|
152
|
+
</div>
|
|
153
|
+
</AnimatedRow>
|
|
154
|
+
))}
|
|
155
|
+
|
|
156
|
+
<AnimatedRow key='divider'>
|
|
157
|
+
<Divider className={classes.costsDivider} />
|
|
158
|
+
</AnimatedRow>
|
|
159
|
+
|
|
160
|
+
{prices?.grand_total && (
|
|
161
|
+
<AnimatedRow
|
|
162
|
+
className={clsx(classes.costsRow, classes.costsGrandTotal)}
|
|
163
|
+
key='grand_total'
|
|
164
|
+
>
|
|
165
|
+
<div>Grand total</div>
|
|
166
|
+
<div className={classes.money}>
|
|
167
|
+
<Money {...prices.grand_total} />
|
|
168
|
+
</div>
|
|
169
|
+
</AnimatedRow>
|
|
170
|
+
)}
|
|
171
|
+
|
|
172
|
+
{inclTax &&
|
|
173
|
+
prices?.applied_taxes?.map((tax) => (
|
|
174
|
+
<AnimatedRow
|
|
175
|
+
className={clsx(classes.costsRow, classes.costsTax)}
|
|
176
|
+
key={`incl${tax?.label}`}
|
|
177
|
+
>
|
|
178
|
+
<div>Including {tax?.label}</div>
|
|
179
|
+
<div className={classes.money}>
|
|
180
|
+
<Money {...tax?.amount} />
|
|
181
|
+
</div>
|
|
182
|
+
</AnimatedRow>
|
|
183
|
+
))}
|
|
184
|
+
</AnimatePresence>
|
|
185
|
+
</AnimatedRow>
|
|
186
|
+
)
|
|
187
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as Types from '@graphcommerce/graphql';
|
|
3
|
+
|
|
4
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
5
|
+
|
|
6
|
+
export const GetCartTotalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetCartTotals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cartId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cart"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"cart_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cartId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shipping_addresses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"selected_shipping_method"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"carrier_code"}},{"kind":"Field","name":{"kind":"Name","value":"method_code"}},{"kind":"Field","name":{"kind":"Name","value":"method_title"}},{"kind":"Field","name":{"kind":"Name","value":"carrier_title"}},{"kind":"Field","name":{"kind":"Name","value":"amount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"available_shipping_methods"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"carrier_code"}},{"kind":"Field","name":{"kind":"Name","value":"method_code"}},{"kind":"Field","name":{"kind":"Name","value":"price_incl_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"price_excl_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"prices"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"applied_taxes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"amount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"discounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"amount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"grand_total"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"subtotal_excluding_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"subtotal_including_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"subtotal_with_discount_excluding_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetCartTotalsQuery, GetCartTotalsQueryVariables>;
|
|
7
|
+
export type GetCartTotalsQueryVariables = Types.Exact<{
|
|
8
|
+
cartId: Types.Scalars['String'];
|
|
9
|
+
}>;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export type GetCartTotalsQuery = { cart?: Types.Maybe<{ shipping_addresses: Array<Types.Maybe<{ selected_shipping_method?: Types.Maybe<{ carrier_code: string, method_code: string, method_title: string, carrier_title: string, amount: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>, available_shipping_methods?: Types.Maybe<Array<Types.Maybe<{ carrier_code: string, method_code?: Types.Maybe<string>, price_incl_tax: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }, price_excl_tax: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>>> }>>, prices?: Types.Maybe<{ __typename: 'CartPrices', applied_taxes?: Types.Maybe<Array<Types.Maybe<{ label: string, amount: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>>>, discounts?: Types.Maybe<Array<Types.Maybe<{ label: string, amount: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>>>, grand_total?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }>, subtotal_excluding_tax?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }>, subtotal_including_tax?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }>, subtotal_with_discount_excluding_tax?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }> }> }> };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { makeStyles, Theme, Typography } from '@material-ui/core'
|
|
2
|
+
import { responsiveVal, SvgImage, iconSadShoppingBag } from '@graphcommerce/next-ui'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
const useStyles = makeStyles(
|
|
6
|
+
(theme: Theme) => ({
|
|
7
|
+
root: {
|
|
8
|
+
textAlign: 'center',
|
|
9
|
+
display: 'flex',
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
[theme.breakpoints.down('sm')]: {
|
|
13
|
+
minHeight: '70vh',
|
|
14
|
+
},
|
|
15
|
+
[theme.breakpoints.up('md')]: {
|
|
16
|
+
minHeight: '60vh',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
img: {
|
|
20
|
+
display: 'block',
|
|
21
|
+
margin: `0 auto ${theme.spacings.xxs} auto`,
|
|
22
|
+
width: responsiveVal(120, 180),
|
|
23
|
+
height: responsiveVal(120, 180),
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
{ name: 'EmptyCart' },
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
type EmptyCartProps = { children?: React.ReactNode }
|
|
30
|
+
export default function EmptyCart(props: EmptyCartProps) {
|
|
31
|
+
const { children } = props
|
|
32
|
+
const classes = useStyles()
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className={classes.root}>
|
|
36
|
+
<div>
|
|
37
|
+
<SvgImage
|
|
38
|
+
src={iconSadShoppingBag}
|
|
39
|
+
alt='Empty Cart'
|
|
40
|
+
className={classes.img}
|
|
41
|
+
loading='eager'
|
|
42
|
+
size='large'
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
{children ?? (
|
|
46
|
+
<>
|
|
47
|
+
<Typography variant='h3' gutterBottom component='h1'>
|
|
48
|
+
Your cart is empty
|
|
49
|
+
</Typography>
|
|
50
|
+
<Typography>Discover our collection and add items to your basket!</Typography>
|
|
51
|
+
</>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from './AddToCartButton/AddToCartButton'
|
|
2
|
+
export { default as AddToCartButton } from './AddToCartButton/AddToCartButton'
|
|
3
|
+
|
|
4
|
+
export * from './CartFab/CartFab'
|
|
5
|
+
export { default as CartFab } from './CartFab/CartFab'
|
|
6
|
+
|
|
7
|
+
export * from './CartStartCheckout/CartStartCheckout'
|
|
8
|
+
export { default as CartStartCheckout } from './CartStartCheckout/CartStartCheckout'
|
|
9
|
+
|
|
10
|
+
export * from './CartTotals/CartTotals'
|
|
11
|
+
export { default as CartTotals } from './CartTotals/CartTotals'
|
|
12
|
+
|
|
13
|
+
export { default as EmptyCart } from './EmptyCart/EmptyCart'
|
|
14
|
+
|
|
15
|
+
export { default as ApolloCartErrorAlert } from './ApolloCartError/ApolloCartErrorAlert'
|
|
16
|
+
export * from './ApolloCartError/ApolloCartErrorAlert'
|
|
17
|
+
|
|
18
|
+
// export { default as ApolloCartErrorFullPage } from './ApolloCartError/ApolloCartErrorFullPage'
|
|
19
|
+
// export * from './ApolloCartError/ApolloCartErrorFullPage'
|
|
20
|
+
|
|
21
|
+
export * from './CartSummary'
|
|
22
|
+
export { default as CartSummary } from './CartSummary'
|
|
23
|
+
|
|
24
|
+
export { default as CartItemSummary } from './CartItemSummary'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as Types from '@graphcommerce/graphql';
|
|
3
|
+
|
|
4
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
5
|
+
|
|
6
|
+
export const CreateEmptyCartDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateEmptyCart"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createEmptyCart"}}]}}]} as unknown as DocumentNode<CreateEmptyCartMutation, CreateEmptyCartMutationVariables>;
|
|
7
|
+
export type CreateEmptyCartMutationVariables = Types.Exact<{ [key: string]: never; }>;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export type CreateEmptyCartMutation = { createEmptyCart?: Types.Maybe<string> };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as Types from '@graphcommerce/graphql';
|
|
3
|
+
|
|
4
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
5
|
+
|
|
6
|
+
export const CurrentCartIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CurrentCartId"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentCartId"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<CurrentCartIdQuery, CurrentCartIdQueryVariables>;
|
|
7
|
+
export type CurrentCartIdQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export type CurrentCartIdQuery = { currentCartId?: Types.Maybe<{ __typename: 'CurrentCartId', id?: Types.Maybe<string> }> };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as Types from '@graphcommerce/graphql';
|
|
3
|
+
|
|
4
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
5
|
+
|
|
6
|
+
export const CustomerCartDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CustomerCart"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"customerCart"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"uid"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total_quantity"}},{"kind":"Field","name":{"kind":"Name","value":"prices"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"grand_total"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"applied_taxes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"amount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"discounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"amount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"subtotal_excluding_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"subtotal_including_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"subtotal_with_discount_excluding_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"shipping_addresses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"selected_shipping_method"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"carrier_code"}},{"kind":"Field","name":{"kind":"Name","value":"method_code"}},{"kind":"Field","name":{"kind":"Name","value":"method_title"}},{"kind":"Field","name":{"kind":"Name","value":"carrier_title"}},{"kind":"Field","name":{"kind":"Name","value":"amount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"available_shipping_methods"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"carrier_code"}},{"kind":"Field","name":{"kind":"Name","value":"method_code"}},{"kind":"Field","name":{"kind":"Name","value":"price_incl_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"price_excl_tax"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<CustomerCartQuery, CustomerCartQueryVariables>;
|
|
7
|
+
export type CustomerCartQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export type CustomerCartQuery = { customerCart: { __typename: 'Cart', id: string, total_quantity: number, items?: Types.Maybe<Array<Types.Maybe<{ __typename: 'BundleCartItem', uid: string, quantity: number } | { __typename: 'ConfigurableCartItem', uid: string, quantity: number } | { __typename: 'DownloadableCartItem', uid: string, quantity: number } | { __typename: 'SimpleCartItem', uid: string, quantity: number } | { __typename: 'VirtualCartItem', uid: string, quantity: number }>>>, prices?: Types.Maybe<{ __typename: 'CartPrices', grand_total?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }>, applied_taxes?: Types.Maybe<Array<Types.Maybe<{ label: string, amount: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>>>, discounts?: Types.Maybe<Array<Types.Maybe<{ label: string, amount: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>>>, subtotal_excluding_tax?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }>, subtotal_including_tax?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }>, subtotal_with_discount_excluding_tax?: Types.Maybe<{ currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }> }>, shipping_addresses: Array<Types.Maybe<{ selected_shipping_method?: Types.Maybe<{ carrier_code: string, method_code: string, method_title: string, carrier_title: string, amount: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>, available_shipping_methods?: Types.Maybe<Array<Types.Maybe<{ carrier_code: string, method_code?: Types.Maybe<string>, price_incl_tax: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> }, price_excl_tax: { currency?: Types.Maybe<Types.CurrencyEnum>, value?: Types.Maybe<number> } }>>> }>> } };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as Types from '@graphcommerce/graphql';
|
|
3
|
+
|
|
4
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
5
|
+
|
|
6
|
+
export const UseCartRedirectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UseCartRedirect"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cartId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cart"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"cart_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cartId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<UseCartRedirectQuery, UseCartRedirectQueryVariables>;
|
|
7
|
+
export type UseCartRedirectQueryVariables = Types.Exact<{
|
|
8
|
+
cartId: Types.Scalars['String'];
|
|
9
|
+
}>;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export type UseCartRedirectQuery = { cart?: Types.Maybe<{ id: string }> };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as Types from '@graphcommerce/graphql';
|
|
3
|
+
|
|
4
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
5
|
+
|
|
6
|
+
export const UseMergeCustomerCartDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UseMergeCustomerCart"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sourceCartId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"destinationCartId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"mergeCarts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"source_cart_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sourceCartId"}}},{"kind":"Argument","name":{"kind":"Name","value":"destination_cart_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"destinationCartId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<UseMergeCustomerCartMutation, UseMergeCustomerCartMutationVariables>;
|
|
7
|
+
export type UseMergeCustomerCartMutationVariables = Types.Exact<{
|
|
8
|
+
sourceCartId: Types.Scalars['String'];
|
|
9
|
+
destinationCartId: Types.Scalars['String'];
|
|
10
|
+
}>;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export type UseMergeCustomerCartMutation = { mergeCarts: { __typename: 'Cart', id: string } };
|
package/hooks/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './useAssignCurrentCartId'
|
|
2
|
+
export * from './useCurrentCartId'
|
|
3
|
+
export * from './useCartQuery'
|
|
4
|
+
export * from './useClearCurrentCartId'
|
|
5
|
+
export * from './useCartIdCreate'
|
|
6
|
+
export * from './useFormGqlMutationCart'
|
|
7
|
+
export * from './useMergeCustomerCart'
|
|
8
|
+
export * from './useDisplayInclTax'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useApolloClient } from '@apollo/client'
|
|
2
|
+
import { useCallback } from 'react'
|
|
3
|
+
import { CurrentCartIdDocument } from './CurrentCartId.gql'
|
|
4
|
+
|
|
5
|
+
export function useAssignCurrentCartId() {
|
|
6
|
+
const { cache } = useApolloClient()
|
|
7
|
+
|
|
8
|
+
return useCallback(
|
|
9
|
+
(id: string) => {
|
|
10
|
+
cache.writeQuery({
|
|
11
|
+
query: CurrentCartIdDocument,
|
|
12
|
+
data: { currentCartId: { __typename: 'CurrentCartId', id } },
|
|
13
|
+
broadcast: true,
|
|
14
|
+
})
|
|
15
|
+
},
|
|
16
|
+
[cache],
|
|
17
|
+
)
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useMutation } from '@apollo/client'
|
|
2
|
+
import { CreateEmptyCartDocument } from './CreateEmptyCart.gql'
|
|
3
|
+
import { useAssignCurrentCartId } from './useAssignCurrentCartId'
|
|
4
|
+
import { useCurrentCartId } from './useCurrentCartId'
|
|
5
|
+
|
|
6
|
+
export function useCartIdCreate() {
|
|
7
|
+
const cartId = useCurrentCartId()
|
|
8
|
+
const [create] = useMutation(CreateEmptyCartDocument)
|
|
9
|
+
const assignCurrentCartId = useAssignCurrentCartId()
|
|
10
|
+
|
|
11
|
+
return async (): Promise<string> => {
|
|
12
|
+
if (cartId) return cartId
|
|
13
|
+
|
|
14
|
+
const { data } = await create()
|
|
15
|
+
if (!data?.createEmptyCart) throw Error('Could not create an empty cart')
|
|
16
|
+
|
|
17
|
+
// We store the cartId that is returned as the currentCartId result
|
|
18
|
+
assignCurrentCartId(data.createEmptyCart)
|
|
19
|
+
|
|
20
|
+
return data.createEmptyCart
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useQuery, TypedDocumentNode, QueryHookOptions } from '@apollo/client'
|
|
2
|
+
import { useRouter } from 'next/router'
|
|
3
|
+
import { useCurrentCartId } from './useCurrentCartId'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Requires the query to have a `$cartId: String!` argument. It will automatically inject the
|
|
7
|
+
* currently active cart_id.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const { data } = useCartQuery(CartFabQueryDocument)
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function useCartQuery<Q, V extends { cartId: string; [index: string]: unknown }>(
|
|
16
|
+
document: TypedDocumentNode<Q, V>,
|
|
17
|
+
options: QueryHookOptions<Q, Omit<V, 'cartId'>> & { allowUrl?: boolean } = {},
|
|
18
|
+
) {
|
|
19
|
+
const { allowUrl = false, ...queryOptions } = options
|
|
20
|
+
|
|
21
|
+
const router = useRouter()
|
|
22
|
+
const currentCartId = useCurrentCartId()
|
|
23
|
+
const urlCartId = router.query.cartId
|
|
24
|
+
const usingUrl = allowUrl && typeof urlCartId === 'string'
|
|
25
|
+
|
|
26
|
+
const cartId = usingUrl ? urlCartId : currentCartId
|
|
27
|
+
|
|
28
|
+
if (usingUrl && typeof queryOptions.fetchPolicy === 'undefined')
|
|
29
|
+
queryOptions.fetchPolicy = 'cache-only'
|
|
30
|
+
if (usingUrl && typeof queryOptions.returnPartialData === 'undefined')
|
|
31
|
+
queryOptions.returnPartialData = true
|
|
32
|
+
queryOptions.variables = { cartId, ...options?.variables } as V
|
|
33
|
+
queryOptions.skip = queryOptions?.skip || !cartId
|
|
34
|
+
queryOptions.ssr = false
|
|
35
|
+
|
|
36
|
+
return useQuery(document, queryOptions)
|
|
37
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useApolloClient } from '@apollo/client'
|
|
2
|
+
import { CurrentCartIdDocument } from './CurrentCartId.gql'
|
|
3
|
+
import { useCurrentCartId } from './useCurrentCartId'
|
|
4
|
+
|
|
5
|
+
export function useClearCurrentCartId() {
|
|
6
|
+
const { cache } = useApolloClient()
|
|
7
|
+
const currentCartId = useCurrentCartId()
|
|
8
|
+
|
|
9
|
+
if (!currentCartId) return undefined
|
|
10
|
+
|
|
11
|
+
return () => {
|
|
12
|
+
cache.writeQuery({
|
|
13
|
+
query: CurrentCartIdDocument,
|
|
14
|
+
data: { currentCartId: { __typename: 'CurrentCartId', id: null } },
|
|
15
|
+
broadcast: true,
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useRouter } from 'next/router'
|
|
2
|
+
|
|
3
|
+
export function useDisplayInclTax(): boolean {
|
|
4
|
+
const { locale } = useRouter()
|
|
5
|
+
const locales = (process.env.NEXT_PUBLIC_DISPLAY_INCL_TAX ?? '').split(',').map((i) => i.trim())
|
|
6
|
+
return locale ? locales.includes(locale) : false
|
|
7
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MutationHookOptions, TypedDocumentNode } from '@apollo/client'
|
|
2
|
+
import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
|
|
3
|
+
import {
|
|
4
|
+
useFormGqlMutation,
|
|
5
|
+
UseFormGqlMutationReturn,
|
|
6
|
+
UseFormGraphQlOptions,
|
|
7
|
+
} from '@graphcommerce/react-hook-form'
|
|
8
|
+
import { useCartIdCreate } from './useCartIdCreate'
|
|
9
|
+
|
|
10
|
+
export function useFormGqlMutationCart<Q, V extends { cartId: string; [index: string]: unknown }>(
|
|
11
|
+
document: TypedDocumentNode<Q, V>,
|
|
12
|
+
options: UseFormGraphQlOptions<Q, V> = {},
|
|
13
|
+
operationOptions?: MutationHookOptions<Q, V>,
|
|
14
|
+
): UseFormGqlMutationReturn<Q, V> {
|
|
15
|
+
const cartId = useCartIdCreate()
|
|
16
|
+
|
|
17
|
+
const onBeforeSubmit = async (variables: V) => {
|
|
18
|
+
const vars = { ...variables, cartId: await cartId() }
|
|
19
|
+
return options.onBeforeSubmit ? options.onBeforeSubmit(vars) : vars
|
|
20
|
+
}
|
|
21
|
+
const result = useFormGqlMutation<Q, V>(
|
|
22
|
+
document,
|
|
23
|
+
{ ...options, onBeforeSubmit },
|
|
24
|
+
{ errorPolicy: 'all', ...operationOptions },
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return result
|
|
28
|
+
}
|