@graphcommerce/magento-product-bundle 4.0.57 → 4.1.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.
@@ -1,28 +1,3 @@
1
- import { BundleItemsFragment } from './BundleItems.gql'
2
-
3
- type BundleItemsFormProps = BundleItemsFragment
4
-
5
- export function BundleItemsForm(props: BundleItemsFormProps) {
6
- const { items } = props
7
- return (
8
- <>
9
- {items?.map((item) => {
10
- if (!item?.type) return null
11
- // const type = item.type as 'radio' | 'checkbox'
12
-
13
- return (
14
- <div key={item?.uid ?? ''}>
15
- {item?.title}
16
-
17
- {item?.required}
18
-
19
- {item?.type}
20
- {item?.options?.map((option) => (
21
- <div key={option?.uid ?? ''}>{option?.label}</div>
22
- ))}
23
- </div>
24
- )
25
- })}
26
- </>
27
- )
1
+ export function BundleItemsForm(props: Record<string, unknown>) {
2
+ return null
28
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1642](https://github.com/graphcommerce-org/graphcommerce/pull/1642) [`ad63ebf4e`](https://github.com/graphcommerce-org/graphcommerce/commit/ad63ebf4e33bfb0e5c9e5e68ab69b14775f3f8a8) Thanks [@paales](https://github.com/paales)! - Introduced `<AddProductsToCartForm/>`, which is allows for adding all product types to the cart with a single react-hook-form form.
8
+
9
+ Which allows you to fully compose the form on the product page without having to modify the page.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [[`ad63ebf4e`](https://github.com/graphcommerce-org/graphcommerce/commit/ad63ebf4e33bfb0e5c9e5e68ab69b14775f3f8a8), [`9e6fd498e`](https://github.com/graphcommerce-org/graphcommerce/commit/9e6fd498e3242ab30602767ae77a8e22f80d9fd3), [`b6bf2c941`](https://github.com/graphcommerce-org/graphcommerce/commit/b6bf2c94197ddacbf8f1fc0d352cd0d46e096f30)]:
14
+ - @graphcommerce/ecommerce-ui@1.5.0
15
+ - @graphcommerce/magento-product@4.6.0
16
+ - @graphcommerce/magento-product-simple@4.1.0
17
+ - @graphcommerce/magento-product-virtual@4.1.0
18
+ - @graphcommerce/magento-store@4.3.0
19
+ - @graphcommerce/next-ui@4.27.0
20
+ - @graphcommerce/magento-cart@4.8.4
21
+ - @graphcommerce/magento-cart-items@3.1.11
22
+
23
+ ## 4.0.58
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies []:
28
+ - @graphcommerce/magento-cart@4.8.3
29
+ - @graphcommerce/magento-cart-items@3.1.10
30
+ - @graphcommerce/magento-product@4.5.10
31
+ - @graphcommerce/magento-product-simple@4.0.58
32
+ - @graphcommerce/magento-product-virtual@4.0.58
33
+
3
34
  ## 4.0.57
4
35
 
5
36
  ### Patch Changes
@@ -1,14 +1,9 @@
1
1
  fragment ProductPageBundleQueryFragment on Query {
2
2
  typeProducts: products(filter: { url_key: { eq: $urlKey } }) {
3
- ...ProductSpecs
4
3
  items {
5
4
  __typename
6
5
  uid
7
- ... on BundleProduct {
8
- ...ProductWeight
9
- ...ProductCustomizable
10
- ...BundleItems
11
- }
6
+ ...BundleProductOptions
12
7
  }
13
8
  }
14
9
  }
@@ -0,0 +1,57 @@
1
+ import { useFormAddProductsToCart } from '@graphcommerce/magento-product/components'
2
+ import {
3
+ SectionHeader,
4
+ ActionCardListForm,
5
+ ActionCardItemBase,
6
+ filterNonNullableKeys,
7
+ } from '@graphcommerce/next-ui'
8
+ import { i18n } from '@lingui/core'
9
+ import React, { useMemo } from 'react'
10
+ import { BundleOptionValue } from './BundleOptionValue'
11
+ import { BundleOptionProps, BundleOptionValueProps } from './types'
12
+
13
+ export const BundleOption = React.memo<BundleOptionProps>((props) => {
14
+ const { idx, index, options, title, color, layout, size, variant, required: _required } = props
15
+ const { control } = useFormAddProductsToCart()
16
+
17
+ const can_change_quantity = options?.some((o) => o?.can_change_quantity)
18
+ const required = _required ?? false
19
+
20
+ return (
21
+ <div>
22
+ <SectionHeader labelLeft={title} sx={{ mt: 0 }} />
23
+ <ActionCardListForm<BundleOptionValueProps & ActionCardItemBase>
24
+ control={control}
25
+ required={required}
26
+ color={color}
27
+ layout={layout}
28
+ size={size}
29
+ variant={variant}
30
+ defaultValue={options?.find((opt) => opt?.is_default)?.uid}
31
+ rules={{
32
+ required: required
33
+ ? i18n._(/* i18n*/ 'Please select a value for ‘{label}’', { label: title })
34
+ : false,
35
+ }}
36
+ name={
37
+ options?.some((o) => o?.can_change_quantity)
38
+ ? `cartItems.${index}.entered_options.${idx}.uid`
39
+ : `cartItems.${index}.selected_options.${idx}`
40
+ }
41
+ collapse={can_change_quantity}
42
+ render={BundleOptionValue}
43
+ items={useMemo(
44
+ () =>
45
+ filterNonNullableKeys(options).map((option) => ({
46
+ ...option,
47
+ value: option.uid,
48
+ idx,
49
+ index,
50
+ required,
51
+ })),
52
+ [idx, index, options, required],
53
+ )}
54
+ />
55
+ </div>
56
+ )
57
+ })
@@ -0,0 +1,101 @@
1
+ import { TextFieldElement } from '@graphcommerce/ecommerce-ui'
2
+ import { Image } from '@graphcommerce/image'
3
+ import { useFormAddProductsToCart } from '@graphcommerce/magento-product/components'
4
+ import { Money } from '@graphcommerce/magento-store'
5
+ import {
6
+ responsiveVal,
7
+ ActionCardItemRenderProps,
8
+ ActionCard,
9
+ Button,
10
+ } from '@graphcommerce/next-ui'
11
+ import { Trans } from '@lingui/react'
12
+ import { BundleOptionValueProps } from './types'
13
+
14
+ const swatchSizes = {
15
+ small: responsiveVal(30, 40),
16
+ medium: responsiveVal(30, 50),
17
+ large: responsiveVal(50, 80),
18
+ }
19
+
20
+ export const BundleOptionValue = (props: ActionCardItemRenderProps<BundleOptionValueProps>) => {
21
+ const {
22
+ selected,
23
+ idx,
24
+ index,
25
+ price,
26
+ product,
27
+ label,
28
+ size = 'large',
29
+ color,
30
+ can_change_quantity,
31
+ quantity = 1,
32
+ required,
33
+ onReset,
34
+ } = props
35
+ const { control } = useFormAddProductsToCart()
36
+
37
+ const thumbnail = product?.thumbnail?.url
38
+
39
+ return (
40
+ <ActionCard
41
+ {...props}
42
+ title={label}
43
+ price={price ? <Money value={price} /> : undefined}
44
+ image={
45
+ thumbnail &&
46
+ !thumbnail.includes('/placeholder/') && (
47
+ <Image
48
+ src={thumbnail}
49
+ width={40}
50
+ height={40}
51
+ alt={label ?? ''}
52
+ sizes={swatchSizes[size]}
53
+ sx={{
54
+ display: 'block',
55
+ width: swatchSizes[size],
56
+ height: swatchSizes[size],
57
+ objectFit: 'cover',
58
+ }}
59
+ />
60
+ )
61
+ }
62
+ action={
63
+ (can_change_quantity || !required) && (
64
+ <Button disableTouchRipple variant='inline' color='secondary' size='small'>
65
+ <Trans id='Select' />
66
+ </Button>
67
+ )
68
+ }
69
+ reset={
70
+ (can_change_quantity || !required) && (
71
+ <Button
72
+ disableTouchRipple
73
+ variant='inline'
74
+ color='secondary'
75
+ size='small'
76
+ onClick={onReset}
77
+ >
78
+ {can_change_quantity ? <Trans id='Change' /> : <Trans id='Remove' />}
79
+ </Button>
80
+ )
81
+ }
82
+ secondaryAction={
83
+ selected &&
84
+ can_change_quantity && (
85
+ <TextFieldElement
86
+ size='small'
87
+ label='Quantity'
88
+ color={color}
89
+ required
90
+ defaultValue={`${quantity}`}
91
+ control={control}
92
+ sx={{ width: responsiveVal(80, 120), mt: 2 }}
93
+ name={`cartItems.${index}.entered_options.${idx}.value`}
94
+ type='number'
95
+ onMouseDown={(e) => e.stopPropagation()}
96
+ />
97
+ )
98
+ }
99
+ />
100
+ )
101
+ }
@@ -1,4 +1,4 @@
1
- fragment BundleItems on BundleProduct {
1
+ fragment BundleProductOptions on BundleProduct {
2
2
  ship_bundle_items
3
3
  dynamic_sku
4
4
  dynamic_price
@@ -21,11 +21,17 @@ fragment BundleItems on BundleProduct {
21
21
  quantity
22
22
  uid
23
23
  product {
24
+ swatch_image
24
25
  uid
25
26
  __typename
26
- ...ProductListItem
27
- ...ProductListItemSimple
28
- ...ProductListItemVirtual
27
+ name
28
+ url_key
29
+ thumbnail {
30
+ disabled
31
+ label
32
+ position
33
+ url
34
+ }
29
35
  }
30
36
  }
31
37
  }
@@ -0,0 +1,34 @@
1
+ import { ActionCardListProps, filterNonNullableKeys } from '@graphcommerce/next-ui'
2
+ import { BundleOption } from './BundleOption'
3
+ import { BundleOptionValue } from './BundleOptionValue'
4
+ import { BundleProductOptionsFragment } from './BundleProductOptions.gql'
5
+ import { BundleOptionValueProps } from './types'
6
+
7
+ type BundelProductOptionsProps = Pick<
8
+ ActionCardListProps,
9
+ 'size' | 'layout' | 'color' | 'variant'
10
+ > & {
11
+ renderer?: React.FC<BundleOptionValueProps>
12
+ index?: number
13
+ product: BundleProductOptionsFragment
14
+ }
15
+
16
+ export function BundleProductOptions(props: BundelProductOptionsProps) {
17
+ const { product, index = 0 } = props
18
+
19
+ return (
20
+ <>
21
+ {filterNonNullableKeys(product?.items, ['uid', 'title', 'type']).map((item) => (
22
+ <BundleOption
23
+ index={index}
24
+ key={item.uid}
25
+ color='primary'
26
+ {...props}
27
+ {...item}
28
+ idx={item.position ?? 0 + 1000}
29
+ renderer={BundleOptionValue}
30
+ />
31
+ ))}
32
+ </>
33
+ )
34
+ }
@@ -0,0 +1 @@
1
+ export * from './BundleProductOptions'
@@ -0,0 +1,17 @@
1
+ import { ActionCardItemRenderProps, ActionCardListProps } from '@graphcommerce/next-ui'
2
+ import { BundleProductOptionsFragment } from './BundleProductOptions.gql'
3
+
4
+ export type BundleOptionProps = {
5
+ idx: number
6
+ index: number
7
+ renderer?: React.FC<ActionCardItemRenderProps<BundleOptionValueProps>>
8
+ } & NonNullable<NonNullable<BundleProductOptionsFragment['items']>[number]> &
9
+ Pick<ActionCardListProps, 'size' | 'layout' | 'color' | 'variant'>
10
+
11
+ export type BundleOptionValueProps = NonNullable<
12
+ NonNullable<BundleOptionProps['options']>[number]
13
+ > & {
14
+ idx: number
15
+ index: number
16
+ required: boolean
17
+ }
package/index.ts CHANGED
@@ -2,3 +2,4 @@ export * from './ProductListItemBundle'
2
2
  export * from './BundleItemsForm/BundleItemsForm'
3
3
  export * from './BundleCartItem/BundleCartItem'
4
4
  export * from './BundleProductPage.gql'
5
+ export * from './components/BundleProductOptions'
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-product-bundle",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "4.0.57",
5
+ "version": "4.1.0",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -18,12 +18,16 @@
18
18
  "@playwright/test": "^1.21.1"
19
19
  },
20
20
  "dependencies": {
21
+ "@graphcommerce/ecommerce-ui": "1.5.0",
21
22
  "@graphcommerce/graphql": "3.4.8",
22
- "@graphcommerce/magento-cart": "4.8.2",
23
- "@graphcommerce/magento-cart-items": "3.1.9",
24
- "@graphcommerce/magento-product": "4.5.9",
25
- "@graphcommerce/magento-product-simple": "4.0.57",
26
- "@graphcommerce/magento-product-virtual": "4.0.57"
23
+ "@graphcommerce/image": "3.1.9",
24
+ "@graphcommerce/magento-cart": "4.8.4",
25
+ "@graphcommerce/magento-cart-items": "3.1.11",
26
+ "@graphcommerce/magento-product": "4.6.0",
27
+ "@graphcommerce/magento-product-simple": "4.1.0",
28
+ "@graphcommerce/magento-product-virtual": "4.1.0",
29
+ "@graphcommerce/magento-store": "4.3.0",
30
+ "@graphcommerce/next-ui": "4.27.0"
27
31
  },
28
32
  "peerDependencies": {
29
33
  "@lingui/react": "^3.13.2",
@@ -1,25 +0,0 @@
1
- mutation AddBundleProductToCart(
2
- $cartId: String!
3
- $sku: String!
4
- $bundleOptions: [BundleOptionInput!]!
5
- $quantity: Float = 1
6
- $customizableOptions: [CustomizableOptionInput] = []
7
- ) {
8
- addBundleProductsToCart(
9
- input: {
10
- cart_id: $cartId
11
- cart_items: [
12
- {
13
- data: { quantity: $quantity, sku: $sku }
14
- customizable_options: $customizableOptions
15
- bundle_options: $bundleOptions
16
- }
17
- ]
18
- }
19
- ) {
20
- cart {
21
- id
22
- __typename
23
- }
24
- }
25
- }