@riosst100/pwa-marketplace 3.0.3 → 3.0.5

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 (58) hide show
  1. package/i18n/en_US.json +3 -3
  2. package/i18n/id_ID.json +2 -2
  3. package/package.json +1 -1
  4. package/src/componentOverrideMapping.js +1 -0
  5. package/src/components/CrossSeller/item.js +3 -4
  6. package/src/components/LinkToOtherStores/index.js +4 -4
  7. package/src/components/OrderDetail/components/itemsOrdered.js +1 -6
  8. package/src/components/ProductListTab/productListTab.js +1 -1
  9. package/src/components/RMAPage/components/productItem.js +13 -43
  10. package/src/components/SellerCoupon/index.js +1 -0
  11. package/src/components/SellerCoupon/sellerCoupon.js +41 -6
  12. package/src/components/SellerCoupon/sellerCoupon.module.css +22 -0
  13. package/src/components/SellerCoupon/sellerCouponCheckout.js +36 -19
  14. package/src/components/SellerCoupon/sellerCouponCheckout.shimmer.js +21 -0
  15. package/src/components/commons/Select/index.js +8 -4
  16. package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/priceSummaryFragments.gql.js +3 -0
  17. package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/usePriceSummary.js +2 -2
  18. package/src/overwrites/peregrine/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +4 -0
  19. package/src/overwrites/peregrine/lib/talons/CheckoutPage/checkoutPage.extended.gql.js +20 -1
  20. package/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js +3 -3
  21. package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +7 -8
  22. package/src/overwrites/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js +5 -0
  23. package/src/overwrites/venia-ui/lib/components/Breadcrumbs/breadcrumbs.js +20 -1
  24. package/src/overwrites/venia-ui/lib/components/CartPage/PriceAdjustments/CouponCode/couponCode.js +24 -27
  25. package/src/overwrites/venia-ui/lib/components/CartPage/PriceAdjustments/CouponCode/couponCode.module.css +2 -0
  26. package/src/overwrites/venia-ui/lib/components/CartPage/PriceSummary/priceSummary.js +14 -5
  27. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.js +41 -1
  28. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.module.css +1 -1
  29. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListingBySeller/productListingBySeller.js +41 -8
  30. package/src/overwrites/venia-ui/lib/components/CartPage/cartPage.js +0 -7
  31. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.js +43 -2
  32. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.module.css +36 -0
  33. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js +8 -2
  34. package/src/overwrites/venia-ui/lib/components/CheckoutPage/OrderSummary/orderSummary.js +4 -0
  35. package/src/overwrites/venia-ui/lib/components/CheckoutPage/PriceAdjustments/priceAdjustments.js +65 -57
  36. package/src/overwrites/venia-ui/lib/components/CheckoutPage/PriceAdjustments/priceAdjustments.module.css +29 -0
  37. package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.js +9 -4
  38. package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.module.css +2 -0
  39. package/src/overwrites/venia-ui/lib/components/FilterModal/CurrentFilters/currentFilters.js +1 -1
  40. package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +1 -1
  41. package/src/overwrites/venia-ui/lib/components/Gallery/item.js +2 -10
  42. package/src/overwrites/venia-ui/lib/components/Gallery/item.module.css +5 -4
  43. package/src/overwrites/venia-ui/lib/components/OrderHistoryPage/Reviews/index.js +1 -0
  44. package/src/overwrites/venia-ui/lib/components/OrderHistoryPage/Reviews/reviewModal.js +316 -0
  45. package/src/overwrites/venia-ui/lib/components/OrderHistoryPage/Reviews/starInput.js +33 -0
  46. package/src/overwrites/venia-ui/lib/components/OrderHistoryPage/orderHistoryPage.js +29 -2
  47. package/src/overwrites/venia-ui/lib/components/OrderHistoryPage/orderRow.js +70 -34
  48. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/CustomAttributes/customAttributes.js +10 -2
  49. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/modalFormReview.js +8 -8
  50. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/preOrderDetail.js +195 -37
  51. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/productReview.js +4 -27
  52. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +194 -63
  53. package/src/talons/ProductContent/productContent.gql.js +11 -1
  54. package/src/talons/ProductContent/useProductContent.js +14 -2
  55. package/src/talons/ReviewModal/reviewModal.gql.js +45 -0
  56. package/src/talons/ReviewModal/useReviewModal.js +87 -0
  57. package/src/components/RMAPage/components/productItem.css +0 -15
  58. package/src/components/RMAPage/components/productItem.module.css +0 -15
@@ -189,11 +189,11 @@ export const useFilterSidebar = props => {
189
189
  },
190
190
  {
191
191
  'label': 'Preorder',
192
- 'value': 'lof_preorder',
192
+ 'value': 'card_pre_orders',
193
193
  'path': '',
194
194
  'options': [
195
- {'value':'0','label':'No','title':'No'},
196
- {'value':'1','label':'Yes','title':'Yes'}
195
+ {'value':'0','label':'','title':''},
196
+ {'value':'1','label':'Pre Orders','title':'Pre Orders'}
197
197
  ]
198
198
  },
199
199
  {
@@ -579,7 +579,7 @@ export const useProductFullDetail = props => {
579
579
 
580
580
  const handleAddToCart = useCallback(
581
581
  async formValues => {
582
- const { quantity } = formValues;
582
+ const { quantity, preorder } = formValues;
583
583
 
584
584
  /*
585
585
  @deprecated in favor of general addProductsToCart mutation. Will support until the next MAJOR.
@@ -636,15 +636,13 @@ export const useProductFullDetail = props => {
636
636
  product: {
637
637
  sku: product.sku,
638
638
  quantity
639
- },
640
- entered_options: [
641
- {
642
- uid: product.uid,
643
- value: product.name
644
- }
645
- ]
639
+ }
646
640
  };
647
641
 
642
+ if (preorder && Object.keys(preorder).length) {
643
+ variables.product.preorder = preorder;
644
+ }
645
+
648
646
  if (selectedOptionsArray.length) {
649
647
  variables.product.selected_options = selectedOptionsArray;
650
648
  }
@@ -721,6 +719,7 @@ export const useProductFullDetail = props => {
721
719
  price_range: product?.price_range,
722
720
  sku: productSku,
723
721
  publish_status: product.publish_status,
722
+ custom_table_metadata: product.custom_table_metadata,
724
723
  term_and_conditions: product.term_and_conditions,
725
724
  link_to_other_stores: product.link_to_other_stores,
726
725
  shipping_policy: product.shipping_policy,
@@ -116,6 +116,11 @@ export const ProductDetailsFragment = gql`
116
116
  pre_order_date
117
117
  }
118
118
  term_and_conditions
119
+ custom_table_metadata {
120
+ mainAttrCode
121
+ mainAttrVal
122
+ mainAttrLabel
123
+ }
119
124
  shipping_policy
120
125
  return_policy
121
126
  small_image {
@@ -22,7 +22,7 @@ import { useLocation } from 'react-router-dom';
22
22
  const Breadcrumbs = props => {
23
23
  const classes = useStyle(defaultClasses, props.classes);
24
24
 
25
- const { categoryId, currentProduct, customPage, currentFilter } = props;
25
+ const { categoryId, currentProduct, customPage, currentFilter, currentProductCustomTableMetadata, customAttributesDetails } = props;
26
26
 
27
27
  const talonProps = useBreadcrumbs({ categoryId });
28
28
 
@@ -103,6 +103,25 @@ const Breadcrumbs = props => {
103
103
 
104
104
  const params = removeShopbyParam(search);
105
105
 
106
+ if (currentProductCustomTableMetadata) {
107
+ const mainAttrCode = currentProductCustomTableMetadata.mainAttrCode;
108
+ const mainAttrVal = currentProductCustomTableMetadata.mainAttrVal;
109
+ const mainAttrLabel = currentProductCustomTableMetadata.mainAttrLabel;
110
+
111
+ filterBreadcrumbsElement.push(
112
+ <Fragment>
113
+ <span className={classes.divider}>{DELIMITER}</span>
114
+ <Link
115
+ className={classes.link}
116
+ to={resourceUrl('/' + currentCategoryPath + '?' + mainAttrCode + '[filter]=' + mainAttrLabel + ',' + mainAttrVal)}
117
+ onClick={handleClick}
118
+ >
119
+ {mainAttrLabel}
120
+ </Link>
121
+ </Fragment>
122
+ )
123
+ }
124
+
106
125
  currentFilter && currentFilter.length && currentFilter.map((filter, index) => {
107
126
  currentProduct ? (
108
127
  filterBreadcrumbsElement.push(
@@ -93,31 +93,31 @@ const CouponCode = props => {
93
93
  }
94
94
 
95
95
  if (data.cart.applied_coupons) {
96
- const codes = data.cart.applied_coupons.map(({ code }) => {
97
- return (
98
- <Fragment key={code}>
99
- <span>{code}</span>
100
- <LinkButton
101
- className={classes.removeButton}
102
- disabled={removingCoupon}
103
- data-cy="CouponCode-removeCouponButton"
104
- onClick={() => {
105
- handleRemoveCoupon(code);
106
- }}
107
- onKeyDown={() => {
108
- handleRemoveCouponOnEnter(code);
109
- }}
110
- >
111
- <FormattedMessage
112
- id={'couponCode.removeButton'}
113
- defaultMessage={'Remove'}
114
- />
115
- </LinkButton>
116
- </Fragment>
117
- );
118
- });
96
+ // const codes = data.cart.applied_coupons.map(({ code }) => {
97
+ // return (
98
+ // <Fragment key={code}>
99
+ // <span>{code}</span>
100
+ // <LinkButton
101
+ // className={classes.removeButton}
102
+ // disabled={removingCoupon}
103
+ // data-cy="CouponCode-removeCouponButton"
104
+ // onClick={() => {
105
+ // handleRemoveCoupon(code);
106
+ // }}
107
+ // onKeyDown={() => {
108
+ // handleRemoveCouponOnEnter(code);
109
+ // }}
110
+ // >
111
+ // <FormattedMessage
112
+ // id={'couponCode.removeButton'}
113
+ // defaultMessage={'Remove'}
114
+ // />
115
+ // </LinkButton>
116
+ // </Fragment>
117
+ // );
118
+ // });
119
119
 
120
- return <div className={classes.appliedCoupon}>{codes}</div>;
120
+ return '';
121
121
  } else {
122
122
  const errorMessage = deriveErrorMessage([
123
123
  errors.get('applyCouponMutation')
@@ -160,9 +160,6 @@ const CouponCode = props => {
160
160
  priority={'normal'}
161
161
  type={'submit'}
162
162
  onKeyDown={handleApplyCouponOnEnter}
163
- classes={{
164
- content: 'gap-1.5 grid-flow-col inline-grid items-center justify-center justify-items-center capitalize font-medium'
165
- }}
166
163
  >
167
164
  <FormattedMessage
168
165
  id={'couponCode.apply'}
@@ -2,6 +2,7 @@
2
2
  .entryForm,
3
3
  .entryFormError {
4
4
  composes: gap-x-sm from global;
5
+ composes: pb-2 from global;
5
6
  composes: grid from global;
6
7
  composes: grid-cols-autoLast from global;
7
8
  }
@@ -14,6 +15,7 @@
14
15
  /* switch to rows. */
15
16
  grid-template-columns: unset;
16
17
  grid-template-rows: 1fr 1fr;
18
+ composes: pb-2 from global;
17
19
  }
18
20
  }
19
21
 
@@ -10,6 +10,7 @@ import GiftCardSummary from './giftCardSummary';
10
10
  import GiftOptionsSummary from './giftOptionsSummary';
11
11
  import ShippingSummary from './shippingSummary';
12
12
  import TaxSummary from './taxSummary';
13
+ import Shimmer from '@magento/venia-ui/lib/components/Shimmer';
13
14
  import cn from 'classnames';
14
15
 
15
16
  /**
@@ -74,9 +75,10 @@ const PriceSummary = props => {
74
75
 
75
76
  const isPriceUpdating = isUpdating || isLoading;
76
77
  const priceClass = isPriceUpdating ? classes.priceUpdating : classes.price;
77
- const totalPriceClass = isPriceUpdating
78
- ? classes.priceUpdating
79
- : classes.totalPrice;
78
+ const totalPriceClass = classes.totalPrice;
79
+ // const totalPriceClass = isPriceUpdating
80
+ // ? classes.priceUpdating
81
+ // : classes.totalPrice;
80
82
 
81
83
  const totalPriceLabel = isCheckout
82
84
  ? formatMessage({
@@ -88,7 +90,7 @@ const PriceSummary = props => {
88
90
  defaultMessage: 'Estimated Total'
89
91
  });
90
92
 
91
- const proceedToCheckoutButton = (
93
+ const proceedToCheckoutButton = !isCheckout && (
92
94
  <div className={cn(classes.checkoutButton_container, 'block !mt-6 !min-h-auto')}>
93
95
  <Button
94
96
  disabled={isPriceUpdating}
@@ -127,8 +129,15 @@ const PriceSummary = props => {
127
129
  );
128
130
 
129
131
  return (
130
- <div className={cn(classes.root, 'pb-6 px-3')} data-cy="PriceSummary-root">
132
+ <div className={cn(classes.root, isCheckout ? 'pb-0 px-3' : 'pb-6 px-3')} data-cy="PriceSummary-root">
131
133
  {isCheckout && (
134
+ isPriceUpdating ? <>
135
+ <Shimmer width="100%" height="20px" />
136
+ <Shimmer width="100%" height="20px" />
137
+ <Shimmer width="100%" height="20px" />
138
+ <Shimmer width="100%" height="20px" />
139
+ <Shimmer width="100%" height="20px" />
140
+ </> :
132
141
  <div>
133
142
  <ul>
134
143
  <li className={classes.lineItems}>
@@ -30,7 +30,6 @@ const HeartIcon = <Heart size="16" color="#909090" />;
30
30
 
31
31
  const Product = props => {
32
32
  const { item } = props;
33
-
34
33
  const { formatMessage } = useIntl();
35
34
  const talonProps = useProduct({
36
35
  operations: {
@@ -123,8 +122,49 @@ const Product = props => {
123
122
  </Link>
124
123
  <div className='flex flex-col'>
125
124
  <div className={cn(classes.name, 'text-[14px] font-normal max-w-[260px]')} data-cy="Product-name">
125
+ {item.is_preorder && (
126
+ <span className="inline-flex items-center gap-1 px-2 py-[2px] mb-3 rounded-full bg-blue-600 text-white border border-blue-700 text-[11px] font-medium">
127
+ Preorder
128
+ </span>
129
+ )}
130
+ <br/>
126
131
  <Link to={itemLink}>{name}</Link>
127
132
  </div>
133
+ {item.is_preorder && (
134
+ <div className="mt-2 flex flex-col gap-1" aria-label="Preorder information">
135
+ <div className="flex flex-wrap items-center gap-2">
136
+ <span className="text-[11px] text-amber-800">
137
+ Release: {(() => {
138
+ const rd = item?.product?.release_date;
139
+ if (!rd) return '-';
140
+ const d = new Date(rd);
141
+ if (isNaN(d.getTime())) return rd;
142
+ const dd = String(d.getDate()).padStart(2, '0');
143
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
144
+ const yyyy = d.getFullYear();
145
+ return `${dd}/${mm}/${yyyy}`;
146
+ })()}
147
+ </span>
148
+ {item.pre_order_payment_type === 'deposit' && item.pre_order_deposit != null && (
149
+ <span className="text-[11px] text-amber-800">
150
+ {(() => {
151
+ const raw = item.pre_order_deposit;
152
+ const n = typeof raw === 'number' ? raw : Number.parseFloat(String(raw).replace(/[^0-9.-]/g,''));
153
+ if (!Number.isFinite(n)) {
154
+ return `Deposit: ${raw}`;
155
+ }
156
+ let str = n.toString();
157
+ if (str.includes('.')) {
158
+ str = str.replace(/\.0+$/,'');
159
+ str = str.replace(/\.(\d*[1-9])0+$/,'.$1');
160
+ }
161
+ return `Deposit: ${str}%`;
162
+ })()}
163
+ </span>
164
+ )}
165
+ </div>
166
+ </div>
167
+ )}
128
168
  <ProductOptions
129
169
  options={options}
130
170
  classes={{
@@ -71,7 +71,7 @@
71
71
  /* composes: font-medium from global; */
72
72
  grid-area: name;
73
73
  display: -webkit-box;
74
- -webkit-line-clamp: 2;
74
+ -webkit-line-clamp: 3;
75
75
  -webkit-box-orient: vertical;
76
76
  overflow: hidden;
77
77
  line-height: normal;
@@ -80,7 +80,46 @@ const ProductListingBySeller = props => {
80
80
  wishlistConfig={wishlistConfig}
81
81
  />
82
82
  ));
83
-
83
+ // Helpers for currency + subtotal formatting
84
+ const aggregateSubtotal = items => {
85
+ let total = 0;
86
+ let currency = null;
87
+ for (const it of items) {
88
+ const priceObj = it?.prices?.price;
89
+ if (priceObj) {
90
+ if (!currency) currency = priceObj.currency;
91
+ const unit = Number(priceObj.value) || 0;
92
+ const qty = Number(it?.quantity) || 0;
93
+ total += unit * qty;
94
+ }
95
+ }
96
+ return { total, currency };
97
+ };
98
+
99
+ const formatMoney = (value, currency) => {
100
+ if (value == null || !isFinite(value)) return '-';
101
+ if (!currency) return value.toFixed(2);
102
+ try {
103
+ const locale = currency === 'IDR' ? 'id-ID' : (currency === 'SGD' ? 'en-SG' : 'en-US');
104
+ const opts = currency === 'IDR'
105
+ ? { style: 'currency', currency, minimumFractionDigits: 0, maximumFractionDigits: 0 }
106
+ : { style: 'currency', currency, minimumFractionDigits: 2, maximumFractionDigits: 2 };
107
+ let formatted = new Intl.NumberFormat(locale, opts).format(value);
108
+ if (currency === 'SGD') {
109
+ formatted = 'SGD ' + formatted
110
+ .replace(/^S?\$/,'')
111
+ .replace(/^SGD\s*/,'')
112
+ .trim();
113
+ }
114
+ return formatted;
115
+ } catch (e) {
116
+ return currency + ' ' + value.toFixed(2);
117
+ }
118
+ };
119
+
120
+ const { total: subtotalValue, currency: detectedCurrency } = aggregateSubtotal(items);
121
+ const displayCurrency = detectedCurrency || seller.seller_currency || 'SGD';
122
+ const formattedSubtotal = formatMoney(subtotalValue, displayCurrency);
84
123
  const priceSummary = hasItems ? (
85
124
  <PriceSummary isProceedToCheckout={isProceedToCheckout} setIsProceedToCheckout={setIsProceedToCheckout} setIsCartUpdating={setIsCartUpdating} isUpdating={isCartUpdating} sellerUrl={seller.seller_url} />
86
125
  ) : null;
@@ -103,13 +142,7 @@ const ProductListingBySeller = props => {
103
142
  {productComponents}
104
143
  <div className={classes.subtotalContainer}>
105
144
  <div className={classes.subtotalLabel}>Subtotal:</div>
106
- <div className={classes.subtotalAmount}>
107
- {seller.seller_currency || 'SGD'} {items.reduce((total, item) => {
108
- const itemPrice = item?.prices?.price?.value || 0;
109
- const quantity = item?.quantity || 0;
110
- return total + (itemPrice * quantity);
111
- }, 0).toFixed(2)}
112
- </div>
145
+ <div className={classes.subtotalAmount}>{formattedSubtotal}</div>
113
146
  </div>
114
147
  <div className={classes.summary_container}>
115
148
  <div className={classes.summary_contents}>
@@ -75,10 +75,6 @@ const CartPage = props => {
75
75
  return fullPageLoadingIndicator;
76
76
  }
77
77
 
78
- const priceSummary = hasItems ? (
79
- <PriceSummary isUpdating={isCartUpdating} />
80
- ) : null;
81
-
82
78
  const productListing = hasItems ? (
83
79
  <ProductListing
84
80
  onAddToWishlistSuccess={onAddToWishlistSuccess}
@@ -132,9 +128,6 @@ const CartPage = props => {
132
128
  {priceAdjustments}
133
129
  </div> */}
134
130
  {/* <div className={classes.summary_container}>
135
- <div className={classes.summary_contents}>
136
- {priceSummary}
137
- </div>
138
131
  </div> */}
139
132
  </div>
140
133
  </div>
@@ -15,11 +15,35 @@ const Item = props => {
15
15
  quantity,
16
16
  configurable_options,
17
17
  isHidden,
18
- configurableThumbnailSource
18
+ configurableThumbnailSource,
19
+ // Preorder-related fields passed via {...item}
20
+ is_preorder,
21
+ pre_order_payment_type,
22
+ pre_order_deposit,
23
+ release_date
19
24
  } = props;
20
25
  const classes = useStyle(defaultClasses, propClasses);
21
26
  const className = isHidden ? classes.root_hidden : classes.root_visible;
22
27
  const configured_variant = configuredVariant(configurable_options, product);
28
+ const formatDate = value => {
29
+ if (!value) return '-';
30
+ const d = value instanceof Date ? value : new Date(value);
31
+ if (Number.isNaN(d.getTime())) return '-';
32
+ const dd = String(d.getDate()).padStart(2, '0');
33
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
34
+ const yyyy = d.getFullYear();
35
+ return `${dd}/${mm}/${yyyy}`;
36
+ };
37
+ const formatDepositPercent = raw => {
38
+ const n = typeof raw === 'number' ? raw : Number.parseFloat(String(raw).replace(/[^0-9.-]/g,''));
39
+ if (!Number.isFinite(n)) return raw;
40
+ let str = n.toString();
41
+ if (str.includes('.')) {
42
+ str = str.replace(/\.0+$/,'');
43
+ str = str.replace(/\.(\d*[1-9])0+$/,'.$1');
44
+ }
45
+ return `${str}%`;
46
+ };
23
47
  return (
24
48
  <div className={className}>
25
49
  <Image
@@ -33,7 +57,24 @@ const Item = props => {
33
57
  : product.thumbnail.url
34
58
  }
35
59
  />
36
- <span className={classes.name}>{product.name}</span>
60
+ <div className={classes.headerRow}>
61
+ {is_preorder && (
62
+ <span className={classes.preorderBadge}>Preorder</span>
63
+ )}
64
+ <span className={classes.name}>{product.name}</span>
65
+ </div>
66
+ {is_preorder && (
67
+ <div className={classes.preorderMeta} aria-label="Preorder information">
68
+ <span className={classes.metaItem}>
69
+ Release: {formatDate(typeof release_date !== 'undefined' ? release_date : product?.release_date)}
70
+ </span>
71
+ {pre_order_payment_type === 'deposit' && pre_order_deposit != null && (
72
+ <span className={classes.metaItem}>
73
+ Deposit: {formatDepositPercent(pre_order_deposit)}
74
+ </span>
75
+ )}
76
+ </div>
77
+ )}
37
78
  <ProductOptions
38
79
  options={configurable_options}
39
80
  classes={{
@@ -63,3 +63,39 @@
63
63
  grid-column: 2 / span 1;
64
64
  grid-row: 2 / span 1;
65
65
  }
66
+
67
+ .headerRow {
68
+ grid-column: 2 / span 1;
69
+ grid-row: 1 / span 1;
70
+ align-items: center;
71
+ gap: 8px;
72
+ }
73
+
74
+ .preorderBadge {
75
+ display: inline-flex;
76
+ align-items: center;
77
+ gap: 4px;
78
+ padding: 2px 8px;
79
+ border-radius: 9999px;
80
+ background: #f26313; /* orange accent for visibility */
81
+ color: #fff;
82
+ border: 1px solid #f26313;
83
+ font-size: 10px;
84
+ font-weight: 600;
85
+ margin-bottom: 5px;
86
+ }
87
+
88
+ .preorderMeta {
89
+ grid-column: 2 / span 1;
90
+ grid-row: 2 / span 1;
91
+ margin-top: 4px;
92
+ display: flex;
93
+ flex-wrap: wrap;
94
+ gap: 12px;
95
+ color: #000; /* amber-ish */
96
+ font-size: 11px;
97
+ }
98
+
99
+ .metaItem {
100
+ display: inline-block;
101
+ }
@@ -15,8 +15,8 @@ import defaultClasses from './itemsReview.module.css';
15
15
  * @param {Object} props.data an optional static data object to render instead of making a query for data.
16
16
  */
17
17
  const ItemsReview = props => {
18
- const { classes: propClasses } = props;
19
-
18
+ const { classes: propClasses, isPreorder, preOrderDeposit, preOrderPaymentType, releaseDate } = props;
19
+
20
20
  const classes = useStyle(defaultClasses, propClasses);
21
21
 
22
22
  const talonProps = useItemsReview({
@@ -38,6 +38,12 @@ const ItemsReview = props => {
38
38
  {...item}
39
39
  isHidden={!showAllItems && index >= 2}
40
40
  configurableThumbnailSource={configurableThumbnailSource}
41
+ // Forward explicit preorder values from parent if provided
42
+ is_preorder={typeof isPreorder !== 'undefined' ? isPreorder : item.is_preorder}
43
+ pre_order_payment_type={typeof preOrderPaymentType !== 'undefined' ? preOrderPaymentType : item.pre_order_payment_type}
44
+ pre_order_deposit={typeof preOrderDeposit !== 'undefined' ? preOrderDeposit : item.pre_order_deposit}
45
+ // release_date may come from parent or item.product
46
+ release_date={typeof releaseDate !== 'undefined' ? releaseDate : (item?.product?.release_date)}
41
47
  />
42
48
  ));
43
49
 
@@ -7,6 +7,9 @@ import defaultClasses from './orderSummary.module.css';
7
7
 
8
8
  const OrderSummary = props => {
9
9
  const classes = useStyle(defaultClasses, props.classes);
10
+
11
+ const { placeOrderButton } = props
12
+
10
13
  return (
11
14
  <div data-cy="OrderSummary-root" className={classes.root}>
12
15
  <h2 aria-live="polite" className="text-[16px] font-medium mb-4">
@@ -26,6 +29,7 @@ const OrderSummary = props => {
26
29
  }
27
30
  `}
28
31
  </style>
32
+ {placeOrderButton}
29
33
  </div>
30
34
  );
31
35
  };