@riosst100/pwa-marketplace 2.7.8 → 2.8.0
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/i18n/en_US.json +4 -2
- package/i18n/id_ID.json +2 -0
- package/package.json +1 -1
- package/src/components/FavoriteSeller/AddToListButton/addToListButton.js +4 -2
- package/src/components/Seller/StoreLocationCard.js +29 -0
- package/src/components/SellerAccountPage/sellerAccountPage.js +15 -29
- package/src/components/SellerAccountPage/sellerAccountPage.module.css +62 -2
- package/src/components/SellerDetail/sellerDetail.js +53 -68
- package/src/components/SellerInformation/sellerInformation.js +28 -22
- package/src/components/SellerMegaMenu/sellerMegaMenu.js +27 -22
- package/src/components/SellerProducts/productContent.js +6 -5
- package/src/components/SellerReview/sellerReview.js +161 -123
- package/src/components/commons/Rating/index.js +34 -0
- package/src/overwrites/peregrine/lib/talons/AccountMenu/useAccountMenuItems.js +10 -10
- package/src/overwrites/venia-ui/lib/components/CartPage/PriceSummary/priceSummary.module.css +6 -0
- package/src/overwrites/venia-ui/lib/components/CartPage/ProductListing/product.js +1 -1
- package/src/overwrites/venia-ui/lib/components/CartPage/ProductListingBySeller/productListingBySeller.js +12 -4
- package/src/overwrites/venia-ui/lib/components/CartPage/ProductListingBySeller/productListingBySeller.module.css +18 -0
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +38 -2
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.module.css +19 -0
- package/src/talons/BecomeSeller/useBecomeSeller.js +1 -1
- package/src/talons/FavoriteSeller/AddToListButton/useAddToFavoriteListButton.js +4 -1
package/i18n/en_US.json
CHANGED
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
"global.name": "Name",
|
|
251
251
|
"global.newPassword": "New Password",
|
|
252
252
|
"global.password": "Password",
|
|
253
|
-
"global.phoneNumber": "
|
|
253
|
+
"global.phoneNumber": "Phone Number",
|
|
254
254
|
"global.private": "Private",
|
|
255
255
|
"global.public": "Public",
|
|
256
256
|
"global.quantity": "Quantity",
|
|
@@ -330,7 +330,7 @@
|
|
|
330
330
|
"pagination.lastPage": "move to the last page",
|
|
331
331
|
"pagination.nextPage": "move to the next page",
|
|
332
332
|
"pagination.prevPage": "move to the previous page",
|
|
333
|
-
"postcode.label": "Postal Code",
|
|
333
|
+
"postcode.label": "ZIP/Postal Code",
|
|
334
334
|
"priceAdjustments.couponCode": "Enter Coupon Code",
|
|
335
335
|
"priceAdjustments.giftOptions": "See Gift Options",
|
|
336
336
|
"priceAdjustments.shippingMethod": "Estimate your Shipping",
|
|
@@ -366,6 +366,8 @@
|
|
|
366
366
|
"productFullDetail.details": "Details",
|
|
367
367
|
"productFullDetail.unavailableProduct": "This product is currently unavailable for purchase.",
|
|
368
368
|
"productFullDetail.outOfStockProduct": "This item is currently out of stock",
|
|
369
|
+
"productFullDetail.addToCartSuccess": "Product successfully added to cart!",
|
|
370
|
+
"productFullDetail.addToCartError": "Failed to add product to cart.",
|
|
369
371
|
"productImageCarousel.previousButtonAriaLabel": "Previous Image",
|
|
370
372
|
"productImageCarousel.nextButtonAriaLabel": "Next Image",
|
|
371
373
|
"productList.each": " ea.",
|
package/i18n/id_ID.json
CHANGED
|
@@ -367,6 +367,8 @@
|
|
|
367
367
|
"productFullDetail.details": "Details",
|
|
368
368
|
"productFullDetail.unavailableProduct": "This product is currently unavailable for purchase.",
|
|
369
369
|
"productFullDetail.outOfStockProduct": "This item is currently out of stock",
|
|
370
|
+
"productFullDetail.addToCartSuccess": "Produk berhasil ditambahkan ke keranjang!",
|
|
371
|
+
"productFullDetail.addToCartError": "Gagal menambahkan produk ke keranjang.",
|
|
370
372
|
"productImageCarousel.previousButtonAriaLabel": "Previous Image",
|
|
371
373
|
"productImageCarousel.nextButtonAriaLabel": "Next Image",
|
|
372
374
|
"productList.each": " ea.",
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useRef } from 'react';
|
|
2
|
-
import { element, func, shape, string } from 'prop-types';
|
|
2
|
+
import { element, func, shape, string, bool } from 'prop-types';
|
|
3
3
|
import { Heart } from 'react-feather';
|
|
4
4
|
import { useAddToFavoriteListButton } from '@riosst100/pwa-marketplace/src/talons/FavoriteSeller/AddToListButton/useAddToFavoriteListButton';
|
|
5
5
|
import { useButton } from 'react-aria';
|
|
@@ -33,6 +33,7 @@ const AddToFavoriteListButton = props => {
|
|
|
33
33
|
return (
|
|
34
34
|
<button ref={buttonRef} className={buttonClass} {...ariaButtonProps}>
|
|
35
35
|
{props.icon}
|
|
36
|
+
{buttonText && <span className={`text-[#f76b1c] text-[14px] font-medium whitespace-nowrap ${props.hideTextOnMobile ? 'md_block xs_hidden' : ''}`}>{buttonText}</span>}
|
|
36
37
|
</button>
|
|
37
38
|
);
|
|
38
39
|
};
|
|
@@ -50,5 +51,6 @@ AddToFavoriteListButton.propTypes = {
|
|
|
50
51
|
root: string,
|
|
51
52
|
root_selected: string
|
|
52
53
|
}),
|
|
53
|
-
icon: element
|
|
54
|
+
icon: element,
|
|
55
|
+
hideTextOnMobile: bool
|
|
54
56
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Location, Clock } from 'iconsax-react';
|
|
3
|
+
import OperatingHours from '@riosst100/pwa-marketplace/src/components/OperatingHours';
|
|
4
|
+
|
|
5
|
+
const StoreLocationCard = ({ store }) => {
|
|
6
|
+
if (!store) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { name, address_line_1, region, country, operating_hours } = store;
|
|
11
|
+
|
|
12
|
+
const address = [address_line_1, region, country].filter(Boolean).join(', ');
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="border border-[#E6E9EA] rounded-lg p-4 flex flex-col gap-2">
|
|
16
|
+
<h3 className="font-bold text-base">{name}</h3>
|
|
17
|
+
<div className="flex items-start gap-2">
|
|
18
|
+
<Location size="18" color="#666" />
|
|
19
|
+
<span className="text-sm text-gray-600">{address}</span>
|
|
20
|
+
</div>
|
|
21
|
+
<div className="flex flex-row gap-1">
|
|
22
|
+
<Clock size="18" color="#666" />
|
|
23
|
+
<OperatingHours values={operating_hours} simple={true} />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default StoreLocationCard;
|
|
@@ -43,39 +43,25 @@ const SellerAccountPage = props => {
|
|
|
43
43
|
sellerLoginAccount = (
|
|
44
44
|
<Fragment>
|
|
45
45
|
<div className={classes.accountDetails}>
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<span className={classes.emailLabel}>
|
|
54
|
-
<FormattedMessage
|
|
55
|
-
id={'global.email'}
|
|
56
|
-
defaultMessage={'Email'}
|
|
57
|
-
/>
|
|
58
|
-
</span>
|
|
59
|
-
<span className={classes.emailValue}>
|
|
60
|
-
{customer.email}
|
|
61
|
-
</span>
|
|
62
|
-
<span className={classes.passwordLabel}>
|
|
63
|
-
<FormattedMessage
|
|
64
|
-
id={'global.password'}
|
|
65
|
-
defaultMessage={'Password'}
|
|
66
|
-
/>
|
|
67
|
-
</span>
|
|
68
|
-
<span className={classes.passwordValue}>
|
|
69
|
-
{passwordValue}
|
|
70
|
-
</span>
|
|
46
|
+
<div className={classes.container}>
|
|
47
|
+
<div className={classes.success}>
|
|
48
|
+
{/* <h2 className={classes.title}>Seller Registration Successful!</h2> */}
|
|
49
|
+
<p className={classes.message}>
|
|
50
|
+
Congratulations! Your registration as a seller was successful.
|
|
51
|
+
Please log in to the <strong>Seller Dashboard</strong> with your account to complete the verification process and start managing your listings.
|
|
52
|
+
</p>
|
|
71
53
|
</div>
|
|
72
|
-
|
|
73
|
-
|
|
54
|
+
|
|
55
|
+
{/* <div className={classes.card}> */}
|
|
56
|
+
<div className={classes.actions}>
|
|
57
|
+
<a href={process.env.MAGENTO_BACKEND_URL + "/lofmarketplace/seller/login"} className={classes.btn} role="button">
|
|
74
58
|
<FormattedMessage
|
|
75
59
|
id={'global.sellerDashboardText'}
|
|
76
|
-
defaultMessage={'Seller Dashboard'}
|
|
77
|
-
/>
|
|
60
|
+
defaultMessage={'Go to Seller Dashboard'}
|
|
61
|
+
/> →
|
|
78
62
|
</a>
|
|
63
|
+
</div>
|
|
64
|
+
{/* </div> */}
|
|
79
65
|
</div>
|
|
80
66
|
</div>
|
|
81
67
|
</Fragment>
|
|
@@ -5,9 +5,69 @@
|
|
|
5
5
|
composes: py-md from global;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
.container {
|
|
9
|
+
max-width: 600px;
|
|
10
|
+
margin: 0px auto;
|
|
11
|
+
padding: 20px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.success {
|
|
15
|
+
background: #ecfdf5;
|
|
16
|
+
border: 1px solid #a7f3d0;
|
|
17
|
+
border-radius: 10px;
|
|
18
|
+
padding: 16px 20px;
|
|
19
|
+
margin-bottom: 20px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.title {
|
|
23
|
+
color: #065f46;
|
|
24
|
+
font-size: 18px;
|
|
25
|
+
font-weight: 700;
|
|
26
|
+
margin-bottom: 8px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.message {
|
|
30
|
+
color: #065f46;
|
|
31
|
+
font-size: 14px;
|
|
32
|
+
line-height: 1.5;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.card {
|
|
36
|
+
background: #ffffff;
|
|
37
|
+
border: 1px solid #e5e7eb;
|
|
38
|
+
border-radius: 10px;
|
|
39
|
+
padding: 18px 20px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.actions {
|
|
43
|
+
/* margin-top: 16px; */
|
|
44
|
+
text-align: center;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.btn {
|
|
48
|
+
display: inline-block;
|
|
49
|
+
background: #f76b1c;
|
|
50
|
+
color: #fff;
|
|
51
|
+
text-decoration: none;
|
|
52
|
+
padding: 10px 16px;
|
|
53
|
+
border-radius: 8px;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
transition: background 0.15s ease, transform 0.15s ease;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.btn:hover {
|
|
59
|
+
background: #f76b1c;
|
|
60
|
+
transform: translateY(-1px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.nameLabel {
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
8
68
|
.title {
|
|
9
69
|
composes: font-bold from global;
|
|
10
|
-
composes: font-serif from global;
|
|
70
|
+
/* composes: font-serif from global; */
|
|
11
71
|
composes: justify-self-center from global;
|
|
12
72
|
}
|
|
13
73
|
|
|
@@ -16,7 +76,7 @@
|
|
|
16
76
|
composes: grid from global;
|
|
17
77
|
composes: grid-cols-1 from global;
|
|
18
78
|
|
|
19
|
-
composes: lg_grid-cols-
|
|
79
|
+
composes: lg_grid-cols-1 from global;
|
|
20
80
|
}
|
|
21
81
|
|
|
22
82
|
.lineItemsContainer {
|
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
Shop,
|
|
20
20
|
} from 'iconsax-react';
|
|
21
21
|
import Image from '@magento/venia-ui/lib/components/Image';
|
|
22
|
-
import LiveChat from '@riosst100/pwa-marketplace/src/components/LiveChat';
|
|
23
22
|
import Button from '@magento/venia-ui/lib/components/Button';
|
|
24
23
|
import cn from 'classnames';
|
|
24
|
+
import Rating from '@riosst100/pwa-marketplace/src/components/commons/Rating';
|
|
25
25
|
const FavoriteSellerButton = React.lazy(() => import('@riosst100/pwa-marketplace/src/components/FavoriteSeller/AddToListButton'));
|
|
26
26
|
|
|
27
27
|
const SellerDetail = props => {
|
|
@@ -30,7 +30,6 @@ const SellerDetail = props => {
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
const { error, loading, seller, favoriteSellerButtonProps } = talonProps;
|
|
33
|
-
|
|
34
33
|
if (loading && !seller)
|
|
35
34
|
return '';
|
|
36
35
|
// return <SellerShimmer />;
|
|
@@ -48,6 +47,22 @@ const SellerDetail = props => {
|
|
|
48
47
|
);
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
const dummyRating = {
|
|
51
|
+
rating_summary: {
|
|
52
|
+
average_rating_percent: 70,
|
|
53
|
+
positive_percentage: 80,
|
|
54
|
+
rating_count: 2
|
|
55
|
+
},
|
|
56
|
+
followers_count: 12
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Use the real data if available, otherwise fallback to dummy data
|
|
60
|
+
const sellerData = {
|
|
61
|
+
...seller,
|
|
62
|
+
rating_summary: seller.rating_summary || dummyRating.rating_summary,
|
|
63
|
+
followers_count: seller.followers_count || dummyRating.followers_count
|
|
64
|
+
};
|
|
65
|
+
|
|
51
66
|
const dataTabs =
|
|
52
67
|
[
|
|
53
68
|
{
|
|
@@ -96,7 +111,8 @@ const SellerDetail = props => {
|
|
|
96
111
|
return (
|
|
97
112
|
<div className=' py-8'>
|
|
98
113
|
<Slider seller={seller} rootClassname='mb-[30px]' />
|
|
99
|
-
<div className='flex xs_flex-col
|
|
114
|
+
<div className='flex xs_flex-col lg_flex-row justify-between mb-[30px] p-[20px] rounded-[6px] border border-solid border-gray-100 shadow-[0px_0px_5px_3px_#d9d9d933]'>
|
|
115
|
+
{/* Left: logo + info */}
|
|
100
116
|
<div className='flex xs_flex-col md_flex-row xs_items-center md_items-start items-start gap-[15px] relative'>
|
|
101
117
|
{seller?.thumbnail ? (
|
|
102
118
|
<Image
|
|
@@ -110,87 +126,56 @@ const SellerDetail = props => {
|
|
|
110
126
|
</div>
|
|
111
127
|
)}
|
|
112
128
|
|
|
113
|
-
<div className='flex flex-col xs_items-center md_items-start justify-between relative gap-y-[
|
|
129
|
+
<div className='flex flex-col xs_items-center md_items-start justify-between relative gap-y-[10px]'>
|
|
114
130
|
<div className='flex flex-col xs_items-center md_items-start gap-[6px] relative'>
|
|
115
131
|
<div className="gap-x-[10px] gap-y-1 flex xs_flex-col md_flex-row xs_items-center md_items-start relative">
|
|
116
|
-
<div className="relative w-fit mt-[-1.00px] font-medium text-[20px] tracking-[0] leading-[24px] whitespace-nowrap">
|
|
132
|
+
<div className="relative w-fit mt-[-1.00px] font-medium text-[20px] tracking-[0] leading-[24px] whitespace-nowrap text-center md_text-left">
|
|
117
133
|
{seller ? seller.name : ''}
|
|
118
134
|
</div>
|
|
119
|
-
<div className="flex items-center gap-[5px] relative">
|
|
120
|
-
<Verify variant='Bold' color='#f76b1c' size={20} />
|
|
121
|
-
<div className="relative w-fit font-medium text-[#192221b3] text-[12px] tracking-[0] leading-[normal] whitespace-nowrap">
|
|
122
|
-
Verified
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
135
|
</div>
|
|
126
|
-
<div class="relative w-fit font-normal text-[#999999] text-[12px] tracking-[0] leading-[14px] whitespace-nowrap">
|
|
127
|
-
{seller ? getSellerAddressDisplay(seller) : ''}
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
<div className='flex flex-wrap items-start gap-4 relative'>
|
|
131
|
-
<button class="flex items-center justify-center gap-[5px] xs_p-[11px] lg_px-[20px] lg_py-[8px] relative bg-white rounded-[30px] border border-solid border-[#f76b1c]">
|
|
132
|
-
<div class="flex items-center justify-center gap-[10px] relative">
|
|
133
|
-
<Sms color="#f76b1c" size={14} variant="Outline" className='stroke-[#f76b1c]' />
|
|
134
|
-
<div class="relative xs_hidden lg_flex w-fit font-medium text-[#f76b1c] text-base tracking-[0] leading-[20px] whitespace-nowrap">
|
|
135
|
-
Message
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
</button>
|
|
139
|
-
<Button
|
|
140
|
-
priority='high'
|
|
141
|
-
classes={{
|
|
142
|
-
content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
|
|
143
|
-
}}
|
|
144
|
-
className='flex items-center justify-center gap-[5px] xs_p-[11px] lg_px-[20px] lg_py-[8px] relative bg-[#280135] rounded-[30px] border border-solid border-[#280135]'
|
|
145
|
-
onClick={toggleChat}
|
|
146
|
-
>
|
|
147
|
-
<Message color='#FFFFFF' size={14} variant="Outline" className='stroke-[#FFFFFF]' />
|
|
148
|
-
<div class="relative xs_hidden lg_flex w-fit font-medium text-[#fff] text-base tracking-[0] leading-[20px] whitespace-nowrap">
|
|
149
|
-
<FormattedMessage
|
|
150
|
-
id={'seller.chatWithSeller'}
|
|
151
|
-
defaultMessage={'Chat With Seller'}
|
|
152
|
-
/>
|
|
153
|
-
</div>
|
|
154
|
-
</Button>
|
|
155
|
-
<Suspense fallback={null}>
|
|
156
|
-
<FavoriteSellerButton
|
|
157
|
-
classes={{
|
|
158
|
-
root: 'flex items-center justify-center gap-[5px] p-[11px] relative bg-white rounded-[30px] overflow-hidden border border-solid border-[#f76b1c]'
|
|
159
|
-
}}
|
|
160
|
-
{...favoriteSellerButtonProps}
|
|
161
|
-
buttonText={''}
|
|
162
|
-
/>
|
|
163
|
-
</Suspense>
|
|
164
|
-
<button class="flex items-center justify-center gap-[5px] p-[11px] relative bg-white rounded-[30px] overflow-hidden border border-solid border-[#f76b1c]">
|
|
165
|
-
<Share color='#f76b1c' size={14} variant="Outline" className='stroke-[#f76b1c]' />
|
|
166
|
-
</button>
|
|
167
136
|
</div>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
0.0
|
|
137
|
+
|
|
138
|
+
{/* Rating summary and followers */}
|
|
139
|
+
<div className='flex flex-col gap-[4px]'>
|
|
140
|
+
<div className='flex items-center gap-[6px] flex-wrap justify-center md_justify-start'>
|
|
141
|
+
<Rating percentage={sellerData.rating_summary.average_rating_percent} />
|
|
142
|
+
<span className='text-[12px] text-[#1a1a1a] text-center md_text-left'>
|
|
143
|
+
<b>{sellerData.rating_summary.positive_percentage}% positive</b> in last 12 month ({sellerData.rating_summary.rating_count} Ratings)
|
|
144
|
+
</span>
|
|
177
145
|
</div>
|
|
178
|
-
|
|
179
|
-
<div class="relative w-fit [font-family:'Frederik-Regular',Helvetica] font-normal text-[#009a7b] text-[10px] tracking-[0] leading-[normal] whitespace-nowrap">
|
|
180
|
-
Rating & Reviews
|
|
146
|
+
<div className='text-[12px] text-[#666] text-center md_text-left'>{sellerData.followers_count} Followers</div>
|
|
181
147
|
</div>
|
|
182
148
|
</div>
|
|
183
149
|
</div>
|
|
150
|
+
|
|
151
|
+
{/* Right: action buttons */}
|
|
152
|
+
<div className='flex xs_flex-wrap items-center xs_justify-center lg_justify-end gap-[10px] xs_mt-4 lg_mt-0 xs_pt-2 lg_pt-0 relative'>
|
|
153
|
+
<button className='flex items-center justify-center gap-[8px] px-[14px] py-[8px] bg-white rounded-[30px] border border-solid border-[#f76b1c] min-w-[44px]'>
|
|
154
|
+
<Sms color="#f76b1c" size={16} variant='Outline' className='stroke-[#f76b1c]' />
|
|
155
|
+
<span className='text-[#f76b1c] text-[14px] font-medium whitespace-nowrap md_block xs_hidden'>Send Message</span>
|
|
156
|
+
</button>
|
|
157
|
+
<Suspense fallback={null}>
|
|
158
|
+
<FavoriteSellerButton
|
|
159
|
+
classes={{
|
|
160
|
+
root: 'flex items-center justify-center gap-[8px] px-[14px] py-[8px] bg-white rounded-[30px] border border-solid border-[#f76b1c] min-w-[44px]'
|
|
161
|
+
}}
|
|
162
|
+
{...favoriteSellerButtonProps}
|
|
163
|
+
buttonText={'Follow Seller'}
|
|
164
|
+
hideTextOnMobile={true}
|
|
165
|
+
/>
|
|
166
|
+
</Suspense>
|
|
167
|
+
<button className='flex items-center justify-center gap-[8px] px-[14px] py-[8px] bg-white rounded-[30px] border border-solid border-[#f76b1c] min-w-[44px]'>
|
|
168
|
+
<Share color='#f76b1c' size={16} variant='Outline' className='stroke-[#f76b1c]' />
|
|
169
|
+
<span className='text-[#f76b1c] text-[14px] font-medium whitespace-nowrap md_block xs_hidden'>Share</span>
|
|
170
|
+
</button>
|
|
171
|
+
</div>
|
|
184
172
|
</div>
|
|
185
173
|
<Tabs
|
|
186
174
|
data={dataTabs}
|
|
187
175
|
tabContentWrapperClassName='!p-0'
|
|
188
176
|
hasContent
|
|
189
177
|
tabWrapperClassName='xl_gap-x-[60px]'
|
|
190
|
-
|
|
191
|
-
<LiveChat
|
|
192
|
-
open={openChat}
|
|
193
|
-
setOpen={setOpenChat}
|
|
178
|
+
tabActiveClassName='!border-[#FF6E26] !border-b-[3px]'
|
|
194
179
|
/>
|
|
195
180
|
</div>
|
|
196
181
|
)
|
|
@@ -4,30 +4,28 @@ import { Location, ShopAdd } from 'iconsax-react';
|
|
|
4
4
|
import OperatingHours from '@riosst100/pwa-marketplace/src/components/OperatingHours';
|
|
5
5
|
import SellerAddressCard from '@riosst100/pwa-marketplace/src/components/Seller/sellerAddressCard';
|
|
6
6
|
import SellerSocialMedia from '@riosst100/pwa-marketplace/src/components/SellerSocialMedia';
|
|
7
|
+
import StoreLocationCard from '@riosst100/pwa-marketplace/src/components/Seller/StoreLocationCard';
|
|
7
8
|
|
|
8
9
|
const SellerInformation = ({ seller }) => {
|
|
9
10
|
return (
|
|
10
11
|
<>
|
|
11
12
|
<div class="flex flex-col items-start gap-[30px] px-[10px]">
|
|
12
|
-
<div class="grid xs_grid-cols-1 md_grid-cols-2 xl_grid-cols-
|
|
13
|
-
<div class="flex flex-col items-start gap-[30px] relative self-stretch">
|
|
13
|
+
<div class="grid xs_grid-cols-1 md_grid-cols-2 xl_grid-cols-2 relative w-full grow xs_gap-y-6 md_gap-x-14 xl_gap-x-14">
|
|
14
|
+
<div class="flex flex-col items-start gap-[30px] relative self-stretch xs_border-r-0 md_border-r-solid md_border-r xl_border-r-solid xl_border-r border-[#E6E9EA] xs_pr-0 md_pr-7 xl_pr-7 xs_pb-6 md_pb-0">
|
|
14
15
|
<div class="flex flex-col items-start gap-[15px] relative self-stretch w-full flex-[0_0_auto]">
|
|
15
16
|
<div class="relative w-fit mt-[-1.00px] [font-family:'Frederik-DemiBold',Helvetica] font-bold text-[14px] tracking-[0] leading-[normal] whitespace-nowrap">Description</div>
|
|
16
17
|
<div class="inline-flex items-center justify-center gap-[10px] relative flex-[0_0_auto]">
|
|
17
18
|
<p class="relative mt-[-1.00px] font-normal text-base tracking-[0] leading-[16px]">
|
|
18
|
-
{seller ? seller.description : ''}
|
|
19
|
-
<br />
|
|
20
|
-
<br />
|
|
21
|
-
{seller ? seller.contact_number : ''}
|
|
19
|
+
{seller ? seller.description : ''}
|
|
22
20
|
</p>
|
|
23
21
|
</div>
|
|
24
22
|
<div class="inline-flex items-center gap-[10px] relative flex-[0_0_auto]">
|
|
25
|
-
<Location color="#
|
|
26
|
-
<p class="relative w-fit font-normal text-[#
|
|
23
|
+
<Location color="#f76b1c" size={18} variant="Outline" className='stroke-[#f76b1c] stroke-[0.5px]' />
|
|
24
|
+
<p class="relative w-fit font-normal text-[#f76b1c] text-base tracking-[0] leading-[normal] whitespace-nowrap"><SellerAddressCard address={seller} /></p>
|
|
27
25
|
</div>
|
|
28
26
|
<div class="inline-flex items-center gap-[10px] relative flex-[0_0_auto]">
|
|
29
|
-
<ShopAdd color="#
|
|
30
|
-
<div class="relative self-stretch mt-[-1.00px] font-normal text-[#
|
|
27
|
+
<ShopAdd color="#f76b1c" size={18} variant="Outline" className='stroke-[#f76b1c] stroke-[0.5px]' />
|
|
28
|
+
<div class="relative self-stretch mt-[-1.00px] font-normal text-[#f76b1c] text-base tracking-[0] leading-[normal]">Joined: {seller ? seller.creation_time : ''}</div>
|
|
31
29
|
</div>
|
|
32
30
|
</div>
|
|
33
31
|
</div>
|
|
@@ -43,27 +41,35 @@ const SellerInformation = ({ seller }) => {
|
|
|
43
41
|
</div>
|
|
44
42
|
</div>
|
|
45
43
|
</div>
|
|
46
|
-
<div class="flex flex-col items-start gap-[15px] relative">
|
|
47
|
-
<div class="inline-flex items-start gap-[10px] relative flex-[0_0_auto]">
|
|
48
|
-
<div class="relative w-fit mt-[-1.00px] [font-family:'Frederik-DemiBold',Helvetica] font-bold text-[14px] tracking-[0] leading-[normal] whitespace-nowrap">Ship To</div>
|
|
49
|
-
</div>
|
|
50
|
-
<div class="flex flex-wrap items-start gap-[10px_10px] relative flex-[0_0_auto]">
|
|
51
|
-
{seller ? <SellerShipTo seller={seller} /> : '' }
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
44
|
</div>
|
|
55
45
|
<div class="flex items-start relative self-stretch w-full flex-[0_0_auto]">
|
|
56
46
|
<div class="flex flex-col items-start gap-[15px] relative flex-1 grow">
|
|
57
47
|
<div class="relative w-fit mt-[-1.00px] [font-family:'Frederik-DemiBold',Helvetica] font-bold text-[14px] tracking-[0] leading-[normal] whitespace-nowrap">Terms & Condition</div>
|
|
58
48
|
<div class="inline-flex items-center justify-center gap-[10px] relative flex-[0_0_auto]">
|
|
59
|
-
<div class="flex flex-col items-start gap-[
|
|
60
|
-
{seller
|
|
49
|
+
<div class="flex flex-col items-start gap-[10px]">
|
|
50
|
+
{seller && seller.term_and_conditions
|
|
51
|
+
? seller.term_and_conditions.split('\n').map((item, index) => (
|
|
52
|
+
<p key={index} className="relative font-normal text-base tracking-[0] leading-normal">
|
|
53
|
+
- {item}
|
|
54
|
+
</p>
|
|
55
|
+
))
|
|
56
|
+
: ''}
|
|
61
57
|
</div>
|
|
62
58
|
</div>
|
|
63
59
|
</div>
|
|
64
60
|
</div>
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
{seller && seller.store_locators && seller.store_locators.length > 0 && (
|
|
62
|
+
<div className="flex flex-col items-start gap-[15px] self-stretch w-full">
|
|
63
|
+
<h2 className="relative w-fit mt-[-1.00px] [font-family:'Frederik-DemiBold',Helvetica] font-bold text-[14px] tracking-[0] leading-[normal] whitespace-nowrap">
|
|
64
|
+
Our Store
|
|
65
|
+
</h2>
|
|
66
|
+
<div className="grid xs_grid-cols-1 md_grid-cols-2 lg_grid-cols-3 gap-4 self-stretch w-full">
|
|
67
|
+
{seller.store_locators.map((store, index) => (
|
|
68
|
+
<StoreLocationCard key={index} store={store} />
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
67
73
|
</div>
|
|
68
74
|
</>
|
|
69
75
|
)
|
|
@@ -30,6 +30,12 @@ const SellerMegaMenu = (props) => {
|
|
|
30
30
|
handleNavigate,
|
|
31
31
|
handleClickOutside
|
|
32
32
|
} = useSellerMegaMenu({ mainNavRef });
|
|
33
|
+
|
|
34
|
+
const allowedCategoryUids = props.allowedCategoryUids || ['NTI=', 'NTA=', 'NTM=', 'MjY='];
|
|
35
|
+
|
|
36
|
+
const filteredChildren = Array.isArray(megaMenuData?.children)
|
|
37
|
+
? megaMenuData.children.filter(c => allowedCategoryUids.includes(c.uid))
|
|
38
|
+
: [];
|
|
33
39
|
|
|
34
40
|
const [mainNavWidth, setMainNavWidth] = useState(0);
|
|
35
41
|
const shouldRenderItems = useIsInViewport({
|
|
@@ -54,28 +60,27 @@ const SellerMegaMenu = (props) => {
|
|
|
54
60
|
};
|
|
55
61
|
}, [setMainNavWidth]);
|
|
56
62
|
|
|
57
|
-
const items =
|
|
58
|
-
?
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
sellerSubMenuState={sellerSubMenuState}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
const items = filteredChildren.length
|
|
64
|
+
? filteredChildren.map(category => {
|
|
65
|
+
return (
|
|
66
|
+
<SellerMegaMenuItem
|
|
67
|
+
category={category}
|
|
68
|
+
activeCategoryId={activeCategoryId}
|
|
69
|
+
categoryUrlSuffix={categoryUrlSuffix}
|
|
70
|
+
mainNavWidth={mainNavWidth}
|
|
71
|
+
onNavigate={handleNavigate}
|
|
72
|
+
key={category.uid}
|
|
73
|
+
seller={seller}
|
|
74
|
+
// sellerSubMenuState={sellerSubMenuState}
|
|
75
|
+
disableFocus={disableFocus}
|
|
76
|
+
handleSellerSubMenuFocus={handleSellerSubMenuFocus}
|
|
77
|
+
handleClickOutside={handleClickOutside}
|
|
78
|
+
sellerMegaMenuItemClassname={sellerMegaMenuItemClassname}
|
|
79
|
+
titleClassName={titleClassName}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
})
|
|
83
|
+
: null;
|
|
79
84
|
return (
|
|
80
85
|
<nav
|
|
81
86
|
ref={mainNavRef}
|
|
@@ -4,7 +4,7 @@ import Filter from '@riosst100/pwa-marketplace/src/components/Filter';
|
|
|
4
4
|
import Search from '@riosst100/pwa-marketplace/src/components/Search';
|
|
5
5
|
import SortBy from '@riosst100/pwa-marketplace/src/components/SortBy';
|
|
6
6
|
import { useStyle } from '@magento/venia-ui/lib/classify';
|
|
7
|
-
import { Link } from "react-router-dom";
|
|
7
|
+
import { Link, Route } from "react-router-dom";
|
|
8
8
|
import { FilterSidebarShimmer } from '@magento/venia-ui/lib/components/FilterSidebar';
|
|
9
9
|
import { useIsInViewport } from '@magento/peregrine/lib/hooks/useIsInViewport';
|
|
10
10
|
import defaultClasses from '@riosst100/pwa-marketplace/src/overwrites/venia-ui/lib/RootComponents/Category/category.module.css';
|
|
@@ -40,6 +40,7 @@ const FilterTop = React.lazy(() =>
|
|
|
40
40
|
import('@riosst100/pwa-marketplace/src/components/FilterTop')
|
|
41
41
|
);
|
|
42
42
|
|
|
43
|
+
|
|
43
44
|
const ProductContent = props => {
|
|
44
45
|
const {
|
|
45
46
|
categoryId,
|
|
@@ -49,9 +50,8 @@ const ProductContent = props => {
|
|
|
49
50
|
sortProps,
|
|
50
51
|
seller,
|
|
51
52
|
isLoading,
|
|
52
|
-
pageSize
|
|
53
|
+
pageSize,
|
|
53
54
|
} = props;
|
|
54
|
-
|
|
55
55
|
const [currentSort] = sortProps;
|
|
56
56
|
|
|
57
57
|
const [activeTab, setActiveTab] = useState('all');
|
|
@@ -60,6 +60,7 @@ const ProductContent = props => {
|
|
|
60
60
|
const classes = useStyle(defaultClasses, props.classes);
|
|
61
61
|
|
|
62
62
|
const sidebarRef = useRef(null);
|
|
63
|
+
const searchRef = useRef(null);
|
|
63
64
|
|
|
64
65
|
const shouldRenderSidebarContent = useIsInViewport({
|
|
65
66
|
elementRef: sidebarRef
|
|
@@ -80,7 +81,7 @@ const ProductContent = props => {
|
|
|
80
81
|
categoryName,
|
|
81
82
|
totalPagesFromData
|
|
82
83
|
} = talonProps;
|
|
83
|
-
|
|
84
|
+
|
|
84
85
|
const shouldShowFilterButtons = filters && filters.length;
|
|
85
86
|
const shouldShowFilterShimmer = filters === null;
|
|
86
87
|
|
|
@@ -208,7 +209,7 @@ const ProductContent = props => {
|
|
|
208
209
|
totalPagesFromData,
|
|
209
210
|
activeLetter
|
|
210
211
|
]);
|
|
211
|
-
|
|
212
|
+
|
|
212
213
|
const { search } = useLocation();
|
|
213
214
|
const allActiveFilters = getFiltersFromSearch(search);
|
|
214
215
|
|
|
@@ -4,149 +4,187 @@ import Pagination from '../Pagination';
|
|
|
4
4
|
import { Star1 } from 'iconsax-react';
|
|
5
5
|
import { useSellerReview } from '@riosst100/pwa-marketplace/src/talons/SellerReview/useSellerReview';
|
|
6
6
|
|
|
7
|
+
// Dummy reviews data
|
|
8
|
+
const dummyReviews = {
|
|
9
|
+
__typename: 'SellerRates',
|
|
10
|
+
total_count: 2,
|
|
11
|
+
items: [
|
|
12
|
+
{
|
|
13
|
+
__typename: 'SellerRate',
|
|
14
|
+
id: 1,
|
|
15
|
+
name: 'John Doe',
|
|
16
|
+
date: '18 January 2024',
|
|
17
|
+
rating: 5,
|
|
18
|
+
comment: 'Got item at a great price. Arrived way quicker than expected, extremely well packaged and exactly as described. Highly recommend the seller.'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
__typename: 'SellerRate',
|
|
22
|
+
id: 2,
|
|
23
|
+
name: 'Roger Taylor',
|
|
24
|
+
date: '25 January 2024',
|
|
25
|
+
rating: 2,
|
|
26
|
+
comment: 'Got item at a great price. Arrived way quicker than expected, extremely well packaged and exactly as described. Highly recommend the seller.'
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
page_info: {
|
|
30
|
+
__typename: 'SearchResultPageInfo',
|
|
31
|
+
total_pages: 1,
|
|
32
|
+
page_size: 10,
|
|
33
|
+
current_page: 1,
|
|
34
|
+
total_count: 2
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
7
38
|
const SellerReview = ({ seller }) => {
|
|
8
|
-
const talonProps = useSellerReview({
|
|
9
|
-
|
|
10
|
-
});
|
|
39
|
+
// const talonProps = useSellerReview({
|
|
40
|
+
// sellerUrl: seller.url_key
|
|
41
|
+
// });
|
|
42
|
+
// const { reviews, loading } = talonProps;
|
|
43
|
+
|
|
44
|
+
const reviews = dummyReviews;
|
|
45
|
+
|
|
46
|
+
// count stars
|
|
47
|
+
const getStarCounts = () => {
|
|
48
|
+
const counts = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };
|
|
49
|
+
if (reviews && reviews.items) {
|
|
50
|
+
reviews.items.forEach(item => {
|
|
51
|
+
if (counts[item.rating] !== undefined) {
|
|
52
|
+
counts[item.rating]++;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return counts;
|
|
57
|
+
};
|
|
11
58
|
|
|
12
|
-
const
|
|
59
|
+
const starCounts = getStarCounts();
|
|
13
60
|
|
|
14
61
|
return (
|
|
15
62
|
<>
|
|
16
|
-
<div className='w-full
|
|
17
|
-
<div
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
<div className='w-full'>
|
|
64
|
+
<div>
|
|
65
|
+
<h2 className="text-xl font-bold mb-4">Buyer Reviews</h2>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div className='w-full flex items-start xs_flex-col lg_flex-row gap-[30px]'>
|
|
69
|
+
<div className="w-full xs_max-w-full lg_max-w-[365px] border border-[#E6E9EA] rounded-md p-6">
|
|
70
|
+
<div className="flex justify-between items-start mb-1">
|
|
71
|
+
{/* Left - Star rating */}
|
|
72
|
+
<div className="flex flex-col">
|
|
73
|
+
<div className="flex items-center gap-1 mb-1">
|
|
74
|
+
{[...Array(5)].map((_, i) => (
|
|
75
|
+
<div key={i} className="w-4 h-4">
|
|
76
|
+
<Star1
|
|
77
|
+
color={i < 4 ? '#F7C317' : '#D9D9D9'}
|
|
78
|
+
size={16}
|
|
79
|
+
className={i < 4 ? 'fill-[#F7C317]' : ''}
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
))}
|
|
83
|
+
<span className="ml-1 font-medium text-sm">4.5 out of 5</span>
|
|
36
84
|
</div>
|
|
85
|
+
<div className="text-xs text-gray-600">100% Positive Rating (2 Ratings)</div>
|
|
37
86
|
</div>
|
|
38
|
-
<div
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<div className="gap-[5px] flex items-center">
|
|
45
|
-
<div className="w-3.5 h-3.5 relative">
|
|
46
|
-
<Star1 color='#F7C317' size={14} className='fill-[#F7C317]' />
|
|
47
|
-
</div>
|
|
48
|
-
<div className="gap-2.5 flex">
|
|
49
|
-
<div className="text-center text-zinc-900 text-base font-normal leading-[18px]">5</div>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
<div className="xs_w-full lg_w-40 h-[6px] relative">
|
|
53
|
-
<div className="w-full h-[6px] absolute bg-[#E4EBF5] rounded" />
|
|
54
|
-
<div className="w-full h-[6px] absolute bg-[#f76b1c] rounded" />
|
|
55
|
-
</div>
|
|
87
|
+
<div>
|
|
88
|
+
<select className="border border-[#E6E9EA] rounded px-2 py-1 text-xs">
|
|
89
|
+
<option>12 month</option>
|
|
90
|
+
<option>6 month</option>
|
|
91
|
+
<option>3 month</option>
|
|
92
|
+
</select>
|
|
56
93
|
</div>
|
|
57
|
-
<div className="w-10 text-zinc-900 text-base font-normal leading-[18px]">12</div>
|
|
58
94
|
</div>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
95
|
+
|
|
96
|
+
{/* Rating Bars */}
|
|
97
|
+
<div className="mt-4">
|
|
98
|
+
{[5, 4, 3, 2, 1].map(star => {
|
|
99
|
+
const count = starCounts[star] || 0;
|
|
100
|
+
const percentage = reviews.total_count ? Math.round((count / reviews.total_count) * 100) : 0;
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div key={star} className="flex items-center mb-2">
|
|
104
|
+
{/* Star number */}
|
|
105
|
+
<div className="flex items-center mr-2">
|
|
106
|
+
<Star1 color="#F7C317" size={14} className="fill-[#F7C317]" />
|
|
107
|
+
<span className="text-sm ml-1">{star}</span>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{/* Progress bar */}
|
|
111
|
+
<div className="relative h-[8px] flex-1 bg-[#E4EBF5] rounded-sm mr-2">
|
|
112
|
+
<div
|
|
113
|
+
className="absolute h-[8px] bg-[#FF7A00] rounded-sm"
|
|
114
|
+
style={{width: `${percentage}%`}}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
{/* Percentage */}
|
|
119
|
+
<span className="text-sm text-right">{percentage}%</span>
|
|
67
120
|
</div>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
<div className="w-full h-[6px] absolute bg-[#E4EBF5] rounded" />
|
|
71
|
-
<div className="w-[80%] h-[6px] absolute bg-[#f76b1c] rounded" />
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
<div className="w-10 text-zinc-900 text-base font-normal leading-[18px]">8</div>
|
|
121
|
+
);
|
|
122
|
+
})}
|
|
75
123
|
</div>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
</
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
</
|
|
90
|
-
</
|
|
91
|
-
<div className="w-10 text-zinc-900 text-base font-normal leading-[18px]">5</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
{/* Right Column - Reviews */}
|
|
127
|
+
<div className="flex-1">
|
|
128
|
+
{/* Filter */}
|
|
129
|
+
<div className="flex items-center mb-6">
|
|
130
|
+
<span className="font-medium mr-3">Filter By</span>
|
|
131
|
+
<select className="border border-[#E6E9EA] rounded px-3 py-2 text-sm">
|
|
132
|
+
<option>All Stars</option>
|
|
133
|
+
<option>5 Stars</option>
|
|
134
|
+
<option>4 Stars</option>
|
|
135
|
+
<option>3 Stars</option>
|
|
136
|
+
<option>2 Stars</option>
|
|
137
|
+
<option>1 Stars</option>
|
|
138
|
+
</select>
|
|
92
139
|
</div>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
140
|
+
|
|
141
|
+
{/* Reviews List */}
|
|
142
|
+
<div className="space-y-4 mb-6">
|
|
143
|
+
{reviews && reviews.items && reviews.items.map((review, index) => (
|
|
144
|
+
<div key={index} className="border border-[#E6E9EA] rounded-md p-4">
|
|
145
|
+
<div className="flex items-center mb-2">
|
|
146
|
+
<div className="w-10 h-10 rounded-full bg-indigo-600 text-white flex items-center justify-center font-bold mr-3">
|
|
147
|
+
Pict
|
|
148
|
+
</div>
|
|
149
|
+
<div>
|
|
150
|
+
<div className="font-medium">{review.name}</div>
|
|
151
|
+
<div className="text-gray-500 text-sm">{review.date}</div>
|
|
152
|
+
</div>
|
|
98
153
|
</div>
|
|
99
|
-
|
|
100
|
-
|
|
154
|
+
|
|
155
|
+
{/* Star Rating */}
|
|
156
|
+
<div className="flex mb-3">
|
|
157
|
+
{[...Array(5)].map((_, i) => (
|
|
158
|
+
<Star1
|
|
159
|
+
key={i}
|
|
160
|
+
color={i < review.rating ? '#F7C317' : '#D9D9D9'}
|
|
161
|
+
size={16}
|
|
162
|
+
className={i < review.rating ? 'fill-[#F7C317]' : ''}
|
|
163
|
+
/>
|
|
164
|
+
))}
|
|
101
165
|
</div>
|
|
166
|
+
|
|
167
|
+
{/* Review Text */}
|
|
168
|
+
<p className="text-gray-700">{review.comment}</p>
|
|
102
169
|
</div>
|
|
103
|
-
|
|
104
|
-
<div className="w-full h-[6px] absolute bg-[#E4EBF5] rounded" />
|
|
105
|
-
<div className="w-[1%] h-[6px] absolute bg-[#f76b1c] rounded" />
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
<div className="w-10 text-zinc-900 text-base font-normal leading-[18px]">1</div>
|
|
170
|
+
))}
|
|
109
171
|
</div>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<div className="xs_w-full lg_w-40 h-[6px] relative">
|
|
121
|
-
<div className="w-full h-[6px] absolute bg-[#E4EBF5] rounded" />
|
|
122
|
-
<div className="w-[0%] h-[6px] absolute bg-[#f76b1c] rounded" />
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
<div className="w-10 text-zinc-900 text-base font-normal leading-[18px]">0</div>
|
|
172
|
+
|
|
173
|
+
{/* Pagination */}
|
|
174
|
+
<div className="flex justify-center">
|
|
175
|
+
{reviews && reviews.page_info && reviews.page_info.total_pages > 0 && (
|
|
176
|
+
<Pagination
|
|
177
|
+
currentPage={reviews.page_info.current_page}
|
|
178
|
+
totalPages={reviews.page_info.total_pages}
|
|
179
|
+
pageSize={reviews.page_info.page_size}
|
|
180
|
+
/>
|
|
181
|
+
)}
|
|
126
182
|
</div>
|
|
127
183
|
</div>
|
|
128
|
-
<div className="xs_self-end lg_self-stretch px-[30px] py-2.5 bg-white rounded-[30px] border border-indigo-600 justify-center items-center gap-2.5 inline-flex">
|
|
129
|
-
<div className="text-indigo-600 text-base font-medium leading-tight">Write a review</div>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
<div className='flex flex-col w-full'>
|
|
133
|
-
<div className='flex flex-col w-full items-start gap-[20px] relative mb-[30px]'>
|
|
134
|
-
<SellerReviews reviews={reviews} />
|
|
135
|
-
</div>
|
|
136
|
-
<div className='pagination-container w-full flex justify-center'>
|
|
137
|
-
{reviews && reviews.page_info ? <Pagination
|
|
138
|
-
currentPage={reviews.page_info.current_page}
|
|
139
|
-
totalPages={reviews.page_info.total_pages}
|
|
140
|
-
pageSize={reviews.page_info.page_size} /> : ''}
|
|
141
|
-
</div>
|
|
142
184
|
</div>
|
|
143
185
|
</div>
|
|
144
186
|
</>
|
|
145
|
-
)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const SellerReviews = ({ reviews }) => {
|
|
149
|
-
return reviews && reviews.items.length ? reviews.items.map((review, index) => <SellerReviewItem review={review} key={index} /> ) : ''
|
|
150
|
-
}
|
|
187
|
+
);
|
|
188
|
+
};
|
|
151
189
|
|
|
152
190
|
export default SellerReview;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Star1 } from 'iconsax-react';
|
|
3
|
+
|
|
4
|
+
const Rating = ({ percentage = 0, starSize = 16 }) => {
|
|
5
|
+
const totalStars = 5;
|
|
6
|
+
const filledStars = Math.round((percentage / 100) * totalStars);
|
|
7
|
+
|
|
8
|
+
const stars = [];
|
|
9
|
+
for (let i = 0; i < totalStars; i++) {
|
|
10
|
+
if (i < filledStars) {
|
|
11
|
+
stars.push(
|
|
12
|
+
<Star1
|
|
13
|
+
key={`star-filled-${i}`}
|
|
14
|
+
color="#F7C317"
|
|
15
|
+
size={starSize}
|
|
16
|
+
className="fill-[#F7C317]"
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
} else {
|
|
20
|
+
stars.push(
|
|
21
|
+
<Star1
|
|
22
|
+
key={`star-empty-${i}`}
|
|
23
|
+
color="#D9D9D9"
|
|
24
|
+
size={starSize}
|
|
25
|
+
className="fill-[#D9D9D9]"
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <div className="flex items-center">{stars}</div>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default Rating;
|
|
@@ -56,16 +56,16 @@ export const useAccountMenuItems = props => {
|
|
|
56
56
|
}
|
|
57
57
|
];
|
|
58
58
|
|
|
59
|
-
if (storage && storage.getItem('is_seller')) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
59
|
+
// if (storage && storage.getItem('is_seller')) {
|
|
60
|
+
// MENU_ITEMS = [
|
|
61
|
+
// ...MENU_ITEMS,
|
|
62
|
+
// {
|
|
63
|
+
// name: 'Seller Account Information',
|
|
64
|
+
// id: 'accountMenu.sellerAccountInfoLink',
|
|
65
|
+
// url: '/seller-account'
|
|
66
|
+
// }
|
|
67
|
+
// ];
|
|
68
|
+
// }
|
|
69
69
|
|
|
70
70
|
return {
|
|
71
71
|
handleSignOut,
|
|
@@ -139,7 +139,7 @@ const Product = props => {
|
|
|
139
139
|
</div>
|
|
140
140
|
<div className="flex flex-col">
|
|
141
141
|
|
|
142
|
-
<span className={cn(classes.price, 'text-[16px] font-medium text-right mb-5')} data-cy="Product-price">
|
|
142
|
+
<span className={cn(classes.price, 'text-[16px] font-medium text-right mb-5 text-blue-600')} data-cy="Product-price">
|
|
143
143
|
<Price currencyCode={currency} value={unitPrice} />
|
|
144
144
|
{/* <FormattedMessage
|
|
145
145
|
id={'product.price'}
|
|
@@ -78,11 +78,10 @@ const ProductListingBySeller = props => {
|
|
|
78
78
|
wishlistConfig={wishlistConfig}
|
|
79
79
|
/>
|
|
80
80
|
));
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
const priceSummary = hasItems ? (
|
|
83
83
|
<PriceSummary isUpdating={isCartUpdating} sellerUrl={seller.seller_url} />
|
|
84
84
|
) : null;
|
|
85
|
-
|
|
86
85
|
return (
|
|
87
86
|
<Fragment>
|
|
88
87
|
<ErrorMessage error={error} />
|
|
@@ -97,10 +96,19 @@ const ProductListingBySeller = props => {
|
|
|
97
96
|
"display": "flex",
|
|
98
97
|
"gap": "7px"
|
|
99
98
|
}}>
|
|
100
|
-
|
|
101
|
-
{seller?.seller_name}<span style={{"paddingTop": "3px"}}><ArrowRight2 size="18" color="#999999" /></span></span></Link>
|
|
99
|
+
{seller?.seller_name}</span></Link>
|
|
102
100
|
</div>
|
|
103
101
|
{productComponents}
|
|
102
|
+
<div className={classes.subtotalContainer}>
|
|
103
|
+
<div className={classes.subtotalLabel}>Subtotal:</div>
|
|
104
|
+
<div className={classes.subtotalAmount}>
|
|
105
|
+
{seller.seller_currency || 'SGD'} {items.reduce((total, item) => {
|
|
106
|
+
const itemPrice = item?.prices?.price?.value || 0;
|
|
107
|
+
const quantity = item?.quantity || 0;
|
|
108
|
+
return total + (itemPrice * quantity);
|
|
109
|
+
}, 0).toFixed(2)}
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
104
112
|
<div className={classes.summary_container}>
|
|
105
113
|
<div className={classes.summary_contents}>
|
|
106
114
|
{priceSummary}
|
|
@@ -30,4 +30,22 @@
|
|
|
30
30
|
border-radius: 5px;
|
|
31
31
|
/* outline: none; */
|
|
32
32
|
cursor: pointer;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.subtotalContainer {
|
|
36
|
+
display: flex;
|
|
37
|
+
justify-content: flex-end;
|
|
38
|
+
padding: 15px;
|
|
39
|
+
border-bottom: 2px solid #f1f1f1;
|
|
40
|
+
gap: 5rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.subtotalLabel {
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
font-size: 16px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.subtotalAmount {
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
font-size: 16px;
|
|
33
51
|
}
|
|
@@ -3,6 +3,7 @@ import { FormattedMessage, useIntl } from 'react-intl';
|
|
|
3
3
|
import { arrayOf, bool, number, shape, string } from 'prop-types';
|
|
4
4
|
import { Form } from 'informed';
|
|
5
5
|
import { Info } from 'react-feather';
|
|
6
|
+
import { useToasts } from '@magento/peregrine/lib';
|
|
6
7
|
|
|
7
8
|
import Price from '@magento/venia-ui/lib/components/Price';
|
|
8
9
|
import { useProductFullDetail } from '@magento/peregrine/lib/talons/ProductFullDetail/useProductFullDetail';
|
|
@@ -86,7 +87,7 @@ const ProductFullDetail = props => {
|
|
|
86
87
|
const {
|
|
87
88
|
breadcrumbCategoryId,
|
|
88
89
|
errorMessage,
|
|
89
|
-
handleAddToCart,
|
|
90
|
+
handleAddToCart: originalHandleAddToCart,
|
|
90
91
|
handleSelectionChange,
|
|
91
92
|
isOutOfStock,
|
|
92
93
|
isEverythingOutOfStock,
|
|
@@ -100,7 +101,9 @@ const ProductFullDetail = props => {
|
|
|
100
101
|
wishlistButtonProps,
|
|
101
102
|
sellerDetails
|
|
102
103
|
} = talonProps;
|
|
103
|
-
|
|
104
|
+
|
|
105
|
+
const [, { addToast }] = useToasts();
|
|
106
|
+
|
|
104
107
|
const { formatMessage } = useIntl();
|
|
105
108
|
|
|
106
109
|
const classes = useStyle(defaultClasses, props.classes);
|
|
@@ -533,6 +536,39 @@ const ProductFullDetail = props => {
|
|
|
533
536
|
</div>
|
|
534
537
|
) : null;
|
|
535
538
|
|
|
539
|
+
const handleAddToCart = async (...args) => {
|
|
540
|
+
try {
|
|
541
|
+
await originalHandleAddToCart(...args);
|
|
542
|
+
addToast({
|
|
543
|
+
type: 'success',
|
|
544
|
+
message: formatMessage({
|
|
545
|
+
id: 'productFullDetail.addToCartSuccess',
|
|
546
|
+
defaultMessage: 'Product successfully added to cart!'
|
|
547
|
+
})
|
|
548
|
+
});
|
|
549
|
+
} catch (e) {
|
|
550
|
+
addToast({
|
|
551
|
+
type: 'error',
|
|
552
|
+
message: formatMessage({
|
|
553
|
+
id: 'productFullDetail.addToCartError',
|
|
554
|
+
defaultMessage: 'Failed to add product to cart.'
|
|
555
|
+
})
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
useEffect(() => {
|
|
561
|
+
const toastRoot = document.getElementById('toast-root');
|
|
562
|
+
if (toastRoot) {
|
|
563
|
+
toastRoot.classList.add('toast-center-bottom');
|
|
564
|
+
}
|
|
565
|
+
return () => {
|
|
566
|
+
if (toastRoot) {
|
|
567
|
+
toastRoot.classList.remove('toast-center-bottom');
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}, []);
|
|
571
|
+
|
|
536
572
|
return (
|
|
537
573
|
<Fragment>
|
|
538
574
|
{breadcrumbs}
|
package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.module.css
CHANGED
|
@@ -254,4 +254,23 @@
|
|
|
254
254
|
.leftContainer {
|
|
255
255
|
composes: max-w-[100%] from global;
|
|
256
256
|
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* productFullDetail.module.css */
|
|
260
|
+
:global(#toast-root).toast-center-bottom {
|
|
261
|
+
position: fixed !important;
|
|
262
|
+
left: 50% !important;
|
|
263
|
+
bottom: 2rem !important;
|
|
264
|
+
right: auto !important;
|
|
265
|
+
top: auto !important;
|
|
266
|
+
transform: translateX(-50%) !important;
|
|
267
|
+
z-index: 9999 !important;
|
|
268
|
+
margin: 0 !important;
|
|
269
|
+
max-width: 90vw !important;
|
|
270
|
+
min-width: 320px !important;
|
|
271
|
+
width: auto !important;
|
|
272
|
+
display: flex !important;
|
|
273
|
+
flex-direction: column !important;
|
|
274
|
+
align-items: center !important;
|
|
275
|
+
justify-content: flex-end !important;
|
|
257
276
|
}
|
|
@@ -62,7 +62,7 @@ export const useBecomeSeller = props => {
|
|
|
62
62
|
// Create the account and then sign in.
|
|
63
63
|
const result = await becomeSeller({
|
|
64
64
|
variables: {
|
|
65
|
-
seller_type:
|
|
65
|
+
seller_type: formValues.seller.seller_type,
|
|
66
66
|
group_id: '',
|
|
67
67
|
url_key: formValues.seller.store_url,
|
|
68
68
|
name: formValues.seller.seller_profile_name,
|
|
@@ -142,7 +142,10 @@ export const useAddToFavoriteListButton = props => {
|
|
|
142
142
|
|
|
143
143
|
return {
|
|
144
144
|
buttonProps,
|
|
145
|
-
buttonText:
|
|
145
|
+
buttonText:
|
|
146
|
+
typeof props.buttonText === 'function'
|
|
147
|
+
? props.buttonText(isSelected)
|
|
148
|
+
: props.buttonText,
|
|
146
149
|
// customerFavoriteSellers,
|
|
147
150
|
errorToastProps,
|
|
148
151
|
handleClick,
|