@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 CHANGED
@@ -1,6 +1,48 @@
1
1
  # Change Log
2
2
 
3
- ## 4.13.2
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
 
@@ -8,4 +8,11 @@ fragment ConfigurableCartItem on ConfigurableCartItem @inject(into: ["CartItem"]
8
8
  configurable_customizable: customizable_options {
9
9
  ...SelectedCustomizableOption
10
10
  }
11
+ configured_variant {
12
+ uid
13
+ name
14
+ thumbnail {
15
+ ...ProductImage
16
+ }
17
+ }
11
18
  }
@@ -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 { configurable_options, ...cartItemProps } = props
6
+ const {
7
+ configurable_options,
8
+ configurable_customizable,
9
+ configured_variant,
10
+ product,
11
+ ...cartItemProps
12
+ } = props
7
13
  return (
8
- <CartItem {...cartItemProps} withOptions>
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 & { sku: string }
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: string[]
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({ attributes, configurable_options }: SwatchListProps) {
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', 'swatch_data']).map((ov) => ({
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
- configurable_options {
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
- uid
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
  }
@@ -0,0 +1,15 @@
1
+ fragment ConfiguredVariant on SimpleProduct @injectable {
2
+ __typename
3
+ uid
4
+ name
5
+ price_range {
6
+ minimum_price {
7
+ final_price {
8
+ ...Money
9
+ }
10
+ regular_price {
11
+ ...Money
12
+ }
13
+ }
14
+ }
15
+ }
@@ -1,5 +1,6 @@
1
1
  query GetConfigurableOptionsSelection($urlKey: String!, $selectedOptions: [ID!] = []) {
2
2
  products(filter: { url_key: { eq: $urlKey } }) {
3
+ __typename
3
4
  items {
4
5
  __typename
5
6
  uid
@@ -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
@@ -5,3 +5,4 @@ export * from './ConfigurableProductAddToCart/ConfigurableProductAddToCart'
5
5
  export * from './ConfigurableProductPage.gql'
6
6
  export * from './graphql'
7
7
  export * from './hooks'
8
+ export * from './utils'
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.13.2",
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.30.1",
23
- "@graphcommerce/graphql-mesh": "4.30.1",
24
- "@graphcommerce/image": "4.30.1",
25
- "@graphcommerce/magento-cart": "4.13.2",
26
- "@graphcommerce/magento-cart-items": "4.13.2",
27
- "@graphcommerce/magento-category": "4.13.2",
28
- "@graphcommerce/magento-customer": "4.13.2",
29
- "@graphcommerce/magento-product": "4.13.2",
30
- "@graphcommerce/magento-product-simple": "4.13.2",
31
- "@graphcommerce/magento-store": "4.13.2",
32
- "@graphcommerce/next-ui": "4.30.1",
33
- "@graphcommerce/react-hook-form": "4.30.1"
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,13 @@
1
+ fragment DefaultConfigurableOptionsSelection on Products {
2
+ items {
3
+ uid
4
+ __typename
5
+ url_key
6
+ ...ProductPageGallery
7
+ ...ConfigurableOptions
8
+
9
+ ... on SimpleProduct {
10
+ ...ConfiguredVariant
11
+ }
12
+ }
13
+ }
@@ -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'