@graphcommerce/magento-cart-items 8.1.0-canary.19 → 8.1.0-canary.20

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,17 @@
1
1
  # Change Log
2
2
 
3
+ ## 8.1.0-canary.20
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2246](https://github.com/graphcommerce-org/graphcommerce/pull/2246) [`13524f9`](https://github.com/graphcommerce-org/graphcommerce/commit/13524f991a810c1679db49b3b8b4f04f90d0d6c1) - Added the ability to edit cart items with full support for all product types and custom options
8
+ ([@Jessevdpoel](https://github.com/Jessevdpoel))
9
+
10
+ ### Patch Changes
11
+
12
+ - [#2246](https://github.com/graphcommerce-org/graphcommerce/pull/2246) [`fc5c04d`](https://github.com/graphcommerce-org/graphcommerce/commit/fc5c04d4a2c0301be7d3cc983d9b31f6fcaf6fe6) - Create useRemoveItemFromCart hook to allow for reuse while keeping compatibility with plugins.
13
+ ([@Jessevdpoel](https://github.com/Jessevdpoel))
14
+
3
15
  ## 8.1.0-canary.19
4
16
 
5
17
  ## 8.1.0-canary.18
@@ -93,10 +93,7 @@ export function CartItem(props: CartItemProps) {
93
93
  color='default'
94
94
  badgeContent={
95
95
  <RemoveItemFromCartFab
96
- uid={uid}
97
- quantity={quantity}
98
- prices={prices}
99
- product={product}
96
+ {...props}
100
97
  fabProps={{ className: classes.badge }}
101
98
  sx={(theme) => ({
102
99
  '& > button': {
@@ -1,13 +1,15 @@
1
1
  import { Image } from '@graphcommerce/image'
2
2
  import { useDisplayInclTax } from '@graphcommerce/magento-cart/hooks'
3
+ import { ProductLinkProps } from '@graphcommerce/magento-product'
3
4
  import { Money } from '@graphcommerce/magento-store'
4
5
  import {
5
6
  ActionCard,
6
7
  ActionCardProps,
7
- responsiveVal,
8
8
  filterNonNullableKeys,
9
+ actionCardImageSizes,
9
10
  } from '@graphcommerce/next-ui'
10
- import { Box, Link } from '@mui/material'
11
+ import { Trans } from '@lingui/react'
12
+ import { Box, Button, Link } from '@mui/material'
11
13
  import { CartItemFragment } from '../../Api/CartItem.gql'
12
14
  import { RemoveItemFromCart } from '../RemoveItemFromCart/RemoveItemFromCart'
13
15
  import { UpdateItemQuantity } from '../UpdateItemQuantity/UpdateItemQuantity'
@@ -17,16 +19,8 @@ export type CartItemActionCardProps = { cartItem: CartItemFragment; readOnly?: b
17
19
  'value' | 'image' | 'price' | 'title' | 'action'
18
20
  >
19
21
 
20
- export const productImageSizes = {
21
- small: responsiveVal(60, 80),
22
- medium: responsiveVal(60, 80),
23
- large: responsiveVal(100, 120),
24
- }
25
-
26
- const typographySizes = {
27
- small: 'body2',
28
- medium: 'body1',
29
- large: 'subtitle1',
22
+ export function productEditLink(link: ProductLinkProps) {
23
+ return `/checkout/item/${link.url_key}`
30
24
  }
31
25
 
32
26
  export function CartItemActionCard(props: CartItemActionCardProps) {
@@ -49,6 +43,11 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
49
43
  price = prices?.price.value
50
44
  }
51
45
 
46
+ const hasOptions = !(
47
+ (cartItem.__typename === 'SimpleCartItem' || cartItem.__typename === 'VirtualCartItem') &&
48
+ cartItem.customizable_options.length === 0
49
+ )
50
+
52
51
  return (
53
52
  <ActionCard
54
53
  value={uid}
@@ -58,7 +57,7 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
58
57
  px: 0,
59
58
  py: theme.spacings.xs,
60
59
  },
61
- '& .MuiBox-root': {
60
+ '& .ActionCard-rootInner': {
62
61
  justifyContent: 'space-between',
63
62
  alignItems: 'stretch',
64
63
  },
@@ -66,9 +65,7 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
66
65
  px: 0,
67
66
  },
68
67
  '&.sizeResponsive': {
69
- [theme.breakpoints.down('md')]: {
70
- px: 0,
71
- },
68
+ [theme.breakpoints.down('md')]: { px: 0 },
72
69
  },
73
70
  '& .ActionCard-end': {
74
71
  justifyContent: readOnly ? 'center' : 'space-between',
@@ -80,30 +77,11 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
80
77
  alignSelf: 'flex-start',
81
78
  },
82
79
  '& .ActionCard-secondaryAction': {
83
- typography:
84
- size === 'responsive'
85
- ? {
86
- xs: typographySizes.small,
87
- md: typographySizes.medium,
88
- lg: typographySizes.large,
89
- }
90
- : typographySizes[size],
91
- display: 'flex',
92
- alignItems: 'center',
93
- color: 'text.secondary',
94
- mt: 1,
95
- gap: '10px',
96
- justifyContent: 'start',
80
+ display: 'grid',
81
+ rowGap: theme.spacings.xs,
82
+ justifyItems: 'start',
97
83
  },
98
84
  '& .ActionCard-price': {
99
- typography:
100
- size === 'responsive'
101
- ? {
102
- xs: typographySizes.small,
103
- md: typographySizes.medium,
104
- lg: typographySizes.large,
105
- }
106
- : typographySizes[size],
107
85
  pr: readOnly ? 0 : theme.spacings.xs,
108
86
  mb: { xs: 0.5, sm: 0 },
109
87
  },
@@ -116,27 +94,13 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
116
94
  layout='fill'
117
95
  src={thumbnail?.url}
118
96
  sx={{
119
- width:
120
- size === 'responsive'
121
- ? {
122
- xs: productImageSizes.small,
123
- md: productImageSizes.medium,
124
- lg: productImageSizes.large,
125
- }
126
- : productImageSizes[size],
127
- height:
128
- size === 'responsive'
129
- ? {
130
- xs: productImageSizes.small,
131
- md: productImageSizes.medium,
132
- lg: productImageSizes.large,
133
- }
134
- : productImageSizes[size],
97
+ width: actionCardImageSizes[size],
98
+ height: actionCardImageSizes[size],
135
99
  display: 'block',
136
100
  borderRadius: 1,
137
101
  objectFit: 'contain',
138
102
  }}
139
- sizes={size === 'responsive' ? productImageSizes.small : productImageSizes[size]}
103
+ sizes={actionCardImageSizes[size]}
140
104
  />
141
105
  )
142
106
  }
@@ -159,10 +123,30 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
159
123
  }
160
124
  secondaryAction={
161
125
  <>
162
- {readOnly ? quantity : <UpdateItemQuantity uid={uid} quantity={quantity} />}
163
- {' ⨉ '}
126
+ <Box
127
+ sx={{
128
+ display: 'flex',
129
+ alignItems: 'center',
130
+ color: 'text.secondary',
131
+ mt: 1,
132
+ gap: '10px',
133
+ justifyContent: 'start',
134
+ }}
135
+ >
136
+ {readOnly ? quantity : <UpdateItemQuantity uid={uid} quantity={quantity} />}
137
+ {' ⨉ '}
164
138
 
165
- <Money value={price} currency={prices?.price.currency} />
139
+ <Money value={price} currency={prices?.price.currency} />
140
+ </Box>
141
+ {hasOptions && (
142
+ <Button
143
+ variant='inline'
144
+ color='secondary'
145
+ href={`${productEditLink(product)}?cartItemId=${uid}`}
146
+ >
147
+ <Trans id='Edit options' />
148
+ </Button>
149
+ )}
166
150
  </>
167
151
  }
168
152
  price={<Money {...(inclTaxes ? prices?.row_total_including_tax : prices?.row_total)} />}
@@ -181,6 +165,7 @@ export function CartItemActionCard(props: CartItemActionCardProps) {
181
165
  </Box>
182
166
  ))}
183
167
  {...rest}
168
+ details={<>{rest.details}</>}
184
169
  />
185
170
  )
186
171
  }
@@ -7,7 +7,13 @@ import {
7
7
 
8
8
  export type CartProps = Omit<ActionCardLayoutProps, 'className'> & {
9
9
  cart?: CartItemsFragment | null
10
+ /**
11
+ * @deprecated Not used anymore, please use the size prop
12
+ */
10
13
  sizeSm?: CartItemActionCardProps['size']
14
+ /**
15
+ * @deprecated Not used anymore, please use the size prop
16
+ */
11
17
  sizeMd?: CartItemActionCardProps['size']
12
18
  variant?: CartItemActionCardProps['variant']
13
19
  itemProps?: Omit<
@@ -0,0 +1,15 @@
1
+ import {
2
+ AddProductsToCartButton,
3
+ AddProductsToCartButtonProps,
4
+ } from '@graphcommerce/magento-product'
5
+ import { Trans } from '@lingui/react'
6
+
7
+ export function EditCartItemButton(props: AddProductsToCartButtonProps) {
8
+ const { children, ...rest } = props
9
+
10
+ return (
11
+ <AddProductsToCartButton color='secondary' {...rest}>
12
+ <Trans id='Save changes' />
13
+ </AddProductsToCartButton>
14
+ )
15
+ }
@@ -0,0 +1,8 @@
1
+ fragment EditCartItemForm on ProductInterface {
2
+ ...ProductCustomizable
3
+ ...ProductWeight
4
+ ...ProductPageItem
5
+ ...ConfigurableOptions
6
+ ...DownloadableProductOptions
7
+ ...BundleProductOptions
8
+ }
@@ -0,0 +1,59 @@
1
+ import { UseHistoryLink, useHistoryGo } from '@graphcommerce/framer-next-pages'
2
+ import {
3
+ useFormAddProductsToCart,
4
+ AddProductsToCartFormProps,
5
+ AddToCartItemSelector,
6
+ AddProductsToCartForm,
7
+ } from '@graphcommerce/magento-product'
8
+ import { useEffect } from 'react'
9
+ import {
10
+ UseRemoveItemFromCartProps,
11
+ useRemoveItemFromCart,
12
+ } from '../../../hooks/useRemoveItemFromCart'
13
+ import {
14
+ CartItemToCartItemInputProps,
15
+ cartItemToCartItemInput,
16
+ } from '../../../utils/cartItemToCartItemInput'
17
+
18
+ type EditInitProps = CartItemToCartItemInputProps & AddToCartItemSelector
19
+
20
+ function EditInit(props: EditInitProps) {
21
+ const { product, selectors, cartItem, index = 0 } = props
22
+ const { setValue } = useFormAddProductsToCart()
23
+
24
+ useEffect(() => {
25
+ const cartItemInput = cartItemToCartItemInput({ product, cartItem, selectors })
26
+ if (cartItemInput) setValue(`cartItems.${index}`, cartItemInput)
27
+ }, [cartItem, index, product, selectors, setValue])
28
+
29
+ return null
30
+ }
31
+
32
+ export type EditCartItemFormProps = CartItemToCartItemInputProps &
33
+ AddToCartItemSelector &
34
+ UseHistoryLink &
35
+ AddProductsToCartFormProps
36
+
37
+ export function EditCartItemForm(props: EditCartItemFormProps) {
38
+ const { product, cartItem, onBeforeSubmit, onComplete, index = 0, children, href } = props
39
+
40
+ const remove = useRemoveItemFromCart(cartItem as UseRemoveItemFromCartProps)
41
+ const goToCart = useHistoryGo({ href })
42
+
43
+ return (
44
+ <AddProductsToCartForm
45
+ {...props}
46
+ onBeforeSubmit={async (variables) => {
47
+ await remove.submit()
48
+ return onBeforeSubmit?.(variables) ?? variables
49
+ }}
50
+ onComplete={async (result, variables) => {
51
+ await goToCart()
52
+ return onComplete?.(result, variables)
53
+ }}
54
+ >
55
+ {children}
56
+ <EditInit product={product} cartItem={cartItem} index={index} />
57
+ </AddProductsToCartForm>
58
+ )
59
+ }
@@ -0,0 +1,3 @@
1
+ export * from './EditCartItemButton/EditCartItemButton'
2
+ export * from './EditCartItemForm/EditCartItemForm'
3
+ export * from './EditCartItemForm/EditCartItemForm.gql'
@@ -1,12 +1,13 @@
1
- import { ApolloCartErrorSnackbar, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
1
+ import { ApolloCartErrorSnackbar } from '@graphcommerce/magento-cart'
2
2
  import { Button, ButtonProps } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
4
  import { SxProps, Theme, styled } from '@mui/material'
5
- import type { DistributedOmit } from 'type-fest'
6
- import { CartItemFragment } from '../../Api/CartItem.gql'
7
- import { RemoveItemFromCartDocument } from './RemoveItemFromCart.gql'
5
+ import {
6
+ UseRemoveItemFromCartProps,
7
+ useRemoveItemFromCart,
8
+ } from '../../hooks/useRemoveItemFromCart'
8
9
 
9
- export type RemoveItemFromCartProps = DistributedOmit<CartItemFragment, '__typename'> & {
10
+ export type RemoveItemFromCartProps = UseRemoveItemFromCartProps & {
10
11
  sx?: SxProps<Theme>
11
12
  buttonProps?: Omit<ButtonProps, 'type' | 'loading'>
12
13
  }
@@ -15,12 +16,10 @@ const Form = styled('form')({})
15
16
 
16
17
  export function RemoveItemFromCart(props: RemoveItemFromCartProps) {
17
18
  const { uid, quantity, prices, buttonProps, ...formProps } = props
18
- const form = useFormGqlMutationCart(RemoveItemFromCartDocument, { defaultValues: { uid } })
19
- const { handleSubmit, formState, error } = form
20
- const submitHandler = handleSubmit(() => {})
21
19
 
20
+ const { submit, formState, error } = useRemoveItemFromCart(props)
22
21
  return (
23
- <Form noValidate onSubmit={submitHandler} {...formProps}>
22
+ <Form noValidate onSubmit={submit} {...formProps}>
24
23
  <Button
25
24
  variant='inline'
26
25
  color='secondary'
@@ -1,11 +1,13 @@
1
- import { ApolloCartErrorSnackbar, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
1
+ import { ApolloCartErrorSnackbar } from '@graphcommerce/magento-cart'
2
2
  import { Fab, FabProps, iconClose } from '@graphcommerce/next-ui'
3
3
  import { i18n } from '@lingui/core'
4
4
  import { SxProps, Theme, styled } from '@mui/material'
5
- import { CartItemFragment } from '../../Api/CartItem.gql'
6
- import { RemoveItemFromCartDocument } from './RemoveItemFromCart.gql'
5
+ import {
6
+ UseRemoveItemFromCartProps,
7
+ useRemoveItemFromCart,
8
+ } from '../../hooks/useRemoveItemFromCart'
7
9
 
8
- export type RemoveItemFromCartFabProps = Omit<CartItemFragment, '__typename'> & {
10
+ export type RemoveItemFromCartFabProps = UseRemoveItemFromCartProps & {
9
11
  sx?: SxProps<Theme>
10
12
  fabProps?: Omit<FabProps, 'type' | 'icon' | 'loading'>
11
13
  }
@@ -14,12 +16,11 @@ const Form = styled('form')({})
14
16
 
15
17
  export function RemoveItemFromCartFab(props: RemoveItemFromCartFabProps) {
16
18
  const { uid, quantity, prices, product, ...formProps } = props
17
- const form = useFormGqlMutationCart(RemoveItemFromCartDocument, { defaultValues: { uid } })
18
- const { handleSubmit, formState, error } = form
19
- const submitHandler = handleSubmit(() => {})
19
+
20
+ const { submit, formState, error } = useRemoveItemFromCart(props)
20
21
 
21
22
  return (
22
- <Form noValidate onSubmit={submitHandler} {...formProps}>
23
+ <Form noValidate onSubmit={submit} {...formProps}>
23
24
  <Fab
24
25
  aria-label={i18n._(/* i18n */ 'Remove Product')}
25
26
  size='small'
@@ -22,29 +22,20 @@ export function SelectedCustomizableOptions(props: SelectedCustomizableOptionPro
22
22
  return (
23
23
  <>
24
24
  {options.map((option) => (
25
- <Box>
26
- <Box key={option.customizable_option_uid} sx={{ color: 'text.primary' }}>
27
- {option.label}
28
- </Box>
25
+ <Box key={option.customizable_option_uid}>
26
+ <Box sx={{ color: 'text.primary' }}>{option.label}</Box>
29
27
  {option.values.filter(nonNullable).map((value) => (
30
28
  <Box
31
- key={option.customizable_option_uid}
29
+ key={value.customizable_option_value_uid}
32
30
  sx={(theme) => ({
33
31
  display: 'flex',
34
32
  gap: theme.spacings.xxs,
35
33
  flexDirection: 'row',
36
34
  })}
37
35
  >
38
- {value.label && (
39
- <span key={`${value.customizable_option_value_uid}_${value.label}`}>
40
- {value.label}
41
- </span>
42
- )}
36
+ {value.label && <span>{value.label}</span>}
43
37
  {value.price.value > 0 && productPrice && (
44
- <Box
45
- sx={(theme) => ({ position: 'absolute', right: theme.spacings.xs })}
46
- key={`${value.customizable_option_value_uid}_${value.price.value}`}
47
- >
38
+ <Box sx={(theme) => ({ position: 'absolute', right: theme.spacings.xs })}>
48
39
  <Money
49
40
  value={
50
41
  value.price.type === 'PERCENT'
@@ -0,0 +1,28 @@
1
+ import { useFormGqlMutationCart } from '@graphcommerce/magento-cart/hooks'
2
+ import { UseFormGraphQlOptions } from '@graphcommerce/react-hook-form'
3
+ import type { DistributedOmit } from 'type-fest'
4
+ import { CartItemFragment } from '../Api/CartItem.gql'
5
+ import {
6
+ RemoveItemFromCartMutation,
7
+ RemoveItemFromCartMutationVariables,
8
+ RemoveItemFromCartDocument,
9
+ } from '../components/RemoveItemFromCart/RemoveItemFromCart.gql'
10
+
11
+ export type UseRemoveItemFromCartProps = DistributedOmit<CartItemFragment, '__typename'> &
12
+ Omit<
13
+ UseFormGraphQlOptions<RemoveItemFromCartMutation, RemoveItemFromCartMutationVariables>,
14
+ 'errors'
15
+ >
16
+
17
+ export function useRemoveItemFromCart(props: UseRemoveItemFromCartProps) {
18
+ const { uid, errors, ...options } = props
19
+
20
+ const form = useFormGqlMutationCart(RemoveItemFromCartDocument, {
21
+ defaultValues: { uid },
22
+ ...options,
23
+ })
24
+
25
+ const { handleSubmit } = form
26
+ const submit = handleSubmit(() => {})
27
+ return { ...form, submit }
28
+ }
package/index.ts CHANGED
@@ -9,3 +9,5 @@ export * from './components/RemoveItemFromCart/RemoveItemFromCart.gql'
9
9
  export * from './components/RemoveItemFromCart/RemoveItemFromCartFab'
10
10
  export * from './components/SelectedCustomizableOptions/SelectedCustomizableOptions'
11
11
  export * from './components/UpdateItemQuantity/UpdateItemQuantity'
12
+ export * from './components/EditCartItem'
13
+ export * from './hooks/useRemoveItemFromCart'
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-cart-items",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "8.1.0-canary.19",
5
+ "version": "8.1.0-canary.20",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,17 +12,18 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.19",
16
- "@graphcommerce/graphql": "^8.1.0-canary.19",
17
- "@graphcommerce/image": "^8.1.0-canary.19",
18
- "@graphcommerce/magento-cart": "^8.1.0-canary.19",
19
- "@graphcommerce/magento-customer": "^8.1.0-canary.19",
20
- "@graphcommerce/magento-product": "^8.1.0-canary.19",
21
- "@graphcommerce/magento-store": "^8.1.0-canary.19",
22
- "@graphcommerce/next-ui": "^8.1.0-canary.19",
23
- "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.19",
24
- "@graphcommerce/react-hook-form": "^8.1.0-canary.19",
25
- "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.19",
15
+ "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.20",
16
+ "@graphcommerce/framer-next-pages": "^8.1.0-canary.20",
17
+ "@graphcommerce/graphql": "^8.1.0-canary.20",
18
+ "@graphcommerce/image": "^8.1.0-canary.20",
19
+ "@graphcommerce/magento-cart": "^8.1.0-canary.20",
20
+ "@graphcommerce/magento-customer": "^8.1.0-canary.20",
21
+ "@graphcommerce/magento-product": "^8.1.0-canary.20",
22
+ "@graphcommerce/magento-store": "^8.1.0-canary.20",
23
+ "@graphcommerce/next-ui": "^8.1.0-canary.20",
24
+ "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.20",
25
+ "@graphcommerce/react-hook-form": "^8.1.0-canary.20",
26
+ "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.20",
26
27
  "@lingui/core": "^4.2.1",
27
28
  "@lingui/macro": "^4.2.1",
28
29
  "@lingui/react": "^4.2.1",
@@ -0,0 +1,117 @@
1
+ import {
2
+ AddProductsToCartFields,
3
+ AnyOption,
4
+ CustomizableProductOptionBase,
5
+ OptionValueSelector,
6
+ SelectorsProp,
7
+ productCustomizableSelectors,
8
+ } from '@graphcommerce/magento-product'
9
+ import { isTypename, filterNonNullableKeys, nonNullable } from '@graphcommerce/next-ui'
10
+ import { CartItemFragment } from '../Api/CartItem.gql'
11
+ import { EditCartItemFormFragment } from '../components/EditCartItem/EditCartItemForm/EditCartItemForm.gql'
12
+
13
+ type CartItemInput = AddProductsToCartFields['cartItems'][number]
14
+
15
+ export type CartItemToCartItemInputProps = {
16
+ product: EditCartItemFormFragment
17
+ cartItem: CartItemFragment
18
+ } & SelectorsProp
19
+
20
+ export function cartItemToCartItemInput(
21
+ props: CartItemToCartItemInputProps,
22
+ ): CartItemInput | undefined {
23
+ const { product, cartItem, selectors } = props
24
+
25
+ if (isTypename(product, ['GroupedProduct']) || !product.sku || !cartItem) return undefined
26
+
27
+ const allSelectors: OptionValueSelector = { ...productCustomizableSelectors, ...selectors }
28
+
29
+ const cartItemInput: CartItemInput = {
30
+ sku: product.sku,
31
+ quantity: cartItem.quantity,
32
+ customizable_options: {},
33
+ selected_options: [],
34
+ entered_options: [],
35
+ }
36
+
37
+ const cartItemCustomizableOptions = filterNonNullableKeys(
38
+ isTypename(cartItem, ['ConfigurableCartItem'])
39
+ ? cartItem.configurable_customizable
40
+ : cartItem.customizable_options,
41
+ )
42
+
43
+ if (cartItemCustomizableOptions.length > 0) {
44
+ product.options?.filter(nonNullable).forEach((productOption) => {
45
+ // @todo Date option: Magento's backend does not provide an ISO date string that can be used, only localized strings are available which can not be parsed.
46
+ // @todo File option: We do not support file options yet.
47
+ if (isTypename(productOption, ['CustomizableDateOption', 'CustomizableFileOption'])) return
48
+
49
+ const selector = allSelectors[productOption.__typename] as
50
+ | undefined
51
+ | ((option: AnyOption) => CustomizableProductOptionBase | CustomizableProductOptionBase[])
52
+ const possibleProductValues = selector ? selector(productOption) : null
53
+
54
+ const cartItemCustomizableOption = cartItemCustomizableOptions.find(
55
+ (option) => option?.customizable_option_uid === productOption.uid,
56
+ )
57
+
58
+ const cartItemCustomizableOptionValue = filterNonNullableKeys(
59
+ cartItemCustomizableOption?.values,
60
+ )
61
+ if (cartItemCustomizableOptionValue.length === 0) return
62
+
63
+ if (Array.isArray(possibleProductValues)) {
64
+ const value = cartItemCustomizableOptionValue.map((v) => v.customizable_option_value_uid)
65
+ if (!cartItemInput.customizable_options) cartItemInput.customizable_options = {}
66
+ cartItemInput.customizable_options[productOption.uid] = isTypename(productOption, [
67
+ 'CustomizableRadioOption',
68
+ 'CustomizableDropDownOption',
69
+ ])
70
+ ? value[0]
71
+ : value
72
+ } else {
73
+ const idx = (productOption.sort_order ?? 0) + 100
74
+
75
+ if (!cartItemInput.entered_options) cartItemInput.entered_options = []
76
+ cartItemInput.entered_options[idx] = {
77
+ uid: productOption.uid,
78
+ value: cartItemCustomizableOptionValue[0].value,
79
+ }
80
+ }
81
+ })
82
+ }
83
+
84
+ if (isTypename(cartItem, ['ConfigurableCartItem']) && cartItem.configurable_options) {
85
+ cartItemInput.selected_options = filterNonNullableKeys(cartItem.configurable_options).map(
86
+ (option) => option.configurable_product_option_value_uid,
87
+ )
88
+ }
89
+
90
+ if (isTypename(cartItem, ['BundleCartItem']) && isTypename(product, ['BundleProduct'])) {
91
+ filterNonNullableKeys(product.items).forEach((productBundleItem, i) => {
92
+ const cartItemBundleOption = cartItem.bundle_options.find(
93
+ (option) => option?.uid === productBundleItem?.uid,
94
+ )
95
+
96
+ if (!cartItemBundleOption) return
97
+
98
+ // todo multi select..
99
+ const idx = productBundleItem.position ?? 0 + 1000
100
+ const value = cartItemBundleOption.values[0]
101
+
102
+ if (!value) return
103
+ if (productBundleItem.options?.some((o) => o?.can_change_quantity)) {
104
+ if (!cartItemInput.entered_options) cartItemInput.entered_options = []
105
+ cartItemInput.entered_options[idx] = {
106
+ uid: value.uid,
107
+ value: `${value.quantity}`,
108
+ }
109
+ } else {
110
+ if (!cartItemInput.selected_options) cartItemInput.selected_options = []
111
+ cartItemInput.selected_options[idx] = value.uid
112
+ }
113
+ })
114
+ }
115
+
116
+ return cartItemInput
117
+ }