@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,127 +1,211 @@
1
- import React from 'react';
1
+ import React, { useMemo, useRef, useCallback, useEffect, useState } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { StoreTitle } from '@magento/venia-ui/lib/components/Head';
4
4
  import Image from '@magento/venia-ui/lib/components/Image';
5
- import { Link } from 'react-router-dom';
5
+ import { Link, useParams } from 'react-router-dom';
6
6
  import Button from '@magento/venia-ui/lib/components/Button';
7
7
  import ChatContent from '../LiveChat/chatContent';
8
8
  import cn from 'classnames';
9
9
  import { Send, Printer } from 'iconsax-react';
10
- import Item from './components/productItem';
10
+ import useRmaPage from '@riosst100/pwa-marketplace/src/talons/RMAPage/useRmaPage';
11
+ import { useToasts } from '@magento/peregrine/lib/Toasts';
12
+ import { CheckCircle as CheckCircleIcon } from 'react-feather';
11
13
 
12
14
  const RMADetail = () => {
13
15
  const { formatMessage } = useIntl();
16
+ const { urlKey } = useParams();
17
+ const rmaId = urlKey;
18
+ const {
19
+ rmaDetail,
20
+ rmaDetailLoading,
21
+ rmaDetailError,
22
+ confirmShipping,
23
+ confirmShippingLoading,
24
+ confirmShippingError,
25
+ confirmShippingData,
26
+ refetchRmaDetail,
27
+ sendRmaMessage,
28
+ sendRmaMessageLoading,
29
+ sendRmaMessageError,
30
+ sendRmaMessageData
31
+ } = useRmaPage({ rmaId });
32
+ const [, { addToast }] = useToasts();
33
+ // State untuk input chat
34
+ const [chatInput, setChatInput] = useState('');
35
+ const [chatSending, setChatSending] = useState(false);
36
+ // Handler kirim pesan chat
37
+ const handleSendChat = useCallback(async () => {
38
+ if (!chatInput.trim()) return;
39
+ setChatSending(true);
40
+ const input = {
41
+ rma_id: rmaId,
42
+ text: chatInput.trim()
43
+ };
44
+ const { data, error } = await sendRmaMessage(input);
45
+ setChatSending(false);
46
+ if (error || !data?.lofmpSendRmaMessage?.success) {
47
+ addToast({
48
+ type: 'error',
49
+ message: (data?.lofmpSendRmaMessage?.message || error?.message || 'Failed to send message'),
50
+ dismissable: true,
51
+ timeout: 4000
52
+ });
53
+ return;
54
+ }
55
+ setChatInput('');
56
+ if (typeof refetchRmaDetail === 'function') refetchRmaDetail();
57
+ }, [chatInput, rmaId, sendRmaMessage, addToast, refetchRmaDetail]);
14
58
  const PAGE_TITLE = formatMessage({
15
59
  id: 'Quotes.pageTitleTextRMADetail',
16
60
  defaultMessage: 'Return Detail'
17
61
  });
18
62
 
19
- 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';
20
- const dummyChat = [
21
- {
22
- "message": "May I help you",
23
- "type": "seller",
24
- "timeStamp": "03-06-2024 2:59 pm"
25
- },
26
- {
27
- "message": "Yes",
28
- "type": "buyer",
29
- "timeStamp": "03-06-2024 2:59 pm"
30
- },
31
- {
32
- "message": "can i get a discount",
33
- "type": "buyer",
34
- "timeStamp": "03-06-2024 2:59 pm"
35
- },
36
- {
37
- "message": "you can redeem this code 'JunePlay'",
38
- "type": "seller",
39
- "timeStamp": "03-06-2024 2:59 pm"
40
- },
41
- {
42
- "message": "or this code 'collectfest'",
43
- "type": "seller",
44
- "timeStamp": "03-06-2024 2:59 pm"
45
- },
46
- {
47
- "message": "May I help you",
48
- "type": "seller",
49
- "timeStamp": "03-06-2024 2:59 pm"
50
- },
51
- {
52
- "message": "Yes",
53
- "type": "buyer",
54
- "timeStamp": "03-06-2024 2:59 pm"
55
- },
56
- {
57
- "message": "can i get a discount",
58
- "type": "buyer",
59
- "timeStamp": "03-06-2024 2:59 pm"
60
- },
61
- {
62
- "message": "you can redeem this code 'JunePlay'",
63
- "type": "seller",
64
- "timeStamp": "03-06-2024 2:59 pm"
65
- },
66
- {
67
- "message": "or this code 'collectfest'",
68
- "type": "seller",
69
- "timeStamp": "03-06-2024 2:59 pm"
70
- },
71
- ]
63
+ const chatData = useMemo(() => {
64
+ const messages = (rmaDetail && rmaDetail.messages) ? rmaDetail.messages : [];
65
+ const email = rmaDetail && rmaDetail.shipping_address && rmaDetail.shipping_address.email;
66
+ const mapped = messages.map(m => ({
67
+ message: m.text,
68
+ type: email && m.sender_email === email ? 'buyer' : 'seller',
69
+ timeStamp: m.created_at,
70
+ senderName: m.sender_name || ''
71
+ }));
72
+ return mapped.length > 0 ? mapped : dummyChat;
73
+ }, [rmaDetail]);
74
+
75
+ const formatted = useMemo(() => {
76
+ if (!rmaDetail) return {};
77
+ const toDate = (d) => {
78
+ if (!d) return '';
79
+ const iso = d.replace(' ', 'T');
80
+ const dt = new Date(iso);
81
+ if (isNaN(dt.getTime())) return d;
82
+ return dt.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
83
+ };
84
+ return {
85
+ status: rmaDetail.status_label || rmaDetail.status,
86
+ increment_id: rmaDetail.increment_id || rmaDetail.increment_id,
87
+ rmaNumber: rmaDetail.increment_id || rmaDetail.rma_id,
88
+ orderNumber: rmaDetail.order && rmaDetail.order.increment_id ? rmaDetail.order.increment_id : '-',
89
+ orderDate: rmaDetail.order && rmaDetail.order.created_at ? toDate(rmaDetail.order.created_at) : '',
90
+ dateRequested: rmaDetail.rma_date ? toDate(rmaDetail.rma_date) : '',
91
+ shipping: rmaDetail.shipping_address,
92
+ items: rmaDetail.items || [],
93
+ rawStatus: rmaDetail.status_label,
94
+ };
95
+ }, [rmaDetail]);
96
+ // Use same in-page print approach as OrderDetail: CSS hides everything except .print-area
97
+ const printRef = useRef(null);
98
+ const handlePrint = useCallback(() => {
99
+ const styleId = 'rma-detail-print-style';
100
+ let style = document.getElementById(styleId);
101
+ if (!style) {
102
+ style = document.createElement('style');
103
+ style.id = styleId;
104
+ style.type = 'text/css';
105
+ style.media = 'print';
106
+ style.appendChild(document.createTextNode(`
107
+ @page { size: A4; margin: 0; }
108
+ @media print {
109
+ body { margin: 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
110
+ body * { visibility: hidden !important; }
111
+ .print-area, .print-area * { visibility: visible !important; }
112
+ .print-area { position: relative; left: 0; top: -20px; width: 100%; }
113
+ .no-print { display: none !important; }
114
+ }
115
+ `));
116
+ document.head.appendChild(style);
117
+ }
118
+ window.print();
119
+ }, []);
120
+
121
+ // Show toast and refetch on confirm shipping success
122
+ useEffect(() => {
123
+ if (
124
+ confirmShippingData &&
125
+ confirmShippingData.lofmpRmaShippingConfirm &&
126
+ confirmShippingData.lofmpRmaShippingConfirm.success
127
+ ) {
128
+ const message = confirmShippingData.lofmpRmaShippingConfirm.message || 'Shipping confirmed!';
129
+ addToast({
130
+ type: 'success',
131
+ icon: <CheckCircleIcon size={18} />,
132
+ message,
133
+ dismissable: true,
134
+ timeout: 4000
135
+ });
136
+ if (typeof refetchRmaDetail === 'function') refetchRmaDetail();
137
+ }
138
+ }, [confirmShippingData, refetchRmaDetail, addToast]);
72
139
 
73
140
  return (
74
- <div className='relative grid gap-y-md'>
141
+ <div className='print-area relative grid gap-y-md' ref={printRef}>
75
142
  <StoreTitle>{PAGE_TITLE}</StoreTitle>
76
143
  <div aria-live="polite" className="text-xl font-medium text-left">
77
- {PAGE_TITLE} - DEV123123123
144
+ {PAGE_TITLE} {formatted.increment_id ? `#${formatted.increment_id}` : ''}
78
145
  </div>
79
146
  <div className='block relative'>
80
- <div className='flex gap-x-4 justify-end mb-2'>
81
- <Button
82
- priority='high'
83
- classes={{
84
- content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
85
- }}
86
- className={cn(
87
- "bg-white px-6 py-2 rounded-md text-gray-900 hover_!text-white border border-solid",
88
- "border-gray-900 focus-visible_outline-none hover_bg-gray-900"
89
- )}
90
- >
91
- <span className='flex gap-x-3 justify-center group-hover_!text-white'>
92
- <Printer
93
- size="24"
94
- className=''
95
- />
96
- {
97
- formatMessage({
98
- id: 'RMA.printRMAPackingSlip',
99
- defaultMessage: 'Print RMA Packing Slip'
100
- })
101
- }
102
- </span>
103
- </Button>
147
+ {(formatted.rawStatus === 'Approved' || formatted.rawStatus === 'approved') && (
148
+ <div className='flex flex-col gap-y-2 mb-2 no-print'>
149
+ <div className='flex gap-x-4 justify-end'>
150
+ <Button
151
+ priority='high'
152
+ classes={{
153
+ content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
154
+ }}
155
+ className={cn(
156
+ "bg-white px-6 py-2 rounded-md text-gray-900 hover_!text-white border border-solid",
157
+ "border-gray-900 focus-visible_outline-none hover_bg-gray-900"
158
+ )}
159
+ onClick={handlePrint}
160
+ >
161
+ <span className='flex gap-x-3 justify-center group-hover_!text-white'>
162
+ <Printer
163
+ size="24"
164
+ className=''
165
+ />
166
+ {
167
+ formatMessage({
168
+ id: 'RMA.printRMAPackingSlip',
169
+ defaultMessage: 'Print RMA Packing Slip'
170
+ })
171
+ }
172
+ </span>
173
+ </Button>
104
174
 
105
- <Button
106
- priority='high'
107
- classes={{
108
- content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
109
- }}
110
- className={cn(
111
- "bg-blue-600 px-6 py-2 rounded-md text-white border ",
112
- "border-blue-600 hover_bg-blue-700 hover_border-blue-700 focus-visible_outline-none"
175
+ <Button
176
+ priority='high'
177
+ classes={{
178
+ content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
179
+ }}
180
+ className={cn(
181
+ "bg-blue-600 px-6 py-2 rounded-md text-white border ",
182
+ "border-blue-600 hover_bg-blue-700 hover_border-blue-700 focus-visible_outline-none"
183
+ )}
184
+ onClick={async () => {
185
+ if (!confirmShippingLoading) await confirmShipping(Number(rmaId));
186
+ }}
187
+ disabled={confirmShippingLoading}
188
+ >
189
+ <span className='flex gap-x-3 justify-center'>
190
+ {confirmShippingLoading
191
+ ? formatMessage({ id: 'RMA.confirmShippingLoading', defaultMessage: 'Processing...' })
192
+ : formatMessage({ id: 'RMA.confirmShipping', defaultMessage: 'Confirm Shipping' })
193
+ }
194
+ </span>
195
+ </Button>
196
+ </div>
197
+ {confirmShippingError && (
198
+ <div className='text-[13px] text-red-600 text-right'>
199
+ {confirmShippingError.message}
200
+ </div>
113
201
  )}
114
- >
115
- <span className='flex gap-x-3 justify-center'>
116
- {
117
- formatMessage({
118
- id: 'RMA.confirmShipping',
119
- defaultMessage: 'Confirm Shipping'
120
- })
121
- }
122
- </span>
123
- </Button>
124
- </div>
202
+ {confirmShippingData && confirmShippingData.lofmpRmaShippingConfirm && !confirmShippingData.lofmpRmaShippingConfirm.success && (
203
+ <div className='text-[13px] text-red-600 text-right'>
204
+ {confirmShippingData.lofmpRmaShippingConfirm.message}
205
+ </div>
206
+ )}
207
+ </div>
208
+ )}
125
209
  <div aria-live="polite" className="text-lg font-medium text-left mb-4">
126
210
  {
127
211
  formatMessage({
@@ -138,12 +222,12 @@ const RMADetail = () => {
138
222
  {
139
223
  formatMessage({
140
224
  id: 'RMA.Status',
141
- defaultMessage: 'Status'
225
+ defaultMessage: 'Status Return'
142
226
  })
143
227
  }
144
228
  </span>
145
229
  <span className='font-medium block text-blue-700'>
146
- Pending Approval
230
+ {formatted.status || '-'}
147
231
  </span>
148
232
  </p>
149
233
  </div>
@@ -158,7 +242,7 @@ const RMADetail = () => {
158
242
  }
159
243
  </span>
160
244
  <span className='font-normal block'>
161
- DEV123123123-12
245
+ {formatted.rmaNumber || '-'}
162
246
  </span>
163
247
  </p>
164
248
  </div>
@@ -173,7 +257,7 @@ const RMADetail = () => {
173
257
  }
174
258
  </span>
175
259
  <span className='font-normal block'>
176
- DEV123123123 at Nov 8, 2024
260
+ {`${formatted.orderNumber || '-'}${formatted.orderDate ? ` at ${formatted.orderDate}` : ''}`}
177
261
  </span>
178
262
  </p>
179
263
  </div>
@@ -188,7 +272,7 @@ const RMADetail = () => {
188
272
  }
189
273
  </span>
190
274
  <span className='font-normal block'>
191
- Nov 17, 2024
275
+ {formatted.dateRequested || '-'}
192
276
  </span>
193
277
  </p>
194
278
  </div>
@@ -206,49 +290,20 @@ const RMADetail = () => {
206
290
  </span>
207
291
  </p>
208
292
  <p className='text-[13px] text-colorDefault whitespace-pre-wrap'>
209
- John Doe{'\n'}
210
- johndoe@email.com{'\n'}
211
- 1233123412{'\n'}
212
- 6164 Honey Bluff Parkway{'\n'}
213
- Calder{'\n'}
214
- Michigan{'\n'}
215
- UnitedState{'\n'}
293
+ {
294
+ formatted.shipping
295
+ ? `${formatted.shipping.firstname || ''} ${formatted.shipping.lastname || ''}\n` +
296
+ `${formatted.shipping.email || ''}\n` +
297
+ `${formatted.shipping.telephone || ''}\n` +
298
+ `${formatted.shipping.street || ''}\n` +
299
+ `${formatted.shipping.city || ''}\n` +
300
+ `${formatted.shipping.region || ''}\n` +
301
+ `${formatted.shipping.country_id || ''}\n`
302
+ : ''
303
+ }
216
304
  </p>
217
305
  </div>
218
306
  </div>
219
- {/* <div className='relative flex w-full md_w-6/12 justify-center flex-col mb-10 md_mb-0'>
220
- <Image
221
- alt='product image'
222
- className="relative max-w-[300px]"
223
- src={urlImage}
224
- classes={{
225
- root: ' relative self-center mb-5'
226
- }}
227
- />
228
-
229
- <p className='text-[16px] font-medium text-colorDefault text-center'>
230
- $60.00
231
- </p>
232
-
233
- <Link to="/pop-mart-star-wars-series-blind-box-confirmed-figures-designer-art-new-toys-gift.html" className="max-w-[360px] self-center mb-5">
234
- <span className=" text-[13px] block text-center font-medium text-colorDefault w-full">
235
- POP MART Star Wars Series Blind Box Confirmed Figures Designer Art New Toys Gift
236
- </span>
237
- </Link>
238
- <Button
239
- priority='high'
240
- classes={{
241
- content: 'capitalize text-[16px] font-semibold'
242
- }}
243
- >
244
- {
245
- formatMessage({
246
- id: 'Quotes.addToCart',
247
- defaultMessage: 'Add To Cart'
248
- })
249
- }
250
- </Button>
251
- </div> */}
252
307
  </div>
253
308
  </div>
254
309
  <div className=' flex flex-col'>
@@ -256,23 +311,50 @@ const RMADetail = () => {
256
311
  Items
257
312
  </div>
258
313
  <div className='border-t border-gray-100 py-4 flex flex-col gap-y-4'>
259
- {[...Array(2)].map((item) => (
260
- <Item />
314
+ {!rmaDetailLoading && formatted.items && formatted.items.length === 0 && (
315
+ <div className='text-[13px] text-colorDefault'>No items</div>
316
+ )}
317
+ {!rmaDetailLoading && formatted.items && formatted.items.map((it, idx) => (
318
+ <div key={it.id || idx} className='flex gap-4 items-start'>
319
+ <div className='w-[70px] h-[70px] overflow-hidden rounded-md bg-gray-50 flex items-center justify-center'>
320
+ {it.image_url ? (
321
+ <img src={it.image_url} alt={it.name} width={70} height={70} />
322
+ ) : (
323
+ <div className='text-[10px] text-gray-400'>No Image</div>
324
+ )}
325
+ </div>
326
+ <div className='flex flex-col text-[13px]'>
327
+ <span className='font-medium'>{it.name}</span>
328
+ <span>SKU : {it.sku || '-'}</span>
329
+ <span>Qty : {it.qty_requested || 0}</span>
330
+ <span>Reason : {it.reason || '-'}</span>
331
+ <span>Resolution : {it.resolution || '-'}</span>
332
+ <span>Condition : {it.condition || '-'}</span>
333
+ </div>
334
+ </div>
261
335
  ))}
262
336
  </div>
263
337
  </div>
264
- <div className=' flex flex-col mb-10'>
338
+ <div className=' flex flex-col mb-10 no-print'>
265
339
  <div aria-live="polite" className="text-lg font-medium text-left mb-4">
266
340
  Messages
267
341
  </div>
268
342
  <div className='rounded-md border border-gray-100 p-4 pr-0 pt-0 flex flex-col gap-y-6'>
269
343
  <div className='max-h-[600px] overflow-auto relative chat-container pr-4 pt-4'>
270
- <ChatContent chatData={dummyChat} />
344
+ {rmaDetailError ? (
345
+ <div className='text-[13px] text-red-600'>Failed to load messages.</div>
346
+ ) : (
347
+ <ChatContent chatData={chatData} />
348
+ )}
271
349
  </div>
272
350
  <div className='flex gap-2 pr-4'>
273
351
  <textarea
274
352
  className='w-full focus-visible_outline-none border border-gray-100 p-1 rounded-md'
275
353
  cols={5}
354
+ value={chatInput}
355
+ onChange={e => setChatInput(e.target.value)}
356
+ placeholder={formatMessage({ id: 'RMA.chatPlaceholder', defaultMessage: 'Type your message...' })}
357
+ disabled={chatSending || sendRmaMessageLoading}
276
358
  />
277
359
  <Button
278
360
  priority='high'
@@ -283,11 +365,18 @@ const RMADetail = () => {
283
365
  "bg-blue-600 px-6 py-2 rounded-full text-white border ",
284
366
  "border-blue-600 hover_bg-blue-700 hover_border-blue-700 focus-visible_outline-none"
285
367
  )}
368
+ onClick={handleSendChat}
369
+ disabled={chatSending || sendRmaMessageLoading || !chatInput.trim()}
370
+ aria-label={formatMessage({ id: 'RMA.sendMessage', defaultMessage: 'Send Message' })}
286
371
  >
287
- <Send
288
- size="24"
289
- className='text-white'
290
- />
372
+ {chatSending || sendRmaMessageLoading ? (
373
+ <span className="inline-block h-4 w-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
374
+ ) : (
375
+ <Send
376
+ size="24"
377
+ className='text-white'
378
+ />
379
+ )}
291
380
  </Button>
292
381
  </div>
293
382
  </div>