@riosst100/pwa-marketplace 3.0.4 → 3.0.6

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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/componentOverrideMapping.js +1 -0
  3. package/src/components/CrossSeller/item.js +3 -4
  4. package/src/components/LinkToOtherStores/index.js +4 -4
  5. package/src/components/ProductListTab/productListTab.js +1 -1
  6. package/src/components/commons/Select/index.js +8 -4
  7. package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/priceSummaryFragments.gql.js +3 -0
  8. package/src/overwrites/peregrine/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +4 -0
  9. package/src/overwrites/peregrine/lib/talons/CheckoutPage/PaymentInformation/usePaymentMethods.js +84 -0
  10. package/src/overwrites/peregrine/lib/talons/CheckoutPage/checkoutPage.extended.gql.js +20 -1
  11. package/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js +3 -3
  12. package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +7 -8
  13. package/src/overwrites/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js +5 -0
  14. package/src/overwrites/venia-ui/lib/components/Breadcrumbs/breadcrumbs.js +20 -1
  15. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.js +41 -1
  16. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.module.css +1 -1
  17. package/src/overwrites/venia-ui/lib/components/CartPage/ProductListingBySeller/productListingBySeller.js +41 -8
  18. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.js +43 -2
  19. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.module.css +36 -0
  20. package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js +8 -2
  21. package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.js +7 -2
  22. package/src/overwrites/venia-ui/lib/components/FilterModal/CurrentFilters/currentFilters.js +1 -1
  23. package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +1 -1
  24. package/src/overwrites/venia-ui/lib/components/Gallery/item.js +2 -10
  25. package/src/overwrites/venia-ui/lib/components/Gallery/item.module.css +5 -4
  26. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/CustomAttributes/customAttributes.js +10 -2
  27. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/preOrderDetail.js +195 -37
  28. package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +194 -63
  29. package/src/talons/ProductContent/productContent.gql.js +11 -1
  30. package/src/talons/ProductContent/useProductContent.js +14 -2
@@ -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
  };
@@ -27,7 +27,8 @@ export const useProductContent = props => {
27
27
  getCategoryContentQuery,
28
28
  getProductFiltersByCategoryQuery,
29
29
  getCategoryAvailableSortMethodsQuery,
30
- getStoreConfigQuery
30
+ getStoreConfigQuery,
31
+ getPaymentTypesQuery
31
32
  } = operations;
32
33
 
33
34
  const placeholderItems = Array.from({ length: pageSize }).fill(null);
@@ -36,6 +37,13 @@ export const useProductContent = props => {
36
37
  fetchPolicy: 'cache-and-network'
37
38
  });
38
39
 
40
+ const { data: paymentTypeData, loading: paymentTypeLoading } = useQuery(
41
+ getPaymentTypesQuery,
42
+ {
43
+ fetchPolicy: 'cache-and-network'
44
+ }
45
+ );
46
+
39
47
  const virtualCategoryFilters = useMemo(() => {
40
48
  if (storeConfigData) {
41
49
  const data = storeConfigData.storeConfig.custommarketplace_plp_filters_virtualcategory;
@@ -161,6 +169,8 @@ export const useProductContent = props => {
161
169
  ? sortData.products.sort_fields.options
162
170
  : null;
163
171
 
172
+ const paymentTypeOptions = paymentTypeData?.getPaymentType || [];
173
+
164
174
  useEffect(() => {
165
175
  if (!categoryLoading && categoryData.categories.items.length > 0) {
166
176
  dispatch({
@@ -187,6 +197,8 @@ export const useProductContent = props => {
187
197
  parent,
188
198
  attributesBlock,
189
199
  category,
190
- virtualCategoryFilters
200
+ virtualCategoryFilters,
201
+ paymentTypeOptions,
202
+ paymentTypeLoading
191
203
  };
192
204
  };