@graphcommerce/magento-product-configurable 9.0.0-canary.99 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +87 -1054
  2. package/ConfigurableCartItem/ConfigurableCartItem.tsx +7 -2
  3. package/ConfigurableCartItem/OptionsList.tsx +5 -4
  4. package/SwatchList.tsx +3 -3
  5. package/Swatches/ColorSwatchData.tsx +7 -6
  6. package/Swatches/ImageSwatchData.tsx +8 -6
  7. package/Swatches/TextSwatchData.tsx +6 -5
  8. package/Swatches/types.ts +4 -4
  9. package/components/ConfigurableCartItemOptions/ConfigurableCartItemOptions.tsx +4 -3
  10. package/components/ConfigurableOptionValue/ConfigurableOptionValue.tsx +2 -2
  11. package/components/ConfigurableOptionValueColor/ConfigurableOptionValueColor.tsx +2 -2
  12. package/components/ConfigurableOptionValueImage/ConfigurableOptionValueImage.tsx +2 -2
  13. package/components/ConfigurableOptionValueText/ConfigurableOptionValueText.tsx +2 -2
  14. package/components/ConfigurableProductOptions/ConfigurableProductOption.tsx +16 -13
  15. package/components/ConfigurableProductOptions/ConfigurableProductOptions.tsx +11 -5
  16. package/components/ProductListItemConfigurable/ProductListItemConfigurable.tsx +3 -6
  17. package/hooks/useConfigurableOptionsSelection.ts +2 -1
  18. package/index.ts +0 -2
  19. package/package.json +19 -19
  20. package/plugins/ConfigurableProductPage/ConfigurableProductPageDescription.tsx +2 -2
  21. package/plugins/ConfigurableProductPage/ConfigurableProductPageGallery.tsx +1 -0
  22. package/plugins/ConfigurableProductPage/ConfigurableProductPageMeta.tsx +2 -5
  23. package/plugins/ConfigurableProductPage/ConfigurableProductPagePrice.tsx +1 -1
  24. package/test/addConfigurableProductToCart.ts +2 -1
  25. package/utils/defaultConfigurableOptionsSelection.ts +3 -3
  26. package/ConfigurableContext/ConfigurableContext.tsx +0 -165
  27. package/ConfigurableContext/cheapestVariant.ts +0 -14
  28. package/ConfigurableOptions/ConfigurableOptions.tsx +0 -143
  29. package/ConfigurableProductAddToCart/ConfigurableProductAddToCart.tsx +0 -185
@@ -1,143 +0,0 @@
1
- import { Controller, FieldErrors, UseControllerProps } from '@graphcommerce/ecommerce-ui'
2
- import {
3
- RenderType,
4
- SectionHeader,
5
- ToggleButton,
6
- ToggleButtonGroup,
7
- extendableComponent,
8
- } from '@graphcommerce/next-ui'
9
- import { BaseTextFieldProps, FormHelperText, SxProps } from '@mui/material'
10
- import React from 'react'
11
- import { Selected, useConfigurableContext } from '../ConfigurableContext/ConfigurableContext'
12
- import { ColorSwatchData } from '../Swatches/ColorSwatchData'
13
- import { ImageSwatchData } from '../Swatches/ImageSwatchData'
14
- import { TextSwatchData } from '../Swatches/TextSwatchData'
15
- import { SwatchTypeRenderer, SwatchSize } from '../Swatches/types'
16
-
17
- export type ConfigurableOptionsInputProps = {
18
- sku: string
19
- errors?: FieldErrors
20
- size?: SwatchSize
21
- sx?: SxProps
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
- } & UseControllerProps<any> &
24
- Pick<BaseTextFieldProps, 'FormHelperTextProps' | 'helperText'> & {
25
- optionEndLabels?: Record<string, React.ReactNode>
26
- }
27
-
28
- const renderer: SwatchTypeRenderer = { TextSwatchData, ImageSwatchData, ColorSwatchData }
29
-
30
- const compName = 'ConfigurableOptionsInput' as const
31
- const parts = ['buttonGroup', 'button', 'helperText'] as const
32
- const { classes } = extendableComponent(compName, parts)
33
-
34
- export function ConfigurableOptionsInput(props: ConfigurableOptionsInputProps) {
35
- const {
36
- sku,
37
- FormHelperTextProps,
38
- name,
39
- defaultValue,
40
- errors,
41
- helperText,
42
- optionEndLabels,
43
- size = 'large',
44
- sx,
45
- ...controlProps
46
- } = props
47
-
48
- const { options, selection, select, getVariants } = useConfigurableContext(sku)
49
-
50
- return (
51
- <>
52
- {options?.map((option) => {
53
- if (!option?.uid || !option.attribute_code) return null
54
-
55
- const { attribute_code } = option
56
- const error = errors?.[attribute_code]
57
-
58
- return (
59
- <Controller
60
- key={option.uid}
61
- defaultValue={selection[attribute_code] ?? ''}
62
- name={`${name}[${attribute_code}]`}
63
- {...controlProps}
64
- render={({
65
- field: { onChange, value, name: inputName, ref, onBlur },
66
- fieldState: { error: errorHelperText },
67
- }) => (
68
- <>
69
- <SectionHeader
70
- labelLeft={option?.label}
71
- labelRight={optionEndLabels?.[option?.attribute_code ?? '']}
72
- />
73
- <ToggleButtonGroup
74
- defaultValue={selection[attribute_code] ?? ''}
75
- required
76
- exclusive
77
- onChange={(_, val: string | number) => {
78
- onChange(val)
79
- select((prev) => ({ ...prev, [attribute_code]: val } as Selected))
80
- }}
81
- ref={ref}
82
- onBlur={onBlur}
83
- value={value}
84
- className={classes.buttonGroup}
85
- size={size}
86
- sx={sx}
87
- >
88
- {option?.values?.map((val) => {
89
- if (!val?.uid || !option.attribute_code) return null
90
-
91
- // Fall back to text swatch if no swatch is given
92
- const swatch_data = val.swatch_data ?? {
93
- __typename: 'TextSwatchData',
94
- value: val.store_label,
95
- }
96
-
97
- const copySelection = { ...selection }
98
- delete copySelection[attribute_code]
99
-
100
- const itemVariant = getVariants(copySelection).find((variant) =>
101
- variant?.attributes?.find((attribute) => attribute?.uid === val.uid),
102
- )
103
-
104
- return (
105
- <ToggleButton
106
- key={val.uid}
107
- value={val.uid ?? ''}
108
- name={inputName}
109
- className={classes.button}
110
- disabled={!itemVariant}
111
- size={size}
112
- >
113
- <RenderType
114
- renderer={renderer}
115
- {...val}
116
- {...swatch_data}
117
- price={itemVariant?.product?.price_range.minimum_price.final_price}
118
- size={size}
119
- />
120
- </ToggleButton>
121
- )
122
- })}
123
- </ToggleButtonGroup>
124
- {error && (
125
- <FormHelperText
126
- error
127
- {...FormHelperTextProps}
128
- className={classes.helperText}
129
- sx={{
130
- position: 'absolute',
131
- }}
132
- >
133
- {`${option.label} is ${errorHelperText?.type}`}
134
- </FormHelperText>
135
- )}
136
- </>
137
- )}
138
- />
139
- )
140
- })}
141
- </>
142
- )
143
- }
@@ -1,185 +0,0 @@
1
- import { NumberFieldElement } from '@graphcommerce/ecommerce-ui'
2
- import { ApolloCartErrorAlert, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
3
- import { Money } from '@graphcommerce/magento-store'
4
- import {
5
- Button,
6
- extendableComponent,
7
- iconChevronRight,
8
- MessageSnackbar,
9
- IconSvg,
10
- } from '@graphcommerce/next-ui'
11
- import { Trans } from '@lingui/macro'
12
- import { Divider, Typography, Alert, Box, SxProps, Theme } from '@mui/material'
13
- import React from 'react'
14
- import { useConfigurableContext } from '../ConfigurableContext/ConfigurableContext'
15
- import cheapestVariant from '../ConfigurableContext/cheapestVariant'
16
- import {
17
- ConfigurableOptionsInput,
18
- ConfigurableOptionsInputProps,
19
- } from '../ConfigurableOptions/ConfigurableOptions'
20
- import {
21
- ConfigurableProductAddToCartDocument,
22
- ConfigurableProductAddToCartMutationVariables,
23
- } from '../graphql/ConfigurableProductAddToCart.gql'
24
-
25
- type ConfigurableProductAddToCartProps = {
26
- variables: Omit<ConfigurableProductAddToCartMutationVariables, 'cartId' | 'selectedOptions'>
27
- name: string
28
- optionEndLabels?: Record<string, React.ReactNode>
29
- children?: React.ReactNode
30
- additionalButtons?: React.ReactNode
31
- sx?: SxProps<Theme>
32
- optionsProps?: Omit<
33
- ConfigurableOptionsInputProps,
34
- 'name' | 'sku' | 'control' | 'rules' | 'errors' | 'optionEndLabels'
35
- >
36
- }
37
-
38
- const compName = 'ConfigurableOptionsInput' as const
39
- const parts = ['form', 'button', 'finalPrice', 'quantity', 'divider', 'buttonWrapper'] as const
40
- const { classes } = extendableComponent(compName, parts)
41
-
42
- /**
43
- * @deprecated
44
- */
45
- export function ConfigurableProductAddToCart(props: ConfigurableProductAddToCartProps) {
46
- const {
47
- name,
48
- children,
49
- variables,
50
- optionEndLabels,
51
- optionsProps,
52
- additionalButtons,
53
- sx = [],
54
- ...buttonProps
55
- } = props
56
-
57
- const { getVariants, selection } = useConfigurableContext(variables.sku)
58
-
59
- const form = useFormGqlMutationCart(ConfigurableProductAddToCartDocument, {
60
- defaultValues: { ...variables },
61
- onBeforeSubmit: ({ selectedOptions, ...vars }) => ({
62
- ...vars,
63
- selectedOptions: Object.values(selectedOptions),
64
- }),
65
- })
66
-
67
- const { handleSubmit, formState, required, control, error, data } = form
68
- const submitHandler = handleSubmit(() => {})
69
-
70
- return (
71
- <Box
72
- component='form'
73
- onSubmit={submitHandler}
74
- noValidate
75
- className={classes.form}
76
- sx={[
77
- {
78
- width: '100%',
79
- },
80
- ...(Array.isArray(sx) ? sx : [sx]),
81
- ]}
82
- >
83
- <Divider className={classes.divider} sx={(theme) => ({ margin: `${theme.spacings.sm} 0` })} />
84
- <ConfigurableOptionsInput
85
- name='selectedOptions'
86
- sku={variables.sku}
87
- control={control}
88
- rules={{ required: required.selectedOptions }}
89
- errors={formState.errors}
90
- optionEndLabels={optionEndLabels}
91
- {...optionsProps}
92
- />
93
-
94
- <NumberFieldElement
95
- variant='outlined'
96
- error={formState.isSubmitted && !!formState.errors.quantity}
97
- required={required.quantity}
98
- inputProps={{ min: 1 }}
99
- name='quantity'
100
- rules={{ required: required.quantity }}
101
- control={control}
102
- helperText={formState.isSubmitted && formState.errors.quantity?.message}
103
- // disabled={loading}
104
- size='small'
105
- className={classes.quantity}
106
- sx={(theme) => ({ marginTop: theme.spacings.sm })}
107
- />
108
- <Divider className={classes.divider} sx={(theme) => ({ margin: `${theme.spacings.sm} 0` })} />
109
- <Typography
110
- component='div'
111
- variant='h3'
112
- className={classes.finalPrice}
113
- sx={(theme) => ({ marginTop: theme.spacings.sm })}
114
- >
115
- <Money
116
- {...cheapestVariant(getVariants(selection))?.product?.price_range.minimum_price
117
- .final_price}
118
- />
119
- </Typography>
120
- {children}
121
- <Box
122
- sx={(theme) => ({
123
- display: 'flex',
124
- alignItems: 'center',
125
- columnGap: theme.spacings.xs,
126
- })}
127
- className={classes.buttonWrapper}
128
- >
129
- <Button
130
- type='submit'
131
- loading={formState.isSubmitting}
132
- color='primary'
133
- variant='pill'
134
- size='large'
135
- className={classes.button}
136
- {...buttonProps}
137
- sx={(theme) => ({
138
- marginTop: theme.spacings.sm,
139
- marginBottom: theme.spacings.sm,
140
- width: '100%',
141
- })}
142
- >
143
- <Trans>Add to Cart</Trans>
144
- </Button>
145
- {additionalButtons}
146
- </Box>
147
-
148
- <ApolloCartErrorAlert error={error} />
149
-
150
- {data?.addProductsToCart?.user_errors.map((e) => (
151
- <Box key={e?.code}>
152
- <Alert severity='error'>{e?.message}</Alert>
153
- </Box>
154
- ))}
155
-
156
- <MessageSnackbar
157
- open={
158
- !formState.isSubmitting &&
159
- formState.isSubmitSuccessful &&
160
- !error?.message &&
161
- !data?.addProductsToCart?.user_errors?.length
162
- }
163
- variant='pill'
164
- severity='success'
165
- autoHide
166
- action={
167
- <Button
168
- href='/cart'
169
- id='view-shopping-cart-button'
170
- size='medium'
171
- variant='pill'
172
- color='secondary'
173
- endIcon={<IconSvg src={iconChevronRight} />}
174
- >
175
- <Trans>View shopping cart</Trans>
176
- </Button>
177
- }
178
- >
179
- <Trans>
180
- <strong>{name}</strong> has been added to your shopping cart!
181
- </Trans>
182
- </MessageSnackbar>
183
- </Box>
184
- )
185
- }