@rebuy/rebuy-hydrogen 3.0.0-beta.10 → 3.0.0-beta.2

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 (97) hide show
  1. package/dist/components/AddToCartBtn/AddToCartBtn.d.ts.map +1 -1
  2. package/dist/components/AddToCartBtn/HydrogenAddToCartBtn.d.ts.map +1 -1
  3. package/dist/components/AddToCartBtn/HydrogenReactAddToCartBtn.d.ts.map +1 -1
  4. package/dist/components/ProductCard/ProductCard.d.ts.map +1 -1
  5. package/dist/components/ProductPrice/ProductPrice.d.ts +1 -1
  6. package/dist/components/ProductPrice/ProductPrice.d.ts.map +1 -1
  7. package/dist/components/VariantSelect/VariantSelect.d.ts +1 -1
  8. package/dist/components/VariantSelect/VariantSelect.d.ts.map +1 -1
  9. package/dist/hooks/titleLevel.d.ts.map +1 -1
  10. package/dist/index.css +88 -88
  11. package/dist/index.css.map +4 -4
  12. package/dist/index.js +421 -195
  13. package/dist/index.js.map +4 -4
  14. package/dist/index.mjs +430 -196
  15. package/dist/index.mjs.map +4 -4
  16. package/dist/providers/RebuyHydrogenContextProvider.d.ts +1 -1
  17. package/dist/providers/RebuyHydrogenContextProvider.d.ts.map +1 -1
  18. package/dist/providers/RebuyHydrogenReactContextProvider.d.ts.map +1 -1
  19. package/dist/providers/types.d.ts +1 -7
  20. package/dist/providers/types.d.ts.map +1 -1
  21. package/dist/types/rebuyCustom.d.ts +0 -1
  22. package/dist/types/rebuyCustom.d.ts.map +1 -1
  23. package/dist/types/shopify.d.ts.map +1 -1
  24. package/dist/types/widgets.d.ts +1 -1
  25. package/dist/types/widgets.d.ts.map +1 -1
  26. package/dist/utils/convertToRebuyProduct.d.ts.map +1 -1
  27. package/dist/utils/createContextParameters.d.ts.map +1 -1
  28. package/dist/utils/getEncodedAttributes.d.ts.map +1 -1
  29. package/dist/utils/getRebuyConfig.d.ts +1 -1
  30. package/dist/utils/getRebuyConfig.d.ts.map +1 -1
  31. package/dist/widgetContainer/RebuyWidgetContainer.d.ts +1 -1
  32. package/dist/widgetContainer/RebuyWidgetContainer.d.ts.map +1 -1
  33. package/dist/widgets/RebuyCompleteTheLook/RebuyCompleteTheLook.d.ts.map +1 -1
  34. package/dist/widgets/RebuyDynamicBundleProducts/BundleImages.d.ts.map +1 -1
  35. package/dist/widgets/RebuyDynamicBundleProducts/BundlePrice.d.ts.map +1 -1
  36. package/dist/widgets/RebuyDynamicBundleProducts/BundleSelection.d.ts +1 -1
  37. package/dist/widgets/RebuyDynamicBundleProducts/BundleSelection.d.ts.map +1 -1
  38. package/dist/widgets/RebuyDynamicBundleProducts/RebuyDynamicBundleProducts.d.ts.map +1 -1
  39. package/dist/widgets/RebuyDynamicBundleProducts/Select.d.ts.map +1 -1
  40. package/dist/widgets/RebuyProductAddOns/RebuyProductAddOnCard.d.ts.map +1 -1
  41. package/dist/widgets/RebuyProductAddOns/RebuyProductAddOns.d.ts.map +1 -1
  42. package/dist/widgets/RebuyProductAddOns/types.d.ts.map +1 -1
  43. package/dist/widgets/RebuyProductRecommendations/RebuyProductRecommendations.d.ts.map +1 -1
  44. package/package.json +36 -48
  45. package/src/components/AddToCartBtn/AddToCartBtn.tsx +45 -0
  46. package/src/components/AddToCartBtn/HydrogenAddToCartBtn.tsx +43 -0
  47. package/src/components/AddToCartBtn/HydrogenReactAddToCartBtn.tsx +35 -0
  48. package/src/components/AddToCartBtn/index.ts +1 -0
  49. package/src/components/AddToCartBtn/types.ts +27 -0
  50. package/src/components/ProductCard/ProductCard.tsx +70 -0
  51. package/src/components/ProductCard/index.ts +1 -0
  52. package/src/components/ProductCard/types.ts +10 -0
  53. package/src/components/ProductPrice/ProductPrice.tsx +49 -0
  54. package/src/components/ProductPrice/index.ts +1 -0
  55. package/src/components/Title/Title.tsx +19 -0
  56. package/src/components/Title/index.ts +1 -0
  57. package/src/components/Title/types.ts +7 -0
  58. package/src/components/VariantSelect/VariantSelect.tsx +45 -0
  59. package/src/components/VariantSelect/index.ts +1 -0
  60. package/src/components/VariantSelect/types.ts +6 -0
  61. package/src/context/RebuyContext.tsx +9 -0
  62. package/src/hooks/titleLevel.tsx +42 -0
  63. package/src/index.ts +7 -0
  64. package/src/providers/RebuyHydrogenContextProvider.tsx +112 -0
  65. package/src/providers/RebuyHydrogenReactContextProvider.tsx +192 -0
  66. package/src/providers/types.ts +58 -0
  67. package/src/queries/cart.queries.ts +467 -0
  68. package/src/types/common.ts +8 -0
  69. package/src/types/css.d.ts +11 -0
  70. package/src/types/env.d.ts +12 -0
  71. package/src/types/rebuy.d.ts +31 -0
  72. package/src/types/rebuyCustom.ts +263 -0
  73. package/src/types/rebuySmartCart.ts +188 -0
  74. package/src/types/shopify.ts +142 -0
  75. package/src/types/widgets.ts +29 -0
  76. package/src/utils/convertToRebuyProduct.tsx +319 -0
  77. package/src/utils/createContextParameters.ts +142 -0
  78. package/src/utils/getEncodedAttributes.ts +11 -0
  79. package/src/utils/getRebuyConfig.ts +31 -0
  80. package/src/widgetContainer/RebuyWidgetContainer.tsx +183 -0
  81. package/src/widgets/RebuyCompleteTheLook/RebuyCompleteTheLook.tsx +50 -0
  82. package/src/widgets/RebuyCompleteTheLook/index.ts +1 -0
  83. package/src/widgets/RebuyCompleteTheLook/types.ts +5 -0
  84. package/src/widgets/RebuyDynamicBundleProducts/BundleImages.tsx +62 -0
  85. package/src/widgets/RebuyDynamicBundleProducts/BundlePrice.tsx +93 -0
  86. package/src/widgets/RebuyDynamicBundleProducts/BundleSelection.tsx +65 -0
  87. package/src/widgets/RebuyDynamicBundleProducts/RebuyDynamicBundleProducts.tsx +118 -0
  88. package/src/widgets/RebuyDynamicBundleProducts/Select.tsx +41 -0
  89. package/src/widgets/RebuyDynamicBundleProducts/index.ts +1 -0
  90. package/src/widgets/RebuyDynamicBundleProducts/types.ts +23 -0
  91. package/src/widgets/RebuyProductAddOns/RebuyProductAddOnCard.tsx +66 -0
  92. package/src/widgets/RebuyProductAddOns/RebuyProductAddOns.tsx +218 -0
  93. package/src/widgets/RebuyProductAddOns/index.ts +1 -0
  94. package/src/widgets/RebuyProductAddOns/types.ts +24 -0
  95. package/src/widgets/RebuyProductRecommendations/RebuyProductRecommendations.tsx +50 -0
  96. package/src/widgets/RebuyProductRecommendations/index.ts +1 -0
  97. package/src/widgets/RebuyProductRecommendations/types.ts +5 -0
@@ -0,0 +1,50 @@
1
+ import styles from '~/widgets/RebuyCompleteTheLook/RebuyCompleteTheLook.module.css';
2
+
3
+ import type { RebuyCompleteTheLookProps } from './types';
4
+
5
+ import { ProductCard } from '~/components/ProductCard';
6
+ import { Title } from '~/components/Title';
7
+ import { getTitleLevel } from '~/hooks/titleLevel';
8
+
9
+ // Component implementation
10
+ export const RebuyCompleteTheLook = (props: RebuyCompleteTheLookProps) => {
11
+ const {
12
+ addToCartBtnText = 'Add to cart',
13
+ addToCartCallback,
14
+ customTitle = `These pair with ${props.product?.title}`,
15
+ customTitleLevel = 'h2',
16
+ customTitleStyle,
17
+ products = [],
18
+ } = props;
19
+
20
+ if (products.length === 0) {
21
+ console.log('RebuyCompleteTheLook: No products found');
22
+ return null;
23
+ }
24
+
25
+ return (
26
+ <section className={styles.container}>
27
+ <Title
28
+ level={getTitleLevel(customTitleLevel)}
29
+ style={customTitleStyle}
30
+ text={customTitle}
31
+ />
32
+ <ul className={styles.productGrid}>
33
+ {products.map((product) => (
34
+ <li className={styles.productItem} key={product.id}>
35
+ <ProductCard
36
+ addToCartBtnText={addToCartBtnText}
37
+ addToCartCallback={addToCartCallback}
38
+ isHydrogenReact={props.isHydrogenReact}
39
+ product={product}
40
+ productCardTitleLevel={getTitleLevel(
41
+ customTitleLevel,
42
+ true
43
+ )}
44
+ />
45
+ </li>
46
+ ))}
47
+ </ul>
48
+ </section>
49
+ );
50
+ };
@@ -0,0 +1 @@
1
+ export * from './RebuyCompleteTheLook';
@@ -0,0 +1,5 @@
1
+ import type { WidgetChildProps } from '~/types/widgets';
2
+
3
+ export type RebuyCompleteTheLookProps = {
4
+ addToCartBtnText?: string;
5
+ } & WidgetChildProps;
@@ -0,0 +1,62 @@
1
+ import { Link } from '@remix-run/react';
2
+ import { Image } from '@shopify/hydrogen';
3
+ import { Fragment } from 'react';
4
+
5
+ import styles from '~/widgets/RebuyDynamicBundleProducts/RebuyDynamicBundleProducts.module.css';
6
+
7
+ import type { BundleProduct } from '~/widgets/RebuyDynamicBundleProducts/types';
8
+
9
+ export const BundleImages = ({ products }: { products: BundleProduct[] }) => {
10
+ const selected = products.filter((product) => product.selected);
11
+
12
+ return (
13
+ <ul className={styles.bundleImages}>
14
+ {products.map((product, index) => {
15
+ const image = product.selectedVariant?.image;
16
+ const productImage = image ? (
17
+ <Image
18
+ alt={image.altText || `Picture of ${product.title}`}
19
+ className={styles.bundleImage}
20
+ data={image}
21
+ height={80}
22
+ title={product.title}
23
+ width={80}
24
+ />
25
+ ) : (
26
+ // No image defined
27
+ product.title
28
+ );
29
+ // Hide delimiter for first selected item
30
+ const showDelimiter = selected[0]?.id !== product.id;
31
+
32
+ return (
33
+ <Fragment key={product.id + '-BundleImages-' + index}>
34
+ {product.selected && (
35
+ <>
36
+ {showDelimiter && (
37
+ <li className={styles.bundleImageDelimiter}>
38
+ <span>+</span>
39
+ </li>
40
+ )}
41
+ <li className="flex items-center">
42
+ {product.default ? (
43
+ // Already on product page
44
+ productImage
45
+ ) : (
46
+ // Link to product
47
+ <Link
48
+ title={product.title}
49
+ to={`/products/${product.handle}`}
50
+ >
51
+ {productImage}
52
+ </Link>
53
+ )}
54
+ </li>
55
+ </>
56
+ )}
57
+ </Fragment>
58
+ );
59
+ })}
60
+ </ul>
61
+ );
62
+ };
@@ -0,0 +1,93 @@
1
+ import { Money } from '@shopify/hydrogen';
2
+
3
+ import styles from './RebuyDynamicBundleProducts.module.css';
4
+
5
+ import type {
6
+ CurrencyCode,
7
+ MoneyV2,
8
+ } from '@shopify/hydrogen-react/storefront-api-types';
9
+ import type { BundleProduct } from '~/widgets/RebuyDynamicBundleProducts/types';
10
+
11
+ export const BundlePrice = ({ products }: { products: BundleProduct[] }) => {
12
+ const isDisabled =
13
+ products.filter((product) => product.selected).length < 1;
14
+
15
+ const totalBundlePrice = () => {
16
+ let total = 0;
17
+ let currencyCode = 'USD' as CurrencyCode;
18
+
19
+ for (const product of products) {
20
+ if (product.selected && product.selectedVariant) {
21
+ const { priceV2: price } = product.selectedVariant;
22
+
23
+ total += Number(price?.amount);
24
+ currencyCode = (price?.currencyCode || 'USD') as CurrencyCode;
25
+ }
26
+ }
27
+
28
+ return {
29
+ amount: String(total),
30
+ currencyCode,
31
+ };
32
+ };
33
+
34
+ const totalBundleCompareAtPrice = () => {
35
+ let compareAtTotal = 0;
36
+ let currencyCode = 'USD' as CurrencyCode;
37
+
38
+ for (const product of products) {
39
+ if (product.selected && product.selectedVariant) {
40
+ const { compareAtPriceV2: compareAtPrice, priceV2: price } =
41
+ product.selectedVariant;
42
+
43
+ currencyCode = (price?.currencyCode || 'USD') as CurrencyCode;
44
+ compareAtTotal += Number((compareAtPrice || price)?.amount);
45
+ }
46
+ }
47
+
48
+ return {
49
+ amount: String(compareAtTotal),
50
+ currencyCode,
51
+ };
52
+ };
53
+ const isDiscounted = (
54
+ price: { amount: string; currencyCode: string } | null,
55
+ compareAtPrice: { amount: string; currencyCode: string } | null
56
+ ) => Number(compareAtPrice?.amount) > Number(price?.amount);
57
+
58
+ const price = totalBundlePrice();
59
+ const compareAtPrice = totalBundleCompareAtPrice();
60
+
61
+ const CompareAtPrice = ({
62
+ data: compareAtPrice,
63
+ }: {
64
+ data: MoneyV2 | null;
65
+ }) => {
66
+ return (
67
+ compareAtPrice && (
68
+ <Money
69
+ as="span"
70
+ className={styles.compareAtPrice}
71
+ data={compareAtPrice}
72
+ withoutTrailingZeros
73
+ />
74
+ )
75
+ );
76
+ };
77
+
78
+ return (
79
+ products.length > 0 && (
80
+ <div className="flex items-center flex-col">
81
+ {!isDisabled && (
82
+ <p className="flex items-center gap-2 mb-2">
83
+ <span>Total Price:</span>
84
+ <Money as="span" data={price} withoutTrailingZeros />
85
+ {isDiscounted(price, compareAtPrice) && (
86
+ <CompareAtPrice data={compareAtPrice} />
87
+ )}
88
+ </p>
89
+ )}
90
+ </div>
91
+ )
92
+ );
93
+ };
@@ -0,0 +1,65 @@
1
+ import styles from '~/widgets/RebuyDynamicBundleProducts/RebuyDynamicBundleProducts.module.css';
2
+
3
+ import type { BundleSelectionProps } from '~/widgets/RebuyDynamicBundleProducts/types';
4
+
5
+ import { RebuyProductPrice } from '~/components/ProductPrice';
6
+ import { Select } from '~/widgets/RebuyDynamicBundleProducts/Select';
7
+
8
+ export const BundleSelection = ({
9
+ onSelectVariant,
10
+ onToggleBundleItem,
11
+ products,
12
+ }: BundleSelectionProps) => {
13
+ return (
14
+ <ul>
15
+ {products.map((product, index) => {
16
+ const { availableForSale } = product.selectedVariant;
17
+ const isOutOfStock = !availableForSale;
18
+
19
+ return (
20
+ <li
21
+ className={`${styles.bundleItemRowContainer} ${
22
+ !product.selected && styles.unselected
23
+ }`}
24
+ key={product.id + '-BundleSelection' + index}
25
+ >
26
+ <div className={styles.bundleItemRow}>
27
+ <input
28
+ checked={product.selected && availableForSale}
29
+ className="mt-1 rounded-sm accent-black cursor-pointer"
30
+ disabled={isOutOfStock}
31
+ id={`${product.id}-toggle`}
32
+ onChange={() => onToggleBundleItem(product)}
33
+ type="checkbox"
34
+ value={product.id}
35
+ />
36
+ <div className={styles.bundleItemInput}>
37
+ <label
38
+ className={styles.bundleItemLabel}
39
+ htmlFor={`${product.id}-toggle`}
40
+ >
41
+ {isOutOfStock && <b>SOLD OUT</b>}
42
+ {product.default && <b>This item:</b>}
43
+ {product.title}
44
+
45
+ <RebuyProductPrice
46
+ selectedVariant={
47
+ product.selectedVariant
48
+ }
49
+ />
50
+ </label>
51
+
52
+ {product.variants.nodes.length > 1 && (
53
+ <Select
54
+ onSelectVariant={onSelectVariant}
55
+ product={product}
56
+ />
57
+ )}
58
+ </div>
59
+ </div>
60
+ </li>
61
+ );
62
+ })}
63
+ </ul>
64
+ );
65
+ };
@@ -0,0 +1,118 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+
3
+ import { BundlePrice } from './BundlePrice';
4
+
5
+ import styles from './RebuyDynamicBundleProducts.module.css';
6
+
7
+ import type {
8
+ BundleProduct,
9
+ RebuyDynamicBundleProductsProps,
10
+ } from '~/widgets/RebuyDynamicBundleProducts/types';
11
+
12
+ import { AddToCartBtn } from '~/components/AddToCartBtn';
13
+ import { Title } from '~/components/Title';
14
+ import { getTitleLevel } from '~/hooks/titleLevel';
15
+ import { convertToRebuyProduct } from '~/utils/convertToRebuyProduct';
16
+ import { BundleImages } from '~/widgets/RebuyDynamicBundleProducts/BundleImages';
17
+ import { BundleSelection } from '~/widgets/RebuyDynamicBundleProducts/BundleSelection';
18
+
19
+ export const RebuyDynamicBundleProducts = (
20
+ props: RebuyDynamicBundleProductsProps
21
+ ) => {
22
+ const {
23
+ addToCartBtnText = 'Add to cart',
24
+ addToCartCallback,
25
+ customTitle = `These pair with ${props.product?.title}`,
26
+ customTitleLevel = 'h2',
27
+ customTitleStyle,
28
+ isHydrogenReact,
29
+ product,
30
+ products = [],
31
+ } = props;
32
+ const [bundleProducts, setBundleProducts] = useState<BundleProduct[]>([]);
33
+
34
+ // Initializiation
35
+ useEffect(() => {
36
+ const mainProduct: BundleProduct = convertToRebuyProduct(
37
+ isHydrogenReact || false,
38
+ product
39
+ );
40
+
41
+ const formattedProducts = products.map((product) => {
42
+ return {
43
+ ...product,
44
+ selected: true,
45
+ selectedVariant: product.variants.nodes[0],
46
+ };
47
+ });
48
+
49
+ setBundleProducts([mainProduct, ...formattedProducts]);
50
+ }, [product, products, isHydrogenReact]);
51
+
52
+ const onToggleBundleItem = useCallback(
53
+ (product: BundleProduct) => {
54
+ product.selected = !product.selected;
55
+
56
+ setBundleProducts([...bundleProducts]);
57
+ },
58
+ [bundleProducts]
59
+ );
60
+
61
+ const onSelectVariant = useCallback(
62
+ (product: BundleProduct, variant_id: string) => {
63
+ const variant = product.variants.nodes.find(
64
+ ({ id }) => id === variant_id
65
+ );
66
+
67
+ if (variant) {
68
+ product.selectedVariant = variant;
69
+ product.selected = variant.availableForSale || false;
70
+
71
+ setBundleProducts([...bundleProducts]);
72
+ }
73
+ },
74
+ [bundleProducts]
75
+ );
76
+
77
+ if (products.length === 0) {
78
+ console.log('RebuyDynamicBundleProducts: No products found');
79
+ return null;
80
+ }
81
+
82
+ return (
83
+ <section className={styles.container}>
84
+ <Title
85
+ level={getTitleLevel(customTitleLevel)}
86
+ style={customTitleStyle}
87
+ text={customTitle}
88
+ />
89
+ <div className={styles.bundleContainer}>
90
+ <BundleImages products={bundleProducts} />
91
+ <BundlePrice products={bundleProducts} />
92
+
93
+ <div className={styles.addCartBtnContainer}>
94
+ <AddToCartBtn
95
+ addToCartBtnText={addToCartBtnText}
96
+ addToCartCallback={addToCartCallback}
97
+ disabled={
98
+ bundleProducts.filter((product) => product.selected)
99
+ .length === 0
100
+ }
101
+ isHydrogenReact={isHydrogenReact}
102
+ selectedVariants={bundleProducts
103
+ .filter((product) => product.selected)
104
+ .map((product) => {
105
+ return product.selectedVariant;
106
+ })}
107
+ />
108
+ </div>
109
+
110
+ <BundleSelection
111
+ onSelectVariant={onSelectVariant}
112
+ onToggleBundleItem={onToggleBundleItem}
113
+ products={bundleProducts}
114
+ />
115
+ </div>
116
+ </section>
117
+ );
118
+ };
@@ -0,0 +1,41 @@
1
+ import styles from '~/widgets/RebuyDynamicBundleProducts/RebuyDynamicBundleProducts.module.css';
2
+
3
+ import type {
4
+ BundleProduct,
5
+ BundleSelectProps,
6
+ } from '~/widgets/RebuyDynamicBundleProducts/types';
7
+
8
+ export const Select = ({ onSelectVariant, product }: BundleSelectProps) => {
9
+ const getOptionsLabel = (product: BundleProduct) => {
10
+ const options = product.variants.nodes[0].selectedOptions;
11
+ const optionsFromKeys = options ? Object.keys(options[0]) : [];
12
+ const optionsFromValues = options
13
+ ? options.map((option) => option.name)
14
+ : [];
15
+ const useValues = optionsFromKeys.every((key) =>
16
+ ['name', 'value'].includes(key)
17
+ );
18
+
19
+ // Return delimited label for available option(s) e.g. Color / Size, Scent, etc
20
+ return (useValues ? optionsFromValues : optionsFromKeys).join(' / ');
21
+ };
22
+
23
+ return (
24
+ product && (
25
+ <select
26
+ aria-label="select variant"
27
+ className={styles.select}
28
+ onChange={(e) => onSelectVariant(product, e.target.value)}
29
+ value={product.selectedVariant.id}
30
+ >
31
+ <optgroup label={getOptionsLabel(product)}>
32
+ {product.variants.nodes.map(({ id, title }) => (
33
+ <option key={id + '-BundleVariant'} value={id}>
34
+ {title}
35
+ </option>
36
+ ))}
37
+ </optgroup>
38
+ </select>
39
+ )
40
+ );
41
+ };
@@ -0,0 +1 @@
1
+ export * from './RebuyDynamicBundleProducts';
@@ -0,0 +1,23 @@
1
+ import type { RebuyProduct } from '~/types/rebuyCustom';
2
+ import type { WidgetChildProps } from '~/types/widgets';
3
+
4
+ export type BundleProductOptions = {
5
+ default?: boolean;
6
+ };
7
+
8
+ export type BundleProduct = RebuyProduct & BundleProductOptions;
9
+
10
+ export type BundleSelectionProps = {
11
+ onSelectVariant: (product: BundleProduct, variantId: string) => void;
12
+ onToggleBundleItem: (product: BundleProduct) => void;
13
+ products: BundleProduct[];
14
+ };
15
+
16
+ export type BundleSelectProps = {
17
+ onSelectVariant: (product: BundleProduct, variantId: string) => void;
18
+ product: BundleProduct;
19
+ };
20
+
21
+ export type RebuyDynamicBundleProductsProps = {
22
+ addToCartBtnText?: string;
23
+ } & WidgetChildProps;
@@ -0,0 +1,66 @@
1
+ import { Link } from '@remix-run/react';
2
+ import { Image } from '@shopify/hydrogen';
3
+
4
+ import styles from './RebuyProductAddOns.module.css';
5
+
6
+ import type { RebuyProductAddOnCardProps } from './types';
7
+
8
+ import { RebuyProductPrice } from '~/components/ProductPrice';
9
+ import { Title } from '~/components/Title';
10
+
11
+ export const RebuyProductAddOnCard = ({
12
+ handleChange,
13
+ learnMoreText,
14
+ outOfStockText,
15
+ product,
16
+ titleLevel,
17
+ }: RebuyProductAddOnCardProps) => {
18
+ const { availableForSale, image } = product.selectedVariant || {};
19
+
20
+ return (
21
+ <label className={styles.addOnCard} htmlFor={product.id}>
22
+ <div className={styles.addOnCardContent}>
23
+ <input
24
+ checked={Boolean(product.selected)}
25
+ className={styles.addOnCardInput}
26
+ disabled={!product.variants.nodes[0].availableForSale}
27
+ id={product.id}
28
+ name={product.title}
29
+ onChange={(event) => handleChange(event, product)}
30
+ type="checkbox"
31
+ value=""
32
+ />
33
+ <div className={styles.addOnCardContentImage}>
34
+ {image && (
35
+ <Image
36
+ alt={image.altText || `Picture of ${product.title}`}
37
+ data={image}
38
+ height={150}
39
+ width={300}
40
+ />
41
+ )}
42
+ </div>
43
+
44
+ <div className={styles.addOnCardTextContent}>
45
+ {!availableForSale && (
46
+ <p className={styles.addOnCardOutOfStock}>
47
+ {outOfStockText}
48
+ </p>
49
+ )}
50
+
51
+ <Title level={titleLevel} text={product.title} />
52
+
53
+ <RebuyProductPrice
54
+ selectedVariant={product.selectedVariant}
55
+ />
56
+ <Link
57
+ className={styles.addOnCardLearnMore}
58
+ to={`/products/${product.handle}`}
59
+ >
60
+ {learnMoreText}
61
+ </Link>
62
+ </div>
63
+ </div>
64
+ </label>
65
+ );
66
+ };