@graphcommerce/magento-product-configurable 4.13.2 → 4.14.0-canary.10
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 +43 -1
- package/ConfigurableCartItem/ConfigurableCartItem.graphql +7 -0
- package/ConfigurableCartItem/ConfigurableCartItem.tsx +16 -2
- package/ConfigurableCartItem/OptionsList.tsx +1 -1
- package/ConfigurableContext/ConfigurableContext.tsx +5 -5
- package/SwatchList.tsx +3 -2
- package/components/ConfigurableProductOptions/ConfigurableProductOptions.tsx +1 -1
- package/components/ProductListItemConfigurable/ProductListItemConfigurable.tsx +1 -1
- package/graphql/ConfigurableOptionsSelection.graphql +3 -32
- package/graphql/ConfiguredVariant.graphql +15 -0
- package/graphql/GetConfigurableOptionsSelection.graphql +1 -0
- package/hooks/useConfigurableOptionsSelection.ts +0 -1
- package/index.ts +1 -0
- package/package.json +13 -13
- package/utils/DefaultConfigurableOptionsSelection.graphql +13 -0
- package/utils/defaultConfigurableOptionsSelection.ts +116 -0
- package/utils/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
## 4.
|
|
3
|
+
## 4.14.0-canary.10
|
|
4
|
+
|
|
5
|
+
## 4.14.0-canary.9
|
|
6
|
+
|
|
7
|
+
## 4.14.0-canary.8
|
|
8
|
+
|
|
9
|
+
## 4.14.0-canary.7
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#1738](https://github.com/graphcommerce-org/graphcommerce/pull/1738) [`41f907dd4`](https://github.com/graphcommerce-org/graphcommerce/commit/41f907dd4eea20624ba87bdea48d9c330b8c0762) - Fix issue where the configurable cart item couldn’t be properly loaded ([@paales](https://github.com/paales))
|
|
14
|
+
|
|
15
|
+
## 4.14.0-canary.6
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- [#1737](https://github.com/graphcommerce-org/graphcommerce/pull/1737) [`1f5ece0c2`](https://github.com/graphcommerce-org/graphcommerce/commit/1f5ece0c24524f33561614adf09f669d305666b0) - Allow Simple Products to show the Confgurable product page. Created a new defaultConfigurableOptionsSelection utility function to set up all the data correctly. ([@paales](https://github.com/paales))
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- [#1737](https://github.com/graphcommerce-org/graphcommerce/pull/1737) [`c278116d4`](https://github.com/graphcommerce-org/graphcommerce/commit/c278116d4c6f984a0b542fbf9426b8fc676ab36e) - Render the configured_variant image in the cart ([@paales](https://github.com/paales))
|
|
24
|
+
|
|
25
|
+
- [#1737](https://github.com/graphcommerce-org/graphcommerce/pull/1737) [`3916fdd7a`](https://github.com/graphcommerce-org/graphcommerce/commit/3916fdd7a801b381df6ce1708bf388a2c581eab1) - Make sure configurable_options without swatch data still render correctly ([@paales](https://github.com/paales))
|
|
26
|
+
|
|
27
|
+
## 4.14.0-canary.5
|
|
28
|
+
|
|
29
|
+
## 4.14.0-canary.4
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- [#1733](https://github.com/graphcommerce-org/graphcommerce/pull/1733) [`29eb2e94f`](https://github.com/graphcommerce-org/graphcommerce/commit/29eb2e94f04b120bc060ab945ff28aabf3f3ecfd) - Dependency issue with Magento 2.4.5 ([@paales](https://github.com/paales))
|
|
34
|
+
|
|
35
|
+
## 4.14.0-canary.3
|
|
36
|
+
|
|
37
|
+
## 4.14.0-canary.2
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- [#1718](https://github.com/graphcommerce-org/graphcommerce/pull/1718) [`37e86cdc8`](https://github.com/graphcommerce-org/graphcommerce/commit/37e86cdc86ccca3db77d6c59b1e14c8112bb7893) - Remove usage of PropsWithChildren ([@paales](https://github.com/paales))
|
|
42
|
+
|
|
43
|
+
## 4.13.2-canary.1
|
|
44
|
+
|
|
45
|
+
## 4.13.2-canary.0
|
|
4
46
|
|
|
5
47
|
## 4.13.1
|
|
6
48
|
|
|
@@ -3,9 +3,23 @@ import { ConfigurableCartItemFragment } from './ConfigurableCartItem.gql'
|
|
|
3
3
|
import { OptionsList } from './OptionsList'
|
|
4
4
|
|
|
5
5
|
export function ConfigurableCartItem(props: ConfigurableCartItemFragment & CartItemProps) {
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
configurable_options,
|
|
8
|
+
configurable_customizable,
|
|
9
|
+
configured_variant,
|
|
10
|
+
product,
|
|
11
|
+
...cartItemProps
|
|
12
|
+
} = props
|
|
7
13
|
return (
|
|
8
|
-
<CartItem
|
|
14
|
+
<CartItem
|
|
15
|
+
{...cartItemProps}
|
|
16
|
+
product={{
|
|
17
|
+
...product,
|
|
18
|
+
name: configured_variant?.name ?? product.name,
|
|
19
|
+
thumbnail: configured_variant?.thumbnail ?? product.thumbnail,
|
|
20
|
+
}}
|
|
21
|
+
withOptions
|
|
22
|
+
>
|
|
9
23
|
<OptionsList configurable_options={configurable_options} />
|
|
10
24
|
</CartItem>
|
|
11
25
|
)
|
|
@@ -2,7 +2,7 @@ import { extendableComponent } from '@graphcommerce/next-ui'
|
|
|
2
2
|
import { Box, SxProps, Theme } from '@mui/material'
|
|
3
3
|
import { ConfigurableCartItemFragment } from './ConfigurableCartItem.gql'
|
|
4
4
|
|
|
5
|
-
type CartItemOptionsListProps = ConfigurableCartItemFragment & {
|
|
5
|
+
type CartItemOptionsListProps = Partial<ConfigurableCartItemFragment> & {
|
|
6
6
|
sx?: SxProps<Theme>
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useContext,
|
|
3
3
|
createContext,
|
|
4
|
-
PropsWithChildren,
|
|
5
4
|
Context,
|
|
6
5
|
useState,
|
|
7
6
|
Dispatch,
|
|
@@ -12,7 +11,10 @@ import {
|
|
|
12
11
|
import { ConfigurableProductFormFragment } from './ConfigurableProductForm.gql'
|
|
13
12
|
import cheapestVariant from './cheapestVariant'
|
|
14
13
|
|
|
15
|
-
type ConfigurableProductFormProps = ConfigurableProductFormFragment & {
|
|
14
|
+
type ConfigurableProductFormProps = ConfigurableProductFormFragment & {
|
|
15
|
+
sku: string
|
|
16
|
+
children?: React.ReactNode
|
|
17
|
+
}
|
|
16
18
|
|
|
17
19
|
export type Selected = { [attrCode: string]: number }
|
|
18
20
|
export type Variants = NonNullable<ConfigurableProductFormProps['variants']>
|
|
@@ -114,9 +116,7 @@ function traverseAttrTree(selection: Selected, attrTree: AttributeTree | undefin
|
|
|
114
116
|
return variantList
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
export function ConfigurableContextProvider(
|
|
118
|
-
props: PropsWithChildren<ConfigurableProductFormProps>,
|
|
119
|
-
) {
|
|
119
|
+
export function ConfigurableContextProvider(props: ConfigurableProductFormProps) {
|
|
120
120
|
const { children, sku, configurable_options, variants: providedVariants } = props
|
|
121
121
|
const [selection, select] = useState<Selected>({})
|
|
122
122
|
|
package/SwatchList.tsx
CHANGED
|
@@ -8,7 +8,7 @@ import { SwatchSize, SwatchTypeRenderer } from './Swatches/types'
|
|
|
8
8
|
import { ProductListItemConfigurableFragment } from './components/ProductListItemConfigurable/ProductListItemConfigurable.gql'
|
|
9
9
|
|
|
10
10
|
type SwatchListProps = {
|
|
11
|
-
attributes
|
|
11
|
+
attributes?: string[]
|
|
12
12
|
configurable_options?: Maybe<ProductListItemConfigurableFragment['configurable_options']>
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -18,7 +18,8 @@ const renderer: SwatchTypeRenderer = {
|
|
|
18
18
|
ColorSwatchData,
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export function SwatchList(
|
|
21
|
+
export function SwatchList(props: SwatchListProps) {
|
|
22
|
+
const { attributes = [], configurable_options } = props
|
|
22
23
|
const options =
|
|
23
24
|
configurable_options?.filter((option) => attributes.includes(option?.attribute_code ?? '')) ??
|
|
24
25
|
[]
|
|
@@ -38,7 +38,7 @@ export function ConfigurableProductOptions(props: ConfigurableProductOptionsProp
|
|
|
38
38
|
filterNonNullableKeys(product.configurable_options, ['attribute_code', 'label']).map(
|
|
39
39
|
(option) => ({
|
|
40
40
|
...option,
|
|
41
|
-
values: filterNonNullableKeys(option.values, ['uid'
|
|
41
|
+
values: filterNonNullableKeys(option.values, ['uid']).map((ov) => ({
|
|
42
42
|
value: ov.uid,
|
|
43
43
|
...ov,
|
|
44
44
|
})),
|
|
@@ -14,7 +14,7 @@ export type ProductListItemConfigurableActionProps = ProductListItemConfigurable
|
|
|
14
14
|
|
|
15
15
|
export type ProdustListItemConfigurableProps = ProductListItemConfigurableFragment &
|
|
16
16
|
ProductListItemProps & {
|
|
17
|
-
swatchLocations?: Record<OverlayAreaKeys, string[]
|
|
17
|
+
swatchLocations?: Partial<Record<OverlayAreaKeys, string[]>>
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function ProductListItemConfigurable(props: ProdustListItemConfigurableProps) {
|
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
fragment ConfigurableOptionsSelection on ConfigurableProduct @injectable {
|
|
2
2
|
configurable_product_options_selection(configurableOptionValueUids: $selectedOptions) {
|
|
3
|
-
|
|
4
|
-
attribute_code
|
|
5
|
-
label
|
|
6
|
-
values {
|
|
7
|
-
is_available
|
|
8
|
-
is_use_default
|
|
9
|
-
label
|
|
10
|
-
swatch {
|
|
11
|
-
value
|
|
12
|
-
... on ImageSwatchData {
|
|
13
|
-
thumbnail
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
uid
|
|
17
|
-
}
|
|
18
|
-
}
|
|
3
|
+
__typename
|
|
19
4
|
options_available_for_selection {
|
|
5
|
+
__typename
|
|
20
6
|
attribute_code
|
|
21
|
-
option_value_uids
|
|
22
7
|
}
|
|
23
8
|
media_gallery {
|
|
24
9
|
__typename
|
|
@@ -29,21 +14,7 @@ fragment ConfigurableOptionsSelection on ConfigurableProduct @injectable {
|
|
|
29
14
|
...ProductVideo
|
|
30
15
|
}
|
|
31
16
|
variant {
|
|
32
|
-
|
|
33
|
-
name
|
|
34
|
-
thumbnail {
|
|
35
|
-
...ProductImage
|
|
36
|
-
}
|
|
37
|
-
price_range {
|
|
38
|
-
minimum_price {
|
|
39
|
-
final_price {
|
|
40
|
-
...Money
|
|
41
|
-
}
|
|
42
|
-
regular_price {
|
|
43
|
-
...Money
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
17
|
+
...ConfiguredVariant
|
|
47
18
|
}
|
|
48
19
|
}
|
|
49
20
|
}
|
|
@@ -19,7 +19,6 @@ export function useConfigurableOptionsSelection({
|
|
|
19
19
|
const cpc = useQuery(GetConfigurableOptionsSelectionDocument, {
|
|
20
20
|
variables: { urlKey: url_key ?? '', selectedOptions },
|
|
21
21
|
skip: !url_key || !selectedOptions.length,
|
|
22
|
-
ssr: false,
|
|
23
22
|
})
|
|
24
23
|
|
|
25
24
|
const configured = findByTypename(
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/magento-product-configurable",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.14.0-canary.10",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -19,18 +19,18 @@
|
|
|
19
19
|
"type-fest": "^2.12.2"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@graphcommerce/graphql": "4.
|
|
23
|
-
"@graphcommerce/graphql-mesh": "4.
|
|
24
|
-
"@graphcommerce/image": "4.
|
|
25
|
-
"@graphcommerce/magento-cart": "4.
|
|
26
|
-
"@graphcommerce/magento-cart-items": "4.
|
|
27
|
-
"@graphcommerce/magento-category": "4.
|
|
28
|
-
"@graphcommerce/magento-customer": "4.
|
|
29
|
-
"@graphcommerce/magento-product": "4.
|
|
30
|
-
"@graphcommerce/magento-product-simple": "4.
|
|
31
|
-
"@graphcommerce/magento-store": "4.
|
|
32
|
-
"@graphcommerce/next-ui": "4.
|
|
33
|
-
"@graphcommerce/react-hook-form": "4.
|
|
22
|
+
"@graphcommerce/graphql": "4.31.0-canary.6",
|
|
23
|
+
"@graphcommerce/graphql-mesh": "4.31.0-canary.6",
|
|
24
|
+
"@graphcommerce/image": "4.31.0-canary.6",
|
|
25
|
+
"@graphcommerce/magento-cart": "4.14.0-canary.10",
|
|
26
|
+
"@graphcommerce/magento-cart-items": "4.14.0-canary.10",
|
|
27
|
+
"@graphcommerce/magento-category": "4.14.0-canary.10",
|
|
28
|
+
"@graphcommerce/magento-customer": "4.14.0-canary.10",
|
|
29
|
+
"@graphcommerce/magento-product": "4.14.0-canary.10",
|
|
30
|
+
"@graphcommerce/magento-product-simple": "4.14.0-canary.10",
|
|
31
|
+
"@graphcommerce/magento-store": "4.14.0-canary.10",
|
|
32
|
+
"@graphcommerce/next-ui": "4.31.0-canary.6",
|
|
33
|
+
"@graphcommerce/react-hook-form": "4.31.0-canary.6"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@lingui/react": "^3.13.2",
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ApolloClient } from '@graphcommerce/graphql'
|
|
2
|
+
import { AddProductsToCartFormProps } from '@graphcommerce/magento-product'
|
|
3
|
+
import { findByTypename, filterNonNullableKeys } from '@graphcommerce/next-ui'
|
|
4
|
+
import { GetConfigurableOptionsSelectionDocument } from '../graphql'
|
|
5
|
+
import { DefaultConfigurableOptionsSelectionFragment } from './DefaultConfigurableOptionsSelection.gql'
|
|
6
|
+
|
|
7
|
+
type BaseQuery =
|
|
8
|
+
| { products?: DefaultConfigurableOptionsSelectionFragment | null | undefined }
|
|
9
|
+
| null
|
|
10
|
+
| undefined
|
|
11
|
+
|
|
12
|
+
let warned = false
|
|
13
|
+
/**
|
|
14
|
+
* This method writes the GetConfigurableOptionsSelection query result to the Apollo cache and sets
|
|
15
|
+
* the defaultValues for the `<AddProductsToCartForm defaultValues={{}}/>`.
|
|
16
|
+
*/
|
|
17
|
+
export function defaultConfigurableOptionsSelection<Q extends BaseQuery = BaseQuery>(
|
|
18
|
+
urlKey: string,
|
|
19
|
+
client: ApolloClient<object>,
|
|
20
|
+
query: Q,
|
|
21
|
+
): Q & Pick<AddProductsToCartFormProps, 'defaultValues'> {
|
|
22
|
+
const requested = query?.products?.items?.find((p) => p?.url_key === urlKey)
|
|
23
|
+
if (!requested || requested?.__typename !== 'SimpleProduct')
|
|
24
|
+
return { ...query, defaultValues: {} }
|
|
25
|
+
|
|
26
|
+
const configurable = findByTypename(query?.products?.items, 'ConfigurableProduct')
|
|
27
|
+
const variant = findByTypename(query?.products?.items, 'SimpleProduct')
|
|
28
|
+
|
|
29
|
+
if (!configurable?.url_key || !variant) return { ...query, products: { items: [requested] } }
|
|
30
|
+
|
|
31
|
+
const selectedOptions: string[] = []
|
|
32
|
+
|
|
33
|
+
const options = filterNonNullableKeys(configurable.configurable_options)
|
|
34
|
+
|
|
35
|
+
const warnFor: string[] = []
|
|
36
|
+
options.forEach((o, index) => {
|
|
37
|
+
const simpleValue = variant[o.attribute_code]
|
|
38
|
+
if (!simpleValue) warnFor.push(o.attribute_code)
|
|
39
|
+
|
|
40
|
+
filterNonNullableKeys(o.values).forEach((v) => {
|
|
41
|
+
if (Buffer.from(v.uid, 'base64').toString('utf8').endsWith(`/${simpleValue}`)) {
|
|
42
|
+
selectedOptions[index] = v.uid
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if (process.env.NODE_ENV !== 'production' && warnFor.length && !warned) {
|
|
48
|
+
warned = true
|
|
49
|
+
const warnStr = warnFor.join(', ')
|
|
50
|
+
console.warn(
|
|
51
|
+
`[@graphcommerce/magento-product-configurable]: The following attributes were found in the configurable options: ${warnStr}. However, they were not found in the simple product. Please add the following attributes to the simple product: ${warnStr}`,
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
if (warnFor.length) {
|
|
55
|
+
return {
|
|
56
|
+
...query,
|
|
57
|
+
products: { items: [requested] },
|
|
58
|
+
defaultValues: {},
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!selectedOptions.length) return { ...query, defaultValues: {} }
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* We're using writeQuery to the Apollo Client cache, to to avoid a second request to the GraphQL
|
|
66
|
+
* API. However, this is resulting in somewhat brittle code, because when the
|
|
67
|
+
* GetConfigurableOptionsSelectionDocument query is modified, this code can break.
|
|
68
|
+
*
|
|
69
|
+
* Even if this code won't break the frontend will throw an hydration error if addtional fields
|
|
70
|
+
* need to be requested.
|
|
71
|
+
*
|
|
72
|
+
* The code below by default does the exact same thing as:
|
|
73
|
+
*
|
|
74
|
+
* ```ts
|
|
75
|
+
* await client.query({
|
|
76
|
+
* query: GetConfigurableOptionsSelectionDocument,
|
|
77
|
+
* variables: { urlKey: configurable.url_key, selectedOptions },
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
client.cache.writeQuery({
|
|
82
|
+
query: GetConfigurableOptionsSelectionDocument,
|
|
83
|
+
variables: { urlKey: configurable.url_key, selectedOptions },
|
|
84
|
+
data: {
|
|
85
|
+
products: {
|
|
86
|
+
__typename: 'Products',
|
|
87
|
+
items: [
|
|
88
|
+
{
|
|
89
|
+
__typename: 'ConfigurableProduct',
|
|
90
|
+
uid: configurable.uid,
|
|
91
|
+
configurable_product_options_selection: {
|
|
92
|
+
__typename: 'ConfigurableProductOptionsSelection',
|
|
93
|
+
media_gallery: variant.media_gallery,
|
|
94
|
+
variant: {
|
|
95
|
+
__typename: 'SimpleProduct',
|
|
96
|
+
price_range: variant.price_range,
|
|
97
|
+
uid: variant.uid,
|
|
98
|
+
name: variant.name,
|
|
99
|
+
},
|
|
100
|
+
options_available_for_selection: options.map(({ attribute_code }) => ({
|
|
101
|
+
__typename: 'ConfigurableOptionAvailableForSelection' as const,
|
|
102
|
+
attribute_code,
|
|
103
|
+
})),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
...query,
|
|
113
|
+
products: { items: [configurable] },
|
|
114
|
+
defaultValues: { cartItems: [{ selected_options: selectedOptions }] },
|
|
115
|
+
}
|
|
116
|
+
}
|
package/utils/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './defaultConfigurableOptionsSelection'
|