@riosst100/pwa-marketplace 2.9.5 → 2.9.7

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.
@@ -1,4 +1,6 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
+ import { useLocation, useHistory } from 'react-router-dom';
3
+ import { useRmaPage } from '@riosst100/pwa-marketplace/src/talons/RMAPage/useRmaPage';
2
4
  import { useIntl } from 'react-intl';
3
5
  import { StoreTitle } from '@magento/venia-ui/lib/components/Head';
4
6
  import Button from '@magento/venia-ui/lib/components/Button';
@@ -6,142 +8,278 @@ import ChatContent from '../LiveChat/chatContent';
6
8
  import cn from 'classnames';
7
9
  import { Send } from 'iconsax-react';
8
10
  import Item from './components/productItem';
11
+ import { useQuery } from '@apollo/client';
12
+ import { GET_LOFMP_RMA_CONFIGURATIONS } from '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/RMAPage/rmaPage.gql';
13
+ import { useToasts } from '@magento/peregrine/lib/Toasts';
14
+ import { CheckCircle as CheckCircleIcon, AlertCircle as AlertCircleIcon } from 'react-feather';
9
15
 
10
16
  const RMACreate = () => {
17
+ const location = useLocation();
18
+ const history = useHistory();
19
+ let order = location.state && location.state.order;
20
+ if (!order) {
21
+ try {
22
+ order = JSON.parse(localStorage.getItem('rma_order'));
23
+ } catch (e) {
24
+ order = undefined;
25
+ }
26
+ }
27
+
28
+ const {
29
+ createRma,
30
+ createRmaLoading,
31
+ createRmaError,
32
+ createRmaData
33
+ } = useRmaPage();
34
+
35
+ const [submitError, setSubmitError] = useState(null);
36
+ const [submitSuccess, setSubmitSuccess] = useState(null);
37
+ const [, { addToast }] = useToasts();
38
+
39
+ // State untuk setiap item yang di-checklist
40
+ const [itemReturnState, setItemReturnState] = useState({});
41
+
42
+ // Ambil konfigurasi RMA (reasons, conditions, resolutions)
43
+ const { data: rmaConfigData } = useQuery(GET_LOFMP_RMA_CONFIGURATIONS);
44
+
45
+ // Handler untuk update state per item
46
+ const handleItemChange = (itemId, field, value) => {
47
+ setItemReturnState(prev => ({
48
+ ...prev,
49
+ [itemId]: {
50
+ ...prev[itemId],
51
+ [field]: value
52
+ }
53
+ }));
54
+ };
55
+
56
+ // Handler untuk checklist item
57
+ const handleItemCheck = (itemId, checked) => {
58
+ setItemReturnState(prev => {
59
+ const current = prev[itemId] || {};
60
+ // Set default values when checked true
61
+ let defaults = {};
62
+ if (checked) {
63
+ defaults = {
64
+ qty_requested: current.qty_requested != null ? current.qty_requested : 1,
65
+ reason_id: '',
66
+ condition_id: '',
67
+ resolution_id: ''
68
+ };
69
+ }
70
+ return {
71
+ ...prev,
72
+ [itemId]: {
73
+ ...current,
74
+ ...defaults,
75
+ checked
76
+ }
77
+ };
78
+ });
79
+ };
80
+
81
+
82
+ // Check if at least one item is checked and all checked items have required fields
83
+ const checkedItems = Object.values(itemReturnState).filter(state => state && state.checked);
84
+ const isAllCheckedItemsValid =
85
+ checkedItems.length > 0 &&
86
+ checkedItems.every(state => {
87
+ return (
88
+ state.qty_requested &&
89
+ state.reason_id !== undefined && state.reason_id !== null && state.reason_id !== '' && state.reason_id !== 0 && state.reason_id !== "" &&
90
+ state.condition_id !== undefined && state.condition_id !== null && state.condition_id !== '' && state.condition_id !== 0 && state.condition_id !== "" &&
91
+ state.resolution_id !== undefined && state.resolution_id !== null && state.resolution_id !== '' && state.resolution_id !== 0 && state.resolution_id !== ""
92
+ );
93
+ });
94
+
95
+ // Build input mutation sesuai struktur backend
96
+ const buildRmaInput = () => {
97
+ if (!order || !order.items) return null;
98
+ // Ambil shipping address
99
+ const shipping = order.shipping_address || {};
100
+ // Ambil item yang dicentang dan sudah diisi field wajib
101
+ const cfg = rmaConfigData && rmaConfigData.lofmpRmaConfigurations;
102
+ const defReason = cfg && cfg.reasons && cfg.reasons[0] ? cfg.reasons[0].id : 0;
103
+ const defCondition = cfg && cfg.conditions && cfg.conditions[0] ? cfg.conditions[0].id : 0;
104
+ const defResolution = cfg && cfg.resolutions && cfg.resolutions[0] ? cfg.resolutions[0].id : 0;
105
+ const items = order.items
106
+ .filter(it => itemReturnState[it.id] && itemReturnState[it.id].checked)
107
+ .map(it => {
108
+ const st = itemReturnState[it.id] || {};
109
+ let condition_id = parseInt(st.condition_id, 10);
110
+ let qty_requested = parseFloat(st.qty_requested);
111
+ let reason_id = parseInt(st.reason_id, 10);
112
+ let resolution_id = parseInt(st.resolution_id, 10);
113
+ if (isNaN(condition_id)) condition_id = defCondition;
114
+ if (isNaN(qty_requested) || qty_requested <= 0) qty_requested = 1;
115
+ if (isNaN(reason_id)) reason_id = defReason;
116
+ if (isNaN(resolution_id)) resolution_id = defResolution;
117
+ return {
118
+ order_item_id: it.id,
119
+ condition_id,
120
+ qty_requested,
121
+ reason_id,
122
+ resolution_id
123
+ };
124
+ });
125
+ if (!items.length) return null;
126
+ return {
127
+ order_number: order.number || order.increment_id,
128
+ items,
129
+ city: shipping.city,
130
+ country_id: shipping.country_code,
131
+ postcode: shipping.postcode,
132
+ region: shipping.region,
133
+ street: Array.isArray(shipping.street) ? shipping.street.join(' ') : shipping.street
134
+ };
135
+ };
136
+
137
+ const handleSubmit = async () => {
138
+ setSubmitError(null);
139
+ setSubmitSuccess(null);
140
+ const input = buildRmaInput();
141
+ if (!input) {
142
+ setSubmitError('Pilih minimal 1 item dan lengkapi data.');
143
+ return;
144
+ }
145
+
146
+ const { data, error } = await createRma(input);
147
+ if (error) {
148
+ const message = error.message || 'Failed to create RMA.';
149
+ setSubmitError(message);
150
+ addToast({
151
+ type: 'error',
152
+ icon: <AlertCircleIcon size={18} />,
153
+ message,
154
+ dismissable: true,
155
+ timeout: 6000
156
+ });
157
+ return;
158
+ }
159
+ const payload = data && data.lofmpCreateRma;
160
+ if (payload && payload.success) {
161
+ const message = 'RMA request created successfully!';
162
+ setSubmitSuccess(message);
163
+ addToast({
164
+ type: 'success',
165
+ icon: <CheckCircleIcon size={18} />,
166
+ message,
167
+ dismissable: true,
168
+ timeout: 4000
169
+ });
170
+ // Redirect to RMA detail page after brief delay
171
+ const rmaId = payload.rma_id || (payload.rma && payload.rma.id);
172
+ if (rmaId) {
173
+ setTimeout(() => {
174
+ history.push(`/return/view/${rmaId}`);
175
+ }, 400);
176
+ }
177
+ } else {
178
+ const message = (payload && payload.message) || 'Failed to create RMA.';
179
+ setSubmitError(message);
180
+ addToast({
181
+ type: 'error',
182
+ icon: <AlertCircleIcon size={18} />,
183
+ message,
184
+ dismissable: true,
185
+ timeout: 6000
186
+ });
187
+ }
188
+ };
11
189
  const { formatMessage } = useIntl();
12
190
  const PAGE_TITLE = formatMessage({
13
191
  id: 'Quotes.pageTitleTextRMACreate',
14
- defaultMessage: 'New Return'
192
+ defaultMessage: 'New Return For Order'
15
193
  });
16
194
 
17
- const urlImage = 'https://pwa-tcgcollective.local:8255/media/catalog/product/s/-/s-l1600_6__1.jpg?auto=webp&format=pjpg&width=495&height=618.75&fit=cover';
18
- const dummyChat = [
19
- {
20
- "message": "May I help you",
21
- "type": "seller",
22
- "timeStamp": "03-06-2024 2:59 pm"
23
- },
24
- {
25
- "message": "Yes",
26
- "type": "buyer",
27
- "timeStamp": "03-06-2024 2:59 pm"
28
- },
29
- {
30
- "message": "can i get a discount",
31
- "type": "buyer",
32
- "timeStamp": "03-06-2024 2:59 pm"
33
- },
34
- {
35
- "message": "you can redeem this code 'JunePlay'",
36
- "type": "seller",
37
- "timeStamp": "03-06-2024 2:59 pm"
38
- },
39
- {
40
- "message": "or this code 'collectfest'",
41
- "type": "seller",
42
- "timeStamp": "03-06-2024 2:59 pm"
43
- },
44
- {
45
- "message": "May I help you",
46
- "type": "seller",
47
- "timeStamp": "03-06-2024 2:59 pm"
48
- },
49
- {
50
- "message": "Yes",
51
- "type": "buyer",
52
- "timeStamp": "03-06-2024 2:59 pm"
53
- },
54
- {
55
- "message": "can i get a discount",
56
- "type": "buyer",
57
- "timeStamp": "03-06-2024 2:59 pm"
58
- },
59
- {
60
- "message": "you can redeem this code 'JunePlay'",
61
- "type": "seller",
62
- "timeStamp": "03-06-2024 2:59 pm"
63
- },
64
- {
65
- "message": "or this code 'collectfest'",
66
- "type": "seller",
67
- "timeStamp": "03-06-2024 2:59 pm"
68
- },
69
- ]
195
+ // const dummyChat = [
196
+ // {
197
+ // "message": "May I help you",
198
+ // "type": "seller",
199
+ // "timeStamp": "03-06-2024 2:59 pm"
200
+ // },
201
+ // {
202
+ // "message": "Yes",
203
+ // "type": "buyer",
204
+ // "timeStamp": "03-06-2024 2:59 pm"
205
+ // },
206
+ // {
207
+ // "message": "can i get a discount",
208
+ // "type": "buyer",
209
+ // "timeStamp": "03-06-2024 2:59 pm"
210
+ // },
211
+ // {
212
+ // "message": "you can redeem this code 'JunePlay'",
213
+ // "type": "seller",
214
+ // "timeStamp": "03-06-2024 2:59 pm"
215
+ // },
216
+ // {
217
+ // "message": "or this code 'collectfest'",
218
+ // "type": "seller",
219
+ // "timeStamp": "03-06-2024 2:59 pm"
220
+ // },
221
+ // {
222
+ // "message": "May I help you",
223
+ // "type": "seller",
224
+ // "timeStamp": "03-06-2024 2:59 pm"
225
+ // },
226
+ // {
227
+ // "message": "Yes",
228
+ // "type": "buyer",
229
+ // "timeStamp": "03-06-2024 2:59 pm"
230
+ // },
231
+ // {
232
+ // "message": "can i get a discount",
233
+ // "type": "buyer",
234
+ // "timeStamp": "03-06-2024 2:59 pm"
235
+ // },
236
+ // {
237
+ // "message": "you can redeem this code 'JunePlay'",
238
+ // "type": "seller",
239
+ // "timeStamp": "03-06-2024 2:59 pm"
240
+ // },
241
+ // {
242
+ // "message": "or this code 'collectfest'",
243
+ // "type": "seller",
244
+ // "timeStamp": "03-06-2024 2:59 pm"
245
+ // },
246
+ // ]
70
247
 
71
248
  return (
72
249
  <div className='relative grid gap-y-md'>
73
250
  <StoreTitle>{PAGE_TITLE}</StoreTitle>
74
251
  <div aria-live="polite" className="text-xl font-medium text-left">
75
- {PAGE_TITLE} - DEV123123123
252
+ {PAGE_TITLE} {order ? `- #${order.number || order.increment_id}` : ''}
76
253
  </div>
77
254
  <div className='block relative'>
78
255
  <div aria-live="polite" className="text-lg font-medium text-left mb-4">
79
256
  {
80
257
  formatMessage({
81
258
  id: 'RMA.requestReturnInformation',
82
- defaultMessage: 'Request Return Information'
259
+ defaultMessage: 'Order Information'
83
260
  })
84
261
  }
85
262
  </div>
86
263
  <div className='rounded-md border border-gray-100 px-4 py-6 flex flex-col md_flex-row justify-between gap-x-10'>
87
264
  <div className='flex flex-col gap-y-4 w-full mb-4 md_0 md_w-6/12'>
88
- <div className='block p-2 -ml-2 -mr-2 bg-[#F1EFF6] rounded-md'>
89
- <p className='text-[13px] text-blue-700 flex justify-between'>
90
- <span className='font-medium block'>
91
- {
92
- formatMessage({
93
- id: 'RMA.Status',
94
- defaultMessage: 'Status'
95
- })
96
- }
97
- </span>
98
- <span className='font-medium block text-blue-700'>
99
- Pending Approval
100
- </span>
101
- </p>
102
- </div>
103
- <div className='block'>
104
- <p className='text-[13px] text-colorDefault flex justify-between'>
105
- <span className='font-medium block'>
106
- {
107
- formatMessage({
108
- id: 'RMA.RMANumber',
109
- defaultMessage: 'RMA'
110
- })
111
- }
112
- </span>
113
- <span className='font-normal block'>
114
- DEV123123123-12
115
- </span>
116
- </p>
117
- </div>
118
265
  <div className='block'>
119
266
  <p className='text-[13px] text-colorDefault flex justify-between'>
120
267
  <span className='font-medium block'>
121
- {
122
- formatMessage({
123
- id: 'RMA.OrderNumber',
124
- defaultMessage: 'Order Number'
125
- })
126
- }
268
+ {formatMessage({ id: 'RMA.OrderNumber', defaultMessage: 'Order Number' })}
127
269
  </span>
128
270
  <span className='font-normal block'>
129
- DEV123123123 at Nov 8, 2024
271
+ {order ? order.number || order.increment_id : '-'}
272
+ {order && order.order_date ? ` at ${new Date(order.order_date.replace(' ', 'T')).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })}` : ''}
130
273
  </span>
131
274
  </p>
132
275
  </div>
133
276
  <div className='block'>
134
277
  <p className='text-[13px] text-colorDefault flex justify-between'>
135
278
  <span className='font-medium block'>
136
- {
137
- formatMessage({
138
- id: 'RMA.dateRequested',
139
- defaultMessage: 'Date Requested'
140
- })
141
- }
279
+ {formatMessage({ id: 'RMA.dateRequested', defaultMessage: 'Date Requested' })}
142
280
  </span>
143
281
  <span className='font-normal block'>
144
- Nov 17, 2024
282
+ {new Date().toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })}
145
283
  </span>
146
284
  </p>
147
285
  </div>
@@ -159,29 +297,71 @@ const RMACreate = () => {
159
297
  </span>
160
298
  </p>
161
299
  <p className='text-[13px] text-colorDefault whitespace-pre-wrap'>
162
- John Doe{'\n'}
163
- johndoe@email.com{'\n'}
164
- 1233123412{'\n'}
165
- 6164 Honey Bluff Parkway{'\n'}
166
- Calder{'\n'}
167
- Michigan{'\n'}
168
- UnitedState{'\n'}
300
+ {order && order.shipping_address ? (
301
+ <>
302
+ {order.shipping_address.firstname} {order.shipping_address.lastname}{'\n'}
303
+ {order.shipping_address.telephone}{'\n'}
304
+ {order.shipping_address.street && Array.isArray(order.shipping_address.street) ? order.shipping_address.street.join(', ') : order.shipping_address.street}{'\n'}
305
+ {order.shipping_address.city}{order.shipping_address.region ? ', ' + order.shipping_address.region : ''}{'\n'}
306
+ {order.shipping_address.postcode}{'\n'}
307
+ {order.shipping_address.country_code}
308
+ </>
309
+ ) : (
310
+ <>
311
+ -
312
+ </>
313
+ )}
169
314
  </p>
170
315
  </div>
171
316
  </div>
172
317
  </div>
173
318
  </div>
174
319
  <div className=' flex flex-col'>
175
- <div aria-live="polite" className="text-lg font-medium text-left mb-4">
176
- Items
320
+ <div aria-live="polite" className="text-lg font-medium text-left mb-1">
321
+ Select Items to Return
322
+ </div>
323
+ <div className="text-[13px] text-gray-500 mb-3">
324
+ Please check the items you want to return.
177
325
  </div>
178
326
  <div className='border-t border-gray-100 py-4 flex flex-col gap-y-4'>
179
- {[...Array(2)].map((item) => (
180
- <Item withCheckbox />
181
- ))}
327
+ {order && order.items && order.items.length > 0 ? (
328
+ order.items.map((item, idx) => (
329
+ <Item
330
+ key={item.id || idx}
331
+ item={item}
332
+ order={order}
333
+ withCheckbox
334
+ rmaConfigData={rmaConfigData}
335
+ itemState={itemReturnState[item.id] || {}}
336
+ onItemChange={(field, value) => handleItemChange(item.id, field, value)}
337
+ onItemCheck={checked => handleItemCheck(item.id, checked)}
338
+ />
339
+ ))
340
+ ) : (
341
+ <span className='text-gray-400'>No items found.</span>
342
+ )}
182
343
  </div>
183
344
  </div>
184
- <div className=' flex flex-col mb-10'>
345
+ <div className='flex justify-end flex-row mb-4'>
346
+ <Button
347
+ priority='high'
348
+ onClick={handleSubmit}
349
+ disabled={createRmaLoading || !isAllCheckedItemsValid}
350
+ className={cn(
351
+ 'px-6 py-2 rounded-full text-white border flex items-center gap-2',
352
+ createRmaLoading || !isAllCheckedItemsValid
353
+ ? 'bg-gray-400 border-gray-400 cursor-not-allowed'
354
+ : 'bg-blue-700 border-blue-700 hover_bg-blue-700 hover_border-blue-700',
355
+ 'focus-visible_outline-none'
356
+ )}
357
+ >
358
+ {createRmaLoading && (
359
+ <span className="inline-block h-4 w-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
360
+ )}
361
+ {createRmaLoading ? 'Submitting...' : 'Submit Return Request'}
362
+ </Button>
363
+ </div>
364
+ {/* <div className=' flex flex-col mb-10'>
185
365
  <div aria-live="polite" className="text-lg font-medium text-left mb-4">
186
366
  Messages
187
367
  </div>
@@ -211,7 +391,7 @@ const RMACreate = () => {
211
391
  </Button>
212
392
  </div>
213
393
  </div>
214
- </div>
394
+ </div> */}
215
395
  <style jsx="true">
216
396
  {`
217
397
  .chat-container::-webkit-scrollbar {