@graphcommerce/magento-cart 4.6.9 → 4.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.7.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`755d2cf83`](https://github.com/graphcommerce-org/graphcommerce/commit/755d2cf83343a5ad3d61063eff595d821de360aa), [`dc7f2dda4`](https://github.com/graphcommerce-org/graphcommerce/commit/dc7f2dda40ff8572fc11161de6eb62ca13e720dd)]:
8
+ - @graphcommerce/next-ui@4.23.0
9
+ - @graphcommerce/ecommerce-ui@1.2.1
10
+ - @graphcommerce/framer-scroller@2.1.34
11
+ - @graphcommerce/magento-customer@4.10.2
12
+ - @graphcommerce/magento-store@4.2.30
13
+
14
+ ## 4.7.1
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies []:
19
+ - @graphcommerce/magento-customer@4.10.1
20
+ - @graphcommerce/magento-store@4.2.29
21
+
22
+ ## 4.7.0
23
+
24
+ ### Minor Changes
25
+
26
+ - [#1602](https://github.com/graphcommerce-org/graphcommerce/pull/1602) [`5f781a217`](https://github.com/graphcommerce-org/graphcommerce/commit/5f781a217ce63ed56bc1a9983487b04400a8a315) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Default styles and layout fixes
27
+
28
+ - Scaled icons and fonts down. Size in typography is now more gradual: https://graphcommerce.vercel.app/test/typography
29
+ - Multiple accessibility fixes. Missing button/input labels, and fixed spacing issues resulting in high % appropriately sized tap targets
30
+ - Replaced responsiveVal usage with better performaning breakpointVal where possible
31
+ - All buttons are now Pill by default.
32
+ - Cleaned up checkout styles
33
+
34
+ * [#1608](https://github.com/graphcommerce-org/graphcommerce/pull/1608) [`ac6eedbb1`](https://github.com/graphcommerce-org/graphcommerce/commit/ac6eedbb14d3abd8cf1231a98dc2a8b7f4659f1f) Thanks [@mikekeehnen](https://github.com/mikekeehnen)! - Added global errorhandling on cart errors. When a cart query return an error, the currentCartId wil be renewed with the actual cartId when the user is authenticated. When there is an error in a guest cart, a new cartId will be generated and the cart will be empty
35
+
36
+ ### Patch Changes
37
+
38
+ - [#1609](https://github.com/graphcommerce-org/graphcommerce/pull/1609) [`e573278e4`](https://github.com/graphcommerce-org/graphcommerce/commit/e573278e43506a6b17a2981e61d0e9fad41eb2eb) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Remove Cart error message when there isn’t a cart present yet
39
+
40
+ - Updated dependencies [[`04708dacc`](https://github.com/graphcommerce-org/graphcommerce/commit/04708daccc213c6ea927bc67fa3bd0d5b1fad619), [`bb94e7045`](https://github.com/graphcommerce-org/graphcommerce/commit/bb94e7045460cb671c45d612a0833731d7c20c30), [`b0dc4e2e1`](https://github.com/graphcommerce-org/graphcommerce/commit/b0dc4e2e1982d502d38dd50a0f493396360a7a15), [`4a5286dfe`](https://github.com/graphcommerce-org/graphcommerce/commit/4a5286dfeaa1719e594a0078f274fbab53969c4e), [`0ad5159eb`](https://github.com/graphcommerce-org/graphcommerce/commit/0ad5159ebef54b4ce7fee6f71b4bf710dba9ef8e), [`d46d5ed0c`](https://github.com/graphcommerce-org/graphcommerce/commit/d46d5ed0cc5794391b7527fc17bbb68ec2212e33), [`5f781a217`](https://github.com/graphcommerce-org/graphcommerce/commit/5f781a217ce63ed56bc1a9983487b04400a8a315), [`01372b918`](https://github.com/graphcommerce-org/graphcommerce/commit/01372b918a291e01cbf5db40edcb40fb1c2af313)]:
41
+ - @graphcommerce/next-ui@4.22.0
42
+ - @graphcommerce/ecommerce-ui@1.2.0
43
+ - @graphcommerce/magento-customer@4.10.0
44
+ - @graphcommerce/framer-next-pages@3.3.0
45
+ - @graphcommerce/framer-utils@3.2.0
46
+ - @graphcommerce/magento-store@4.2.28
47
+ - @graphcommerce/framer-scroller@2.1.33
48
+ - @graphcommerce/graphql@3.4.7
49
+ - @graphcommerce/image@3.1.9
50
+ - @graphcommerce/magento-graphql@3.1.7
51
+
3
52
  ## 4.6.9
4
53
 
5
54
  ### Patch Changes
@@ -2,31 +2,9 @@ import {
2
2
  ApolloCustomerErrorAlert,
3
3
  ApolloCustomerErrorAlertProps,
4
4
  } from '@graphcommerce/magento-customer'
5
- import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
6
- import { Trans } from '@lingui/react'
7
- import { Button } from '@mui/material'
8
- import { useClearCurrentCartId } from '../../hooks/useClearCurrentCartId'
9
5
 
10
6
  export type ApolloCartErrorAlertProps = ApolloCustomerErrorAlertProps
11
7
 
12
8
  export function ApolloCartErrorAlert(props: ApolloCartErrorAlertProps) {
13
- const { error, graphqlErrorAlertProps } = props
14
- const clear = useClearCurrentCartId()
15
-
16
- const [, noSuchEntity] = graphqlErrorByCategory({ category: 'graphql-no-such-entity', error })
17
-
18
- return (
19
- <ApolloCustomerErrorAlert
20
- {...props}
21
- graphqlErrorAlertProps={{
22
- action: noSuchEntity ? (
23
- <Button onClick={clear}>
24
- <Trans id='Reset Cart' />
25
- </Button>
26
- ) : (
27
- graphqlErrorAlertProps?.action
28
- ),
29
- }}
30
- />
31
- )
9
+ return <ApolloCustomerErrorAlert {...props} />
32
10
  }
@@ -2,49 +2,12 @@ import {
2
2
  ApolloCustomerErrorFullPage,
3
3
  ApolloCustomerErrorFullPageProps,
4
4
  } from '@graphcommerce/magento-customer'
5
- import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
6
5
  import { iconShoppingBag, IconSvg } from '@graphcommerce/next-ui'
7
- import { Trans } from '@lingui/react'
8
- import { Button } from '@mui/material'
9
- import { useCurrentCartId } from '../../hooks'
10
- import { useClearCurrentCartId } from '../../hooks/useClearCurrentCartId'
11
- import { EmptyCart } from '../EmptyCart/EmptyCart'
12
6
 
13
7
  export type ApolloCartErrorFullPageProps = Omit<ApolloCustomerErrorFullPageProps, 'icon'>
14
8
 
15
9
  export function ApolloCartErrorFullPage(props: ApolloCartErrorFullPageProps) {
16
- const { error, button } = props
17
- const clear = useClearCurrentCartId()
18
- const { currentCartId } = useCurrentCartId()
19
-
20
- const [, noSuchEntity] = graphqlErrorByCategory({ category: 'graphql-no-such-entity', error })
21
-
22
- if (noSuchEntity)
23
- return (
24
- <EmptyCart
25
- button={
26
- currentCartId ? (
27
- <Button onClick={clear}>
28
- <Trans id='Reset Cart' />
29
- </Button>
30
- ) : undefined
31
- }
32
- />
33
- )
34
-
35
10
  return (
36
- <ApolloCustomerErrorFullPage
37
- {...props}
38
- icon={<IconSvg src={iconShoppingBag} size='xxl' />}
39
- button={
40
- noSuchEntity ? (
41
- <Button onClick={clear}>
42
- <Trans id='Reset Cart' />
43
- </Button>
44
- ) : (
45
- button
46
- )
47
- }
48
- />
11
+ <ApolloCustomerErrorFullPage {...props} icon={<IconSvg src={iconShoppingBag} size='xxl' />} />
49
12
  )
50
13
  }
@@ -10,23 +10,5 @@ import { useClearCurrentCartId } from '../../hooks/useClearCurrentCartId'
10
10
  export type ApolloCartErrorSnackbarProps = ApolloCustomerErrorSnackbarProps
11
11
 
12
12
  export function ApolloCartErrorSnackbar(props: ApolloCartErrorSnackbarProps) {
13
- const { error, action } = props
14
- const clear = useClearCurrentCartId()
15
-
16
- const [, noSuchEntity] = graphqlErrorByCategory({ category: 'graphql-no-such-entity', error })
17
-
18
- return (
19
- <ApolloCustomerErrorSnackbar
20
- {...props}
21
- action={
22
- noSuchEntity ? (
23
- <Button onClick={clear} variant='pill' color='secondary'>
24
- <Trans id='Reset Cart' />
25
- </Button>
26
- ) : (
27
- action
28
- )
29
- }
30
- />
31
- )
13
+ return <ApolloCustomerErrorSnackbar {...props} />
32
14
  }
@@ -0,0 +1,38 @@
1
+ import { useApolloClient } from '@graphcommerce/graphql'
2
+ import { Button } from '@mui/material'
3
+ import { CurrentCartIdDocument } from '../../hooks/CurrentCartId.gql'
4
+
5
+ export function CartDebugger() {
6
+ const client = useApolloClient()
7
+
8
+ return (
9
+ <div style={{ position: 'fixed', bottom: 0, right: 0, zIndex: 1, opacity: 0.3 }}>
10
+ <Button
11
+ type='button'
12
+ variant='text'
13
+ size='small'
14
+ onClick={() => {
15
+ const currentCardId = client.readQuery({ query: CurrentCartIdDocument })
16
+ if (!currentCardId?.currentCartId) {
17
+ console.log('No customerToken available, nothing to break')
18
+ } else {
19
+ console.log(`Changing current token to a random one)`)
20
+
21
+ client.writeQuery({
22
+ query: CurrentCartIdDocument,
23
+ data: {
24
+ currentCartId: {
25
+ ...currentCardId.currentCartId,
26
+ id: `${Math.random().toString(36).slice(2)}random-cardId`,
27
+ },
28
+ },
29
+ broadcast: true,
30
+ })
31
+ }
32
+ }}
33
+ >
34
+ break cart
35
+ </Button>
36
+ </div>
37
+ )
38
+ }
@@ -7,6 +7,7 @@ import {
7
7
  SectionContainer,
8
8
  IconSvg,
9
9
  extendableComponent,
10
+ breakpointVal,
10
11
  } from '@graphcommerce/next-ui'
11
12
  import { Trans } from '@lingui/react'
12
13
  import { Box, Divider, SxProps, Theme } from '@mui/material'
@@ -47,7 +48,12 @@ export function CartItemSummary(props: OrderSummaryProps) {
47
48
  (theme) => ({
48
49
  padding: `${theme.spacings.sm} ${theme.spacings.sm}`,
49
50
  border: `1px ${theme.palette.divider} solid`,
50
- borderRadius: '4px',
51
+ ...breakpointVal(
52
+ 'borderRadius',
53
+ theme.shape.borderRadius * 2,
54
+ theme.shape.borderRadius * 3,
55
+ theme.breakpoints.values,
56
+ ),
51
57
  }),
52
58
  ...(Array.isArray(sx) ? sx : [sx]),
53
59
  ]}
@@ -65,9 +71,6 @@ export function CartItemSummary(props: OrderSummaryProps) {
65
71
  <Box
66
72
  className={classes.imageScrollerContainer}
67
73
  sx={(theme) => ({
68
- display: 'flex',
69
- alignItems: 'center',
70
- gap: theme.spacings.sm,
71
74
  position: 'relative',
72
75
  })}
73
76
  >
@@ -137,7 +140,7 @@ export function CartItemSummary(props: OrderSummaryProps) {
137
140
  />
138
141
  <CartTotals
139
142
  sx={(theme) => ({
140
- background: theme.palette.background.default,
143
+ background: 'none',
141
144
  padding: 0,
142
145
  })}
143
146
  />
@@ -1,7 +1,7 @@
1
1
  import { useHistoryLink } from '@graphcommerce/framer-next-pages'
2
- import { SectionContainer, extendableComponent } from '@graphcommerce/next-ui'
2
+ import { SectionContainer, extendableComponent, breakpointVal } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
- import { Box, Link, SxProps, Theme, Typography } from '@mui/material'
4
+ import { Box, Link, SxProps, Theme, Typography, lighten } from '@mui/material'
5
5
  import PageLink from 'next/link'
6
6
  import React from 'react'
7
7
  import { useCartQuery } from '../../hooks'
@@ -37,8 +37,20 @@ export function CartSummary(props: CartSummaryProps) {
37
37
  sx={[
38
38
  (theme) => ({
39
39
  margin: `${theme.spacings.sm} 0`,
40
- '& div:last-of-type': {
41
- borderRadius: '0 0 4px 4px',
40
+ '& > div:last-of-type': {
41
+ borderRadius: '0',
42
+ ...breakpointVal(
43
+ 'borderBottomLeftRadius',
44
+ theme.shape.borderRadius * 2,
45
+ theme.shape.borderRadius * 3,
46
+ theme.breakpoints.values,
47
+ ),
48
+ ...breakpointVal(
49
+ 'borderBottomRightRadius',
50
+ theme.shape.borderRadius * 2,
51
+ theme.shape.borderRadius * 3,
52
+ theme.breakpoints.values,
53
+ ),
42
54
  },
43
55
  }),
44
56
  ...(Array.isArray(sx) ? sx : [sx]),
@@ -47,8 +59,22 @@ export function CartSummary(props: CartSummaryProps) {
47
59
  <Box
48
60
  className={classes.detailsContainer}
49
61
  sx={(theme) => ({
50
- borderRadius: '4px 4px 0 0',
51
- background: theme.palette.mode === 'light' ? '#FFE10820' : theme.palette.background.paper,
62
+ ...breakpointVal(
63
+ 'borderTopLeftRadius',
64
+ theme.shape.borderRadius * 2,
65
+ theme.shape.borderRadius * 3,
66
+ theme.breakpoints.values,
67
+ ),
68
+ ...breakpointVal(
69
+ 'borderTopRightRadius',
70
+ theme.shape.borderRadius * 2,
71
+ theme.shape.borderRadius * 3,
72
+ theme.breakpoints.values,
73
+ ),
74
+ background:
75
+ theme.palette.mode === 'light'
76
+ ? theme.palette.background.default
77
+ : lighten(theme.palette.background.default, 0.15),
52
78
  padding: theme.spacings.sm,
53
79
  gridColumnGap: theme.spacings.xxl,
54
80
  gridRowGap: theme.spacings.sm,
@@ -1,8 +1,7 @@
1
1
  import { Money } from '@graphcommerce/magento-store'
2
- import { AnimatedRow, extendableComponent, responsiveVal } from '@graphcommerce/next-ui'
2
+ import { extendableComponent, breakpointVal } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
4
  import { Box, Divider, lighten, SxProps, Theme } from '@mui/material'
5
- import { AnimatePresence } from 'framer-motion'
6
5
  import { useRouter } from 'next/router'
7
6
  import { useCartQuery, useDisplayInclTax } from '../../hooks'
8
7
  import { GetCartTotalsDocument } from './GetCartTotals.gql'
@@ -50,15 +49,19 @@ export function CartTotals(props: CartTotalsProps) {
50
49
  )
51
50
 
52
51
  return (
53
- <AnimatedRow
54
- layout={animateLayout}
52
+ <Box
55
53
  className={classes.root}
56
54
  sx={[
57
55
  (theme) => ({
58
- borderRadius: responsiveVal(theme.shape.borderRadius * 3, theme.shape.borderRadius * 4),
56
+ ...breakpointVal(
57
+ 'borderRadius',
58
+ theme.shape.borderRadius * 3,
59
+ theme.shape.borderRadius * 5,
60
+ theme.breakpoints.values,
61
+ ),
59
62
  background:
60
63
  theme.palette.mode === 'light'
61
- ? '#FFE10820'
64
+ ? theme.palette.background.default
62
65
  : lighten(theme.palette.background.default, 0.15),
63
66
  padding: `${theme.spacings.xs} ${theme.spacings.sm}`,
64
67
 
@@ -70,137 +73,124 @@ export function CartTotals(props: CartTotalsProps) {
70
73
  ]}
71
74
  key='total-costs'
72
75
  >
73
- <AnimatePresence initial={false}>
74
- {prices?.subtotal_including_tax && (
75
- <AnimatedRow
76
- layout={animateLayout}
77
- className={classes.costsRow}
78
- key='subtotal'
79
- sx={{ display: 'flex', justifyContent: 'space-between', typography: 'subtitle1' }}
76
+ {prices?.subtotal_including_tax && (
77
+ <Box
78
+ className={classes.costsRow}
79
+ key='subtotal'
80
+ sx={{ display: 'flex', justifyContent: 'space-between' }}
81
+ >
82
+ <Box>
83
+ <Trans id='Products' />
84
+ </Box>
85
+ <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
86
+ <Money {...(inclTax ? prices.subtotal_including_tax : prices.subtotal_excluding_tax)} />
87
+ </Box>
88
+ </Box>
89
+ )}
90
+
91
+ {prices?.discounts?.map((discount) => {
92
+ const value = inclTax
93
+ ? (discount?.amount.value ?? 0) * -1
94
+ : (discount?.amount.value ?? 0) *
95
+ ((prices.subtotal_excluding_tax?.value ?? 1) /
96
+ (prices.subtotal_including_tax?.value ?? 1)) *
97
+ -1
98
+
99
+ return (
100
+ <Box
101
+ key={discount?.label}
102
+ sx={{
103
+ display: 'flex',
104
+ justifyContent: 'space-between',
105
+ }}
80
106
  >
81
- <Box>
82
- <Trans id='Products' />
83
- </Box>
107
+ <Box>{discount?.label}</Box>
84
108
  <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
85
- <Money
86
- {...(inclTax ? prices.subtotal_including_tax : prices.subtotal_excluding_tax)}
87
- />
109
+ {discount?.amount && <Money {...discount.amount} value={value} />}
88
110
  </Box>
89
- </AnimatedRow>
90
- )}
91
-
92
- {prices?.discounts?.map((discount) => {
93
- const value = inclTax
94
- ? (discount?.amount.value ?? 0) * -1
95
- : (discount?.amount.value ?? 0) *
96
- ((prices.subtotal_excluding_tax?.value ?? 1) /
97
- (prices.subtotal_including_tax?.value ?? 1)) *
98
- -1
99
-
100
- return (
101
- <AnimatedRow
102
- layout={animateLayout}
103
- key={discount?.label}
104
- sx={{
105
- display: 'flex',
106
- justifyContent: 'space-between',
107
- typography: 'subtitle1',
108
- }}
109
- >
110
- <Box>{discount?.label}</Box>
111
- <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
112
- {discount?.amount && <Money {...discount.amount} value={value} />}
113
- </Box>
114
- </AnimatedRow>
115
- )
116
- })}
117
-
118
- {shippingMethod && (
119
- <AnimatedRow
120
- layout={animateLayout}
111
+ </Box>
112
+ )
113
+ })}
114
+
115
+ {shippingMethod && (
116
+ <Box
117
+ className={classes.costsRow}
118
+ key='shippingMethod'
119
+ sx={{ display: 'flex', justifyContent: 'space-between' }}
120
+ >
121
+ <Box>
122
+ <Trans
123
+ id='Shipping ({0} {1})'
124
+ values={{ 0: shippingMethod.carrier_title, 1: shippingMethod.method_title }}
125
+ />
126
+ </Box>
127
+ <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
128
+ <Money
129
+ {...(inclTax
130
+ ? shippingMethodPrices?.price_incl_tax
131
+ : shippingMethodPrices?.price_excl_tax)}
132
+ />
133
+ </Box>
134
+ </Box>
135
+ )}
136
+
137
+ {!inclTax &&
138
+ prices?.applied_taxes?.map((tax) => (
139
+ <Box
121
140
  className={classes.costsRow}
122
- key='shippingMethod'
123
- sx={{ display: 'flex', justifyContent: 'space-between', typography: 'subtitle1' }}
141
+ key={`excl${tax?.label}`}
142
+ sx={{ display: 'flex', justifyContent: 'space-between' }}
124
143
  >
125
- <Box>
126
- <Trans
127
- id='Shipping ({0} {1})'
128
- values={{ 0: shippingMethod.carrier_title, 1: shippingMethod.method_title }}
129
- />
130
- </Box>
144
+ <Box>{tax?.label}</Box>
131
145
  <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
132
- <Money
133
- {...(inclTax
134
- ? shippingMethodPrices?.price_incl_tax
135
- : shippingMethodPrices?.price_excl_tax)}
136
- />
146
+ <Money {...tax?.amount} />
137
147
  </Box>
138
- </AnimatedRow>
139
- )}
140
-
141
- {!inclTax &&
142
- prices?.applied_taxes?.map((tax) => (
143
- <AnimatedRow
144
- layout={animateLayout}
145
- className={classes.costsRow}
146
- key={`excl${tax?.label}`}
147
- sx={{ display: 'flex', justifyContent: 'space-between', typography: 'subtitle1' }}
148
- >
149
- <Box>{tax?.label}</Box>
150
- <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
151
- <Money {...tax?.amount} />
152
- </Box>
153
- </AnimatedRow>
154
- ))}
155
-
156
- <AnimatedRow layout key='divider'>
157
- <Divider className={classes.costsDivider} sx={{ margin: `1em 0` }} />
158
- </AnimatedRow>
159
-
160
- {prices?.grand_total && (
161
- <AnimatedRow
162
- layout={animateLayout}
163
- className={`${classes.costsRow} ${classes.costsGrandTotal}`}
164
- key='grand_total'
165
- sx={(theme) => ({
148
+ </Box>
149
+ ))}
150
+
151
+ <Box key='divider'>
152
+ <Divider className={classes.costsDivider} sx={{ margin: `1em 0` }} />
153
+ </Box>
154
+
155
+ {prices?.grand_total && (
156
+ <Box
157
+ className={`${classes.costsRow} ${classes.costsGrandTotal}`}
158
+ key='grand_total'
159
+ sx={(theme) => ({
160
+ display: 'flex',
161
+ justifyContent: 'space-between',
162
+ color: theme.palette.primary.main,
163
+ })}
164
+ >
165
+ <Box>
166
+ <Trans id='Grand total' />
167
+ </Box>
168
+ <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
169
+ <Money {...prices.grand_total} />
170
+ </Box>
171
+ </Box>
172
+ )}
173
+
174
+ {inclTax &&
175
+ prices?.applied_taxes?.map((tax) => (
176
+ <Box
177
+ className={`${classes.costsRow} ${classes.costsTax}`}
178
+ key={`incl${tax?.label}`}
179
+ sx={{
166
180
  display: 'flex',
167
181
  justifyContent: 'space-between',
168
- typography: 'subtitle1',
169
- color: theme.palette.primary.main,
170
- })}
182
+ color: 'text.disabled',
183
+ paddingTop: 0,
184
+ }}
171
185
  >
172
186
  <Box>
173
- <Trans id='Grand total' />
187
+ <Trans id='Including {0}' values={{ 0: tax?.label }} />
174
188
  </Box>
175
189
  <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
176
- <Money {...prices.grand_total} />
190
+ <Money {...tax?.amount} />
177
191
  </Box>
178
- </AnimatedRow>
179
- )}
180
-
181
- {inclTax &&
182
- prices?.applied_taxes?.map((tax) => (
183
- <AnimatedRow
184
- layout={animateLayout}
185
- className={`${classes.costsRow} ${classes.costsTax}`}
186
- key={`incl${tax?.label}`}
187
- sx={{
188
- display: 'flex',
189
- justifyContent: 'space-between',
190
- typography: 'body1',
191
- color: 'text.disabled',
192
- paddingTop: 0,
193
- }}
194
- >
195
- <Box>
196
- <Trans id='Including {0}' values={{ 0: tax?.label }} />
197
- </Box>
198
- <Box className={classes.money} sx={{ whiteSpace: 'nowrap' }}>
199
- <Money {...tax?.amount} />
200
- </Box>
201
- </AnimatedRow>
202
- ))}
203
- </AnimatePresence>
204
- </AnimatedRow>
192
+ </Box>
193
+ ))}
194
+ </Box>
205
195
  )
206
196
  }
@@ -1,16 +1,7 @@
1
- import { useQuery, TypedDocumentNode, QueryHookOptions, ApolloError } from '@graphcommerce/graphql'
2
- import { GraphQLError } from 'graphql'
1
+ import { useQuery, TypedDocumentNode, QueryHookOptions } from '@graphcommerce/graphql'
3
2
  import { useRouter } from 'next/router'
4
3
  import { useCurrentCartId } from './useCurrentCartId'
5
4
 
6
- const noCartError = new ApolloError({
7
- graphQLErrors: [
8
- new GraphQLError('No cart found', {
9
- extensions: { category: 'graphql-no-such-entity' },
10
- }),
11
- ],
12
- })
13
-
14
5
  /**
15
6
  * Requires the query to have a `$cartId: String!` argument. It will automatically inject the
16
7
  * currently active cart_id.
@@ -30,7 +21,7 @@ export function useCartQuery<Q, V extends { cartId: string; [index: string]: unk
30
21
  ) {
31
22
  const { allowUrl = true, hydration, ...queryOptions } = options
32
23
  const router = useRouter()
33
- const { currentCartId, called } = useCurrentCartId({ hydration })
24
+ const { currentCartId } = useCurrentCartId({ hydration })
34
25
 
35
26
  const urlCartId = router.query.cart_id
36
27
  const usingUrl = allowUrl && typeof urlCartId === 'string'
@@ -49,8 +40,7 @@ export function useCartQuery<Q, V extends { cartId: string; [index: string]: unk
49
40
  const result = useQuery(document, queryOptions)
50
41
 
51
42
  return {
52
- ...useQuery(document, queryOptions),
53
43
  ...result,
54
- error: called && !currentCartId ? noCartError : result.error,
44
+ // error: called && !currentCartId ? noCartError : result.error,
55
45
  }
56
46
  }
package/index.ts CHANGED
@@ -2,3 +2,5 @@ export * from './Api/CartItemCountChanged.gql'
2
2
  export * from './hooks'
3
3
  export * from './components'
4
4
  export * from './typePolicies'
5
+ export * from './link/createCartErrorLink'
6
+ export * from './components/CartDebugger/CartDebugger'
@@ -0,0 +1,71 @@
1
+ import {
2
+ ApolloClient,
3
+ FetchResult,
4
+ fromPromise,
5
+ InMemoryCache,
6
+ NormalizedCacheObject,
7
+ onError,
8
+ Operation,
9
+ } from '@graphcommerce/graphql'
10
+ import { RefObject } from 'react'
11
+ import { useAssignCurrentCartId, writeCartId } from '../hooks'
12
+ import { CreateEmptyCartDocument } from '../hooks/CreateEmptyCart.gql'
13
+ import { CurrentCartIdDocument } from '../hooks/CurrentCartId.gql'
14
+
15
+ type CartOperation = Operation & { variables: { cartId: string } }
16
+ function isCartOperation(operation: Operation): operation is CartOperation {
17
+ return typeof operation.variables.cartId === 'string'
18
+ }
19
+
20
+ function errorIsIncluded(errorPath: readonly (string | number)[] | undefined, keys: string[]) {
21
+ const error = errorPath?.join()
22
+ return keys.some((value) => value === error)
23
+ }
24
+
25
+ export const createCartErrorLink = (clientRef: RefObject<ApolloClient<NormalizedCacheObject>>) =>
26
+ onError(({ graphQLErrors, operation, forward }) => {
27
+ if (!clientRef.current) return undefined
28
+
29
+ const client = clientRef.current
30
+ const { cache } = client
31
+
32
+ if (!isCartOperation(operation) || !graphQLErrors) return undefined
33
+
34
+ const cartErr = graphQLErrors.find(
35
+ (err) =>
36
+ err.extensions?.category === 'graphql-no-such-entity' &&
37
+ errorIsIncluded(err.path, [
38
+ 'cart',
39
+ 'addProductsToCart',
40
+
41
+ /**
42
+ * These mutations can also throw the graphql-no-such-entity exception, however, we're not
43
+ * sure if it also throws for other types of entities.
44
+ */
45
+ // 'removeItemFromCart',
46
+ // 'setBillingAddressOnCart',
47
+ // 'setGuestEmailOnCart',
48
+ // 'setPaymentMethodOnCart',
49
+ // 'setShippingAddressesOnCart',
50
+ // 'setShippingMethodsOnCart',
51
+ // 'updateCartItems',
52
+ // 'applyCouponToCart',
53
+ // 'removeCouponFromCart'
54
+ ]),
55
+ )
56
+
57
+ if (!cartErr) return undefined
58
+
59
+ return fromPromise(client?.mutate({ mutation: CreateEmptyCartDocument }))
60
+ .filter((value) => Boolean(value))
61
+ .flatMap((cartData) => {
62
+ const cartId = cartData.data?.createEmptyCart
63
+ if (!cartId) return forward(operation)
64
+
65
+ writeCartId(cache, cartId)
66
+ operation.variables = { ...operation.variables, cartId }
67
+
68
+ // retry the request, returning the new observable
69
+ return forward(operation)
70
+ })
71
+ })
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-cart",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "4.6.9",
5
+ "version": "4.7.2",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -18,16 +18,16 @@
18
18
  "@playwright/test": "^1.21.1"
19
19
  },
20
20
  "dependencies": {
21
- "@graphcommerce/ecommerce-ui": "1.1.12",
22
- "@graphcommerce/framer-utils": "3.1.5",
23
- "@graphcommerce/framer-next-pages": "3.2.5",
24
- "@graphcommerce/framer-scroller": "2.1.32",
25
- "@graphcommerce/graphql": "3.4.6",
26
- "@graphcommerce/image": "3.1.8",
27
- "@graphcommerce/magento-customer": "4.9.5",
28
- "@graphcommerce/magento-graphql": "3.1.6",
29
- "@graphcommerce/magento-store": "4.2.27",
30
- "@graphcommerce/next-ui": "4.21.0",
21
+ "@graphcommerce/ecommerce-ui": "1.2.1",
22
+ "@graphcommerce/framer-utils": "3.2.0",
23
+ "@graphcommerce/framer-next-pages": "3.3.0",
24
+ "@graphcommerce/framer-scroller": "2.1.34",
25
+ "@graphcommerce/graphql": "3.4.7",
26
+ "@graphcommerce/image": "3.1.9",
27
+ "@graphcommerce/magento-customer": "4.10.2",
28
+ "@graphcommerce/magento-graphql": "3.1.7",
29
+ "@graphcommerce/magento-store": "4.2.30",
30
+ "@graphcommerce/next-ui": "4.23.0",
31
31
  "@graphcommerce/react-hook-form": "3.3.2"
32
32
  },
33
33
  "peerDependencies": {