@riosst100/pwa-marketplace 3.3.3 → 3.3.5

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/id_ID.json CHANGED
@@ -546,5 +546,12 @@
546
546
  "messages.loginRequired": "Silakan masuk ke akun Anda untuk mengirim pesan ke seller.",
547
547
  "messages.messageSent": "Pesan berhasil dikirim.",
548
548
  "messages.replySent": "Balasan berhasil dikirim.",
549
- "messages.messageDeleted": "Pesan berhasil dihapus."
549
+ "messages.messageDeleted": "Pesan berhasil dihapus.",
550
+ "order.track.inTransit": "Sedang Dikirim",
551
+ "order.track.delivered": "Pesanan Tiba",
552
+ "order.track.courier": "Kurir",
553
+ "order.track.waybill": "Resi",
554
+ "order.track.status": "Status",
555
+ "order.track.step1": "Langkah 1 dari 2",
556
+ "order.track.step2": "Langkah 2 dari 2"
550
557
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@riosst100/pwa-marketplace",
3
3
  "author": "riosst100@gmail.com",
4
- "version": "3.3.3",
4
+ "version": "3.3.5",
5
5
  "main": "src/index.js",
6
6
  "pwa-studio": {
7
7
  "targets": {
@@ -18,6 +18,7 @@ const LoadingRequest = props => {
18
18
  const {
19
19
  isLoading
20
20
  } = props;
21
+ // const isLoading = true;
21
22
 
22
23
  const modal = isLoading ? (
23
24
  <div className={modalClasses.overlay} role="dialog" aria-modal="true" aria-label="Modal">
@@ -27,7 +28,8 @@ const LoadingRequest = props => {
27
28
  <img src={process.env.MAGENTO_BACKEND_URL + "/media/images/spinner2.gif"} style={{"width":"15%"}} />
28
29
  <div style={{
29
30
  "marginTop": "10px",
30
- "color": "white"
31
+ "color": "white",
32
+ "fontSize": "14px"
31
33
  }}>Please wait...</div>
32
34
  </div>
33
35
  </div>
@@ -75,8 +75,9 @@
75
75
  .backdrop{
76
76
  position:absolute;
77
77
  inset:0;
78
- background: rgba(0, 0, 0, 0.64);
79
- backdrop-filter: blur(8px);
78
+ /* background: rgba(0, 0, 0, 0.64); */
79
+ background: rgb(0 0 0 / 50%);
80
+ /* backdrop-filter: blur(1px); */
80
81
  }
81
82
  .dialog{
82
83
  position:relative;
@@ -119,6 +120,7 @@
119
120
  text-align: center;
120
121
  flex-wrap: wrap;
121
122
  align-content: center;
123
+ align-items: center;
122
124
  }
123
125
  .triggerBtn{
124
126
  background:#f76b1c;
@@ -0,0 +1,151 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { TickCircle } from 'iconsax-react';
3
+ import { useIntl } from 'react-intl';
4
+
5
+ import useTrackOrder from '@riosst100/pwa-marketplace/src/talons/TrackOrder/useTrackOrder';
6
+
7
+ const TrackOrder = ({ order }) => {
8
+ const incrementId = useMemo(() => {
9
+ const num = order?.number;
10
+ return typeof num === 'number' ? String(num) : (num || '');
11
+ }, [order]);
12
+
13
+ const { trackOrder, isLoadingWithoutData, isBackgroundLoading, errorMessage } = useTrackOrder({ incrementId });
14
+
15
+ const { formatMessage, locale } = useIntl();
16
+
17
+ const status = (order?.status || '').toLowerCase();
18
+ const delivered = status === 'complete';
19
+ const canceled = status === 'canceled' || status === 'cancel' || status === 'cancelled';
20
+ const inTransit = !canceled && status !== '' && !delivered;
21
+
22
+ const summary = trackOrder?.summary;
23
+ const manifests = Array.isArray(trackOrder?.manifest)
24
+ ? trackOrder.manifest
25
+ : (trackOrder?.manifest ? [trackOrder.manifest] : []);
26
+
27
+ const activeManifestIndex = useMemo(() => {
28
+ if (!manifests.length) return -1;
29
+ let bestIdx = 0;
30
+ let bestTime = -Infinity;
31
+ manifests.forEach((m, idx) => {
32
+ const d = m?.manifest_date;
33
+ const t = m?.manifest_time;
34
+ const dt = d && t ? new Date(`${d}T${t}`) : undefined;
35
+ const time = dt && !isNaN(dt) ? dt.getTime() : NaN;
36
+ if (!isNaN(time) && time > bestTime) {
37
+ bestTime = time;
38
+ bestIdx = idx;
39
+ }
40
+ });
41
+ return isFinite(bestTime) ? bestIdx : 0;
42
+ }, [manifests]);
43
+
44
+ const formatManifestDate = m => {
45
+ const d = m?.manifest_date;
46
+ const t = m?.manifest_time;
47
+ if (d && t) {
48
+ const dt = new Date(`${d}T${t}`);
49
+ if (!isNaN(dt)) {
50
+ try {
51
+ return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short' }).format(dt);
52
+ } catch (e) {
53
+ return dt.toLocaleString();
54
+ }
55
+ }
56
+ }
57
+ return [t || '', d || ''].filter(Boolean).join(' ') || '-';
58
+ };
59
+
60
+ const [copied, setCopied] = useState(false);
61
+ const handleCopyWaybill = () => {
62
+ const text = summary?.waybill_number;
63
+ if (!text) return;
64
+ if (navigator?.clipboard?.writeText) {
65
+ navigator.clipboard.writeText(text)
66
+ .then(() => {
67
+ setCopied(true);
68
+ setTimeout(() => setCopied(false), 1500);
69
+ })
70
+ .catch(() => {});
71
+ }
72
+ };
73
+
74
+ const loading = isLoadingWithoutData || isBackgroundLoading;
75
+ return (
76
+ <div className="block-content rounded-md border border-gray-100 px-4 py-6 relative" aria-busy={loading}>
77
+ <div className="relative h-12 mb-6">
78
+ <div className="absolute left-0 right-0 top-[10px] flex">
79
+ <div className={`h-[2px] w-1/2 rounded-l-full ${inTransit || delivered ? 'bg-blue-600' : 'bg-gray-100'}`}></div>
80
+ <div className={`h-[2px] w-1/2 rounded-r-full ${delivered ? 'bg-blue-600' : 'bg-gray-100'}`}></div>
81
+ </div>
82
+ <div className="absolute left-0 right-0 top-[10px] flex justify-between">
83
+ <div className="flex flex-col items-center">
84
+ <span className={`w-3 h-3 rounded-full -translate-y-1/2 ring-2 ring-white shadow ${inTransit || delivered ? 'bg-blue-700' : 'bg-gray-100'} ${inTransit ? 'animate-pulse' : ''}`}></span>
85
+ <span className={`mt-2 text-sm ${inTransit || delivered ? 'text-blue-700 font-medium' : 'text-gray-200'}`}>{formatMessage({ id: 'order.track.inTransit', defaultMessage: 'In Transit' })}</span>
86
+ </div>
87
+ <div className="flex flex-col items-center">
88
+ <span className={`w-5 h-5 rounded-full -translate-y-1/2 flex items-center justify-center ring-2 ring-white shadow transition-transform duration-300 ${delivered ? 'bg-green-500 scale-110' : (delivered || inTransit ? 'bg-blue-700' : 'bg-gray-100')}`}>
89
+ {delivered && <TickCircle size={14} color="#ffffff" variant="Bold" />}
90
+ </span>
91
+ <span className={`mt-2 text-sm ${delivered ? 'text-green-600 font-medium' : 'text-gray-200'}`}>{formatMessage({ id: 'order.track.delivered', defaultMessage: 'Delivered' })}</span>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <div className="flex flex-col gap-2 mb-6">
97
+ {summary && (
98
+ <div className="flex flex-col gap-2">
99
+ <div className="px-2 py-1 rounded bg-gray-100 text-gray-900 text-xs w-[250px]">
100
+ <strong>{formatMessage({ id: 'order.track.courier', defaultMessage: 'Courier' })}:</strong> {summary.courier_name || '-'}
101
+ </div>
102
+ <div className="px-2 py-1 rounded bg-gray-100 text-gray-900 text-xs w-[250px] flex items-center justify-between">
103
+ <div className="truncate" title={summary.waybill_number || ''}>
104
+ <strong>{formatMessage({ id: 'order.track.waybill', defaultMessage: 'Waybill' })}:</strong> {summary.waybill_number || '-'}
105
+ </div>
106
+ {summary.waybill_number && (
107
+ <button type="button" onClick={handleCopyWaybill} className="ml-2 px-2 py-1 rounded bg-blue-600 text-white text-xs hover:bg-blue-700">
108
+ {copied ? formatMessage({ id: 'common.copied', defaultMessage: 'Copied!' }) : formatMessage({ id: 'common.copy', defaultMessage: 'Copy' })}
109
+ </button>
110
+ )}
111
+ </div>
112
+ <div className={`px-2 py-1 rounded text-xs w-[250px] ${summary.status?.toLowerCase() === 'delivered' ? 'bg-green-100 text-green-700' : 'bg-blue-100 text-blue-700'}`}>
113
+ <strong>{formatMessage({ id: 'order.track.status', defaultMessage: 'Status' })}:</strong> {summary.status || '-'}
114
+ </div>
115
+ </div>
116
+ )}
117
+ {errorMessage && (
118
+ <div className="text-red-600 text-sm">{errorMessage}</div>
119
+ )}
120
+ </div>
121
+
122
+ {manifests.length > 0 && (
123
+ <div className="relative flex flex-col gap-4">
124
+ <div className="pointer-events-none absolute left-[4px] top-0 bottom-0 border-l border-gray-100"></div>
125
+ {manifests.map((m, idx) => (
126
+ <div key={idx} className="flex items-start gap-3">
127
+ <div className={`mt-1 w-2 h-2 rounded-full z-10 ${idx === activeManifestIndex ? 'bg-blue-700' : 'bg-gray-100'}`}></div>
128
+ <div className="flex-1">
129
+ <div className="text-sm text-gray-800">{m?.manifest_description || '-'}</div>
130
+ {m?.city_name && (
131
+ <div className="text-xs text-gray-500">{m.city_name}</div>
132
+ )}
133
+ <div className="text-xs text-gray-500">{formatManifestDate(m)}</div>
134
+ </div>
135
+ </div>
136
+ ))}
137
+ </div>
138
+ )}
139
+ {loading && (
140
+ <div className="absolute inset-0 z-20 bg-white/60 backdrop-blur-[1px] flex items-center justify-center">
141
+ <div className="flex items-center gap-2">
142
+ <span className="w-5 h-5 rounded-full border-2 border-gray-200 border-t-blue-600 animate-spin"></span>
143
+ <span className="text-sm text-gray-700">{formatMessage({ id: 'order.track.loading', defaultMessage: 'Loading tracking order…' })}</span>
144
+ </div>
145
+ </div>
146
+ )}
147
+ </div>
148
+ );
149
+ };
150
+
151
+ export default TrackOrder;
@@ -5,6 +5,7 @@ import Button from '@magento/venia-ui/lib/components/Button';
5
5
  import cn from 'classnames';
6
6
  import { Printer, ConvertCard } from 'iconsax-react';
7
7
  import ItemsOrdered from './components/itemsOrdered';
8
+ import TrackOrder from './components/trackOrder';
8
9
  import RMAList from './components/rmaList';
9
10
  import useRmaPage from '@riosst100/pwa-marketplace/src/talons/RMAPage/useRmaPage';
10
11
  import { useLocation, useParams, useHistory } from 'react-router-dom';
@@ -93,6 +94,7 @@ const OrderDetail = (props) => {
93
94
  ? new Date(order.order_date.replace(' ', 'T')).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
94
95
  : '-';
95
96
  const status = order?.status || '-';
97
+ const isClosed = (order?.status || '').toLowerCase() === 'closed';
96
98
  const shippingMethod = order?.shipping_method || '-';
97
99
  const trackingNumber = order?.shipments?.[0]?.tracking?.[0]?.number || '-';
98
100
  const shippingAddress = order?.shipping_address;
@@ -236,6 +238,19 @@ const OrderDetail = (props) => {
236
238
  </div>
237
239
  </div>
238
240
  </div>
241
+ {!isClosed && (
242
+ <div className="block block-order-details-view">
243
+ <div aria-live="polite" className="text-lg font-medium text-left mb-4 block-title">
244
+ {
245
+ formatMessage({
246
+ id: 'order.trackOrder',
247
+ defaultMessage: 'Track Order'
248
+ })
249
+ }
250
+ </div>
251
+ <TrackOrder order={order} />
252
+ </div>
253
+ )}
239
254
  <div className="block block-order-details-view">
240
255
  <div aria-live="polite" className="text-lg font-medium text-left mb-4 block-title">
241
256
  {
@@ -158,6 +158,7 @@ export const useSignIn = props => {
158
158
  }
159
159
 
160
160
  setIsSigningIn(false);
161
+ setIsLoading(false);
161
162
  }
162
163
  },
163
164
  [
@@ -0,0 +1,24 @@
1
+ import { gql } from '@apollo/client';
2
+
3
+ export const GET_TRACK_ORDER = gql`
4
+ query GetTrackOrder($increment_id: String!) {
5
+ trackOrder(increment_id: $increment_id) {
6
+ delivered
7
+ summary {
8
+ courier_name
9
+ waybill_number
10
+ status
11
+ }
12
+ manifest {
13
+ manifest_description
14
+ manifest_date
15
+ city_name
16
+ manifest_time
17
+ }
18
+ }
19
+ }
20
+ `;
21
+
22
+ export default {
23
+ getTrackOrderQuery: GET_TRACK_ORDER
24
+ };
@@ -70,62 +70,6 @@ const Adapter = props => {
70
70
  const currentWebsiteCode = storage && storage.getItem('website_code') || process.env.WEBSITE_CODE;
71
71
 
72
72
  useEffect(() => {
73
- if (!websiteCodeInUrl) {
74
- // history.replace(location.pathname + location.search)
75
- } else if (websiteCodeInUrl && websiteCodeInUrl !== currentWebsiteCode) {
76
- const storeCodeInUrl = websiteStores[websiteCodeInUrl];
77
-
78
-
79
-
80
- // const search = location.search;
81
-
82
- // const query = new URLSearchParams(search);
83
- // const isAccessBaseWebsite = query.get('access_base_website') || (
84
- // storage.getItem('access_base_website') || null
85
- // );
86
-
87
- // routerProps.basename = websiteCodeInUrl != process.env.WEBSITE_CODE && !isAccessBaseWebsite ? '/'+websiteCodeInUrl : '/';
88
-
89
- // setNewRouterProps(routerProps);
90
-
91
- // await removeCart();
92
-
93
- // alert(storeCodeInUrl)
94
-
95
- // update store/website saat url berubah, misal /id ke /sg
96
-
97
- // issue store view code gk berubah, klo di graphql aman
98
-
99
- // ini update di graphql dan di cookie, tapi di cookie beda klo ga di hardcode
100
-
101
- // ini oke, store di graphql dari sini
102
- // storeCodeInUrl = 'id_id_store_view';
103
- // console.log('storeCodeInUrl',storeCodeInUrl)
104
-
105
- // await apolloClient.clearCacheData(apolloClient, 'cart');
106
- // await removeCart();
107
-
108
- // klo enabled jd redirect tros
109
- // storage.removeItem('cartId');
110
-
111
- // storage.setItem('store_view_code', storeCodeInUrl);
112
- // storage.setItem('website_code', websiteCodeInUrl);
113
- // storage.setItem(
114
- // 'store_view_currency',
115
- // storeCurrencies[storeCodeInUrl]
116
- // );
117
- // storage.setItem(
118
- // 'store_view_secure_base_media_url',
119
- // storeSecureBaseMediaUrl[storeCodeInUrl]
120
- // );
121
-
122
- // We're required to reload the page as the basename doesn't
123
- // change entirely without a full page reload.
124
- // history.go(0);
125
- }
126
-
127
- // console.log('currentWebsiteCode',currentWebsiteCode)
128
-
129
73
  if (!websiteCodeInUrl) {
130
74
  const websiteCode = process.env.WEBSITE_CODE;
131
75
  // if (websiteCode != storage.getItem('website_code')) {
@@ -168,7 +112,7 @@ const Adapter = props => {
168
112
  }
169
113
  // }
170
114
  }
171
- }, [websiteCodeInUrl, currentWebsiteCode]);
115
+ }, [websiteCodeInUrl]);
172
116
 
173
117
  // TODO: Replace with app skeleton. See PWA-547.
174
118
  if (!initialized) {
@@ -39,7 +39,18 @@ const StoreCodeRoute = () => {
39
39
  // the storage value and refresh so that we start using the new code.
40
40
  useEffect(() => {
41
41
  if (websiteCodeInUrl) {
42
- let prefix = '';
42
+ const websiteCodes = [];
43
+
44
+ AVAILABLE_WEBSITES.forEach(store => {
45
+ websiteCodes.push(store.website_code);
46
+ });
47
+
48
+ const { location } = globalThis;
49
+ const match = location && location.pathname.split("/")[1];
50
+ const websiteCodeInUrl = websiteCodes.find((str) => str === match);
51
+
52
+ const prefix = websiteCodeInUrl ? websiteCodeInUrl + '_' : '';
53
+
43
54
  let storeCodeInUrl = websiteStores[websiteCodeInUrl];
44
55
 
45
56
  storage.setItem(prefix + 'store_view_code', storeCodeInUrl);
@@ -134,6 +134,7 @@ export const useSocialLogin = props => {
134
134
  }
135
135
 
136
136
  setIsSigningIn(false);
137
+ setIsLoading(false);
137
138
  }
138
139
  }
139
140
  }, [
@@ -0,0 +1,53 @@
1
+ import { useEffect, useMemo } from 'react';
2
+ import { useQuery } from '@apollo/client';
3
+
4
+ import { useAppContext } from '@magento/peregrine/lib/context/app';
5
+ import { deriveErrorMessage } from '@magento/peregrine/lib/util/deriveErrorMessage';
6
+
7
+ import operations from '@riosst100/pwa-marketplace/src/overwrites/peregrine/lib/talons/TrackOrder/trackOrder.gql';
8
+
9
+ export const useTrackOrder = (props = {}) => {
10
+ const { incrementId } = props;
11
+ const { getTrackOrderQuery } = operations;
12
+
13
+ const [
14
+ ,
15
+ {
16
+ actions: { setPageLoading }
17
+ }
18
+ ] = useAppContext();
19
+
20
+ const {
21
+ data,
22
+ error,
23
+ loading,
24
+ refetch
25
+ } = useQuery(getTrackOrderQuery, {
26
+ fetchPolicy: 'cache-and-network',
27
+ variables: { increment_id: incrementId },
28
+ skip: !incrementId
29
+ });
30
+
31
+ const isLoadingWithoutData = !data && loading;
32
+ const isBackgroundLoading = !!data && loading;
33
+
34
+ // Update the page indicator if the GraphQL query is in flight.
35
+ useEffect(() => {
36
+ setPageLoading(isBackgroundLoading);
37
+ }, [isBackgroundLoading, setPageLoading]);
38
+
39
+ const derivedErrorMessage = useMemo(
40
+ () => deriveErrorMessage([error]),
41
+ [error]
42
+ );
43
+
44
+ return {
45
+ errorMessage: derivedErrorMessage,
46
+ isLoadingWithoutData,
47
+ isBackgroundLoading,
48
+ trackOrder: data ? data.trackOrder : undefined,
49
+ refetchTrackOrder: refetch
50
+ };
51
+ };
52
+
53
+ export default useTrackOrder;