@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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@riosst100/pwa-marketplace",
3
3
  "author": "riosst100@gmail.com",
4
- "version": "2.9.5",
4
+ "version": "2.9.7",
5
5
  "main": "src/index.js",
6
6
  "pwa-studio": {
7
7
  "targets": {
@@ -16,6 +16,7 @@ module.exports = componentOverrideMapping = {
16
16
  [`@magento/peregrine/lib/store/actions/cart/asyncActions.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/store/actions/cart/asyncActions.js',
17
17
  [`@magento/peregrine/lib/context/cart.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/context/cart.js',
18
18
  [`@magento/peregrine/lib/talons/CheckoutPage/useCheckoutPage.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/CheckoutPage/useCheckoutPage.js',
19
+ [`@magento/peregrine/lib/talons/CheckoutPage/PaymentInformation/paymentMethods.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/CheckoutPage/PaymentInformation/paymentMethods.gql.js',
19
20
  [`@magento/peregrine/lib/talons/SignIn/signIn.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/SignIn/signIn.gql.js',
20
21
  [`@magento/peregrine/lib/talons/SearchPage/searchPage.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/SearchPage/searchPage.gql.js',
21
22
  [`@magento/peregrine/lib/talons/SignIn/useSignIn.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/SignIn/useSignIn.js',
@@ -85,5 +86,8 @@ module.exports = componentOverrideMapping = {
85
86
  [`@magento/peregrine/lib/talons/ProductOptions/useOption.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/ProductOptions/useOption.js',
86
87
  [`@magento/peregrine/lib/talons/ProductOptions/useTile.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/ProductOptions/useTile.js',
87
88
  [`@magento/peregrine/lib/talons/ProductImageCarousel/useProductImageCarousel.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/ProductImageCarousel/useProductImageCarousel.js',
88
- [`@magento/peregrine/lib/talons/OrderHistoryPage/orderHistoryPage.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/OrderHistoryPage/orderHistoryPage.gql.js'
89
+ [`@magento/peregrine/lib/talons/OrderHistoryPage/orderHistoryPage.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/OrderHistoryPage/orderHistoryPage.gql.js',
90
+ // Added overrides to fix TypeError in useOrderRow and to ensure required GQL queries are present
91
+ [`@magento/peregrine/lib/talons/OrderHistoryPage/useOrderRow.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/OrderHistoryPage/useOrderRow.js',
92
+ [`@magento/peregrine/lib/talons/OrderHistoryPage/orderRow.gql.js`]: '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/OrderHistoryPage/orderRow.gql.js'
89
93
  };
@@ -1,26 +1,42 @@
1
- import React from 'react';
1
+ import React, { useRef, useEffect } from 'react';
2
2
  import cn from 'classnames';
3
3
 
4
4
  const chatContent = (props) => {
5
5
  const { chatData } = props;
6
6
 
7
- return (
8
- <>
9
- <div className='flex flex-col gap-2 w-full'>
10
- {chatData.map((chat) => {
11
- return (
7
+
8
+ const orderedChatData = [...chatData].reverse();
9
+ const messagesContainerRef = useRef(null);
10
+
11
+ useEffect(() => {
12
+ if (messagesContainerRef.current) {
13
+ messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
14
+ }
15
+ }, [orderedChatData]);
16
+
17
+ return (
18
+ <>
19
+ <div
20
+ ref={messagesContainerRef}
21
+ className='flex flex-col gap-2 w-full overflow-y-auto max-h-[400px]'
22
+ >
23
+ {orderedChatData.map((chat, idx) => (
12
24
  <div
25
+ key={idx}
13
26
  className={cn(
14
27
  'w-fit max-w-[70%] flex flex-col gap-1',
15
28
  chat.type === 'seller' ? 'self-start ' : 'self-end items-end',
16
-
17
29
  )}
18
30
  >
31
+ {chat.senderName && (
32
+ <span className='text-[12px] text-gray-500 font-semibold mb-[-2px]'>
33
+ {chat.senderName}
34
+ </span>
35
+ )}
19
36
  <div
20
37
  className={cn(
21
38
  'w-fit py-2 px-3 rounded-md flex flex-col',
22
39
  chat.type === 'seller' ? 'bg-gray-150 rounded-tl-none' : ' bg-[#D9D9D9] rounded-tr-none',
23
-
24
40
  )}
25
41
  >
26
42
  {chat.message}
@@ -29,11 +45,10 @@ const chatContent = (props) => {
29
45
  {chat.timeStamp}
30
46
  </span>
31
47
  </div>
32
- )
33
- })}
34
- </div>
35
- </>
36
- )
48
+ ))}
49
+ </div>
50
+ </>
51
+ )
37
52
  }
38
53
 
39
54
  export default chatContent
@@ -2,108 +2,100 @@ import React from 'react'
2
2
  import { useIntl } from 'react-intl';
3
3
  import { Link } from 'react-router-dom';
4
4
 
5
- const rmaList = () => {
5
+ const rmaList = ({ rmas, isLoadingWithoutData }) => {
6
6
  const { formatMessage } = useIntl();
7
7
 
8
8
  return (
9
9
  <>
10
10
  <div className='rounded-md border border-gray-100'>
11
- <div class="hidden md_block table-wrapper order-items w-full">
12
- <table class="data table table-order-items w-full" id="my-orders-table" summary="Items Ordered">
11
+ <div className="hidden md_block table-wrapper order-items w-full">
12
+ <table className="data table table-order-items w-full" id="my-orders-table" summary="Items Ordered">
13
13
  <thead>
14
14
  <tr className='bg-gray-150'>
15
- <th class="col text-left py-3 px-2.5 rounded-tl-md">RMA</th>
16
- <th class="col text-left py-3 px-2.5">Date</th>
17
- <th class="col text-left py-3 px-2.5">Order</th>
18
- <th class="col text-left py-3 px-2.5">Status</th>
19
- <th class="col text-left py-3 px-2.5 rounded-tr-md">Action</th>
15
+ <th className="col text-left py-3 px-2.5 rounded-tl-md">RMA</th>
16
+ <th className="col text-left py-3 px-2.5">Date</th>
17
+ <th className="col text-left py-3 px-2.5">Order</th>
18
+ <th className="col text-left py-3 px-2.5">Status</th>
19
+ <th className="col text-left py-3 px-2.5 rounded-tr-md">Action</th>
20
20
  </tr>
21
21
  </thead>
22
22
  <tbody>
23
- <tr id="order-item-row-1" className='border-b border-gray-150 last-of-type_border-0'>
24
- <td class="col rma text-left align-top py-3 px-2.5" data-th="Product Name">
25
- <span className='font-semibold'>
26
- 3000000011-2
27
- </span>
28
- </td>
29
- <td class="col date align-top py-3 px-2.5" data-th="SKU">
30
- <span className='font-normal'>
31
- Jun 29, 2024
32
- </span>
33
- </td>
34
- <td class="col order text-left align-top py-3 px-2.5" data-th="Price">
35
- <Link to={'/order/123123'} className="underline">
36
- 3000000011
37
- </Link>
38
- </td>
39
- <td class="col qty text-left align-top py-3 px-2.5" data-th="Qty">
40
- <p className='p-1 bg-[#F1EFF6] rounded-md flex items-center px-5 w-fit'>
41
- <span className='font-medium block text-blue-700'>
42
- Pending Approval
43
- </span>
44
- </p>
45
- </td>
46
- <td class="col subtotal text-left align-top py-3 px-2.5" data-th="Subtotal">
47
- <Link to={'/return/123123'} className="underline">
48
- View Return
49
- </Link>
50
- </td>
51
- </tr>
23
+ {rmas && rmas.length > 0 ? (
24
+ rmas.map((rma, idx) => {
25
+ const formattedDate = rma.created_at ? new Date(rma.created_at.replace(' ', 'T')).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }) : '-';
26
+ return (
27
+ <tr key={rma.rma_id || idx} className='border-b border-gray-150 last-of-type_border-0'>
28
+ <td className="col rma text-left align-top py-3 px-2.5" data-th="RMA">
29
+ <span className='font-semibold'>{rma.increment_id}</span>
30
+ </td>
31
+ <td className="col date align-top py-3 px-2.5" data-th="Date">
32
+ <span className='font-normal'>{formattedDate}</span>
33
+ </td>
34
+ <td className="col order text-left align-top py-3 px-2.5" data-th="Order">
35
+ {rma.order_increment_id || (rma.order && rma.order.increment_id) || '-'}
36
+ </td>
37
+ <td className="col qty text-left align-top py-3 px-2.5" data-th="Status">
38
+ <p className='p-1 flex items-center w-fit'>
39
+ <span className='font-medium block text-blue-700'>{rma.status_label || rma.status}</span>
40
+ </p>
41
+ </td>
42
+ <td className="col subtotal text-left align-top py-3 px-2.5" data-th="Action">
43
+ <Link to={`/return/view/${rma.rma_id}`} className="underline">
44
+ View Return
45
+ </Link>
46
+ </td>
47
+ </tr>
48
+ );
49
+ })
50
+ ) : (
51
+ <tr><td colSpan={5} className='text-center py-4'>No RMA found.</td></tr>
52
+ )}
52
53
  </tbody>
53
54
  </table>
54
55
  </div>
55
56
  <div className='md_hidden'>
56
- <div class="orderDetails-orderTotalContainer-6or m-0 max-w-none min-w-none lg_m-auto lg_max-w-[25rem] lg_min-w-[22rem]">
57
- <div className='item flex flex-col gap-2 p-4 odd_border border-gray-150 last-of-type_border-0'>
58
- <div className='flex gap-3'>
59
- <div className='min-w-[60px] text-[14px] font-semibold'>
60
- RMA
61
- </div>
62
- <div className='min-w-[60px] text-[14px]'>
63
- 3000000011-2
64
- </div>
65
- </div>
66
- <div className='flex gap-3'>
67
- <div className='min-w-[60px] text-[14px] font-semibold'>
68
- Date
69
- </div>
70
- <div className='min-w-[60px] text-[14px]'>
71
- Jun 29, 2024
72
- </div>
73
- </div>
74
- <div className='flex gap-3'>
75
- <div className='min-w-[60px] text-[14px] font-semibold'>
76
- Order
77
- </div>
78
- <div className='min-w-[60px] text-[14px]'>
79
- <Link to={'/order-history/view/123123'} className="underline">
80
- 3000000011
81
- </Link>
82
- </div>
83
- </div>
84
- <div className='flex gap-3'>
85
- <div className='min-w-[60px] text-[14px] font-semibold self-center'>
86
- Status
87
- </div>
88
- <div className='min-w-[60px] text-[14px]'>
89
- <p className='p-1 bg-[#F1EFF6] rounded-md flex items-center px-5 w-fit'>
90
- <span className='font-medium block text-blue-700'>
91
- Pending Approval
92
- </span>
93
- </p>
94
- </div>
95
- </div>
96
- <div className='flex gap-3'>
97
- <div className='min-w-[60px] text-[14px] font-semibold self-center'>
98
- Action
99
- </div>
100
- <div className='min-w-[60px] text-[14px]'>
101
- <Link to={'/return/view/123123'} className="underline">
102
- View Return
103
- </Link>
104
- </div>
105
- </div>
106
- </div>
57
+ <div className="orderDetails-orderTotalContainer-6or m-0 max-w-none min-w-none lg_m-auto lg_max-w-[25rem] lg_min-w-[22rem]">
58
+ {rmas && rmas.length > 0 ? (
59
+ rmas.map((rma, idx) => {
60
+ const formattedDate = rma.created_at ? new Date(rma.created_at.replace(' ', 'T')).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }) : '-';
61
+ return (
62
+ <div key={rma.rma_id || idx} className='item flex flex-col gap-2 p-4 odd_border border-gray-150 last-of-type_border-0'>
63
+ <div className='flex gap-3'>
64
+ <div className='min-w-[60px] text-[14px] font-semibold'>RMA</div>
65
+ <div className='min-w-[60px] text-[14px]'>{rma.increment_id}</div>
66
+ </div>
67
+ <div className='flex gap-3'>
68
+ <div className='min-w-[60px] text-[14px] font-semibold'>Date</div>
69
+ <div className='min-w-[60px] text-[14px]'>{formattedDate}</div>
70
+ </div>
71
+ <div className='flex gap-3'>
72
+ <div className='min-w-[60px] text-[14px] font-semibold'>Order</div>
73
+ <div className='min-w-[60px] text-[14px]'>
74
+ {rma.order_increment_id || (rma.order && rma.order.increment_id) || '-'}
75
+ </div>
76
+ </div>
77
+ <div className='flex gap-3'>
78
+ <div className='min-w-[60px] text-[14px] font-semibold self-center'>Status</div>
79
+ <div className='min-w-[60px] text-[14px]'>
80
+ <p className='p-1 bg-[#F1EFF6] rounded-md flex items-center px-5 w-fit'>
81
+ <span className='font-medium block text-blue-700'>{rma.status_label || rma.status}</span>
82
+ </p>
83
+ </div>
84
+ </div>
85
+ <div className='flex gap-3'>
86
+ <div className='min-w-[60px] text-[14px] font-semibold self-center'>Action</div>
87
+ <div className='min-w-[60px] text-[14px]'>
88
+ <Link to={`/return/view/${rma.rma_id}`} className="underline">
89
+ View Return
90
+ </Link>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ );
95
+ })
96
+ ) : (
97
+ <div className='text-center py-4'>No RMA found.</div>
98
+ )}
107
99
  </div>
108
100
  </div>
109
101
  </div>
@@ -1,12 +1,14 @@
1
- import React, { useCallback, useRef } from 'react';
1
+ import React, { useCallback, useRef, useMemo, 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 Button from '@magento/venia-ui/lib/components/Button';
5
5
  import cn from 'classnames';
6
- import { Printer } from 'iconsax-react';
6
+ import { Printer, ConvertCard } from 'iconsax-react';
7
7
  import ItemsOrdered from './components/itemsOrdered';
8
8
  import RMAList from './components/rmaList';
9
- import { useLocation } from 'react-router-dom';
9
+ import useRmaPage from '@riosst100/pwa-marketplace/src/talons/RMAPage/useRmaPage';
10
+ import { useLocation, useParams, useHistory } from 'react-router-dom';
11
+ import useOrderHistoryPage from '@riosst100/pwa-marketplace/src/talons/OrderHistoryPage/useOrderHistoryPage';
10
12
 
11
13
  const OrderDetail = (props) => {
12
14
  const printRef = useRef(null);
@@ -17,8 +19,74 @@ const OrderDetail = (props) => {
17
19
  defaultMessage: 'Order Detail'
18
20
  });
19
21
 
20
- // Retrieve order data from props or location state
21
- const order = props.order || location.state?.order;
22
+ // Retrieve order data from props or location state, fallback to fetch by orderNumber param
23
+ const params = useParams();
24
+
25
+ // Support both /order-history/view/:orderNumber and /order/:orderNumber
26
+ const orderNumberParam = params.orderNumber || params.urlKey || params.id;
27
+
28
+ // Keep a stable local state for order to avoid it turning undefined on re-renders
29
+ const [order, setOrder] = useState(() => props.order || location.state?.order || null);
30
+ const history = useHistory();
31
+ // Button Return Items: tampil jika status Complete/Delivered
32
+ const isReturnAllowed = useMemo(() => {
33
+ if (!order) return false;
34
+ const status = order.status;
35
+ if (!status) return false;
36
+ return (
37
+ status === 'Complete' ||
38
+ status.toLowerCase() === 'delivered' // antisipasi backend bisa lowercase
39
+ );
40
+ }, [order]);
41
+
42
+ // Handler sama seperti orderRow
43
+ const handleNewReturn = useCallback(() => {
44
+ if (!order) return;
45
+ let orderWithImages = { ...order };
46
+ if (orderWithImages.items && Array.isArray(orderWithImages.items)) {
47
+ orderWithImages = {
48
+ ...orderWithImages,
49
+ items: orderWithImages.items.map(it => {
50
+ let product_image = '';
51
+ if (typeof it.product_image_url === 'string' && it.product_image_url.trim() !== '') {
52
+ product_image = it.product_image_url;
53
+ }
54
+ return {
55
+ ...it,
56
+ product_image
57
+ };
58
+ })
59
+ };
60
+ }
61
+ try {
62
+ localStorage.setItem('rma_order', JSON.stringify(orderWithImages));
63
+ } catch (e) {}
64
+ history.push({
65
+ pathname: `/return/create/${order.number}`,
66
+ state: { order: orderWithImages }
67
+ });
68
+ }, [order, history]);
69
+
70
+ // Fallback: fetch order by orderNumber from order history if not found
71
+ const { orders } = useOrderHistoryPage();
72
+
73
+ const fallbackOrder = useMemo(() => {
74
+ if (!order && orderNumberParam && orders && orders.length > 0) {
75
+ // order.number might be string or number, so use loose equality
76
+ return orders.find(o => o.number == orderNumberParam);
77
+ }
78
+ return undefined;
79
+ }, [order, orderNumberParam, orders]);
80
+
81
+ // Populate order state from fallback if needed (once data available)
82
+ useEffect(() => {
83
+ if (!order && fallbackOrder) {
84
+ setOrder(fallbackOrder);
85
+ }
86
+ }, [fallbackOrder, order]);
87
+ // Fetch RMA data for this order
88
+ const { rmas, isLoadingWithoutData } = useRmaPage({ orderNumber: orderNumberParam });
89
+
22
90
  // Extract order data
23
91
  const invoiceNumber = order?.invoices?.[0]?.number || '-';
24
92
  const orderDate = order?.order_date
@@ -68,6 +136,18 @@ const OrderDetail = (props) => {
68
136
  }, 500);
69
137
  }, []);
70
138
 
139
+ // Early guard: show skeleton if order still resolving
140
+ if (!order && !fallbackOrder) {
141
+ return (
142
+ <div className='print-area relative grid gap-y-md' ref={printRef}>
143
+ <StoreTitle>{PAGE_TITLE}</StoreTitle>
144
+ <div aria-live="polite" className="text-xl font-medium text-left">
145
+ {PAGE_TITLE} - #-
146
+ </div>
147
+ </div>
148
+ );
149
+ }
150
+
71
151
  return (
72
152
  <div className='print-area relative grid gap-y-md' ref={printRef}>
73
153
  <StoreTitle>{PAGE_TITLE}</StoreTitle>
@@ -108,31 +188,52 @@ const OrderDetail = (props) => {
108
188
  </div>
109
189
  </div>
110
190
  <div className='flex flex-col md_flex-row gap-x-4 justify-end no-print'>
111
- <Button
112
- priority='high'
113
- classes={{
114
- content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
115
- }}
116
- className={cn(
117
- "bg-white px-6 py-2 rounded-md text-gray-900 hover_!text-white border border-solid",
118
- "border-gray-900 focus-visible_outline-none hover_bg-gray-900 min-h-[40px]"
191
+ <div className='flex flex-row gap-x-3'>
192
+ <Button
193
+ priority='high'
194
+ classes={{
195
+ content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
196
+ }}
197
+ className={cn(
198
+ "bg-white px-6 py-2 rounded-md text-gray-900 hover_!text-white border border-solid",
199
+ "border-gray-900 focus-visible_outline-none hover_bg-gray-900 min-h-[40px]"
200
+ )}
201
+ onClick={handlePrint}
202
+ aria-label={formatMessage({ id: 'order.printInvoices', defaultMessage: 'Print Invoices' })}
203
+ >
204
+ <span className='flex gap-x-3 justify-center group-hover_!text-white'>
205
+ <Printer
206
+ size="24"
207
+ className=''
208
+ />
209
+ {
210
+ formatMessage({
211
+ id: 'order.PrintInvoices',
212
+ defaultMessage: 'Print Invoices'
213
+ })
214
+ }
215
+ </span>
216
+ </Button>
217
+ {isReturnAllowed && (
218
+ <Button
219
+ priority='high'
220
+ classes={{
221
+ content: "flex justify-center gap-x-2.5 items-center text-[14px] font-medium capitalize"
222
+ }}
223
+ className={cn(
224
+ "bg-blue-700 px-6 py-2 rounded-md text-white border border-blue-700 min-h-[40px]",
225
+ "transition-all duration-300 ease-in-out flex items-center gap-2"
226
+ )}
227
+ onClick={handleNewReturn}
228
+ aria-label={formatMessage({ id: 'orderRow.returnProduct', defaultMessage: 'Return Product' })}
229
+ >
230
+ <span className='flex gap-x-3 justify-center'>
231
+ <ConvertCard size={22} color="#fff" />
232
+ {formatMessage({ id: 'orderRow.ReturnItems', defaultMessage: 'Return Items' })}
233
+ </span>
234
+ </Button>
119
235
  )}
120
- onClick={handlePrint}
121
- aria-label={formatMessage({ id: 'order.printInvoices', defaultMessage: 'Print Invoices' })}
122
- >
123
- <span className='flex gap-x-3 justify-center group-hover_!text-white'>
124
- <Printer
125
- size="24"
126
- className=''
127
- />
128
- {
129
- formatMessage({
130
- id: 'order.PrintInvoices',
131
- defaultMessage: 'Print Invoices'
132
- })
133
- }
134
- </span>
135
- </Button>
236
+ </div>
136
237
  </div>
137
238
  </div>
138
239
  <div className="block block-order-details-view">
@@ -146,17 +247,19 @@ const OrderDetail = (props) => {
146
247
  </div>
147
248
  <ItemsOrdered order={order} />
148
249
  </div>
149
- <div className="block block-order-details-view">
150
- <div aria-live="polite" className="text-lg font-medium text-left mb-4 block-title">
151
- {
152
- formatMessage({
153
- id: 'order.rmaInformation',
154
- defaultMessage: 'RMA Information'
155
- })
156
- }
250
+ {rmas && rmas.length > 0 && (
251
+ <div className="block block-order-details-view">
252
+ <div aria-live="polite" className="text-lg font-medium text-left mb-4 block-title">
253
+ {
254
+ formatMessage({
255
+ id: 'order.rmaInformation',
256
+ defaultMessage: 'RMA Information'
257
+ })
258
+ }
259
+ </div>
260
+ <RMAList rmas={rmas} isLoadingWithoutData={isLoadingWithoutData} />
157
261
  </div>
158
- <RMAList />
159
- </div>
262
+ )}
160
263
  <div className="block block-order-details-view">
161
264
  <div aria-live="polite" className="text-lg font-medium text-left mb-4 block-title">
162
265
  {