@riosst100/pwa-marketplace 2.9.6 → 2.9.9
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/componentOverrideMapping.js +2 -1
- package/src/components/FilterContent/filterContent.js +4 -0
- package/src/components/LiveChat/chatContent.js +28 -13
- package/src/components/OrderDetail/orderDetail.js +86 -26
- package/src/components/RMAPage/RMACreate.js +107 -116
- package/src/components/RMAPage/RMADetail.js +151 -114
- package/src/components/RMAPage/components/productItem.js +32 -7
- package/src/components/RMAPage/orderRow.js +28 -17
- package/src/components/ShopBy/shopBy.js +3 -0
- package/src/components/commons/Select/index.js +6 -2
- package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/priceSummaryFragments.gql.js +54 -0
- package/src/overwrites/peregrine/lib/talons/CartPage/PriceSummary/usePriceSummary.js +2 -4
- package/src/overwrites/peregrine/lib/talons/ProductFullDetail/productReview.gql.js +89 -0
- package/src/overwrites/peregrine/lib/talons/ProductFullDetail/useProductFullDetail.js +72 -3
- package/src/overwrites/peregrine/lib/talons/RMAPage/rmaPage.gql.js +33 -1
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/categoryContent.gql.js +5 -1
- package/src/overwrites/peregrine/lib/talons/RootComponents/Category/useCategoryContent.js +2 -1
- package/src/overwrites/venia-ui/lib/RootComponents/Category/categoryContent.js +4 -3
- package/src/overwrites/venia-ui/lib/components/CartPage/PriceSummary/priceSummary.js +97 -23
- package/src/overwrites/venia-ui/lib/components/FilterModal/FilterList/filterList.js +0 -2
- package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.js +29 -0
- package/src/overwrites/venia-ui/lib/components/FilterSidebar/filterSidebar.module.css +1 -1
- package/src/overwrites/venia-ui/lib/components/OrderHistoryPage/orderRow.js +39 -40
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/modalFormReview.js +102 -95
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/productReview.js +111 -70
- package/src/overwrites/venia-ui/lib/components/ProductFullDetail/productFullDetail.js +19 -3
- package/src/talons/RMAPage/useRmaPage.js +40 -6
package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/modalFormReview.js
CHANGED
|
@@ -1,24 +1,46 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import Modal from '@riosst100/pwa-marketplace/src/components/Modal';
|
|
3
3
|
import { X } from 'react-feather';
|
|
4
4
|
import Field from '@magento/venia-ui/lib/components/Field';
|
|
5
|
-
import TextInput from '@magento/venia-ui/lib/components/TextInput';
|
|
5
|
+
// import TextInput from '@magento/venia-ui/lib/components/TextInput';
|
|
6
6
|
import Button from '@magento/venia-ui/lib/components/Button';
|
|
7
7
|
import { isRequired } from '@magento/venia-ui/lib/util/formValidators';
|
|
8
|
-
import { Form } from 'informed';
|
|
9
8
|
import StarRating from './starInput';
|
|
10
9
|
|
|
11
10
|
import { primary900 } from '@riosst100/pwa-marketplace/src/theme/vars';
|
|
12
11
|
|
|
13
12
|
const modalFormReview = (props) => {
|
|
13
|
+
const { open, setOpen, ratingsMetadata = [], loadingRatingsMetadata, onSubmit, submitting, defaultNickname } = props;
|
|
14
14
|
|
|
15
|
-
const {
|
|
16
|
-
const [currentRating, setCurrentRating] = useState(0);
|
|
15
|
+
const [formState, setFormState] = useState({ nickname: defaultNickname || '' });
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (open && defaultNickname && !formState.nickname) {
|
|
19
|
+
setFormState(prev => ({ ...prev, nickname: defaultNickname }));
|
|
20
|
+
}
|
|
21
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
22
|
+
}, [open, defaultNickname]);
|
|
23
|
+
|
|
24
|
+
// ratings: [{ id, value_id }]
|
|
25
|
+
const [ratings, setRatings] = useState([]);
|
|
26
|
+
|
|
27
|
+
const handleRatingChange = (id, value_id) => {
|
|
28
|
+
setRatings(prev => {
|
|
29
|
+
const filtered = prev.filter(r => r.id !== id);
|
|
30
|
+
return [...filtered, { id, value_id }];
|
|
31
|
+
});
|
|
20
32
|
};
|
|
21
33
|
|
|
34
|
+
const handleChange = (field, value) => {
|
|
35
|
+
setFormState(prev => ({ ...prev, [field]: value }));
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const handleSubmit = (e) => {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
if (onSubmit) {
|
|
41
|
+
onSubmit({ ...formState, ratings });
|
|
42
|
+
}
|
|
43
|
+
};
|
|
22
44
|
|
|
23
45
|
return (
|
|
24
46
|
<>
|
|
@@ -35,106 +57,88 @@ const modalFormReview = (props) => {
|
|
|
35
57
|
<X size={24} color={primary900} />
|
|
36
58
|
</button>
|
|
37
59
|
</div>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
className="flex flex-col gap-y-3"
|
|
42
|
-
initialValues={{}}
|
|
43
|
-
onSubmit={() => { }}
|
|
44
|
-
onChange={() => { }}
|
|
45
|
-
>
|
|
46
|
-
<Field
|
|
47
|
-
id="nickname_field"
|
|
48
|
-
label={'Nickname'}
|
|
49
|
-
>
|
|
50
|
-
<TextInput
|
|
60
|
+
<form className="flex flex-col gap-y-3" onSubmit={handleSubmit}>
|
|
61
|
+
<Field id="nickname_field" label={'Nickname'}>
|
|
62
|
+
<input
|
|
51
63
|
id="nickname"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
name="nickname"
|
|
65
|
+
type="text"
|
|
66
|
+
required
|
|
67
|
+
readOnly
|
|
68
|
+
value={formState.nickname || ''}
|
|
69
|
+
onChange={e => handleChange('nickname', e.target.value)}
|
|
57
70
|
data-cy="nickname"
|
|
58
71
|
aria-label={'nickname'}
|
|
59
72
|
placeholder={'e.g John Doe'}
|
|
73
|
+
className="border border-gray-100 rounded px-3 py-2 bg-gray-50 cursor-not-allowed"
|
|
74
|
+
aria-readonly="true"
|
|
60
75
|
/>
|
|
61
76
|
</Field>
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
{/* Ratings breakdown from metadata */}
|
|
78
|
+
<div className="flex flex-col gap-y-3">
|
|
79
|
+
{loadingRatingsMetadata ? (
|
|
80
|
+
<div>Loading ratings...</div>
|
|
81
|
+
) : ratingsMetadata.length > 0 ? (
|
|
82
|
+
ratingsMetadata.map(rating => {
|
|
83
|
+
const selected = ratings.find(r => r.id === rating.id)?.value_id || '';
|
|
84
|
+
// Find value (1-5) for selected value_id
|
|
85
|
+
const selectedValue = rating.values.find(v => v.value_id === selected)?.value || '';
|
|
86
|
+
return (
|
|
87
|
+
<div key={rating.id} className="mb-2">
|
|
88
|
+
<label className="block mb-1 font-bold text-gray-700">{rating.name}</label>
|
|
89
|
+
<div className="flex items-center gap-1">
|
|
90
|
+
{[1,2,3,4,5].map(star => {
|
|
91
|
+
const valObj = rating.values.find(v => v.value === String(star));
|
|
92
|
+
if (!valObj) return null;
|
|
93
|
+
return (
|
|
94
|
+
<button
|
|
95
|
+
key={valObj.value_id}
|
|
96
|
+
type="button"
|
|
97
|
+
aria-label={`${star} star${star > 1 ? 's' : ''}`}
|
|
98
|
+
className={`focus:outline-none ${selectedValue == star ? 'text-yellow-400' : 'text-gray-300'}`}
|
|
99
|
+
onClick={() => handleRatingChange(rating.id, valObj.value_id)}
|
|
100
|
+
>
|
|
101
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill={selectedValue >= star ? '#F7C317' : '#D9D9D9'} viewBox="0 0 20 20" width="15" height="15">
|
|
102
|
+
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.286 3.967a1 1 0 00.95.69h4.175c.969 0 1.371 1.24.588 1.81l-3.38 2.455a1 1 0 00-.364 1.118l1.287 3.966c.3.922-.755 1.688-1.54 1.118l-3.38-2.454a1 1 0 00-1.175 0l-3.38 2.454c-.784.57-1.838-.196-1.54-1.118l1.287-3.966a1 1 0 00-.364-1.118L2.05 9.394c-.783-.57-.38-1.81.588-1.81h4.175a1 1 0 00.95-.69l1.286-3.967z" />
|
|
103
|
+
</svg>
|
|
104
|
+
</button>
|
|
105
|
+
);
|
|
106
|
+
})}
|
|
107
|
+
{/* <span className="ml-2 text-sm text-gray-600">{selectedValue || ''}</span> */}
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
})
|
|
112
|
+
) : null}
|
|
113
|
+
</div>
|
|
114
|
+
<Field id="summary_field" label={'Summary'}>
|
|
115
|
+
<input
|
|
75
116
|
id="summary"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
117
|
+
name="summary"
|
|
118
|
+
type="text"
|
|
119
|
+
required
|
|
120
|
+
value={formState.summary || ''}
|
|
121
|
+
onChange={e => handleChange('summary', e.target.value)}
|
|
81
122
|
data-cy="summary"
|
|
82
123
|
aria-label={'summary'}
|
|
83
124
|
placeholder={'Summary of your rating'}
|
|
125
|
+
className="border border-gray-100 rounded px-3 py-2"
|
|
84
126
|
/>
|
|
85
127
|
</Field>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
id="review_field"
|
|
89
|
-
label={'Review'}
|
|
90
|
-
>
|
|
91
|
-
<TextInput
|
|
128
|
+
<Field id="review_field" label={'Review'}>
|
|
129
|
+
<textarea
|
|
92
130
|
id="review"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
maskOnBlur={true}
|
|
131
|
+
name="review"
|
|
132
|
+
required
|
|
133
|
+
value={formState.review || ''}
|
|
134
|
+
onChange={e => handleChange('review', e.target.value)}
|
|
98
135
|
data-cy="review"
|
|
99
136
|
aria-label={'review'}
|
|
100
|
-
placeholder={'Let us know your
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<Field
|
|
105
|
-
id="like_reason_field"
|
|
106
|
-
label={'I like about'}
|
|
107
|
-
>
|
|
108
|
-
<TextInput
|
|
109
|
-
id="like_reason"
|
|
110
|
-
field="like_reason"
|
|
111
|
-
validate={isRequired}
|
|
112
|
-
validateOnBlur
|
|
113
|
-
mask={value => value && value.trim()}
|
|
114
|
-
maskOnBlur={true}
|
|
115
|
-
data-cy="like_reason"
|
|
116
|
-
aria-label={'like_reason'}
|
|
117
|
-
placeholder={'Summary of your rating'}
|
|
137
|
+
placeholder={'Let us know your thoughts'}
|
|
138
|
+
className="border border-gray-100 rounded px-3 py-2"
|
|
139
|
+
rows={3}
|
|
118
140
|
/>
|
|
119
141
|
</Field>
|
|
120
|
-
|
|
121
|
-
<Field
|
|
122
|
-
id="dont_like_reason_field"
|
|
123
|
-
label={"I dont't like about"}
|
|
124
|
-
>
|
|
125
|
-
<TextInput
|
|
126
|
-
id="dont_like_reason"
|
|
127
|
-
field="dont_like_reason"
|
|
128
|
-
validate={isRequired}
|
|
129
|
-
validateOnBlur
|
|
130
|
-
mask={value => value && value.trim()}
|
|
131
|
-
maskOnBlur={true}
|
|
132
|
-
data-cy="dont_like_reason"
|
|
133
|
-
aria-label={'dont_like_reason'}
|
|
134
|
-
placeholder={'Summary of your rating'}
|
|
135
|
-
/>
|
|
136
|
-
</Field>
|
|
137
|
-
|
|
138
142
|
<div className='actions flex justify-end gap-x-2.5 mt-4'>
|
|
139
143
|
<Button
|
|
140
144
|
priority='low'
|
|
@@ -142,6 +146,7 @@ const modalFormReview = (props) => {
|
|
|
142
146
|
content: 'capitalize text-[16px] font-medium'
|
|
143
147
|
}}
|
|
144
148
|
onClick={() => setOpen(false)}
|
|
149
|
+
type="button"
|
|
145
150
|
>
|
|
146
151
|
Cancel
|
|
147
152
|
</Button>
|
|
@@ -150,15 +155,17 @@ const modalFormReview = (props) => {
|
|
|
150
155
|
classes={{
|
|
151
156
|
content: 'capitalize text-[16px] font-medium'
|
|
152
157
|
}}
|
|
158
|
+
type="submit"
|
|
159
|
+
disabled={submitting}
|
|
153
160
|
>
|
|
154
|
-
Submit Review
|
|
161
|
+
{submitting ? 'Submitting...' : 'Submit Review'}
|
|
155
162
|
</Button>
|
|
156
163
|
</div>
|
|
157
|
-
</
|
|
164
|
+
</form>
|
|
158
165
|
</div>
|
|
159
166
|
</Modal>
|
|
160
167
|
</>
|
|
161
|
-
)
|
|
162
|
-
}
|
|
168
|
+
);
|
|
169
|
+
};
|
|
163
170
|
|
|
164
|
-
export default modalFormReview
|
|
171
|
+
export default modalFormReview;
|
package/src/overwrites/venia-ui/lib/components/ProductFullDetail/components/productReview.js
CHANGED
|
@@ -4,98 +4,139 @@ import { Star1 } from 'iconsax-react';
|
|
|
4
4
|
import Button from '../../Button';
|
|
5
5
|
import ModalFormReview from './modalFormReview';
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
|
|
7
9
|
const productReview = (props) => {
|
|
10
|
+
const {
|
|
11
|
+
className,
|
|
12
|
+
productReviewData,
|
|
13
|
+
loadingProductReview,
|
|
14
|
+
errorProductReview,
|
|
15
|
+
ratingsMetadataData,
|
|
16
|
+
loadingRatingsMetadata,
|
|
17
|
+
handleSubmitReview,
|
|
18
|
+
defaultNickname,
|
|
19
|
+
product
|
|
20
|
+
} = props;
|
|
8
21
|
|
|
9
|
-
const { className } = props;
|
|
10
22
|
const [open, setOpen] = useState(false);
|
|
11
23
|
const [filter, setFilter] = useState('All');
|
|
24
|
+
const [submitting, setSubmitting] = useState(false);
|
|
12
25
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
items
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
__typename: 'ProductRate',
|
|
29
|
-
id: 2,
|
|
30
|
-
name: 'Roger Taylor',
|
|
31
|
-
date: '25 January 2024',
|
|
32
|
-
rating: 2,
|
|
33
|
-
comment: 'Arrived late and packaging was damaged. Not satisfied.'
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
__typename: 'ProductRate',
|
|
37
|
-
id: 3,
|
|
38
|
-
name: 'Sarah Smith',
|
|
39
|
-
date: '02 February 2024',
|
|
40
|
-
rating: 4,
|
|
41
|
-
comment: 'Good product, but delivery could be faster.'
|
|
42
|
-
},
|
|
43
|
-
{
|
|
26
|
+
let reviewsData = null;
|
|
27
|
+
if (
|
|
28
|
+
productReviewData &&
|
|
29
|
+
productReviewData.products &&
|
|
30
|
+
productReviewData.products.items &&
|
|
31
|
+
productReviewData.products.items.length > 0
|
|
32
|
+
) {
|
|
33
|
+
const item = productReviewData.products.items[0];
|
|
34
|
+
const reviewItems = (item.reviews && item.reviews.items) || [];
|
|
35
|
+
reviewsData = {
|
|
36
|
+
__typename: 'ProductRates',
|
|
37
|
+
total_count: item.review_count || reviewItems.length,
|
|
38
|
+
items: reviewItems.map((r, idx) => ({
|
|
44
39
|
__typename: 'ProductRate',
|
|
45
|
-
id:
|
|
46
|
-
name:
|
|
47
|
-
date:
|
|
48
|
-
rating:
|
|
49
|
-
comment:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
comment: 'Excellent service and product quality! Will buy again.'
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
__typename: 'ProductRate',
|
|
61
|
-
id: 6,
|
|
62
|
-
name: 'David Lee',
|
|
63
|
-
date: '20 February 2024',
|
|
64
|
-
rating: 1,
|
|
65
|
-
comment: 'Item not as described. Very disappointed.'
|
|
40
|
+
id: idx + 1,
|
|
41
|
+
name: r.nickname,
|
|
42
|
+
date: r.created_at,
|
|
43
|
+
rating: r.average_rating ? Math.round(r.average_rating / 20) : (r.ratings_breakdown && r.ratings_breakdown[0] ? parseInt(r.ratings_breakdown[0].value) : 0),
|
|
44
|
+
comment: r.text || r.summary || '',
|
|
45
|
+
summary: r.summary || '',
|
|
46
|
+
productName: r.product?.name || '',
|
|
47
|
+
ratings_breakdown: r.ratings_breakdown || []
|
|
48
|
+
})),
|
|
49
|
+
page_info: productReviewData.products.page_info || {
|
|
50
|
+
total_pages: 1,
|
|
51
|
+
current_page: 1
|
|
66
52
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
__typename: 'SearchResultPageInfo',
|
|
70
|
-
total_pages: 1,
|
|
71
|
-
page_size: 10,
|
|
72
|
-
current_page: 1,
|
|
73
|
-
total_count: 6
|
|
74
|
-
}
|
|
75
|
-
};
|
|
53
|
+
};
|
|
54
|
+
}
|
|
76
55
|
|
|
56
|
+
if (!reviewsData || !reviewsData.items.length) {
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
<ModalFormReview
|
|
60
|
+
open={open}
|
|
61
|
+
setOpen={setOpen}
|
|
62
|
+
defaultNickname={defaultNickname}
|
|
63
|
+
ratingsMetadata={ratingsMetadataData?.productReviewRatingsMetadata?.items || []}
|
|
64
|
+
loadingRatingsMetadata={loadingRatingsMetadata}
|
|
65
|
+
onSubmit={async (formValues) => {
|
|
66
|
+
setSubmitting(true);
|
|
67
|
+
const input = {
|
|
68
|
+
nickname: formValues.nickname,
|
|
69
|
+
summary: formValues.summary,
|
|
70
|
+
text: formValues.review,
|
|
71
|
+
sku: product?.sku,
|
|
72
|
+
ratings: formValues.ratings
|
|
73
|
+
};
|
|
74
|
+
const result = await handleSubmitReview(input);
|
|
75
|
+
setSubmitting(false);
|
|
76
|
+
if (result.success) setOpen(false);
|
|
77
|
+
}}
|
|
78
|
+
submitting={submitting}
|
|
79
|
+
/>
|
|
80
|
+
<div className={className}>
|
|
81
|
+
<div className="flex items-center justify-between mb-6">
|
|
82
|
+
<div />
|
|
83
|
+
<Button
|
|
84
|
+
priority='low'
|
|
85
|
+
classes={{
|
|
86
|
+
content: 'normal-case font-normal text-base'
|
|
87
|
+
}}
|
|
88
|
+
onClick={() => setOpen(true)}
|
|
89
|
+
>
|
|
90
|
+
Write a review
|
|
91
|
+
</Button>
|
|
92
|
+
</div>
|
|
93
|
+
<div className="text-center py-8 text-gray-500">No reviews yet.</div>
|
|
94
|
+
</div>
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
77
98
|
|
|
78
|
-
const totalReviews =
|
|
99
|
+
const totalReviews = reviewsData.items.length;
|
|
79
100
|
const averageRating = totalReviews > 0
|
|
80
|
-
? (
|
|
101
|
+
? (reviewsData.items.reduce((sum, item) => sum + item.rating, 0) / totalReviews).toFixed(1)
|
|
81
102
|
: 0;
|
|
82
103
|
|
|
83
104
|
const starCounts = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };
|
|
84
|
-
|
|
105
|
+
reviewsData.items.forEach(item => {
|
|
85
106
|
if (starCounts[item.rating] !== undefined) {
|
|
86
107
|
starCounts[item.rating]++;
|
|
87
108
|
}
|
|
88
109
|
});
|
|
89
110
|
|
|
90
111
|
const getPercent = (count) => totalReviews > 0 ? Math.round((count / totalReviews) * 100) : 0;
|
|
91
|
-
|
|
112
|
+
|
|
92
113
|
const filteredReviews = filter === 'All'
|
|
93
|
-
?
|
|
94
|
-
:
|
|
114
|
+
? reviewsData.items
|
|
115
|
+
: reviewsData.items.filter(item => item.rating === parseInt(filter));
|
|
95
116
|
|
|
96
117
|
return (
|
|
97
118
|
<>
|
|
98
|
-
<ModalFormReview
|
|
119
|
+
<ModalFormReview
|
|
120
|
+
open={open}
|
|
121
|
+
setOpen={setOpen}
|
|
122
|
+
defaultNickname={defaultNickname}
|
|
123
|
+
ratingsMetadata={ratingsMetadataData?.productReviewRatingsMetadata?.items || []}
|
|
124
|
+
loadingRatingsMetadata={loadingRatingsMetadata}
|
|
125
|
+
onSubmit={async (formValues) => {
|
|
126
|
+
setSubmitting(true);
|
|
127
|
+
const input = {
|
|
128
|
+
nickname: formValues.nickname,
|
|
129
|
+
summary: formValues.summary,
|
|
130
|
+
text: formValues.review,
|
|
131
|
+
sku: product?.sku,
|
|
132
|
+
ratings: formValues.ratings
|
|
133
|
+
};
|
|
134
|
+
const result = await handleSubmitReview(input);
|
|
135
|
+
setSubmitting(false);
|
|
136
|
+
if (result.success) setOpen(false);
|
|
137
|
+
}}
|
|
138
|
+
submitting={submitting}
|
|
139
|
+
/>
|
|
99
140
|
<div className={className}>
|
|
100
141
|
<div className="w-full flex items-start xs_flex-col lg_flex-row gap-[30px]">
|
|
101
142
|
<div className="w-full xs_max-w-full lg_max-w-[365px] border border-[#E6E9EA] rounded-md p-6">
|
|
@@ -167,7 +208,7 @@ const productReview = (props) => {
|
|
|
167
208
|
{/* Reviews List */}
|
|
168
209
|
<div className='space-y-4 mb-6'>
|
|
169
210
|
<Review reviews={{
|
|
170
|
-
...
|
|
211
|
+
...reviewsData,
|
|
171
212
|
items: filteredReviews
|
|
172
213
|
}} />
|
|
173
214
|
</div>
|
|
@@ -57,7 +57,6 @@ const ERROR_FIELD_TO_MESSAGE_MAPPING = {
|
|
|
57
57
|
|
|
58
58
|
const ProductDetailsCollapsible = (props) => {
|
|
59
59
|
const { data } = props;
|
|
60
|
-
|
|
61
60
|
return (
|
|
62
61
|
<>
|
|
63
62
|
{data.map((_data) => (
|
|
@@ -99,7 +98,14 @@ const ProductFullDetail = props => {
|
|
|
99
98
|
productDetails,
|
|
100
99
|
customAttributes,
|
|
101
100
|
wishlistButtonProps,
|
|
102
|
-
sellerDetails
|
|
101
|
+
sellerDetails,
|
|
102
|
+
productReviewData,
|
|
103
|
+
loadingProductReview,
|
|
104
|
+
errorProductReview,
|
|
105
|
+
ratingsMetadataData,
|
|
106
|
+
loadingRatingsMetadata,
|
|
107
|
+
handleSubmitReview,
|
|
108
|
+
defaultNickname
|
|
103
109
|
} = talonProps;
|
|
104
110
|
|
|
105
111
|
const [, { addToast }] = useToasts();
|
|
@@ -493,7 +499,17 @@ const ProductFullDetail = props => {
|
|
|
493
499
|
{
|
|
494
500
|
id: 'product-reviews',
|
|
495
501
|
title: 'Reviews',
|
|
496
|
-
content: <ProductReviews
|
|
502
|
+
content: <ProductReviews
|
|
503
|
+
className={cn(contentContainerClass, classes.contentContainerTabOverride)}
|
|
504
|
+
productReviewData={productReviewData}
|
|
505
|
+
loadingProductReview={loadingProductReview}
|
|
506
|
+
errorProductReview={errorProductReview}
|
|
507
|
+
ratingsMetadataData={ratingsMetadataData}
|
|
508
|
+
loadingRatingsMetadata={loadingRatingsMetadata}
|
|
509
|
+
handleSubmitReview={handleSubmitReview}
|
|
510
|
+
defaultNickname={defaultNickname}
|
|
511
|
+
product={product}
|
|
512
|
+
/>
|
|
497
513
|
}
|
|
498
514
|
];
|
|
499
515
|
|
|
@@ -12,10 +12,27 @@ const PAGE_SIZE = 5;
|
|
|
12
12
|
// Custom RMA Page talon with page-based pagination
|
|
13
13
|
export const useRmaPage = (props = {}) => {
|
|
14
14
|
const { rmaId, orderNumber } = props;
|
|
15
|
-
const { getLofmpRmasQuery, getLofmpRmaDetailQuery, lofmpCreateRmaMutation } = operations;
|
|
15
|
+
const { getLofmpRmasQuery, getLofmpRmaDetailQuery, lofmpCreateRmaMutation, lofmpRmaShippingConfirmMutation, lofmpSendRmaMessageMutation } = operations;
|
|
16
|
+
|
|
17
|
+
// Mutation for sending RMA message
|
|
18
|
+
const [sendRmaMessageMutation, { data: sendRmaMessageData, error: sendRmaMessageError, loading: sendRmaMessageLoading }] = useMutation(lofmpSendRmaMessageMutation);
|
|
19
|
+
|
|
20
|
+
// Handler for sending RMA message
|
|
21
|
+
const sendRmaMessage = useCallback(async (input) => {
|
|
22
|
+
try {
|
|
23
|
+
const { data } = await sendRmaMessageMutation({ variables: { input } });
|
|
24
|
+
return { data, error: null };
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return { data: null, error };
|
|
27
|
+
}
|
|
28
|
+
}, [sendRmaMessageMutation]);
|
|
29
|
+
|
|
16
30
|
// Mutation for creating RMA
|
|
17
31
|
const [createRmaMutation, { data: createRmaData, error: createRmaError, loading: createRmaLoading }] = useMutation(lofmpCreateRmaMutation);
|
|
18
32
|
|
|
33
|
+
// Mutation for confirming shipping
|
|
34
|
+
const [confirmShippingMutation, { data: confirmShippingData, error: confirmShippingError, loading: confirmShippingLoading }] = useMutation(lofmpRmaShippingConfirmMutation);
|
|
35
|
+
|
|
19
36
|
// Handler for creating RMA
|
|
20
37
|
const createRma = useCallback(async (input) => {
|
|
21
38
|
try {
|
|
@@ -26,6 +43,16 @@ export const useRmaPage = (props = {}) => {
|
|
|
26
43
|
}
|
|
27
44
|
}, [createRmaMutation]);
|
|
28
45
|
|
|
46
|
+
// Handler for confirming shipping
|
|
47
|
+
const confirmShipping = useCallback(async (rma_id) => {
|
|
48
|
+
try {
|
|
49
|
+
const { data } = await confirmShippingMutation({ variables: { rma_id } });
|
|
50
|
+
return { data, error: null };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return { data: null, error };
|
|
53
|
+
}
|
|
54
|
+
}, [confirmShippingMutation]);
|
|
55
|
+
|
|
29
56
|
const [
|
|
30
57
|
,
|
|
31
58
|
{
|
|
@@ -47,7 +74,7 @@ export const useRmaPage = (props = {}) => {
|
|
|
47
74
|
variables: {
|
|
48
75
|
filter: orderNumber
|
|
49
76
|
? { order_number: orderNumber }
|
|
50
|
-
: (searchText ? {
|
|
77
|
+
: (searchText ? { order_number: searchText } : undefined),
|
|
51
78
|
pageSize,
|
|
52
79
|
currentPage
|
|
53
80
|
},
|
|
@@ -58,11 +85,13 @@ export const useRmaPage = (props = {}) => {
|
|
|
58
85
|
const {
|
|
59
86
|
data: rmaDetailData,
|
|
60
87
|
error: rmaDetailError,
|
|
61
|
-
loading: rmaDetailLoading
|
|
88
|
+
loading: rmaDetailLoading,
|
|
89
|
+
refetch: refetchRmaDetail
|
|
62
90
|
} = useQuery(getLofmpRmaDetailQuery, {
|
|
63
91
|
fetchPolicy: 'cache-and-network',
|
|
64
92
|
variables: { rmaId },
|
|
65
|
-
skip: !rmaId
|
|
93
|
+
skip: !rmaId,
|
|
94
|
+
pollInterval: 3000 // 1 detik auto-refresh
|
|
66
95
|
});
|
|
67
96
|
|
|
68
97
|
const rmasData = data && data.lofmpRmas ? data.lofmpRmas : undefined;
|
|
@@ -135,10 +164,15 @@ export const useRmaPage = (props = {}) => {
|
|
|
135
164
|
createRmaLoading,
|
|
136
165
|
createRmaError,
|
|
137
166
|
createRmaData,
|
|
138
|
-
|
|
167
|
+
confirmShipping,
|
|
168
|
+
confirmShippingLoading,
|
|
169
|
+
confirmShippingError,
|
|
170
|
+
confirmShippingData,
|
|
139
171
|
rmaDetail: rmaDetailData ? rmaDetailData.lofmpRmaDetail : undefined,
|
|
140
172
|
rmaDetailLoading,
|
|
141
|
-
rmaDetailError
|
|
173
|
+
rmaDetailError,
|
|
174
|
+
refetchRmaDetail
|
|
175
|
+
,sendRmaMessage, sendRmaMessageData, sendRmaMessageError, sendRmaMessageLoading
|
|
142
176
|
};
|
|
143
177
|
};
|
|
144
178
|
|