@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.
- package/package.json +1 -1
- package/src/components/CrossSeller/item.js +3 -4
- package/src/components/LinkToOtherStores/index.js +4 -4
- package/src/components/ProductListTab/productListTab.js +1 -1
- package/src/components/commons/Select/index.js +8 -4
- package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/priceSummaryFragments.gql.js +3 -0
- package/src/overwrites/peregrine/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +4 -0
- package/src/overwrites/peregrine/lib/talons/CheckoutPage/checkoutPage.extended.gql.js +20 -1
- package/src/overwrites/peregrine/lib/talons/FilterSidebar/useFilterSidebar.js +3 -3
- package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +7 -8
- package/src/overwrites/peregrine/lib/talons/RootComponents/Product/productDetailFragment.gql.js +5 -0
- package/src/overwrites/venia-ui/lib/components/Breadcrumbs/breadcrumbs.js +20 -1
- package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.js +41 -1
- package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.module.css +1 -1
- package/src/overwrites/venia-ui/lib/components/CartPage/ProductListingBySeller/productListingBySeller.js +41 -8
- package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.js +43 -2
- package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/item.module.css +36 -0
- package/src/overwrites/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js +8 -2
- package/src/overwrites/venia-ui/lib/components/CheckoutPage/checkoutPage.js +7 -2
- package/src/overwrites/venia-ui/lib/components/FilterModal/CurrentFilters/currentFilters.js +1 -1
- package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +1 -1
- package/src/overwrites/venia-ui/lib/components/Gallery/item.js +2 -10
- package/src/overwrites/venia-ui/lib/components/Gallery/item.module.css +5 -4
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/CustomAttributes/customAttributes.js +10 -2
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/preOrderDetail.js +195 -37
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +194 -63
- package/src/talons/ProductContent/productContent.gql.js +11 -1
- package/src/talons/ProductContent/useProductContent.js +14 -2
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import logoImage from './logo_seller.png';
|
|
|
9
9
|
|
|
10
10
|
const Item = ({ sellerName, sales, price, condition }) => {
|
|
11
11
|
return (
|
|
12
|
-
<div className='flex flex-col items-center text-center lg_text-left md_text-left lg_flex-row md_flex-row bg-white rounded-lg border border-gray-100 p-[15px] gap-y-4'>
|
|
12
|
+
<div className='flex flex-col items-center text-center justify-around lg_text-left md_text-left lg_flex-row md_flex-row bg-white rounded-lg border border-gray-100 p-[15px] gap-y-4'>
|
|
13
13
|
<div className='seller_info-container flex flex-row gap-x-[15px] lg_w-1/3 md_w-1/3'>
|
|
14
14
|
<div className='flex flex-col gap-y-[15px]'>
|
|
15
15
|
<div className='seller_summary-wrapper flex flex-row gap-x-2.5 items-center'>
|
|
@@ -41,16 +41,15 @@ const Item = ({ sellerName, sales, price, condition }) => {
|
|
|
41
41
|
onSubmit={() => { }}
|
|
42
42
|
className="flex flex-col gap-x-7 gap-y-7 items-center lg_flex-row md_flex-row"
|
|
43
43
|
>
|
|
44
|
-
<QuantityStepper min={1} />
|
|
45
44
|
<Button
|
|
46
|
-
data-cy="
|
|
45
|
+
data-cy="viewProductButton"
|
|
47
46
|
classes={{
|
|
48
47
|
content: 'normal-case font-medium text-[16px]'
|
|
49
48
|
}}
|
|
50
49
|
priority="high"
|
|
51
50
|
type="button"
|
|
52
51
|
>
|
|
53
|
-
|
|
52
|
+
View Product
|
|
54
53
|
</Button>
|
|
55
54
|
</Form>
|
|
56
55
|
</div>
|
|
@@ -18,10 +18,10 @@ const LinkToOtherStores = (props) => {
|
|
|
18
18
|
'product_link': 'https://tokopedia.com',
|
|
19
19
|
'stores': 'Tokopedia'
|
|
20
20
|
},
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
21
|
+
// {
|
|
22
|
+
// 'product_link': 'https://lazada.sg',
|
|
23
|
+
// 'stores': 'Lazada'
|
|
24
|
+
// }
|
|
25
25
|
];
|
|
26
26
|
|
|
27
27
|
const getLogo = (stores) => {
|
|
@@ -7,7 +7,9 @@ const Select = (props) => {
|
|
|
7
7
|
className,
|
|
8
8
|
options = [],
|
|
9
9
|
value,
|
|
10
|
-
onChange
|
|
10
|
+
onChange,
|
|
11
|
+
showPlaceholder = true,
|
|
12
|
+
placeholder = 'Choose Option'
|
|
11
13
|
} = props;
|
|
12
14
|
|
|
13
15
|
return (
|
|
@@ -17,9 +19,11 @@ const Select = (props) => {
|
|
|
17
19
|
value={value}
|
|
18
20
|
onChange={onChange}
|
|
19
21
|
>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
{showPlaceholder && (
|
|
23
|
+
<option value=''>
|
|
24
|
+
{placeholder}
|
|
25
|
+
</option>
|
|
26
|
+
)}
|
|
23
27
|
{options.map((item) => (
|
|
24
28
|
<option key={item.value} value={item.value}>
|
|
25
29
|
{item.label}
|
package/src/overwrites/peregrine/lib/talons/CartPage/ProductListing/productListingFragments.gql.js
CHANGED
|
@@ -6,6 +6,9 @@ export const ProductListingFragment = gql`
|
|
|
6
6
|
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
7
7
|
items {
|
|
8
8
|
uid
|
|
9
|
+
is_preorder
|
|
10
|
+
pre_order_payment_type
|
|
11
|
+
pre_order_deposit
|
|
9
12
|
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
10
13
|
seller {
|
|
11
14
|
seller_name
|
|
@@ -17,6 +20,7 @@ export const ProductListingFragment = gql`
|
|
|
17
20
|
name
|
|
18
21
|
sku
|
|
19
22
|
url_key
|
|
23
|
+
release_date
|
|
20
24
|
thumbnail {
|
|
21
25
|
url
|
|
22
26
|
}
|
|
@@ -13,6 +13,20 @@ export const ITEM_SELLER_FRAGMENT = gql`
|
|
|
13
13
|
}
|
|
14
14
|
`;
|
|
15
15
|
|
|
16
|
+
// Extend items to include preorder fields used in ItemsReview/item.js overwrite
|
|
17
|
+
export const ITEM_PREORDER_FRAGMENT = gql`
|
|
18
|
+
fragment ItemPreorderFragment on Cart {
|
|
19
|
+
items {
|
|
20
|
+
is_preorder
|
|
21
|
+
pre_order_payment_type
|
|
22
|
+
pre_order_deposit
|
|
23
|
+
product {
|
|
24
|
+
release_date
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
16
30
|
export const CREATE_CART = gql`
|
|
17
31
|
mutation createCart {
|
|
18
32
|
cartId: createEmptyCart
|
|
@@ -64,10 +78,12 @@ export const GET_ORDER_DETAILS = gql`
|
|
|
64
78
|
}
|
|
65
79
|
...ItemsReviewFragment
|
|
66
80
|
...ItemSellerFragment
|
|
81
|
+
...ItemPreorderFragment
|
|
67
82
|
}
|
|
68
83
|
}
|
|
69
84
|
${ItemsReviewFragment}
|
|
70
85
|
${ITEM_SELLER_FRAGMENT}
|
|
86
|
+
${ITEM_PREORDER_FRAGMENT}
|
|
71
87
|
`;
|
|
72
88
|
|
|
73
89
|
export const GET_CHECKOUT_DETAILS = gql`
|
|
@@ -77,11 +93,13 @@ export const GET_CHECKOUT_DETAILS = gql`
|
|
|
77
93
|
...CheckoutPageFragment
|
|
78
94
|
...ItemsReviewFragment
|
|
79
95
|
...ItemSellerFragment
|
|
96
|
+
...ItemPreorderFragment
|
|
80
97
|
}
|
|
81
98
|
}
|
|
82
99
|
${CheckoutPageFragment}
|
|
83
100
|
${ItemsReviewFragment}
|
|
84
101
|
${ITEM_SELLER_FRAGMENT}
|
|
102
|
+
${ITEM_PREORDER_FRAGMENT}
|
|
85
103
|
`;
|
|
86
104
|
|
|
87
105
|
export const GET_CUSTOMER = gql`
|
|
@@ -100,5 +118,6 @@ export default {
|
|
|
100
118
|
getCustomerQuery: GET_CUSTOMER,
|
|
101
119
|
getOrderDetailsQuery: GET_ORDER_DETAILS,
|
|
102
120
|
placeOrderMutation: PLACE_ORDER,
|
|
103
|
-
itemSellerFragment: ITEM_SELLER_FRAGMENT
|
|
121
|
+
itemSellerFragment: ITEM_SELLER_FRAGMENT,
|
|
122
|
+
itemPreorderFragment: ITEM_PREORDER_FRAGMENT
|
|
104
123
|
};
|
|
@@ -189,11 +189,11 @@ export const useFilterSidebar = props => {
|
|
|
189
189
|
},
|
|
190
190
|
{
|
|
191
191
|
'label': 'Preorder',
|
|
192
|
-
'value': '
|
|
192
|
+
'value': 'card_pre_orders',
|
|
193
193
|
'path': '',
|
|
194
194
|
'options': [
|
|
195
|
-
{'value':'0','label':'
|
|
196
|
-
{'value':'1','label':'
|
|
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,
|
|
@@ -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(
|
|
@@ -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={{
|
|
@@ -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}>
|
|
@@ -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
|
-
<
|
|
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
|
|
|
@@ -84,7 +84,7 @@ const CheckoutPage = props => {
|
|
|
84
84
|
toggleAddressBookContent,
|
|
85
85
|
toggleSignInContent
|
|
86
86
|
} = talonProps;
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
const [, { addToast }] = useToasts();
|
|
89
89
|
|
|
90
90
|
const history = useHistory();
|
|
@@ -301,7 +301,12 @@ const CheckoutPage = props => {
|
|
|
301
301
|
// Show ItemsReview from the beginning, not only at the REVIEW step
|
|
302
302
|
const itemsReview = (
|
|
303
303
|
<div className={classes.items_review_container}>
|
|
304
|
-
<ItemsReview
|
|
304
|
+
<ItemsReview
|
|
305
|
+
isPreorder={cartItems?.[0]?.is_preorder}
|
|
306
|
+
preOrderDeposit={cartItems?.[0]?.pre_order_deposit}
|
|
307
|
+
preOrderPaymentType={cartItems?.[0]?.pre_order_payment_type}
|
|
308
|
+
releaseDate={cartItems?.[0]?.product?.release_date}
|
|
309
|
+
/>
|
|
305
310
|
</div>
|
|
306
311
|
);
|
|
307
312
|
|
|
@@ -20,7 +20,7 @@ const CurrentFilters = props => {
|
|
|
20
20
|
const { title, value } = item || {};
|
|
21
21
|
const key = `${group}::${title}_${value}`;
|
|
22
22
|
|
|
23
|
-
const customAttributeLandingPage = ['bricks_categories','sc_sports_categories','card_game', 'sc_baseball_release','auction','special_price','lof_preorder','sc_baseball_inserts','sc_baseball_parallel','sc_set_type'];
|
|
23
|
+
const customAttributeLandingPage = ['bricks_categories','sc_sports_categories','card_game', 'sc_baseball_release','auction','special_price','lof_preorder','card_pre_orders','sc_baseball_inserts','sc_baseball_parallel','sc_set_type'];
|
|
24
24
|
|
|
25
25
|
if (!customAttributeLandingPage.includes(group)) {
|
|
26
26
|
elements.push(
|
|
@@ -125,7 +125,7 @@ const FilterSidebar = props => {
|
|
|
125
125
|
const groupName = filterNames.get(group);
|
|
126
126
|
const frontendInput = filterFrontendInput.get(group);
|
|
127
127
|
|
|
128
|
-
const hideFilters = ['card_game','bricks_categories','sc_sports_categories','trains','trains_locomotives','trains_supplies_type','lof_preorder','auction','special_price','sc_baseball_inserts','sc_baseball_parallel','sale','sc_set_type','sc_brands'];
|
|
128
|
+
const hideFilters = ['card_game','bricks_categories','sc_sports_categories','trains','trains_locomotives','trains_supplies_type','lof_preorder','card_pre_orders','auction','special_price','sc_baseball_inserts','sc_baseball_parallel','sale','sc_set_type','sc_brands'];
|
|
129
129
|
if (!allowedFiltersArr?.length || filterState.size && allowedFiltersArr.length || !filterState.size && allowedFiltersArr.length && allowedFiltersArr.includes(group)) {
|
|
130
130
|
if (!hideFilters.includes(group) && groupName && !group.includes('card_release') && !group.includes('card_set') && !group.includes('sc_set_name')) {
|
|
131
131
|
|
|
@@ -140,7 +140,7 @@ const GalleryItem = props => {
|
|
|
140
140
|
data-cy="GalleryItem-name">{name}</span>
|
|
141
141
|
{/* </Link> */}
|
|
142
142
|
<div data-cy="GalleryItem-price" className={cn(classes.price, 'mb-2.5 pt-2.5')}>
|
|
143
|
-
<p className='font-medium !text-[#f76b1c]
|
|
143
|
+
<p className='font-medium !text-[#f76b1c] !mb-1'>
|
|
144
144
|
<Price
|
|
145
145
|
value={priceSource.value}
|
|
146
146
|
currencyCode={priceSource.currency}
|
|
@@ -154,16 +154,8 @@ const GalleryItem = props => {
|
|
|
154
154
|
</p> */}
|
|
155
155
|
</div>
|
|
156
156
|
|
|
157
|
-
<div data-cy="GalleryItem-Rating" className={cn('flex gap-[5px] items-center mb-2')}>
|
|
158
|
-
<Star />
|
|
159
|
-
<span className='text-[12px] leading-normal'>
|
|
160
|
-
{rating_summary}
|
|
161
|
-
</span>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
157
|
<div data-cy="GalleryItem-Seller" className={cn('flex gap-[5px] items-center')}>
|
|
165
|
-
<
|
|
166
|
-
<span className='text-[12px] text-gray-300 leading-normal'>
|
|
158
|
+
<span className='text-[12px] text-gray-400 leading-normal'>
|
|
167
159
|
{seller}
|
|
168
160
|
</span>
|
|
169
161
|
</div>
|
|
@@ -74,11 +74,11 @@
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
.name {
|
|
77
|
-
composes: font-medium from global;
|
|
77
|
+
/* composes: font-medium from global; */
|
|
78
78
|
composes: text-base from global;
|
|
79
79
|
composes: mb-1 from global;
|
|
80
80
|
display: -webkit-box;
|
|
81
|
-
-webkit-line-clamp:
|
|
81
|
+
-webkit-line-clamp: 3;
|
|
82
82
|
-webkit-box-orient: vertical;
|
|
83
83
|
overflow: hidden;
|
|
84
84
|
line-height: normal;
|
|
@@ -87,13 +87,14 @@
|
|
|
87
87
|
.name,
|
|
88
88
|
.price {
|
|
89
89
|
composes: text-colorDefault from global;
|
|
90
|
-
composes: text-[14px] from global;
|
|
91
|
-
composes: font-medium from global;
|
|
90
|
+
/* composes: text-[14px] from global; */
|
|
91
|
+
/* composes: font-medium from global; */
|
|
92
92
|
min-height: 1rem;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
.price {
|
|
96
96
|
padding-top: 2.5;
|
|
97
|
+
composes: font-medium from global;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
.unavailableContainer {
|