@riosst100/pwa-marketplace 2.8.0 → 2.8.2
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 +6 -0
- package/i18n/id_ID.json +6 -0
- package/package.json +1 -1
- package/src/components/FavoriteSeller/AddToListButton/addToListButton.js +11 -4
- package/src/components/FavoriteSeller/AddToListButton/addToListButton.module.css +11 -6
- package/src/components/FavoriteSellerPage/favoriteSeller.js +22 -13
- package/src/components/FavoriteSellerPage/item.js +71 -88
- package/src/components/SellerDetail/sellerDetail.js +11 -1
- package/src/talons/FavoriteSeller/AddToListButton/useAddToFavoriteListButton.js +69 -46
- package/src/talons/FavoriteSeller/FavoriteSellerList/favoriteSellerList.gql.js +49 -0
- package/src/talons/FavoriteSeller/FavoriteSellerList/useFavoriteSellerList.js +30 -0
- package/src/talons/FavoriteSeller/FavoriteSellerList/useRemoveFavoriteSeller.js +31 -0
- package/src/talons/FilterTop/filterTop.gql.js +1 -1
package/i18n/en_US.json
CHANGED
|
@@ -368,6 +368,12 @@
|
|
|
368
368
|
"productFullDetail.outOfStockProduct": "This item is currently out of stock",
|
|
369
369
|
"productFullDetail.addToCartSuccess": "Product successfully added to cart!",
|
|
370
370
|
"productFullDetail.addToCartError": "Failed to add product to cart.",
|
|
371
|
+
"favoriteSeller.toastRemoveSuccess": "Successfully removed favorite seller.",
|
|
372
|
+
"favoriteSeller.toastRemoveError": "Failed to remove favorite seller.",
|
|
373
|
+
"favoriteSeller.removing": "Removing...",
|
|
374
|
+
"favoriteSeller.toastUnfollowSuccess": "Successfully unfollowed seller.",
|
|
375
|
+
"favoriteSeller.toastUnfollowError": "Failed to unfollow seller.",
|
|
376
|
+
"favoriteSeller.unfollowing": "Unfollowing...",
|
|
371
377
|
"productImageCarousel.previousButtonAriaLabel": "Previous Image",
|
|
372
378
|
"productImageCarousel.nextButtonAriaLabel": "Next Image",
|
|
373
379
|
"productList.each": " ea.",
|
package/i18n/id_ID.json
CHANGED
|
@@ -369,6 +369,12 @@
|
|
|
369
369
|
"productFullDetail.outOfStockProduct": "This item is currently out of stock",
|
|
370
370
|
"productFullDetail.addToCartSuccess": "Produk berhasil ditambahkan ke keranjang!",
|
|
371
371
|
"productFullDetail.addToCartError": "Gagal menambahkan produk ke keranjang.",
|
|
372
|
+
"favoriteSeller.toastRemoveSuccess": "Berhasil menghapus penjual favorit.",
|
|
373
|
+
"favoriteSeller.toastRemoveError": "Gagal menghapus penjual favorit.",
|
|
374
|
+
"favoriteSeller.removing": "Menghapus...",
|
|
375
|
+
"favoriteSeller.toastUnfollowSuccess": "Berhasil berhenti mengikuti penjual.",
|
|
376
|
+
"favoriteSeller.toastUnfollowError": "Gagal berhenti mengikuti penjual.",
|
|
377
|
+
"favoriteSeller.unfollowing": "Sedang berhenti mengikuti...",
|
|
372
378
|
"productImageCarousel.previousButtonAriaLabel": "Previous Image",
|
|
373
379
|
"productImageCarousel.nextButtonAriaLabel": "Next Image",
|
|
374
380
|
"productList.each": " ea.",
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ import { useCommonToasts } from '@magento/venia-ui/lib/components/Wishlist/AddTo
|
|
|
11
11
|
|
|
12
12
|
const HeartIcon = <Heart color='#f76b1c' size={14} variant="Outline" className='stroke-[#f76b1c]' />;
|
|
13
13
|
|
|
14
|
+
|
|
14
15
|
const AddToFavoriteListButton = props => {
|
|
15
16
|
const talonProps = useAddToFavoriteListButton(props);
|
|
16
17
|
const buttonRef = useRef();
|
|
@@ -21,7 +22,8 @@ const AddToFavoriteListButton = props => {
|
|
|
21
22
|
errorToastProps,
|
|
22
23
|
isSelected,
|
|
23
24
|
loginToastProps,
|
|
24
|
-
successToastProps
|
|
25
|
+
successToastProps,
|
|
26
|
+
isLoading
|
|
25
27
|
} = talonProps;
|
|
26
28
|
|
|
27
29
|
useCommonToasts({ errorToastProps, loginToastProps, successToastProps });
|
|
@@ -30,10 +32,15 @@ const AddToFavoriteListButton = props => {
|
|
|
30
32
|
const classes = useStyle(defaultClasses, props.classes);
|
|
31
33
|
const buttonClass = isSelected ? classes.root_selected : classes.root;
|
|
32
34
|
|
|
35
|
+
// Only hide text on mobile for follow, always show for unfollow
|
|
36
|
+
const textClass = isSelected
|
|
37
|
+
? 'text-[#f76b1c] text-[14px] font-medium whitespace-nowrap'
|
|
38
|
+
: `text-[#f76b1c] text-[14px] font-medium whitespace-nowrap ${props.hideTextOnMobile ? 'md_block xs_hidden' : ''}`;
|
|
39
|
+
|
|
33
40
|
return (
|
|
34
|
-
<button ref={buttonRef} className={buttonClass} {...ariaButtonProps}>
|
|
35
|
-
{props.icon}
|
|
36
|
-
{buttonText && <span className={
|
|
41
|
+
<button ref={buttonRef} className={buttonClass} {...ariaButtonProps} disabled={isLoading}>
|
|
42
|
+
{!isSelected && props.icon}
|
|
43
|
+
{buttonText && <span className={textClass}>{buttonText}</span>}
|
|
37
44
|
</button>
|
|
38
45
|
);
|
|
39
46
|
};
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
|
|
1
2
|
.root {
|
|
2
3
|
composes: gap-x-2xs from global;
|
|
3
4
|
composes: inline-flex from global;
|
|
4
5
|
composes: items-center from global;
|
|
5
|
-
min-height: 3rem;
|
|
6
|
+
/* min-height: 3rem; */
|
|
6
7
|
composes: min-w-[3rem] from global;
|
|
8
|
+
border: 1px solid #f76b1c;
|
|
9
|
+
border-radius: 30px;
|
|
10
|
+
background: #fff;
|
|
11
|
+
color: #f76b1c;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
padding: 8px 14px;
|
|
14
|
+
font-weight: 500;
|
|
15
|
+
font-size: 14px;
|
|
16
|
+
transition: background 0.2s, color 0.2s;
|
|
7
17
|
}
|
|
8
18
|
|
|
9
19
|
.root_selected {
|
|
10
20
|
composes: root;
|
|
11
|
-
|
|
12
|
-
--selectedColor: rgb(var(--venia-global-color-red-400));
|
|
13
|
-
--fill: var(--selectedColor);
|
|
14
|
-
--stroke: var(--selectedColor);
|
|
15
|
-
|
|
16
21
|
composes: no-underline from global;
|
|
17
22
|
}
|
|
@@ -2,31 +2,40 @@ import React from 'react';
|
|
|
2
2
|
import { StoreTitle } from '@magento/venia-ui/lib/components/Head';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
4
|
import Item from './item';
|
|
5
|
+
import useFavoriteSellerList from '@riosst100/pwa-marketplace/src/talons/FavoriteSeller/FavoriteSellerList/useFavoriteSellerList';
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
-
|
|
7
|
+
const FavoriteSeller = () => {
|
|
8
8
|
const { formatMessage } = useIntl();
|
|
9
9
|
const PAGE_TITLE = formatMessage({
|
|
10
10
|
id: 'favoriteSellerPage.pageTitleText',
|
|
11
11
|
defaultMessage: 'Favorite Seller'
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
+
// Fetch favorite seller list
|
|
15
|
+
const { data, loading, error, refetch } = useFavoriteSellerList();
|
|
16
|
+
|
|
14
17
|
return (
|
|
15
18
|
<div className='relative'>
|
|
16
19
|
<StoreTitle>{PAGE_TITLE}</StoreTitle>
|
|
17
20
|
<div aria-live="polite" className="text-xl font-medium text-left mb-[30px]">
|
|
18
21
|
{PAGE_TITLE}
|
|
19
22
|
</div>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
{loading ? (
|
|
24
|
+
<div>Loading...</div>
|
|
25
|
+
) : (
|
|
26
|
+
<div className='flex flex-col gap-5'>
|
|
27
|
+
{error && <div>Error loading favorite sellers.</div>}
|
|
28
|
+
{data && data.items && data.items.length > 0 ? (
|
|
29
|
+
data.items.map(sellerItem => (
|
|
30
|
+
<Item key={sellerItem.id} sellerItem={sellerItem} refetchFavoriteSellerList={refetch} />
|
|
31
|
+
))
|
|
32
|
+
) : !error ? (
|
|
33
|
+
<div>No favorite sellers found.</div>
|
|
34
|
+
) : null}
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
28
37
|
</div>
|
|
29
|
-
)
|
|
30
|
-
}
|
|
38
|
+
);
|
|
39
|
+
};
|
|
31
40
|
|
|
32
|
-
export default
|
|
41
|
+
export default FavoriteSeller;
|
|
@@ -5,81 +5,82 @@ import Image from '@magento/venia-ui/lib/components/Image';
|
|
|
5
5
|
import Verify from '@riosst100/pwa-marketplace/src/components/CrossSeller/verifyIcon';
|
|
6
6
|
import Star from '@riosst100/pwa-marketplace/src/components/CrossSeller/starIcon';
|
|
7
7
|
import logoImage from '@riosst100/pwa-marketplace/src/components/CrossSeller/logo_seller.png';
|
|
8
|
-
import { Share
|
|
8
|
+
import { Share } from 'iconsax-react';
|
|
9
9
|
import SocialShare from '@riosst100/pwa-marketplace/src/components/SocialMediaShare';
|
|
10
10
|
import { X } from 'react-feather';
|
|
11
11
|
import Modal from '@riosst100/pwa-marketplace/src/components/Modal';
|
|
12
12
|
import cn from 'classnames';
|
|
13
13
|
import { primary900 } from '@riosst100/pwa-marketplace/src/theme/vars';
|
|
14
|
-
import { FormattedMessage } from 'react-intl';
|
|
14
|
+
import { FormattedMessage, useIntl } from 'react-intl';
|
|
15
|
+
import useRemoveFavoriteSeller from '@riosst100/pwa-marketplace/src/talons/FavoriteSeller/FavoriteSellerList/useRemoveFavoriteSeller';
|
|
16
|
+
import { useState } from 'react';
|
|
17
|
+
import { useToasts } from '@magento/peregrine';
|
|
15
18
|
|
|
16
|
-
const
|
|
17
|
-
const [open, setOpen] =
|
|
19
|
+
const Item = ({ sellerItem, refetchFavoriteSellerList }) => {
|
|
20
|
+
const [open, setOpen] = useState(false);
|
|
21
|
+
const { remove, loading: removing } = useRemoveFavoriteSeller();
|
|
22
|
+
const [, { addToast }] = useToasts();
|
|
23
|
+
const { formatMessage } = useIntl();
|
|
18
24
|
|
|
19
|
-
const handleRemoveFromFavorite = () => {
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const handleRemoveFromFavorite = async () => {
|
|
26
|
+
try {
|
|
27
|
+
await remove([sellerItem.seller.seller_id]);
|
|
28
|
+
addToast({
|
|
29
|
+
type: 'success',
|
|
30
|
+
message: formatMessage({
|
|
31
|
+
id: 'favoriteSeller.toastUnfollowSuccess',
|
|
32
|
+
defaultMessage: 'Successfully unfollowed seller.'
|
|
33
|
+
}),
|
|
34
|
+
timeout: 3000
|
|
35
|
+
});
|
|
36
|
+
if (typeof refetchFavoriteSellerList === 'function') {
|
|
37
|
+
await refetchFavoriteSellerList();
|
|
38
|
+
}
|
|
39
|
+
} catch (e) {
|
|
40
|
+
addToast({
|
|
41
|
+
type: 'error',
|
|
42
|
+
message: formatMessage({
|
|
43
|
+
id: 'favoriteSeller.toastUnfollowError',
|
|
44
|
+
defaultMessage: 'Failed to unfollow seller.'
|
|
45
|
+
}),
|
|
46
|
+
timeout: 3000
|
|
47
|
+
});
|
|
48
|
+
console.error('Failed to unfollow seller:', e);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
22
51
|
|
|
23
52
|
const handleGoToSellerPage = () => {
|
|
24
|
-
|
|
25
|
-
|
|
53
|
+
if (sellerItem?.seller?.url) {
|
|
54
|
+
window.location.href = sellerItem.seller.url;
|
|
55
|
+
} else {
|
|
56
|
+
alert('to seller page');
|
|
57
|
+
}
|
|
58
|
+
};
|
|
26
59
|
|
|
27
60
|
return (
|
|
28
61
|
<>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<div className='text-lg font-medium'>
|
|
39
|
-
Share to your friends
|
|
40
|
-
</div>
|
|
41
|
-
<button onClick={() => { setOpen(!open) }} >
|
|
42
|
-
<X size={24} color={primary900} />
|
|
43
|
-
</button>
|
|
44
|
-
</div>
|
|
45
|
-
<div className='flex flex-row border border-gray-100 rounded-md px-5 py-2.5 gap-x-2.5 items-center'>
|
|
46
|
-
<div className='flex flex-col'>
|
|
47
|
-
<div className='text-[14px] font-normal'>
|
|
48
|
-
Zen Market.TCG
|
|
49
|
-
</div>
|
|
50
|
-
<div className='text-[12px] font-normal text-gray-200'>
|
|
51
|
-
zenmarket-tcg.link
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
62
|
+
<div className='border border-gray-100 rounded-md p-5 flex flex-col md_flex-row justify-between gap-y-4 relative'>
|
|
63
|
+
{removing && (
|
|
64
|
+
<div className="absolute inset-0 bg-white bg-opacity-60 flex items-center justify-center z-10">
|
|
65
|
+
<span className="text-sm text-gray-700">
|
|
66
|
+
<FormattedMessage
|
|
67
|
+
id="favoriteSeller.unfollowing"
|
|
68
|
+
defaultMessage="Unfollowing..."
|
|
69
|
+
/>
|
|
70
|
+
</span>
|
|
54
71
|
</div>
|
|
55
|
-
|
|
56
|
-
</div>
|
|
57
|
-
</Modal>
|
|
58
|
-
<div className='border border-gray-100 rounded-md p-5 flex flex-col md_flex-row justify-between gap-y-4'>
|
|
72
|
+
)}
|
|
59
73
|
<div className='seller_info-container flex flex-row gap-x-[15px]'>
|
|
60
|
-
<div className='logo_wrapper w-[100px] h-[100px]'>
|
|
61
|
-
<Image
|
|
62
|
-
alt='seller name'
|
|
63
|
-
className="relative mt-[-5px]"
|
|
64
|
-
src={logoImage}
|
|
65
|
-
/>
|
|
66
|
-
</div>
|
|
67
74
|
<div className='flex flex-col gap-y-[15px]'>
|
|
68
75
|
<div className='flex flex-col gap-[6px]'>
|
|
69
76
|
<div className='seller_summary-wrapper flex flex-row gap-x-2.5 items-center'>
|
|
70
77
|
<div className='seller_name text-lg font-medium leading-6'>
|
|
71
|
-
|
|
72
|
-
</div>
|
|
73
|
-
<div className='seller_badge flex flex-row gap-x-[5px] items-center leading-6'>
|
|
74
|
-
<Verify />
|
|
75
|
-
<span className='text-xs font-medium text-gray-600-transparent capitalize'>
|
|
76
|
-
Verified
|
|
77
|
-
</span>
|
|
78
|
+
{sellerItem?.seller?.name || '-'}
|
|
78
79
|
</div>
|
|
79
80
|
</div>
|
|
80
81
|
<div className='flex flex-row gap-x-[5px] items-center'>
|
|
81
82
|
<span className='font-normal text-[12px] text-gray-200 '>
|
|
82
|
-
|
|
83
|
+
{sellerItem?.seller?.description || '-'}
|
|
83
84
|
</span>
|
|
84
85
|
</div>
|
|
85
86
|
</div>
|
|
@@ -87,54 +88,36 @@ const item = () => {
|
|
|
87
88
|
<Button
|
|
88
89
|
classes={{
|
|
89
90
|
content: 'gap-1.5 grid-flow-col inline-grid items-center justify-center justify-items-center capitalize font-medium text-[14px]',
|
|
90
|
-
rootClass: 'py-[0px] h-9 hover_border-
|
|
91
|
+
rootClass: 'py-[0px] h-9 hover_border-orange-500 border-orange-500 text-[#f76b1c]'
|
|
91
92
|
}}
|
|
92
93
|
onClick={handleGoToSellerPage}
|
|
94
|
+
variant="outlined"
|
|
93
95
|
>
|
|
94
96
|
<FormattedMessage
|
|
95
97
|
id={'favoriteSeller.visitStore'}
|
|
96
98
|
defaultMessage={'Visit Store'}
|
|
97
99
|
/>
|
|
98
100
|
</Button>
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
<Button
|
|
102
|
+
classes={{
|
|
103
|
+
content: 'gap-1.5 grid-flow-col inline-grid items-center justify-center justify-items-center capitalize font-medium text-[14px]',
|
|
104
|
+
rootClass: 'py-[0px] h-9 hover_border-orange-500 border-orange-500 text-[#f76b1c]'
|
|
105
|
+
}}
|
|
106
|
+
onClick={handleRemoveFromFavorite}
|
|
107
|
+
disabled={removing}
|
|
108
|
+
variant="outlined"
|
|
102
109
|
>
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
<FormattedMessage
|
|
111
|
+
id={'favoriteSeller.unfollow'}
|
|
112
|
+
defaultMessage={'Unfollow'}
|
|
106
113
|
/>
|
|
107
|
-
</
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
<div className='flex flex-row justify-between md_justify-center items-center gap-5'>
|
|
112
|
-
<div className='flex flex-col gap-y-2'>
|
|
113
|
-
<div className='rating_sales flex flex-row gap-x-[5px] items-center'>
|
|
114
|
-
<Star width={18} height={18} />
|
|
115
|
-
<p className='font-medium text-[18px] text-gray-600'>
|
|
116
|
-
4.7
|
|
117
|
-
</p>
|
|
114
|
+
</Button>
|
|
118
115
|
</div>
|
|
119
|
-
<span className='text-gray-800 text-xs'>
|
|
120
|
-
<FormattedMessage
|
|
121
|
-
id={'favoriteSeller.RatingAndReviews'}
|
|
122
|
-
defaultMessage={'Rating & Reviews'}
|
|
123
|
-
/>
|
|
124
|
-
</span>
|
|
125
|
-
|
|
126
116
|
</div>
|
|
127
|
-
<Button
|
|
128
|
-
data-cy="Product-Section-removeFavorite"
|
|
129
|
-
onClick={handleRemoveFromFavorite}
|
|
130
|
-
className="min-w-min border border-gray-200 rounded-full border-solid w-7 h-7 flex items-center justify-center hover_border-gray-600"
|
|
131
|
-
>
|
|
132
|
-
<Trash size="16" color="#999999" />
|
|
133
|
-
</Button>
|
|
134
117
|
</div>
|
|
135
118
|
</div>
|
|
136
119
|
</>
|
|
137
|
-
)
|
|
138
|
-
}
|
|
120
|
+
);
|
|
121
|
+
};
|
|
139
122
|
|
|
140
|
-
export default
|
|
123
|
+
export default Item;
|
|
@@ -22,17 +22,23 @@ import Image from '@magento/venia-ui/lib/components/Image';
|
|
|
22
22
|
import Button from '@magento/venia-ui/lib/components/Button';
|
|
23
23
|
import cn from 'classnames';
|
|
24
24
|
import Rating from '@riosst100/pwa-marketplace/src/components/commons/Rating';
|
|
25
|
+
|
|
25
26
|
const FavoriteSellerButton = React.lazy(() => import('@riosst100/pwa-marketplace/src/components/FavoriteSeller/AddToListButton'));
|
|
26
27
|
|
|
28
|
+
|
|
29
|
+
import { useHistory } from 'react-router-dom';
|
|
30
|
+
|
|
27
31
|
const SellerDetail = props => {
|
|
28
32
|
const talonProps = useSeller({
|
|
29
33
|
mapSeller
|
|
30
34
|
});
|
|
31
35
|
|
|
32
36
|
const { error, loading, seller, favoriteSellerButtonProps } = talonProps;
|
|
37
|
+
const history = useHistory();
|
|
38
|
+
|
|
33
39
|
if (loading && !seller)
|
|
34
40
|
return '';
|
|
35
|
-
|
|
41
|
+
|
|
36
42
|
if (error && !seller) return <ErrorView />;
|
|
37
43
|
if (!seller) {
|
|
38
44
|
return (
|
|
@@ -162,6 +168,9 @@ const SellerDetail = props => {
|
|
|
162
168
|
{...favoriteSellerButtonProps}
|
|
163
169
|
buttonText={'Follow Seller'}
|
|
164
170
|
hideTextOnMobile={true}
|
|
171
|
+
afterAdd={isSelected => {
|
|
172
|
+
if (!isSelected) history.push('/favorite-seller');
|
|
173
|
+
}}
|
|
165
174
|
/>
|
|
166
175
|
</Suspense>
|
|
167
176
|
<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]'>
|
|
@@ -182,3 +191,4 @@ const SellerDetail = props => {
|
|
|
182
191
|
}
|
|
183
192
|
|
|
184
193
|
export default SellerDetail;
|
|
194
|
+
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { useCallback, useMemo, useState, useRef } from 'react';
|
|
2
3
|
import { useIntl } from 'react-intl';
|
|
3
4
|
import { useMutation, useQuery } from '@apollo/client';
|
|
4
|
-
|
|
5
5
|
import { useUserContext } from '@magento/peregrine/lib/context/user';
|
|
6
6
|
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
7
|
-
|
|
8
7
|
import defaultOperations from './addToListButton.gql';
|
|
8
|
+
import favoriteSellerListGqls from '@riosst100/pwa-marketplace/src/talons/FavoriteSeller/FavoriteSellerList/favoriteSellerList.gql';
|
|
9
|
+
|
|
9
10
|
|
|
10
11
|
export const useAddToFavoriteListButton = props => {
|
|
12
|
+
const unfollowedRef = useRef(false);
|
|
11
13
|
const { afterAdd, beforeAdd, item } = props;
|
|
12
|
-
|
|
13
14
|
const operations = mergeOperations(defaultOperations, props.operations);
|
|
14
15
|
|
|
16
|
+
// Mutation for add
|
|
15
17
|
const [
|
|
16
18
|
addToFavoriteSeller,
|
|
17
19
|
{
|
|
@@ -21,19 +23,28 @@ export const useAddToFavoriteListButton = props => {
|
|
|
21
23
|
}
|
|
22
24
|
] = useMutation(operations.addToFavoriteSellerMutation);
|
|
23
25
|
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// Mutation for remove
|
|
27
|
+
const [removeSeller, { loading: isRemoving }] = useMutation(
|
|
28
|
+
favoriteSellerListGqls.removeSellerFromFavoriteListMutation
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// Query to get current favorite sellers
|
|
32
|
+
const { data: favoriteListData, refetch: refetchFavoriteList } = useQuery(
|
|
33
|
+
favoriteSellerListGqls.getFavoriteSellerListQuery,
|
|
34
|
+
{
|
|
35
|
+
variables: { pageSize: 100, currentPage: 1 },
|
|
36
|
+
fetchPolicy: 'cache-and-network',
|
|
37
|
+
}
|
|
38
|
+
);
|
|
28
39
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const isSelected = false;
|
|
40
|
+
// Determine if this seller is already in favorite list
|
|
41
|
+
const isSelected = useMemo(() => {
|
|
42
|
+
const items = favoriteListData?.favoritelist?.items || [];
|
|
43
|
+
return items.some(i => i.seller?.seller_id == item.seller_id);
|
|
44
|
+
}, [favoriteListData, item.seller_id]);
|
|
35
45
|
|
|
36
46
|
const [showLoginToast, setShowLoginToast] = useState(0);
|
|
47
|
+
const [showUnfollowToast, setShowUnfollowToast] = useState(0);
|
|
37
48
|
|
|
38
49
|
const { formatMessage } = useIntl();
|
|
39
50
|
const [{ isSignedIn }] = useUserContext();
|
|
@@ -46,37 +57,35 @@ export const useAddToFavoriteListButton = props => {
|
|
|
46
57
|
if (beforeAdd) {
|
|
47
58
|
await beforeAdd();
|
|
48
59
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// afterAdd();
|
|
66
|
-
// }
|
|
60
|
+
const wasSelected = isSelected;
|
|
61
|
+
unfollowedRef.current = false;
|
|
62
|
+
if (isSelected) {
|
|
63
|
+
// Unfollow
|
|
64
|
+
unfollowedRef.current = true;
|
|
65
|
+
await removeSeller({ variables: { sellerIds: [item.seller_id] } });
|
|
66
|
+
} else {
|
|
67
|
+
// Follow
|
|
68
|
+
await addToFavoriteSeller({ variables: { sellerId: item.seller_id } });
|
|
69
|
+
}
|
|
70
|
+
await refetchFavoriteList();
|
|
71
|
+
if (unfollowedRef.current) {
|
|
72
|
+
setShowUnfollowToast(current => current + 1);
|
|
73
|
+
unfollowedRef.current = false;
|
|
74
|
+
}
|
|
75
|
+
if (afterAdd) afterAdd(wasSelected);
|
|
67
76
|
} catch (error) {
|
|
68
77
|
console.error(error);
|
|
69
78
|
}
|
|
70
79
|
}
|
|
71
80
|
}, [
|
|
72
81
|
addToFavoriteSeller,
|
|
82
|
+
removeSeller,
|
|
73
83
|
afterAdd,
|
|
74
84
|
beforeAdd,
|
|
75
|
-
// client,
|
|
76
|
-
// customerFavoriteSellers,
|
|
77
85
|
isSignedIn,
|
|
78
86
|
item,
|
|
79
|
-
|
|
87
|
+
isSelected,
|
|
88
|
+
refetchFavoriteList
|
|
80
89
|
]);
|
|
81
90
|
|
|
82
91
|
const loginToastProps = useMemo(() => {
|
|
@@ -107,9 +116,18 @@ export const useAddToFavoriteListButton = props => {
|
|
|
107
116
|
timeout: 5000
|
|
108
117
|
};
|
|
109
118
|
}
|
|
110
|
-
|
|
119
|
+
if (showUnfollowToast) {
|
|
120
|
+
return {
|
|
121
|
+
type: 'success',
|
|
122
|
+
message: formatMessage({
|
|
123
|
+
id: 'favoriteSeller.galleryButton.unfollowSuccessMessage',
|
|
124
|
+
defaultMessage: 'Seller removed from your favorites list.'
|
|
125
|
+
}),
|
|
126
|
+
timeout: 5000
|
|
127
|
+
};
|
|
128
|
+
}
|
|
111
129
|
return null;
|
|
112
|
-
}, [addSellerData, formatMessage]);
|
|
130
|
+
}, [addSellerData, formatMessage, showUnfollowToast]);
|
|
113
131
|
|
|
114
132
|
const errorToastProps = useMemo(() => {
|
|
115
133
|
if (errorAddingProduct) {
|
|
@@ -129,15 +147,20 @@ export const useAddToFavoriteListButton = props => {
|
|
|
129
147
|
|
|
130
148
|
const buttonProps = useMemo(
|
|
131
149
|
() => ({
|
|
132
|
-
'aria-label':
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
150
|
+
'aria-label': isSelected
|
|
151
|
+
? formatMessage({
|
|
152
|
+
id: 'favoriteSellerButton.unfollowText',
|
|
153
|
+
defaultMessage: 'Unfollow Seller'
|
|
154
|
+
})
|
|
155
|
+
: formatMessage({
|
|
156
|
+
id: 'favoriteSellerButton.addText',
|
|
157
|
+
defaultMessage: 'Follow Seller'
|
|
158
|
+
}),
|
|
159
|
+
isDisabled: isAddingToList || isRemoving,
|
|
137
160
|
onPress: handleClick,
|
|
138
161
|
type: 'button'
|
|
139
162
|
}),
|
|
140
|
-
[formatMessage, handleClick]
|
|
163
|
+
[formatMessage, handleClick, isSelected, isAddingToList, isRemoving]
|
|
141
164
|
);
|
|
142
165
|
|
|
143
166
|
return {
|
|
@@ -145,12 +168,12 @@ export const useAddToFavoriteListButton = props => {
|
|
|
145
168
|
buttonText:
|
|
146
169
|
typeof props.buttonText === 'function'
|
|
147
170
|
? props.buttonText(isSelected)
|
|
148
|
-
:
|
|
149
|
-
// customerFavoriteSellers,
|
|
171
|
+
: (isSelected ? 'Unfollow Seller' : 'Follow Seller'),
|
|
150
172
|
errorToastProps,
|
|
151
173
|
handleClick,
|
|
152
174
|
isSelected,
|
|
153
175
|
loginToastProps,
|
|
154
|
-
successToastProps
|
|
176
|
+
successToastProps,
|
|
177
|
+
isLoading: isAddingToList || isRemoving
|
|
155
178
|
};
|
|
156
179
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { gql } from '@apollo/client';
|
|
2
|
+
|
|
3
|
+
export const GET_FAVORITE_SELLER_LIST = gql`
|
|
4
|
+
query GetFavoriteSellerList($filter: FavoriteFilterInput, $pageSize: Int, $currentPage: Int) {
|
|
5
|
+
favoritelist(filter: $filter, pageSize: $pageSize, currentPage: $currentPage) {
|
|
6
|
+
items {
|
|
7
|
+
creation_time
|
|
8
|
+
customer_id
|
|
9
|
+
id
|
|
10
|
+
seller {
|
|
11
|
+
description
|
|
12
|
+
name
|
|
13
|
+
seller_id
|
|
14
|
+
url
|
|
15
|
+
}
|
|
16
|
+
status
|
|
17
|
+
}
|
|
18
|
+
page_info {
|
|
19
|
+
current_page
|
|
20
|
+
page_size
|
|
21
|
+
total_pages
|
|
22
|
+
}
|
|
23
|
+
total_count
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
export const REMOVE_SELLER_FROM_FAVORITE_LIST = gql`
|
|
29
|
+
mutation RemoveSellerFromFavoriteList($sellerIds: [ID]!) {
|
|
30
|
+
removeSellerToFavoritelist(sellerIds: $sellerIds) {
|
|
31
|
+
error
|
|
32
|
+
favorite {
|
|
33
|
+
creation_time
|
|
34
|
+
customer {
|
|
35
|
+
customer_id
|
|
36
|
+
name
|
|
37
|
+
}
|
|
38
|
+
customer_id
|
|
39
|
+
id
|
|
40
|
+
status
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
export default {
|
|
47
|
+
getFavoriteSellerListQuery: GET_FAVORITE_SELLER_LIST,
|
|
48
|
+
removeSellerFromFavoriteListMutation: REMOVE_SELLER_FROM_FAVORITE_LIST
|
|
49
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useQuery } from '@apollo/client';
|
|
2
|
+
import gqls from './favoriteSellerList.gql';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Custom hook untuk mengambil daftar seller yang di-follow user
|
|
6
|
+
* @param {Object} options - Opsi query Apollo (filter, pageSize, currentPage)
|
|
7
|
+
*/
|
|
8
|
+
const useFavoriteSellerList = (options = {}) => {
|
|
9
|
+
const { filter = {}, pageSize = 20, currentPage = 1 } = options;
|
|
10
|
+
const { data, loading, error, refetch } = useQuery(
|
|
11
|
+
gqls.getFavoriteSellerListQuery,
|
|
12
|
+
{
|
|
13
|
+
variables: {
|
|
14
|
+
filter,
|
|
15
|
+
pageSize,
|
|
16
|
+
currentPage
|
|
17
|
+
},
|
|
18
|
+
fetchPolicy: 'cache-and-network'
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
data: data?.favoritelist,
|
|
24
|
+
loading,
|
|
25
|
+
error,
|
|
26
|
+
refetch
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default useFavoriteSellerList;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useMutation } from '@apollo/client';
|
|
2
|
+
import gqls from './favoriteSellerList.gql';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Custom hook untuk menghapus seller dari favorite list
|
|
6
|
+
* @returns { removeSeller, loading, error, data }
|
|
7
|
+
*/
|
|
8
|
+
const useRemoveFavoriteSeller = () => {
|
|
9
|
+
const [removeSeller, { loading, error, data }] = useMutation(
|
|
10
|
+
gqls.removeSellerFromFavoriteListMutation
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Array<string|number>} sellerIds - Array of seller_id yang ingin dihapus
|
|
15
|
+
* @returns {Promise}
|
|
16
|
+
*/
|
|
17
|
+
const remove = (sellerIds) => {
|
|
18
|
+
return removeSeller({
|
|
19
|
+
variables: { sellerIds }
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
remove,
|
|
25
|
+
loading,
|
|
26
|
+
error,
|
|
27
|
+
data
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default useRemoveFavoriteSeller;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { gql } from '@apollo/client';
|
|
2
2
|
|
|
3
3
|
export const GET_CUSTOM_FILTERS = gql`
|
|
4
|
-
query GetCustomFilters($search: String, $filterBy: String, $shopby: String, $category: String
|
|
4
|
+
query GetCustomFilters($search: String, $filterBy: String, $shopby: String, $category: String, $filters: ProductAttributeFilterInput) {
|
|
5
5
|
customSubFilters(search: $search, filterBy: $filterBy, shopby: $shopby, category: $category, filters: $filters) {
|
|
6
6
|
filter_id
|
|
7
7
|
filters {
|