@graphcommerce/magento-cart 8.1.0-canary.2 → 8.1.0-canary.22

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,6 +1,134 @@
1
1
  # Change Log
2
2
 
3
- ## 8.1.0-canary.2
3
+ ## 8.1.0-canary.22
4
+
5
+ ## 8.1.0-canary.21
6
+
7
+ ## 8.1.0-canary.20
8
+
9
+ ## 8.1.0-canary.19
10
+
11
+ ## 8.1.0-canary.18
12
+
13
+ ## 8.1.0-canary.17
14
+
15
+ ## 8.1.0-canary.16
16
+
17
+ ## 8.1.0-canary.15
18
+
19
+ ## 8.1.0-canary.14
20
+
21
+ ## 8.1.0-canary.13
22
+
23
+ ## 8.1.0-canary.12
24
+
25
+ ## 8.1.0-canary.11
26
+
27
+ ## 8.1.0-canary.10
28
+
29
+ ## 8.1.0-canary.9
30
+
31
+ ## 8.1.0-canary.8
32
+
33
+ ### Patch Changes
34
+
35
+ - [#2247](https://github.com/graphcommerce-org/graphcommerce/pull/2247) [`a56a7c6`](https://github.com/graphcommerce-org/graphcommerce/commit/a56a7c67cf27dfb91bf763a873beeec562ab3156) - Solve an issue where the cart would be sometimes undefined, but Partial was too eleborate
36
+ ([@paales](https://github.com/paales))
37
+
38
+ ## 8.1.0-canary.7
39
+
40
+ ## 8.1.0-canary.6
41
+
42
+ ## 8.1.0-canary.5
43
+
44
+ ## 8.0.6-canary.4
45
+
46
+ ## 8.0.6-canary.3
47
+
48
+ ## 8.0.6-canary.2
49
+
50
+ ### Patch Changes
51
+
52
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`0767bc4`](https://github.com/graphcommerce-org/graphcommerce/commit/0767bc40f7b596209f24ca4e745ff0441f3275c9) - Upgrade input components to no longer use muiRegister, which improves INP scores
53
+ ([@FrankHarland](https://github.com/FrankHarland))
54
+
55
+ - [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`530076e`](https://github.com/graphcommerce-org/graphcommerce/commit/530076e3664703cb8b577b7fcf1998a420819f60) - Moved all usages of useFormPersist to the <FormPersist/> component to prevent rerenders.
56
+ ([@FrankHarland](https://github.com/FrankHarland))
57
+
58
+ ## 8.0.6-canary.1
59
+
60
+ ## 8.0.6-canary.0
61
+
62
+ ## 8.0.5
63
+
64
+ ## 8.0.5-canary.10
65
+
66
+ ## 8.0.5-canary.9
67
+
68
+ ## 8.0.5-canary.8
69
+
70
+ ## 8.0.5-canary.7
71
+
72
+ ## 8.0.5-canary.6
73
+
74
+ ## 8.0.5-canary.5
75
+
76
+ ## 8.0.5-canary.4
77
+
78
+ ## 8.0.5-canary.3
79
+
80
+ ## 8.0.5-canary.2
81
+
82
+ ## 8.0.5-canary.1
83
+
84
+ ## 8.0.5-canary.0
85
+
86
+ ## 8.0.4
87
+
88
+ ### Patch Changes
89
+
90
+ - [#2221](https://github.com/graphcommerce-org/graphcommerce/pull/2221) [`0ba1fdc`](https://github.com/graphcommerce-org/graphcommerce/commit/0ba1fdc9a2d005f47cd1725fe723e77da4cc5b9d) - After a user just logged in the checkout, the useFormGqlMutationCart would still run even though the cart was locked.
91
+ ([@paales](https://github.com/paales))
92
+
93
+ ## 8.0.4-canary.1
94
+
95
+ ## 8.0.4-canary.0
96
+
97
+ ### Patch Changes
98
+
99
+ - [#2221](https://github.com/graphcommerce-org/graphcommerce/pull/2221) [`0ba1fdc`](https://github.com/graphcommerce-org/graphcommerce/commit/0ba1fdc9a2d005f47cd1725fe723e77da4cc5b9d) - After a user just logged in the checkout, the useFormGqlMutationCart would still run even though the cart was locked.
100
+ ([@paales](https://github.com/paales))
101
+
102
+ ## 8.0.3
103
+
104
+ ### Patch Changes
105
+
106
+ - [#2205](https://github.com/graphcommerce-org/graphcommerce/pull/2205) [`d67c89d`](https://github.com/graphcommerce-org/graphcommerce/commit/d67c89d464a60f0e2618dab670b63a39f6291341) - Deprecate the allowUrl option for useCartQuery, it was already enabled by default and should never be set to false.
107
+ ([@paales](https://github.com/paales))
108
+
109
+ - [#2205](https://github.com/graphcommerce-org/graphcommerce/pull/2205) [`3fbf3da`](https://github.com/graphcommerce-org/graphcommerce/commit/3fbf3da8a67f2fbaa7fa974a37cbbf34613844e4) - Solve an issue where the user would be presented with the Session expired dialog when the user would be logging in during the checkout process.
110
+ ([@paales](https://github.com/paales))
111
+
112
+ - [#2207](https://github.com/graphcommerce-org/graphcommerce/pull/2207) [`9876b13`](https://github.com/graphcommerce-org/graphcommerce/commit/9876b139b2c12c860a16af97eddea761d1059110) - Remove redundant query on the success page for logged in customers
113
+ ([@paales](https://github.com/paales))
114
+
115
+ ## 8.0.3-canary.6
116
+
117
+ ## 8.0.3-canary.5
118
+
119
+ ## 8.0.3-canary.4
120
+
121
+ ## 8.0.3-canary.3
122
+
123
+ ## 8.0.3-canary.2
124
+
125
+ ### Patch Changes
126
+
127
+ - [#2205](https://github.com/graphcommerce-org/graphcommerce/pull/2205) [`d67c89d`](https://github.com/graphcommerce-org/graphcommerce/commit/d67c89d464a60f0e2618dab670b63a39f6291341) - Deprecate the allowUrl option for useCartQuery, it was already enabled by default and should never be set to false.
128
+ ([@paales](https://github.com/paales))
129
+
130
+ - [#2205](https://github.com/graphcommerce-org/graphcommerce/pull/2205) [`3fbf3da`](https://github.com/graphcommerce-org/graphcommerce/commit/3fbf3da8a67f2fbaa7fa974a37cbbf34613844e4) - Solve an issue where the user would be presented with the Session expired dialog when the user would be logging in during the checkout process.
131
+ ([@paales](https://github.com/paales))
4
132
 
5
133
  ## 8.0.3-canary.1
6
134
 
@@ -2,10 +2,10 @@ import { CheckboxElement } from '@graphcommerce/ecommerce-ui'
2
2
  import { useQuery } from '@graphcommerce/graphql'
3
3
  import { extendableComponent, FormDiv } from '@graphcommerce/next-ui'
4
4
  import {
5
+ FormPersist,
5
6
  useForm,
6
7
  useFormCompose,
7
8
  UseFormComposeOptions,
8
- useFormPersist,
9
9
  } from '@graphcommerce/react-hook-form'
10
10
  import { i18n } from '@lingui/core'
11
11
  import { Box, Link, SxProps, Theme } from '@mui/material'
@@ -39,8 +39,6 @@ export function CartAgreementsForm(props: CartAgreementsFormProps) {
39
39
  console.log(values)
40
40
  })
41
41
 
42
- useFormPersist({ form, name: 'PaymentAgreementsForm' })
43
-
44
42
  useFormCompose({ form, step, submit, key: 'PaymentAgreementsForm' })
45
43
 
46
44
  if (data?.checkoutAgreements?.length === 0) return null
@@ -50,6 +48,7 @@ export function CartAgreementsForm(props: CartAgreementsFormProps) {
50
48
  className={classes.form}
51
49
  sx={[(theme) => ({ pt: theme.spacings.md }), ...(Array.isArray(sx) ? sx : [sx])]}
52
50
  >
51
+ <FormPersist form={form} name='PaymentAgreementsForm' />
53
52
  <form noValidate onSubmit={submit} name='cartAgreements'>
54
53
  <Box className={classes.formInner} sx={{ typography: 'body1', display: 'inline-block' }}>
55
54
  {data?.checkoutAgreements &&
@@ -1,6 +1,6 @@
1
1
  import { useApolloClient } from '@graphcommerce/graphql'
2
2
  import { Button } from '@mui/material'
3
- import { CurrentCartIdDocument } from '../../hooks/CurrentCartId.gql'
3
+ import { readCartId, writeCartId } from '../../hooks'
4
4
 
5
5
  export function CartDebugger() {
6
6
  const client = useApolloClient()
@@ -12,24 +12,14 @@ export function CartDebugger() {
12
12
  variant='text'
13
13
  size='small'
14
14
  onClick={() => {
15
- const currentCardId = client.readQuery({ query: CurrentCartIdDocument })
16
- if (!currentCardId?.currentCartId) {
15
+ const currentCartId = readCartId(client.cache)
16
+ if (!currentCartId) {
17
17
  // eslint-disable-next-line no-console
18
18
  console.log('No customerToken available, nothing to break')
19
19
  } else {
20
20
  // eslint-disable-next-line no-console
21
21
  console.log(`Changing current token to a random one`)
22
-
23
- client.writeQuery({
24
- query: CurrentCartIdDocument,
25
- data: {
26
- currentCartId: {
27
- ...currentCardId.currentCartId,
28
- id: `${Math.random().toString(36).slice(2)}random-cardId`,
29
- },
30
- },
31
- broadcast: true,
32
- })
22
+ writeCartId(client.cache, `${Math.random().toString(36).slice(2)}random-cardId`)
33
23
  }
34
24
  }}
35
25
  >
@@ -38,10 +38,7 @@ type OrderSummaryProps = ActionCardLayoutProps & {
38
38
 
39
39
  export function CartItemSummary(props: OrderSummaryProps) {
40
40
  const { sx = [], size, layout = 'list', itemProps, ...cardLayout } = props
41
- const { data } = useCartQuery(CartItemSummaryDocument, {
42
- allowUrl: true,
43
- fetchPolicy: 'cache-only',
44
- })
41
+ const { data } = useCartQuery(CartItemSummaryDocument, { fetchPolicy: 'cache-only' })
45
42
 
46
43
  if (!data?.cart) return null
47
44
 
@@ -85,7 +82,7 @@ export function CartItemSummary(props: OrderSummaryProps) {
85
82
  className={classes.scrollerContainer}
86
83
  {...cardLayout}
87
84
  >
88
- {items?.filter(nonNullable).map((item) => (
85
+ {(items ?? []).filter(nonNullable).map((item) => (
89
86
  <CartItemActionCard
90
87
  readOnly
91
88
  key={item.uid}
@@ -4,7 +4,6 @@ fragment CartStartCheckout on Cart @injectable {
4
4
  ...Money
5
5
  }
6
6
  }
7
-
8
7
  items {
9
8
  errors {
10
9
  message
@@ -5,12 +5,16 @@ import { Box, Button, ButtonProps, SxProps, Theme } from '@mui/material'
5
5
  import React from 'react'
6
6
  import { CartStartCheckoutFragment } from './CartStartCheckout.gql'
7
7
 
8
- export type CartStartCheckoutProps = CartStartCheckoutFragment & {
8
+ export type CartStartCheckoutProps = {
9
9
  children?: React.ReactNode
10
10
  sx?: SxProps<Theme>
11
11
  buttonProps?: ButtonProps<'button'>
12
12
  disabled?: boolean
13
- onStart?: (e: React.MouseEvent<HTMLButtonElement>, cart: CartStartCheckoutFragment) => void
13
+ cart?: CartStartCheckoutFragment | null | undefined
14
+ onStart?: (
15
+ e: React.MouseEvent<HTMLButtonElement>,
16
+ cart: CartStartCheckoutFragment | null | undefined,
17
+ ) => void
14
18
  }
15
19
 
16
20
  const name = 'CartStartCheckout' as const
@@ -29,11 +33,11 @@ export function CartStartCheckout(props: CartStartCheckoutProps) {
29
33
  buttonProps: { onClick, ...buttonProps } = {},
30
34
  disabled,
31
35
  sx = [],
32
- ...cart
36
+ cart,
33
37
  } = props
34
38
 
35
- const hasTotals = (cart.prices?.grand_total?.value ?? 0) > 0
36
- const hasErrors = cart.items?.some((item) => (item?.errors?.length ?? 0) > 0)
39
+ const hasTotals = (cart?.prices?.grand_total?.value ?? 0) > 0
40
+ const hasErrors = cart?.items?.some((item) => (item?.errors?.length ?? 0) > 0)
37
41
 
38
42
  return (
39
43
  <Box
@@ -71,7 +75,7 @@ export function CartStartCheckout(props: CartStartCheckoutProps) {
71
75
  </Box>{' '}
72
76
  {hasTotals && (
73
77
  <span className={classes.checkoutMoney}>
74
- <Money {...cart.prices?.grand_total} />
78
+ <Money {...cart?.prices?.grand_total} />
75
79
  </span>
76
80
  )}
77
81
  </Button>
@@ -4,13 +4,14 @@ import { SxProps, Theme } from '@mui/material'
4
4
  import React from 'react'
5
5
  import { CartStartCheckoutFragment } from './CartStartCheckout.gql'
6
6
 
7
- export type CartStartCheckoutLinkOrButtonProps = CartStartCheckoutFragment & {
7
+ export type CartStartCheckoutLinkOrButtonProps = {
8
8
  children?: React.ReactNode
9
9
  sx?: SxProps<Theme>
10
10
  disabled?: boolean
11
+ cart?: CartStartCheckoutFragment | null | undefined
11
12
  onStart?: (
12
13
  e: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement & HTMLSpanElement>,
13
- cart: CartStartCheckoutFragment,
14
+ cart: CartStartCheckoutFragment | null | undefined,
14
15
  ) => void
15
16
  linkOrButtonProps?: LinkOrButtonProps
16
17
  }
@@ -21,11 +22,11 @@ export function CartStartCheckoutLinkOrButton(props: CartStartCheckoutLinkOrButt
21
22
  onStart,
22
23
  disabled,
23
24
  linkOrButtonProps: { onClick, button, ...linkOrButtonProps } = {},
24
- ...cart
25
+ cart,
25
26
  } = props
26
27
 
27
- const hasTotals = (cart.prices?.grand_total?.value ?? 0) > 0
28
- const hasErrors = cart.items?.some((item) => (item?.errors?.length ?? 0) > 0)
28
+ const hasTotals = (cart?.prices?.grand_total?.value ?? 0) > 0
29
+ const hasErrors = cart?.items?.some((item) => (item?.errors?.length ?? 0) > 0)
29
30
 
30
31
  return (
31
32
  <LinkOrButton
@@ -21,7 +21,7 @@ const { classes } = extendableComponent<OwnerState, typeof compName, typeof part
21
21
  export function CartSummary(props: CartSummaryProps) {
22
22
  const { children, editable, sx = [] } = props
23
23
 
24
- const { data } = useCartQuery(GetCartSummaryDocument, { allowUrl: true })
24
+ const { data } = useCartQuery(GetCartSummaryDocument)
25
25
  const { href: historyHref, onClick: historyOnClick } = useHistoryLink({
26
26
  href: '/checkout',
27
27
  })
@@ -11,7 +11,7 @@ fragment CartTotals on Cart
11
11
  ...Money
12
12
  }
13
13
  }
14
- # https://github.com/magento/magento2/pull/31322
14
+ # todo: https://github.com/magento/magento2/pull/31322
15
15
  available_shipping_methods {
16
16
  carrier_code
17
17
  method_code
@@ -31,7 +31,7 @@ const { withState } = extendableComponent<OwnerProps, typeof name, typeof parts>
31
31
  * @see https://github.com/magento/magento2/issues/33848
32
32
  */
33
33
  export function CartTotals(props: CartTotalsProps) {
34
- const { data } = useCartQuery(GetCartTotalsDocument, { allowUrl: true })
34
+ const { data } = useCartQuery(GetCartTotalsDocument)
35
35
  const { containerMargin, additionalSubtotals, additionalTotals, sx = [] } = props
36
36
 
37
37
  const classes = withState({ containerMargin })
@@ -2,5 +2,6 @@ query CurrentCartId {
2
2
  currentCartId @client {
3
3
  __typename
4
4
  id
5
+ locked
5
6
  }
6
7
  }
@@ -4,6 +4,7 @@ extend type Query {
4
4
 
5
5
  type CurrentCartId {
6
6
  id: String
7
+ locked: Boolean
7
8
  }
8
9
 
9
10
  input RegisterCartIdInput {
@@ -2,6 +2,5 @@ query CustomerCart {
2
2
  customerCart {
3
3
  id
4
4
  __typename
5
- ...CartItemCountChanged
6
5
  }
7
6
  }
@@ -1,7 +1,6 @@
1
- mutation UseMergeCustomerCart($sourceCartId: String!, $destinationCartId: String!) {
1
+ mutation MergeCarts($sourceCartId: String!, $destinationCartId: String!) {
2
2
  mergeCarts(source_cart_id: $sourceCartId, destination_cart_id: $destinationCartId) {
3
3
  __typename
4
4
  id
5
- ...CartItemCountChanged
6
5
  }
7
6
  }
@@ -8,11 +8,26 @@ export const CART_ID_COOKIE = 'cart'
8
8
  export function writeCartId(cache: ApolloCache<object>, id: string | null = null) {
9
9
  cache.writeQuery({
10
10
  query: CurrentCartIdDocument,
11
- data: { currentCartId: { __typename: 'CurrentCartId', id } },
11
+ data: { currentCartId: { __typename: 'CurrentCartId', locked: false, id } },
12
12
  broadcast: true,
13
13
  })
14
14
  }
15
15
 
16
+ export function readCartId(cache: ApolloCache<object>) {
17
+ return cache.readQuery({ query: CurrentCartIdDocument })?.currentCartId
18
+ }
19
+
20
+ export function cartLock(cache: ApolloCache<object>, locked: boolean) {
21
+ const currentCartId = cache.readQuery({ query: CurrentCartIdDocument })?.currentCartId
22
+ if (currentCartId?.id && currentCartId.locked !== locked) {
23
+ cache.writeQuery({
24
+ query: CurrentCartIdDocument,
25
+ data: { currentCartId: { ...currentCartId, locked } },
26
+ broadcast: true,
27
+ })
28
+ }
29
+ }
30
+
16
31
  export function useAssignCurrentCartId() {
17
32
  const { cache } = useApolloClient()
18
33
 
@@ -1,16 +1,14 @@
1
1
  import { useApolloClient } from '@graphcommerce/graphql'
2
2
  import { i18n } from '@lingui/core'
3
3
  import { CreateEmptyCartDocument } from './CreateEmptyCart.gql'
4
- import { CurrentCartIdDocument } from './CurrentCartId.gql'
5
- import { useAssignCurrentCartId } from './useAssignCurrentCartId'
4
+ import { readCartId, useAssignCurrentCartId } from './useAssignCurrentCartId'
6
5
 
7
6
  export function useCartIdCreate() {
8
7
  const client = useApolloClient()
9
8
  const assignCurrentCartId = useAssignCurrentCartId()
10
9
 
11
10
  return async (): Promise<string> => {
12
- const currentCartId = client.cache.readQuery({ query: CurrentCartIdDocument })?.currentCartId
13
- ?.id
11
+ const currentCartId = readCartId(client.cache)?.id
14
12
 
15
13
  if (currentCartId) return currentCartId
16
14
 
@@ -15,18 +15,21 @@ import { useCurrentCartId } from './useCurrentCartId'
15
15
  export function useCartQuery<Q, V extends { cartId: string; [index: string]: unknown }>(
16
16
  document: TypedDocumentNode<Q, V>,
17
17
  options: QueryHookOptions<Q, Omit<V, 'cartId'>> & {
18
+ /**
19
+ * @deprecated Not used anymore, when the cart_id is in the URL, it will always be used.
20
+ */
18
21
  allowUrl?: boolean
19
22
  } = {},
20
23
  ) {
21
- const { allowUrl = true, ...queryOptions } = options
24
+ const { allowUrl, ...queryOptions } = options
22
25
  const router = useRouter()
23
- const { currentCartId } = useCurrentCartId()
26
+ const { currentCartId, locked } = useCurrentCartId()
24
27
 
25
28
  const urlCartId = router.query.cart_id
26
- const usingUrl = allowUrl && typeof urlCartId === 'string'
29
+ const usingUrl = typeof urlCartId === 'string'
27
30
  const cartId = usingUrl ? urlCartId : currentCartId
28
31
 
29
- if (usingUrl) queryOptions.fetchPolicy = 'cache-first'
32
+ if (usingUrl || locked) queryOptions.fetchPolicy = 'cache-only'
30
33
 
31
34
  if (usingUrl && typeof queryOptions.returnPartialData === 'undefined')
32
35
  queryOptions.returnPartialData = true
@@ -34,10 +37,5 @@ export function useCartQuery<Q, V extends { cartId: string; [index: string]: unk
34
37
  queryOptions.variables = { cartId, ...options?.variables } as V
35
38
  queryOptions.skip = queryOptions?.skip || !cartId
36
39
 
37
- const result = useQuery(document, queryOptions as QueryHookOptions<Q, V>)
38
-
39
- return {
40
- ...result,
41
- // error: called && !currentCartId ? noCartError : result.error,
42
- }
40
+ return useQuery(document, queryOptions as QueryHookOptions<Q, V>)
43
41
  }
@@ -1,20 +1,12 @@
1
1
  import { useApolloClient } from '@graphcommerce/graphql'
2
2
  import { cookie } from '@graphcommerce/next-ui'
3
- import { CurrentCartIdDocument } from './CurrentCartId.gql'
4
3
  import { CART_ID_COOKIE } from './useAssignCurrentCartId'
5
4
 
6
5
  export function useClearCurrentCartId() {
7
6
  const { cache } = useApolloClient()
8
7
 
9
8
  return () => {
10
- const id = cache.readQuery({ query: CurrentCartIdDocument })?.currentCartId?.id
11
- if (!id) return
12
-
13
- cache.writeQuery({
14
- query: CurrentCartIdDocument,
15
- data: { currentCartId: { __typename: 'CurrentCartId', id: null } },
16
- broadcast: true,
17
- })
9
+ cache.evict({ fieldName: 'currentCartId', broadcast: true })
18
10
  cookie(CART_ID_COOKIE, null)
19
11
  }
20
12
  }
@@ -10,5 +10,10 @@ export function useCurrentCartId<
10
10
  V extends CurrentCartIdQueryVariables,
11
11
  >(options: QueryHookOptions<Q, V> = {}) {
12
12
  const queryResults = useQuery<Q, V>(CurrentCartIdDocument, options)
13
- return { currentCartId: queryResults.data?.currentCartId?.id || '', ...queryResults }
13
+
14
+ return {
15
+ currentCartId: queryResults.data?.currentCartId?.id || '',
16
+ locked: queryResults.data?.currentCartId?.locked || false,
17
+ ...queryResults,
18
+ }
14
19
  }
@@ -1,9 +1,10 @@
1
- import { MutationHookOptions, TypedDocumentNode } from '@graphcommerce/graphql'
1
+ import { MutationHookOptions, TypedDocumentNode, useApolloClient } from '@graphcommerce/graphql'
2
2
  import {
3
3
  useFormGqlMutation,
4
4
  UseFormGqlMutationReturn,
5
5
  UseFormGraphQlOptions,
6
6
  } from '@graphcommerce/react-hook-form'
7
+ import { CurrentCartIdDocument } from './CurrentCartId.gql'
7
8
  import { useCartIdCreate } from './useCartIdCreate'
8
9
 
9
10
  export function useFormGqlMutationCart<
@@ -11,18 +12,28 @@ export function useFormGqlMutationCart<
11
12
  V extends { cartId: string; [index: string]: unknown },
12
13
  >(
13
14
  document: TypedDocumentNode<Q, V>,
14
- options: UseFormGraphQlOptions<Q, V> = {},
15
+ options: UseFormGraphQlOptions<Q, V> & { submitWhileLocked?: boolean } = {},
15
16
  operationOptions?: MutationHookOptions<Q, V>,
16
17
  ): UseFormGqlMutationReturn<Q, V> {
17
18
  const cartId = useCartIdCreate()
19
+ const client = useApolloClient()
18
20
 
19
- const onBeforeSubmit = async (variables: V) => {
20
- const vars = { ...variables, cartId: await cartId() }
21
- return options.onBeforeSubmit ? options.onBeforeSubmit(vars) : vars
22
- }
23
21
  const result = useFormGqlMutation<Q, V>(
24
22
  document,
25
- { ...options, onBeforeSubmit },
23
+ {
24
+ ...options,
25
+ onBeforeSubmit: async (variables) => {
26
+ const vars = { ...variables, cartId: await cartId() }
27
+
28
+ const res = client.cache.readQuery({ query: CurrentCartIdDocument })
29
+ if (!options.submitWhileLocked && res?.currentCartId?.locked) {
30
+ console.log('Could not submit form, cart is locked', res.currentCartId.locked)
31
+ return false
32
+ }
33
+
34
+ return options.onBeforeSubmit ? options.onBeforeSubmit(vars) : vars
35
+ },
36
+ },
26
37
  { errorPolicy: 'all', ...operationOptions },
27
38
  )
28
39
 
@@ -1,43 +1,6 @@
1
- import { useMutation } from '@graphcommerce/graphql'
2
- import { useCustomerQuery } from '@graphcommerce/magento-customer'
3
- import { useEffect } from 'react'
4
- import { CustomerCartDocument } from './CustomerCart.gql'
5
- import { UseMergeCustomerCartDocument } from './UseMergeCustomerCart.gql'
6
- import { useAssignCurrentCartId } from './useAssignCurrentCartId'
7
- import { useCurrentCartId } from './useCurrentCartId'
8
-
9
1
  /**
10
- * - Automatically assign the customer cart as the current cart
11
- * - Merge the guest cart into the customer cart
2
+ * @deprecated Is replaced by the useSignInFormMergeCart plugin.
12
3
  */
13
4
  export function useMergeCustomerCart() {
14
- const { currentCartId } = useCurrentCartId()
15
- const assignCurrentCartId = useAssignCurrentCartId()
16
- const [merge] = useMutation(UseMergeCustomerCartDocument, { errorPolicy: 'all' })
17
-
18
- const destinationCartId = useCustomerQuery(CustomerCartDocument, { fetchPolicy: 'network-only' })
19
- ?.data?.customerCart.id
20
-
21
- useEffect(() => {
22
- // If we don't have a customer cart, we're done
23
- // If the vistor cart is the same as the customer cart, we're done
24
- if (!destinationCartId || currentCartId === destinationCartId) return
25
-
26
- // If the visitor has a guest cart, try merging it into the customer cart
27
- if (currentCartId) {
28
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
29
- merge({ variables: { sourceCartId: currentCartId, destinationCartId } })
30
- // We're not handling exceptions here:
31
- // If the merge returns an error, we'll use the customer cart without merging the guest cart.
32
- .catch((e) => {
33
- console.error('Error merging carts', e)
34
- })
35
- .finally(() => {
36
- // Assign the customer cart as the new cart id
37
- assignCurrentCartId(destinationCartId)
38
- })
39
- } else {
40
- assignCurrentCartId(destinationCartId)
41
- }
42
- }, [assignCurrentCartId, destinationCartId, merge, currentCartId])
5
+ return null
43
6
  }
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": "8.1.0-canary.2",
5
+ "version": "8.1.0-canary.22",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,20 +12,20 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/ecommerce-ui": "^8.1.0-canary.2",
16
- "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.2",
17
- "@graphcommerce/framer-next-pages": "^8.1.0-canary.2",
18
- "@graphcommerce/framer-scroller": "^8.1.0-canary.2",
19
- "@graphcommerce/framer-utils": "^8.1.0-canary.2",
20
- "@graphcommerce/graphql": "^8.1.0-canary.2",
21
- "@graphcommerce/image": "^8.1.0-canary.2",
22
- "@graphcommerce/magento-customer": "^8.1.0-canary.2",
23
- "@graphcommerce/magento-graphql": "^8.1.0-canary.2",
24
- "@graphcommerce/magento-store": "^8.1.0-canary.2",
25
- "@graphcommerce/next-ui": "^8.1.0-canary.2",
26
- "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.2",
27
- "@graphcommerce/react-hook-form": "^8.1.0-canary.2",
28
- "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.2",
15
+ "@graphcommerce/ecommerce-ui": "^8.1.0-canary.22",
16
+ "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.22",
17
+ "@graphcommerce/framer-next-pages": "^8.1.0-canary.22",
18
+ "@graphcommerce/framer-scroller": "^8.1.0-canary.22",
19
+ "@graphcommerce/framer-utils": "^8.1.0-canary.22",
20
+ "@graphcommerce/graphql": "^8.1.0-canary.22",
21
+ "@graphcommerce/image": "^8.1.0-canary.22",
22
+ "@graphcommerce/magento-customer": "^8.1.0-canary.22",
23
+ "@graphcommerce/magento-graphql": "^8.1.0-canary.22",
24
+ "@graphcommerce/magento-store": "^8.1.0-canary.22",
25
+ "@graphcommerce/next-ui": "^8.1.0-canary.22",
26
+ "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.22",
27
+ "@graphcommerce/react-hook-form": "^8.1.0-canary.22",
28
+ "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.22",
29
29
  "@lingui/core": "^4.2.1",
30
30
  "@lingui/macro": "^4.2.1",
31
31
  "@lingui/react": "^4.2.1",
@@ -1,12 +1,14 @@
1
1
  import { GraphQLProviderProps } from '@graphcommerce/graphql'
2
- import type { PluginProps } from '@graphcommerce/next-config'
2
+ import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
3
3
  import { cartErrorLink } from '../link/createCartErrorLink'
4
4
  import { cartTypePolicies, migrateCart } from '../typePolicies'
5
5
 
6
- export const component = 'GraphQLProvider'
7
- export const exported = '@graphcommerce/graphql'
6
+ export const config: PluginConfig = {
7
+ type: 'component',
8
+ module: '@graphcommerce/graphql',
9
+ }
8
10
 
9
- function MagentoCartGraphqlProvider(props: PluginProps<GraphQLProviderProps>) {
11
+ export function GraphQLProvider(props: PluginProps<GraphQLProviderProps>) {
10
12
  const { Prev, links = [], policies = [], migrations = [], ...rest } = props
11
13
  return (
12
14
  <Prev
@@ -17,5 +19,3 @@ function MagentoCartGraphqlProvider(props: PluginProps<GraphQLProviderProps>) {
17
19
  />
18
20
  )
19
21
  }
20
-
21
- export const Plugin = MagentoCartGraphqlProvider
@@ -0,0 +1,50 @@
1
+ import { useApolloClient } from '@graphcommerce/graphql'
2
+ import type { useSignInForm } from '@graphcommerce/magento-customer'
3
+ import type { MethodPlugin } from '@graphcommerce/next-config'
4
+ import { cartLock, readCartId, useAssignCurrentCartId } from '../hooks'
5
+ import { CustomerCartDocument } from '../hooks/CustomerCart.gql'
6
+ import { MergeCartsDocument } from '../hooks/MergeCarts.gql'
7
+
8
+ export const func = 'useSignInForm'
9
+ export const exported = '@graphcommerce/magento-customer'
10
+
11
+ const useSignInFormMergeCart: MethodPlugin<typeof useSignInForm> = (useSignInForm, options) => {
12
+ const client = useApolloClient()
13
+ const assignCurrentCartId = useAssignCurrentCartId()
14
+
15
+ return useSignInForm({
16
+ ...options,
17
+ onComplete: async (data, variables) => {
18
+ await options.onComplete?.(data, variables)
19
+
20
+ cartLock(client.cache, true)
21
+
22
+ const destinationCartId = (
23
+ await client.query({
24
+ query: CustomerCartDocument,
25
+ fetchPolicy: 'network-only',
26
+ })
27
+ ).data.customerCart.id
28
+
29
+ try {
30
+ const sourceCartId = readCartId(client.cache)?.id
31
+ if (sourceCartId && sourceCartId !== destinationCartId) {
32
+ await client.mutate({
33
+ mutation: MergeCartsDocument,
34
+ variables: { sourceCartId, destinationCartId },
35
+ })
36
+ }
37
+ } catch (error) {
38
+ console.error(
39
+ 'Error merging carts, continuing without merging, this might cause issues.',
40
+ error,
41
+ )
42
+ } finally {
43
+ // Assign the customer cart as the new cart id
44
+ assignCurrentCartId(destinationCartId)
45
+ }
46
+ },
47
+ })
48
+ }
49
+
50
+ export const plugin = useSignInFormMergeCart
package/typePolicies.ts CHANGED
@@ -2,13 +2,16 @@ import { ApolloCache, NormalizedCacheObject } from '@graphcommerce/graphql'
2
2
  import type { StrictTypedTypePolicies } from '@graphcommerce/graphql'
3
3
  import type { CartPrices, QuerycartArgs, ShippingCartAddress } from '@graphcommerce/graphql-mesh'
4
4
  import { CartFabDocument } from './components/CartFab/CartFab.gql'
5
- import { CurrentCartIdDocument } from './hooks/CurrentCartId.gql'
5
+ import { readCartId, writeCartId } from './hooks'
6
6
 
7
7
  export const cartTypePolicies: StrictTypedTypePolicies = {
8
8
  CurrentCartId: { keyFields: [] },
9
9
  CartPrices: {
10
10
  merge: (exiting, incoming, { mergeObjects }) => mergeObjects(exiting, incoming),
11
11
  },
12
+ CartItemPrices: {
13
+ merge: (exiting, incoming, { mergeObjects }) => mergeObjects(exiting, incoming),
14
+ },
12
15
  Cart: {
13
16
  fields: {
14
17
  shipping_addresses: {
@@ -21,6 +24,7 @@ export const cartTypePolicies: StrictTypedTypePolicies = {
21
24
  return merged ? [merged] : []
22
25
  },
23
26
  },
27
+ items: { merge: (_, incoming) => incoming },
24
28
  prices: {
25
29
  merge: (existing: CartPrices[] | undefined, incoming: CartPrices[], options) =>
26
30
  options.mergeObjects(existing ?? {}, incoming),
@@ -53,11 +57,10 @@ export const migrateCart = (
53
57
  oldCache: ApolloCache<NormalizedCacheObject>,
54
58
  newCache: ApolloCache<NormalizedCacheObject>,
55
59
  ) => {
56
- const currentCartId = oldCache.readQuery({ query: CurrentCartIdDocument })
57
- const cartId = currentCartId?.currentCartId?.id
60
+ const cartId = readCartId(oldCache)?.id
58
61
 
59
62
  if (cartId) {
60
- newCache.writeQuery({ query: CurrentCartIdDocument, data: currentCartId, broadcast: true })
63
+ writeCartId(newCache, cartId)
61
64
 
62
65
  // We have special handling for the CartFab because it tries to load data only from the cache.
63
66
  const cartFab = oldCache.readQuery({ query: CartFabDocument })