@riosst100/pwa-marketplace 3.0.4 → 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 (28) hide show
  1. package/package.json +1 -1
  2. package/src/components/CrossSeller/item.js +3 -4
  3. package/src/components/LinkToOtherStores/index.js +4 -4
  4. package/src/components/ProductListTab/productListTab.js +1 -1
  5. package/src/components/commons/Select/index.js +8 -4
  6. package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/priceSummaryFragments.gql.js +3 -0
  7. package/src/overwrites/peregrine/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +4 -0
  8. package/src/overwrites/peregrine/lib/talons/CheckoutPage/checkoutPage.extended.gql.js +20 -1
  9. package/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js +3 -3
  10. package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +7 -8
  11. package/src/overwrites/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js +5 -0
  12. package/src/overwrites/venia-ui/lib/components/Breadcrumbs/breadcrumbs.js +20 -1
  13. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.js +41 -1
  14. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.module.css +1 -1
  15. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListingBySeller/productListingBySeller.js +41 -8
  16. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.js +43 -2
  17. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.module.css +36 -0
  18. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js +8 -2
  19. package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.js +7 -2
  20. package/src/overwrites/venia-ui/lib/components/FilterModal/CurrentFilters/currentFilters.js +1 -1
  21. package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +1 -1
  22. package/src/overwrites/venia-ui/lib/components/Gallery/item.js +2 -10
  23. package/src/overwrites/venia-ui/lib/components/Gallery/item.module.css +5 -4
  24. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/CustomAttributes/customAttributes.js +10 -2
  25. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/preOrderDetail.js +195 -37
  26. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +194 -63
  27. package/src/talons/ProductContent/productContent.gql.js +11 -1
  28. package/src/talons/ProductContent/useProductContent.js +14 -2
@@ -13,14 +13,22 @@ const CustomAttributes = props => {
13
13
  const { customAttributes, showLabels } = props;
14
14
  const classes = useStyle(defaultClasses, props.classes);
15
15
 
16
+ const systemAttributes = [
17
+ 'term_and_conditions',
18
+ 'sale',
19
+ 'sku'
20
+ ];
21
+
16
22
  const list = useMemo(
17
23
  () =>
18
24
  customAttributes.reduce((previousAttribute, currentAttribute) => {
25
+ console.log('currentAttribute',currentAttribute)
26
+ const attrCode = currentAttribute.attribute_metadata?.code;
19
27
  const usedInComponents =
20
28
  currentAttribute.attribute_metadata?.used_in_components ||
21
29
  [];
22
30
  // Visible on front attributes only
23
- if (usedInComponents.includes(IS_VISIBLE_ON_FRONT)) {
31
+ if (!systemAttributes.includes(attrCode) && usedInComponents.includes(IS_VISIBLE_ON_FRONT)) {
24
32
  const attributeContent = (
25
33
  <li
26
34
  key={currentAttribute.attribute_metadata.uid}
@@ -38,7 +46,7 @@ const CustomAttributes = props => {
38
46
 
39
47
  return previousAttribute;
40
48
  }, []),
41
- [classes, customAttributes, showLabels]
49
+ [classes, customAttributes, showLabels, systemAttributes]
42
50
  );
43
51
 
44
52
  if (list.length === 0) {
@@ -1,58 +1,216 @@
1
- import React, { useMemo } from 'react';
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
2
  import cn from 'classnames';
3
3
  import Divider from '@riosst100/pwa-marketplace/src/components/Divider';
4
+ import Select from '@riosst100/pwa-marketplace/src/components/commons/Select';
4
5
 
5
6
  const preOrderInfo = (props) => {
6
- const { className, productDetails } = props
7
-
8
- const preorderData = productDetails ? productDetails.preorder : null;
7
+ const { className, preOrder, preOrderDate, preOrderDeposite, preOrderNote, preOrderPaymentType, releaseDate, onPaymentTypeChange, paymentTypeOptions = [] } = props;
9
8
 
10
- const isPreOrder = preorderData && preorderData.is_preorder ? true : false;
11
- const preOrderNotes = preorderData ? preorderData.preorder_notes : null;
12
- const preOrderAvailableDate = preorderData ? new Date(preorderData.preorder_availability) : null;
9
+ const isPreOrder = typeof preOrder === 'string'
10
+ ? preOrder.trim().toLowerCase() === 'pre orders'
11
+ : !!(preOrder && preOrder.is_preorder);
12
+
13
+ const normalizePaymentType = (value = '') => {
14
+ const normalized = value.toString().trim().toLowerCase();
15
+
16
+ if (normalized === 'full payment') {
17
+ return 'full';
18
+ }
19
+
20
+ if (normalized === 'deposit' || normalized === 'full') {
21
+ return normalized;
22
+ }
23
+
24
+ return '';
25
+ };
26
+
27
+ const initialPaymentType = useMemo(
28
+ () => normalizePaymentType(preOrderPaymentType),
29
+ [preOrderPaymentType]
30
+ );
31
+
32
+ const [selectedPaymentType, setSelectedPaymentType] = useState(initialPaymentType || 'full');
33
+
34
+ useEffect(() => {
35
+ setSelectedPaymentType(initialPaymentType || 'full');
36
+ }, [initialPaymentType]);
37
+
38
+ // Propagate initial and subsequent selection to parent so submit has value
39
+ useEffect(() => {
40
+ if (typeof onPaymentTypeChange === 'function' && selectedPaymentType) {
41
+ onPaymentTypeChange(selectedPaymentType);
42
+ }
43
+ }, [selectedPaymentType, onPaymentTypeChange]);
44
+
45
+ const normalizedPaymentOptions = useMemo(() => {
46
+ return paymentTypeOptions.reduce((acc, option) => {
47
+ const normalizedValue = normalizePaymentType(option.value);
48
+ if (!normalizedValue) {
49
+ return acc;
50
+ }
51
+
52
+ if (acc.find(item => item.value === normalizedValue)) {
53
+ return acc;
54
+ }
55
+
56
+ const label = option.label || (normalizedValue === 'full' ? 'Full Payment' : 'Deposit');
57
+ acc.push({ label, value: normalizedValue });
58
+ return acc;
59
+ }, []);
60
+ }, [paymentTypeOptions]);
61
+
62
+ const paymentOptions = useMemo(() => {
63
+ const optionsToUse = normalizedPaymentOptions;
64
+
65
+ if (!optionsToUse.length) {
66
+ return [];
67
+ }
68
+
69
+ if (initialPaymentType === 'full') {
70
+ return optionsToUse.filter(option => option.value === 'full');
71
+ }
72
+
73
+ if (initialPaymentType === 'deposit') {
74
+ return optionsToUse;
75
+ }
76
+
77
+ return optionsToUse;
78
+ }, [initialPaymentType, normalizedPaymentOptions]);
79
+
80
+ const handlePaymentTypeChange = (event) => {
81
+ if (!paymentOptions.length) {
82
+ return;
83
+ }
84
+
85
+ const nextValue = event.target.value;
86
+ const availableValues = paymentOptions.map(option => option.value);
87
+ const appliedValue = availableValues.includes(nextValue)
88
+ ? nextValue
89
+ : availableValues[0];
90
+
91
+ setSelectedPaymentType(appliedValue);
92
+
93
+ if (typeof onPaymentTypeChange === 'function') {
94
+ onPaymentTypeChange(appliedValue);
95
+ }
96
+ };
97
+
98
+ const formatDate = (value) => {
99
+ if (!value) {
100
+ return '-';
101
+ }
13
102
 
14
- const month = ["January","February","March","April","May","June","July","August","September","October","November","December"];
103
+ const parsed = value instanceof Date ? value : new Date(value);
104
+ if (Number.isNaN(parsed.getTime())) {
105
+ return '-';
106
+ }
107
+
108
+ const day = String(parsed.getDate()).padStart(2, '0');
109
+ const month = String(parsed.getMonth() + 1).padStart(2, '0');
110
+ const year = parsed.getFullYear();
111
+
112
+ return `${day}/${month}/${year}`;
113
+ };
114
+
115
+ const preOrderNotes = preOrderNote || null;
116
+ const preOrderAvailableDate = releaseDate || null;
117
+ const preOrderClosingDate = preOrderDate || null;
118
+
119
+ const normalizeDeposit = (value) => {
120
+ if (!value && value !== 0) {
121
+ return '-';
122
+ }
123
+
124
+ const numeric = typeof value === 'number'
125
+ ? value
126
+ : Number.parseFloat(value.toString().replace(/[^0-9.-]/g, ''));
127
+
128
+ if (Number.isNaN(numeric)) {
129
+ return value;
130
+ }
131
+
132
+ // Tampilkan sebagai persentase tanpa 0 di belakang koma dan tambahkan '%'
133
+ // Contoh: 10.00 -> '10%'; 12.5 -> '12.5%'; 12.50 -> '12.5%'
134
+ let str = numeric.toString();
135
+ if (str.includes('.')) {
136
+ // hapus trailing zeros di desimal
137
+ str = str.replace(/\.0+$/,'');
138
+ str = str.replace(/\.(\d*[1-9])0+$/,'.$1');
139
+ }
140
+ return `${str}%`;
141
+ };
142
+
143
+ const depositValue = normalizeDeposit(preOrderDeposite);
144
+ const showDepositRow = selectedPaymentType === 'deposit';
145
+
146
+ const isPreOrderClosed = (() => {
147
+ if (!preOrderClosingDate) return false;
148
+
149
+ const parsed = preOrderClosingDate instanceof Date
150
+ ? preOrderClosingDate
151
+ : new Date(preOrderClosingDate);
152
+
153
+ if (Number.isNaN(parsed.getTime())) return false;
154
+
155
+ parsed.setHours(23, 59, 59, 999);
156
+ return new Date().getTime() > parsed.getTime();
157
+ })();
15
158
 
16
159
  return isPreOrder ? (
17
160
  <>
18
161
  <div
19
162
  className={cn(
20
- 'flex flex-col border border-gray-100 rounded-lg p-5 gap-2.5',
163
+ 'flex flex-col border border-gray-100 rounded-lg p-5 m-4 gap-4 bg-white',
21
164
  className
22
165
  )}
23
166
  >
24
- <div className='flex flex-row justify-between gap-[20px]'>
25
- <div className='flex flex-col gap-2.5'>
26
- <div className='text-[14px] font-medium text-gray-500'>
27
- Release Date
28
- </div>
29
- <div className='text-[16px] font-medium text-colorDefault text-center'>
30
- {preOrderAvailableDate ? preOrderAvailableDate.getDate() + ', ' + month[preOrderAvailableDate.getMonth()] + ' ' + preOrderAvailableDate.getFullYear() : 'No Release Date.'}
31
- {/* 27, February 2024 */}
32
- </div>
167
+ <div className='text-[16px] font-semibold text-colorDefault'>
168
+ Pre Order Details
169
+ </div>
170
+ <div className='flex flex-col gap-3'>
171
+ {showDepositRow && (
172
+ <>
173
+ <div className='flex justify-between text-[13px] text-gray-600'>
174
+ <span className='font-medium text-gray-500'>Deposit:</span>
175
+ <span className='font-medium text-colorDefault'>{depositValue}</span>
176
+ </div>
177
+ <Divider className='h-px w-full bg-gray-100' />
178
+ </>
179
+ )}
180
+ <div className='flex justify-between items-center text-[13px] text-gray-600 gap-4'>
181
+ <span className='font-medium text-gray-500'>Payment Type:</span>
182
+ <Select
183
+ wrapperClassname='justify-end w-full max-w-[180px]'
184
+ className='w-full text-[13px]'
185
+ options={paymentOptions}
186
+ value={selectedPaymentType}
187
+ onChange={handlePaymentTypeChange}
188
+ showPlaceholder={false}
189
+ />
33
190
  </div>
34
- <Divider className="w-[1px] h-[50px]" />
35
- <div className='flex flex-col gap-2.5'>
36
- <div className='text-[14px] font-medium text-gray-500'>
37
- Last Date
38
- </div>
39
- <div className='text-[16px] font-medium text-colorDefault text-center'>
40
- 31, March 2024
41
- </div>
191
+ <Divider className='h-px w-full bg-gray-100' />
192
+ <div className='flex justify-between text-[13px] text-gray-600'>
193
+ <span className='font-medium text-gray-500'>Pre Order Closing Date:</span>
194
+ <span className='font-medium text-colorDefault'>{formatDate(preOrderClosingDate)}</span>
42
195
  </div>
43
- <Divider className="w-[1px] h-[50px]" />
44
- <div className='flex flex-col gap-2.5'>
45
- <div className='text-[14px] font-medium text-gray-500'>
46
- Deposite
47
- </div>
48
- <div className='text-[16px] font-medium text-colorDefault text-center'>
49
- 40%
50
- </div>
196
+ <Divider className='h-px w-full bg-gray-100' />
197
+ <div className='flex justify-between text-[13px] text-gray-600'>
198
+ <span className='font-medium text-gray-500'>Release Date:</span>
199
+ <span className='font-medium text-colorDefault'>{formatDate(preOrderAvailableDate)}</span>
51
200
  </div>
201
+ <Divider className='h-px w-full bg-gray-100' />
202
+ <div className='flex justify-between text-[13px] text-gray-600'>
203
+ <span className='font-medium text-gray-500'>Note:</span>
204
+ <span className='font-medium text-colorDefault text-right'>
205
+ {preOrderNotes || '-'}
206
+ </span>
207
+ </div>
208
+ {isPreOrderClosed && (
209
+ <div className='mt-1 text-[12px] text-red-500 font-medium'>
210
+ Pre order is closed. You can no longer place a pre-order for this product.
211
+ </div>
212
+ )}
52
213
  </div>
53
- {preOrderNotes && <p>
54
- Notes : {preOrderNotes}
55
- </p>}
56
214
  </div>
57
215
  </>
58
216
  ) : ''
@@ -1,4 +1,5 @@
1
1
  import React, { useState, useMemo, Fragment, Suspense, useRef, useEffect } from 'react';
2
+ import { useQuery } from '@apollo/client';
2
3
  import { FormattedMessage, useIntl } from 'react-intl';
3
4
  import { arrayOf, bool, number, shape, string } from 'prop-types';
4
5
  import { Form } from 'informed';
@@ -26,6 +27,7 @@ import RichText from '@magento/venia-ui/lib/components/RichText';
26
27
  import { Star1, Verify, Sms, Message, Shop, ArrowUp2 } from 'iconsax-react';
27
28
  import { Link } from "react-router-dom";
28
29
  import Divider from '@riosst100/pwa-marketplace/src/components/Divider';
30
+ import { GET_PAYMENT_TYPES } from '@riosst100/pwa-marketplace/src/talons/ProductContent/productContent.gql.js';
29
31
 
30
32
  const WishlistButton = React.lazy(() => import('@magento/venia-ui/lib/components/Wishlist/AddToListButton'));
31
33
  const Options = React.lazy(() => import('@magento/venia-ui/lib/components/ProductOptions'));
@@ -112,9 +114,16 @@ const ProductFullDetail = props => {
112
114
 
113
115
  const { formatMessage } = useIntl();
114
116
 
117
+ const { data: paymentTypeData } = useQuery(GET_PAYMENT_TYPES, {
118
+ fetchPolicy: 'cache-and-network'
119
+ });
120
+
121
+ const paymentTypeOptions = paymentTypeData?.getPaymentType || [];
122
+
115
123
  const classes = useStyle(defaultClasses, props.classes);
116
124
 
117
125
  const [hoveredMedia, setHoveredMedia] = useState(null);
126
+ const [selectedPaymentType, setSelectedPaymentType] = useState(null);
118
127
 
119
128
  const options = isProductConfigurable(product) ? (
120
129
  <Suspense fallback={<ProductOptionsShimmer />}>
@@ -133,6 +142,7 @@ const ProductFullDetail = props => {
133
142
  <Breadcrumbs
134
143
  categoryId={breadcrumbCategoryId}
135
144
  currentProduct={productDetails.name}
145
+ currentProductCustomTableMetadata={productDetails.custom_table_metadata}
136
146
  />
137
147
  ) : null;
138
148
 
@@ -221,62 +231,6 @@ const ProductFullDetail = props => {
221
231
  };
222
232
  }, [customAttributes, productDetails.sku, formatMessage]);
223
233
 
224
- const cartCallToActionText =
225
- !isEverythingOutOfStock || !isOutOfStock ? (
226
- <FormattedMessage
227
- id="productFullDetail.addItemToCart"
228
- defaultMessage="Add to Cart"
229
- />
230
- ) : (
231
- <FormattedMessage
232
- id="productFullDetail.itemOutOfStock"
233
- defaultMessage="Out of Stock"
234
- />
235
- );
236
- // Error message for screen reader
237
- const cartActionContent = isSupportedProductType ? (
238
- <section className={cn(classes.actButton, 'justify-between flex gap-x-[20px] px-[15px] py-0')}>
239
- <RFQ
240
- disabled={isAddToCartDisabled}
241
- classes={{ rfqButton: cn(classes.rfqButton, "w-full") }}
242
- />
243
- <Button
244
- data-cy="ProductFullDetail-addToCartButton"
245
- disabled={isAddToCartDisabled}
246
- aria-disabled={isAddToCartDisabled}
247
- aria-label={
248
- isEverythingOutOfStock
249
- ? formatMessage({
250
- id: 'productFullDetail.outOfStockProduct',
251
- defaultMessage:
252
- 'This item is currently out of stock'
253
- })
254
- : ''
255
- }
256
- classes={{
257
- rootClass: '!px-0 !py-3',
258
- content: 'w-full normal-case font-medium text-[14px]'
259
- }}
260
- priority="high"
261
- type="submit"
262
- >
263
- {cartCallToActionText}
264
- </Button>
265
- </section>
266
- ) : (
267
- <div className={classes.unavailableContainer}>
268
- <Info />
269
- <p>
270
- <FormattedMessage
271
- id={'productFullDetail.unavailableProduct'}
272
- defaultMessage={
273
- 'This product is currently unavailable for purchase.'
274
- }
275
- />
276
- </p>
277
- </div>
278
- );
279
-
280
234
  const shortDescription = productDetails.shortDescription ? (
281
235
  <RichText
282
236
  rootClassName="px-0"
@@ -392,7 +346,6 @@ const ProductFullDetail = props => {
392
346
  const code = attr.attribute_metadata?.code || "";
393
347
  return useSuffix ? code.endsWith(key) : code === key;
394
348
  });
395
-
396
349
  if (!attr) return "";
397
350
 
398
351
  if (attr.selected_attribute_options?.attribute_option?.length) {
@@ -403,6 +356,12 @@ const ProductFullDetail = props => {
403
356
  return attr.entered_attribute_value?.value || "";
404
357
  };
405
358
 
359
+ const preOrder = getAttributeValue(customAttributesDetails, "card_pre_orders", true);
360
+ const preOrderDate = getAttributeValue(customAttributesDetails, "pre_order_date", true);
361
+ const preOrderDeposite = getAttributeValue(customAttributesDetails, "pre_order_deposit", true);
362
+ const preOrderNote = getAttributeValue(customAttributesDetails, "pre_order_notes", true);
363
+ const preOrderPaymentType = getAttributeValue(customAttributesDetails, "pre_order_payment_type", true);
364
+ const releaseDate = getAttributeValue(customAttributesDetails, "release_date", true);
406
365
  const setNameValue = getAttributeValue(customAttributesDetails, "card_set", true);
407
366
  const cardNameValue = getAttributeValue(customAttributesDetails, "card_name", true);
408
367
  const cardNumberValue = getAttributeValue(customAttributesDetails, "card_number", true);
@@ -410,6 +369,104 @@ const ProductFullDetail = props => {
410
369
  const featureValue = getAttributeValue(customAttributesDetails, "card_feature", true);
411
370
  const conditionValue = getAttributeValue(customAttributesDetails, "card_condition", true);
412
371
  const foilValue = getAttributeValue(customAttributesDetails, "card_foil", true);
372
+
373
+ const isPreOrderProduct = typeof preOrder === 'string'
374
+ ? preOrder.trim().toLowerCase() === 'pre orders'
375
+ : !!(preOrder && preOrder.is_preorder);
376
+
377
+ const parsePreOrderClosingDate = (value) => {
378
+ if (!value) return null;
379
+
380
+ const parsed = value instanceof Date ? value : new Date(value);
381
+ if (Number.isNaN(parsed.getTime())) return null;
382
+
383
+ // Normalise to end of day for fairness
384
+ parsed.setHours(23, 59, 59, 999);
385
+ return parsed;
386
+ };
387
+
388
+ const preOrderClosingDateObj = parsePreOrderClosingDate(preOrderDate);
389
+ const isPreOrderClosed =
390
+ isPreOrderProduct &&
391
+ preOrderClosingDateObj !== null &&
392
+ new Date().getTime() > preOrderClosingDateObj.getTime();
393
+
394
+ const cartCallToActionText =
395
+ isPreOrderClosed
396
+ ? (
397
+ <FormattedMessage
398
+ id="productFullDetail.preOrderClosed"
399
+ defaultMessage="Pre Order Closed"
400
+ />
401
+ )
402
+ : isPreOrderProduct
403
+ ? (
404
+ <FormattedMessage
405
+ id="productFullDetail.preOrderNow"
406
+ defaultMessage="Pre Order Now"
407
+ />
408
+ )
409
+ : !isEverythingOutOfStock || !isOutOfStock
410
+ ? (
411
+ <FormattedMessage
412
+ id="productFullDetail.addItemToCart"
413
+ defaultMessage="Add to Cart"
414
+ />
415
+ )
416
+ : (
417
+ <FormattedMessage
418
+ id="productFullDetail.itemOutOfStock"
419
+ defaultMessage="Out of Stock"
420
+ />
421
+ );
422
+
423
+ // Error message for screen reader
424
+ const cartActionContent = isSupportedProductType ? (
425
+ <section className={cn(classes.actButton, 'justify-between flex gap-x-[20px] px-[15px] py-0')}>
426
+ <RFQ
427
+ disabled={isAddToCartDisabled || isPreOrderClosed}
428
+ classes={{ rfqButton: cn(classes.rfqButton, "w-full") }}
429
+ />
430
+ <Button
431
+ data-cy="ProductFullDetail-addToCartButton"
432
+ disabled={isAddToCartDisabled || isPreOrderClosed}
433
+ aria-disabled={isAddToCartDisabled || isPreOrderClosed}
434
+ aria-label={
435
+ isPreOrderClosed
436
+ ? 'Pre order closing date has passed'
437
+ : isPreOrderProduct
438
+ ? ''
439
+ : isEverythingOutOfStock
440
+ ? formatMessage({
441
+ id: 'productFullDetail.outOfStockProduct',
442
+ defaultMessage:
443
+ 'This item is currently out of stock'
444
+ })
445
+ : ''
446
+ }
447
+ classes={{
448
+ rootClass: '!px-0 !py-3',
449
+ content: 'w-full normal-case font-medium text-[14px]'
450
+ }}
451
+ priority="high"
452
+ type="submit"
453
+ >
454
+ {cartCallToActionText}
455
+ </Button>
456
+ </section>
457
+ ) : (
458
+ <div className={classes.unavailableContainer}>
459
+ <Info />
460
+ <p>
461
+ <FormattedMessage
462
+ id={'productFullDetail.unavailableProduct'}
463
+ defaultMessage={
464
+ 'This product is currently unavailable for purchase.'
465
+ }
466
+ />
467
+ </p>
468
+ </div>
469
+ );
413
470
  const ExpandableSection = ({ children, maxHeight = 480 }) => {
414
471
  const [expanded, setExpanded] = useState(false);
415
472
  const [showButton, setShowButton] = useState(false);
@@ -554,9 +611,33 @@ const ProductFullDetail = props => {
554
611
 
555
612
  const AlertCircleIcon = <Icon src={ShoppingCart} attrs={{ width: 20 }} />;
556
613
 
557
- const handleAddToCart = async (...args) => {
614
+ const handleAddToCart = async formValues => {
558
615
  try {
559
- await originalHandleAddToCart(...args);
616
+ const parseDepositNumber = (value) => {
617
+ if (value === null || value === undefined) return undefined;
618
+ if (typeof value === 'number') return value;
619
+ const numeric = Number.parseFloat(value.toString().replace(/[^0-9.-]/g, ''));
620
+ return Number.isFinite(numeric) ? numeric : undefined;
621
+ };
622
+
623
+ let preorderPayload;
624
+ if (selectedPaymentType) {
625
+ preorderPayload = {
626
+ pre_order_payment_type: selectedPaymentType
627
+ };
628
+ if (selectedPaymentType === 'deposit') {
629
+ const dep = parseDepositNumber(preOrderDeposite);
630
+ if (dep !== undefined) {
631
+ preorderPayload.pre_order_deposit = dep;
632
+ }
633
+ }
634
+ }
635
+
636
+ const nextValues = {
637
+ ...formValues,
638
+ preorder: preorderPayload
639
+ };
640
+ await originalHandleAddToCart(nextValues);
560
641
  } catch (e) {
561
642
  addToast({
562
643
  type: 'error',
@@ -686,7 +767,7 @@ const ProductFullDetail = props => {
686
767
  data-cy="ProductFullDetail-productPrice"
687
768
  className={cn(
688
769
  classes.productPrice,
689
- 'text-[32px] font-medium leading-[32px] mb-0',
770
+ 'text-[24px] font-medium leading-[32px] mb-0',
690
771
  )}
691
772
  >
692
773
  <Price
@@ -697,11 +778,10 @@ const ProductFullDetail = props => {
697
778
  </p>
698
779
  </div>
699
780
  <AuctionDetail className="auction_detail-container" />
700
- <PreorderDetail className={'preorder_detail-container'} />
701
781
  <small className='shipping-calculation-notes text-gray-200 text-xs'>
702
782
  Shipping is calculated on checkout
703
783
  </small>
704
- <div className='flex flex-col xs_items-center md_items-start gap-[6px] relative'>
784
+ {/* <div className='flex flex-col xs_items-center md_items-start gap-[6px] relative'>
705
785
  <div className="gap-x-[10px] gap-y-1 flex xs_flex-col md_flex-row xs_items-center md_items-start relative">
706
786
  <Link to={"/seller/"+sellerDetails.url_key} class="flex items-center justify-center gap-[5px] py-1 relative bg-white">
707
787
  <div class="flex items-center justify-center gap-[5px] relative">
@@ -712,7 +792,7 @@ const ProductFullDetail = props => {
712
792
  </div>
713
793
  </Link>
714
794
  </div>
715
- </div>
795
+ </div> */}
716
796
  </div>
717
797
  </div>
718
798
  <FormError
@@ -743,11 +823,62 @@ const ProductFullDetail = props => {
743
823
  />
744
824
  </Suspense>
745
825
  </div>
826
+ <PreorderDetail
827
+ preOrder={preOrder}
828
+ preOrderDate={preOrderDate}
829
+ preOrderDeposite={preOrderDeposite}
830
+ preOrderNote={preOrderNote}
831
+ preOrderPaymentType={preOrderPaymentType}
832
+ releaseDate={releaseDate}
833
+ className={'preorder_detail-container'}
834
+ paymentTypeOptions={paymentTypeOptions}
835
+ onPaymentTypeChange={setSelectedPaymentType}
836
+ />
746
837
  <div className='product_actions-wrapper'>
747
838
  {cartActionContent}
748
839
  </div>
749
840
  </section>
750
841
  </div>
842
+ <div className={cn('product_otherlink-section', 'border border-[lightgray] rounded-[10px] mb-[15px] p-4')}>
843
+ <div className='flex flex-col xs_items-center md_items-start gap-[6px] relative'>
844
+ <div className="gap-x-[10px] gap-y-1 flex xs_flex-col md_flex-row xs_items-center md_items-start relative">
845
+ <Link to={"/seller/"+sellerDetails.url_key} class="flex items-center justify-center gap-[5px] py-1 relative bg-white">
846
+ <div class="flex items-center justify-center gap-[5px] relative">
847
+ <p>Sold by</p>
848
+ <div class="relative xs_hidden lg_flex w-fit font-medium text-[#f76b1c] text-[14px] tracking-[0] leading-[20px] whitespace-nowrap">
849
+ {sellerDetails ? sellerDetails.name : ''}
850
+ </div>
851
+ </div>
852
+ </Link>
853
+ </div>
854
+ </div>
855
+ <div className='flex flex-col xs_items-center md_items-start gap-[6px] relative'>
856
+ <div className="gap-x-[10px] gap-y-1 flex xs_flex-col md_flex-row xs_items-center md_items-start relative">
857
+ <div class="flex items-center justify-center gap-[5px] py-1 relative bg-white">
858
+ <div class="flex items-center justify-center gap-[5px] relative">
859
+ <div className='flex flex-wrap items-start gap-4 relative'>
860
+ <Link to='#' class="flex items-center justify-center gap-[5px] py-1 px-5 relative bg-white rounded-[30px] border border-solid border-[#f76b1c]">
861
+ <div class="flex items-center justify-center gap-[10px] relative">
862
+ <Sms color="#f76b1c" size={14} variant="Outline" className='stroke-[#f76b1c]' />
863
+ <div class="relative xs_hidden lg_flex w-fit font-medium text-[#f76b1c] text-[14px] tracking-[0] leading-[20px] whitespace-nowrap">
864
+ Send Message
865
+ </div>
866
+ </div>
867
+ </Link>
868
+ <Link to={"/seller/"+sellerDetails.url_key} class="flex items-center justify-center gap-[5px] py-1 px-5 relative bg-white rounded-[30px] border border-solid border-[#f76b1c]">
869
+ <div class="flex items-center justify-center gap-[10px] relative">
870
+ <Shop color="#f76b1c" size={14} variant="Outline" className='stroke-[#f76b1c]' />
871
+ <div class="relative xs_hidden lg_flex w-fit font-medium text-[#f76b1c] text-[14px] tracking-[0] leading-[20px] whitespace-nowrap">
872
+ Visit Store
873
+ </div>
874
+ </div>
875
+ </Link>
876
+ </div>
877
+ </div>
878
+ </div>
879
+ </div>
880
+ </div>
881
+ </div>
751
882
  <div className={cn('product_otherlink-section', 'border border-[lightgray] rounded-[10px] mb-[15px]')}>
752
883
  <LinkToOtherStores productDetails={productDetails} />
753
884
  </div>
@@ -89,10 +89,20 @@ export const GET_STORE_CONFIG_DATA = gql`
89
89
  }
90
90
  `;
91
91
 
92
+ export const GET_PAYMENT_TYPES = gql`
93
+ query getPaymentTypeOptions {
94
+ getPaymentType {
95
+ label
96
+ value
97
+ }
98
+ }
99
+ `;
100
+
92
101
 
93
102
  export default {
94
103
  getCategoryContentQuery: GET_CATEGORY_CONTENT,
95
104
  getProductFiltersByCategoryQuery: GET_PRODUCT_FILTERS_BY_CATEGORY,
96
105
  getCategoryAvailableSortMethodsQuery: GET_CATEGORY_AVAILABLE_SORT_METHODS,
97
- getStoreConfigQuery: GET_STORE_CONFIG_DATA
106
+ getStoreConfigQuery: GET_STORE_CONFIG_DATA,
107
+ getPaymentTypesQuery: GET_PAYMENT_TYPES
98
108
  };