order-management 0.0.50 → 0.0.51
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/.medusa/server/src/admin/index.js +466 -353
- package/.medusa/server/src/admin/index.mjs +470 -357
- package/.medusa/server/src/api/store/swaps/route.js +2 -53
- package/.medusa/server/src/modules/return/service.js +29 -1
- package/.medusa/server/src/modules/swap/service.js +29 -1
- package/.medusa/server/src/subscribers/order-status-change.js +11 -5
- package/.medusa/server/src/utils/notification-handler.js +169 -31
- package/.medusa/server/src/utils/template.js +22 -6
- package/.medusa/server/src/workflows/steps/return/validate-return-items-step.js +46 -51
- package/.medusa/server/src/workflows/steps/swap/validate-swap-items-step.js +45 -46
- package/.medusa/server/src/workflows/swaps/update-swap-workflow.js +3 -2
- package/README.md +18 -1
- package/package.json +1 -1
|
@@ -5,6 +5,114 @@ const adminSdk = require("@medusajs/admin-sdk");
|
|
|
5
5
|
const ui = require("@medusajs/ui");
|
|
6
6
|
const icons = require("@medusajs/icons");
|
|
7
7
|
const reactRouterDom = require("react-router-dom");
|
|
8
|
+
const OrderReturnApprovalNoticeWidget = ({ data }) => {
|
|
9
|
+
const orderId = data == null ? void 0 : data.id;
|
|
10
|
+
const [returns, setReturns] = react.useState([]);
|
|
11
|
+
const [loading, setLoading] = react.useState(true);
|
|
12
|
+
react.useEffect(() => {
|
|
13
|
+
if (!orderId) {
|
|
14
|
+
setLoading(false);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let cancelled = false;
|
|
18
|
+
const load = async () => {
|
|
19
|
+
try {
|
|
20
|
+
const res = await fetch(
|
|
21
|
+
`/admin/returns?order_id=${encodeURIComponent(orderId)}&limit=50`,
|
|
22
|
+
{ credentials: "include" }
|
|
23
|
+
);
|
|
24
|
+
if (!res.ok || cancelled) return;
|
|
25
|
+
const payload = await res.json();
|
|
26
|
+
const list = Array.isArray(payload.returns) ? payload.returns : [];
|
|
27
|
+
if (!cancelled) setReturns(list);
|
|
28
|
+
} catch {
|
|
29
|
+
if (!cancelled) setReturns([]);
|
|
30
|
+
} finally {
|
|
31
|
+
if (!cancelled) setLoading(false);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
void load();
|
|
35
|
+
return () => {
|
|
36
|
+
cancelled = true;
|
|
37
|
+
};
|
|
38
|
+
}, [orderId]);
|
|
39
|
+
const requestedReturns = returns.filter(
|
|
40
|
+
(r) => {
|
|
41
|
+
var _a;
|
|
42
|
+
return ((_a = r.status) == null ? void 0 : _a.toLowerCase()) === "requested";
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
react.useEffect(() => {
|
|
46
|
+
if (requestedReturns.length === 0) return;
|
|
47
|
+
const RECEIVE_BUTTON_MARKER = "data-om-receive-items-hidden";
|
|
48
|
+
const hideReceiveButton = () => {
|
|
49
|
+
const buttons = document.querySelectorAll(
|
|
50
|
+
`button:not([${RECEIVE_BUTTON_MARKER}])`
|
|
51
|
+
);
|
|
52
|
+
for (const btn of buttons) {
|
|
53
|
+
const text = (btn.textContent ?? "").trim();
|
|
54
|
+
if (text === "Receive items" || text.toLowerCase().includes("receive item")) {
|
|
55
|
+
btn.style.setProperty("display", "none", "important");
|
|
56
|
+
btn.setAttribute(RECEIVE_BUTTON_MARKER, "true");
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
62
|
+
if (hideReceiveButton()) return;
|
|
63
|
+
const observer = new MutationObserver(() => {
|
|
64
|
+
hideReceiveButton();
|
|
65
|
+
});
|
|
66
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
67
|
+
const interval = setInterval(() => {
|
|
68
|
+
if (hideReceiveButton()) {
|
|
69
|
+
clearInterval(interval);
|
|
70
|
+
}
|
|
71
|
+
}, 300);
|
|
72
|
+
return () => {
|
|
73
|
+
clearInterval(interval);
|
|
74
|
+
observer.disconnect();
|
|
75
|
+
document.querySelectorAll(`button[${RECEIVE_BUTTON_MARKER}]`).forEach((el) => {
|
|
76
|
+
el.style.removeProperty("display");
|
|
77
|
+
el.removeAttribute(RECEIVE_BUTTON_MARKER);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
}, [requestedReturns.length]);
|
|
81
|
+
if (loading || requestedReturns.length === 0) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mb-6 overflow-hidden rounded-lg border border-ui-border-base bg-ui-bg-subtle p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
85
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
86
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
87
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.InformationCircle, { className: "text-ui-fg-warning" }),
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "plus", className: "text-ui-fg-base", children: "Return request(s) pending approval" })
|
|
89
|
+
] }),
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
|
|
91
|
+
"This order has ",
|
|
92
|
+
requestedReturns.length,
|
|
93
|
+
" return request",
|
|
94
|
+
requestedReturns.length > 1 ? "s" : "",
|
|
95
|
+
' that must be approved in Return Orders before you can receive items. Do not use the "Receive items" button until the return has been approved.'
|
|
96
|
+
] })
|
|
97
|
+
] }),
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: requestedReturns.slice(0, 3).map((r) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99
|
+
ui.Button,
|
|
100
|
+
{
|
|
101
|
+
size: "small",
|
|
102
|
+
variant: "secondary",
|
|
103
|
+
onClick: () => window.open(`/app/returns/${r.id}`, "_self"),
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { className: "mr-1.5 uppercase", color: "orange", children: "Requested" }),
|
|
106
|
+
"Approve return"
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
r.id
|
|
110
|
+
)) })
|
|
111
|
+
] }) });
|
|
112
|
+
};
|
|
113
|
+
adminSdk.defineWidgetConfig({
|
|
114
|
+
zone: "order.details.before"
|
|
115
|
+
});
|
|
8
116
|
const useDebounce$1 = (value, delay) => {
|
|
9
117
|
const [debouncedValue, setDebouncedValue] = react.useState(value);
|
|
10
118
|
react.useEffect(() => {
|
|
@@ -18,21 +126,21 @@ const getStatusBadgeClass$3 = (status) => {
|
|
|
18
126
|
if (statusLower === "requested") {
|
|
19
127
|
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
20
128
|
}
|
|
21
|
-
if (statusLower === "
|
|
129
|
+
if (statusLower === "received") {
|
|
22
130
|
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
23
131
|
}
|
|
24
|
-
if (statusLower === "
|
|
132
|
+
if (statusLower === "requires_action") {
|
|
25
133
|
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
26
134
|
}
|
|
27
135
|
if (statusLower === "completed") {
|
|
28
136
|
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
29
137
|
}
|
|
30
|
-
if (statusLower === "
|
|
138
|
+
if (statusLower === "canceled") {
|
|
31
139
|
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
32
140
|
}
|
|
33
141
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
34
142
|
};
|
|
35
|
-
const
|
|
143
|
+
const ReturnsPage = () => {
|
|
36
144
|
const navigate = reactRouterDom.useNavigate();
|
|
37
145
|
const [items, setItems] = react.useState([]);
|
|
38
146
|
const [statusFilter, setStatusFilter] = react.useState("all");
|
|
@@ -44,7 +152,7 @@ const SwapsPage = () => {
|
|
|
44
152
|
const [offset, setOffset] = react.useState(0);
|
|
45
153
|
const [count, setCount] = react.useState(0);
|
|
46
154
|
const limit = 50;
|
|
47
|
-
const
|
|
155
|
+
const loadReturns = react.useCallback(
|
|
48
156
|
async (nextOffset, replace = false) => {
|
|
49
157
|
var _a;
|
|
50
158
|
try {
|
|
@@ -61,24 +169,25 @@ const SwapsPage = () => {
|
|
|
61
169
|
params.set("status", statusFilter);
|
|
62
170
|
}
|
|
63
171
|
if (debouncedSearchQuery.trim()) {
|
|
64
|
-
params.set("
|
|
172
|
+
params.set("q", debouncedSearchQuery.trim());
|
|
65
173
|
}
|
|
174
|
+
params.set("order", "created_at");
|
|
66
175
|
const response = await fetch(
|
|
67
|
-
`/admin/
|
|
176
|
+
`/admin/returns?${params.toString()}`,
|
|
68
177
|
{ credentials: "include" }
|
|
69
178
|
);
|
|
70
179
|
if (!response.ok) {
|
|
71
180
|
const message = await response.text();
|
|
72
|
-
throw new Error(message || "Unable to load
|
|
181
|
+
throw new Error(message || "Unable to load return orders");
|
|
73
182
|
}
|
|
74
183
|
const payload = await response.json();
|
|
75
184
|
setCount(payload.count ?? 0);
|
|
76
|
-
setOffset(nextOffset + (((_a = payload.
|
|
185
|
+
setOffset(nextOffset + (((_a = payload.returns) == null ? void 0 : _a.length) ?? 0));
|
|
77
186
|
setItems(
|
|
78
|
-
(prev) => replace ? payload.
|
|
187
|
+
(prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
|
|
79
188
|
);
|
|
80
189
|
} catch (loadError) {
|
|
81
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load
|
|
190
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
82
191
|
setError(message);
|
|
83
192
|
} finally {
|
|
84
193
|
setIsLoading(false);
|
|
@@ -88,8 +197,8 @@ const SwapsPage = () => {
|
|
|
88
197
|
[statusFilter, debouncedSearchQuery]
|
|
89
198
|
);
|
|
90
199
|
react.useEffect(() => {
|
|
91
|
-
void
|
|
92
|
-
}, [statusFilter, debouncedSearchQuery,
|
|
200
|
+
void loadReturns(0, true);
|
|
201
|
+
}, [statusFilter, debouncedSearchQuery, loadReturns]);
|
|
93
202
|
const hasMore = react.useMemo(() => offset < count, [offset, count]);
|
|
94
203
|
const availableStatuses = react.useMemo(() => {
|
|
95
204
|
const statuses = /* @__PURE__ */ new Set();
|
|
@@ -99,16 +208,16 @@ const SwapsPage = () => {
|
|
|
99
208
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-6", children: [
|
|
100
209
|
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
101
210
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
102
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
103
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer
|
|
211
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Return Orders" }),
|
|
212
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
|
|
104
213
|
] }),
|
|
105
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "primary", onClick: () =>
|
|
214
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
|
|
106
215
|
] }),
|
|
107
216
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
108
217
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
109
218
|
ui.Input,
|
|
110
219
|
{
|
|
111
|
-
placeholder: "Search by
|
|
220
|
+
placeholder: "Search by return ID, order ID, or customer email",
|
|
112
221
|
value: searchQuery,
|
|
113
222
|
onChange: (event) => setSearchQuery(event.target.value),
|
|
114
223
|
className: "md:max-w-sm"
|
|
@@ -133,50 +242,51 @@ const SwapsPage = () => {
|
|
|
133
242
|
ui.Button,
|
|
134
243
|
{
|
|
135
244
|
variant: "secondary",
|
|
136
|
-
onClick: () =>
|
|
245
|
+
onClick: () => loadReturns(0, true),
|
|
137
246
|
children: "Try again"
|
|
138
247
|
}
|
|
139
248
|
) })
|
|
140
249
|
] }) : null,
|
|
141
|
-
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading
|
|
142
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "text-xl", children: "No
|
|
143
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "
|
|
250
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading return orders..." }) }) : items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
|
|
252
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
|
|
144
253
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
145
254
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
146
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "
|
|
255
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
|
|
147
256
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
257
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
148
258
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
149
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "
|
|
259
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
|
|
150
260
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
151
261
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
152
262
|
] }) }),
|
|
153
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
154
264
|
"tr",
|
|
155
265
|
{
|
|
156
266
|
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
157
|
-
onClick: () => navigate(`/
|
|
267
|
+
onClick: () => navigate(`/returns/${returnOrder.id}`),
|
|
158
268
|
children: [
|
|
159
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
160
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children:
|
|
269
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: returnOrder.id }) }) }),
|
|
270
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
|
|
271
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
161
272
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
162
273
|
ui.Badge,
|
|
163
274
|
{
|
|
164
275
|
size: "2xsmall",
|
|
165
|
-
className: `uppercase ${getStatusBadgeClass$3(
|
|
166
|
-
children:
|
|
276
|
+
className: `uppercase ${getStatusBadgeClass$3(returnOrder.status)}`,
|
|
277
|
+
children: returnOrder.status.replace(/_/g, " ")
|
|
167
278
|
}
|
|
168
279
|
) }),
|
|
169
280
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
170
|
-
const amount =
|
|
281
|
+
const amount = returnOrder.refund_amount;
|
|
171
282
|
if (amount == null || amount === void 0) {
|
|
172
283
|
return "—";
|
|
173
284
|
}
|
|
174
285
|
const displayAmount = Number(amount) / 100;
|
|
175
|
-
const currency =
|
|
176
|
-
|
|
177
|
-
return `${sign}${currency}${displayAmount.toFixed(2)}`;
|
|
286
|
+
const currency = returnOrder.currency_code || "$";
|
|
287
|
+
return `${currency}${displayAmount.toFixed(2)}`;
|
|
178
288
|
})() }),
|
|
179
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(
|
|
289
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
|
|
180
290
|
year: "numeric",
|
|
181
291
|
month: "short",
|
|
182
292
|
day: "numeric",
|
|
@@ -191,14 +301,14 @@ const SwapsPage = () => {
|
|
|
191
301
|
size: "small",
|
|
192
302
|
onClick: (e) => {
|
|
193
303
|
e.stopPropagation();
|
|
194
|
-
navigate(`/
|
|
304
|
+
navigate(`/returns/${returnOrder.id}`);
|
|
195
305
|
},
|
|
196
306
|
children: "View"
|
|
197
307
|
}
|
|
198
308
|
) })
|
|
199
309
|
]
|
|
200
310
|
},
|
|
201
|
-
|
|
311
|
+
returnOrder.id
|
|
202
312
|
)) })
|
|
203
313
|
] }) }),
|
|
204
314
|
hasMore ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -206,14 +316,14 @@ const SwapsPage = () => {
|
|
|
206
316
|
{
|
|
207
317
|
variant: "secondary",
|
|
208
318
|
isLoading: isFetchingMore,
|
|
209
|
-
onClick: () =>
|
|
319
|
+
onClick: () => loadReturns(offset, false),
|
|
210
320
|
children: "Load more"
|
|
211
321
|
}
|
|
212
322
|
) }) : null
|
|
213
323
|
] }) });
|
|
214
324
|
};
|
|
215
325
|
const config$3 = adminSdk.defineRouteConfig({
|
|
216
|
-
label: "
|
|
326
|
+
label: "Return Orders",
|
|
217
327
|
icon: icons.ArrowPath
|
|
218
328
|
});
|
|
219
329
|
const useDebounce = (value, delay) => {
|
|
@@ -229,21 +339,21 @@ const getStatusBadgeClass$2 = (status) => {
|
|
|
229
339
|
if (statusLower === "requested") {
|
|
230
340
|
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
231
341
|
}
|
|
232
|
-
if (statusLower === "
|
|
342
|
+
if (statusLower === "approved") {
|
|
233
343
|
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
234
344
|
}
|
|
235
|
-
if (statusLower === "
|
|
345
|
+
if (statusLower === "rejected") {
|
|
236
346
|
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
237
347
|
}
|
|
238
348
|
if (statusLower === "completed") {
|
|
239
349
|
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
240
350
|
}
|
|
241
|
-
if (statusLower === "
|
|
351
|
+
if (statusLower === "cancelled") {
|
|
242
352
|
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
243
353
|
}
|
|
244
354
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
245
355
|
};
|
|
246
|
-
const
|
|
356
|
+
const SwapsPage = () => {
|
|
247
357
|
const navigate = reactRouterDom.useNavigate();
|
|
248
358
|
const [items, setItems] = react.useState([]);
|
|
249
359
|
const [statusFilter, setStatusFilter] = react.useState("all");
|
|
@@ -255,7 +365,7 @@ const ReturnsPage = () => {
|
|
|
255
365
|
const [offset, setOffset] = react.useState(0);
|
|
256
366
|
const [count, setCount] = react.useState(0);
|
|
257
367
|
const limit = 50;
|
|
258
|
-
const
|
|
368
|
+
const loadSwaps = react.useCallback(
|
|
259
369
|
async (nextOffset, replace = false) => {
|
|
260
370
|
var _a;
|
|
261
371
|
try {
|
|
@@ -272,25 +382,24 @@ const ReturnsPage = () => {
|
|
|
272
382
|
params.set("status", statusFilter);
|
|
273
383
|
}
|
|
274
384
|
if (debouncedSearchQuery.trim()) {
|
|
275
|
-
params.set("
|
|
385
|
+
params.set("order_id", debouncedSearchQuery.trim());
|
|
276
386
|
}
|
|
277
|
-
params.set("order", "created_at");
|
|
278
387
|
const response = await fetch(
|
|
279
|
-
`/admin/
|
|
388
|
+
`/admin/swaps?${params.toString()}`,
|
|
280
389
|
{ credentials: "include" }
|
|
281
390
|
);
|
|
282
391
|
if (!response.ok) {
|
|
283
392
|
const message = await response.text();
|
|
284
|
-
throw new Error(message || "Unable to load
|
|
393
|
+
throw new Error(message || "Unable to load swaps");
|
|
285
394
|
}
|
|
286
395
|
const payload = await response.json();
|
|
287
396
|
setCount(payload.count ?? 0);
|
|
288
|
-
setOffset(nextOffset + (((_a = payload.
|
|
397
|
+
setOffset(nextOffset + (((_a = payload.swaps) == null ? void 0 : _a.length) ?? 0));
|
|
289
398
|
setItems(
|
|
290
|
-
(prev) => replace ? payload.
|
|
399
|
+
(prev) => replace ? payload.swaps ?? [] : [...prev, ...payload.swaps ?? []]
|
|
291
400
|
);
|
|
292
401
|
} catch (loadError) {
|
|
293
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load
|
|
402
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
|
|
294
403
|
setError(message);
|
|
295
404
|
} finally {
|
|
296
405
|
setIsLoading(false);
|
|
@@ -300,8 +409,8 @@ const ReturnsPage = () => {
|
|
|
300
409
|
[statusFilter, debouncedSearchQuery]
|
|
301
410
|
);
|
|
302
411
|
react.useEffect(() => {
|
|
303
|
-
void
|
|
304
|
-
}, [statusFilter, debouncedSearchQuery,
|
|
412
|
+
void loadSwaps(0, true);
|
|
413
|
+
}, [statusFilter, debouncedSearchQuery, loadSwaps]);
|
|
305
414
|
const hasMore = react.useMemo(() => offset < count, [offset, count]);
|
|
306
415
|
const availableStatuses = react.useMemo(() => {
|
|
307
416
|
const statuses = /* @__PURE__ */ new Set();
|
|
@@ -311,16 +420,16 @@ const ReturnsPage = () => {
|
|
|
311
420
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-6", children: [
|
|
312
421
|
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
313
422
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
314
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
315
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer
|
|
423
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Swaps" }),
|
|
424
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer swap requests" })
|
|
316
425
|
] }),
|
|
317
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "primary", onClick: () =>
|
|
426
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "primary", onClick: () => loadSwaps(0, true), children: "Refresh" })
|
|
318
427
|
] }),
|
|
319
428
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
320
429
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
321
430
|
ui.Input,
|
|
322
431
|
{
|
|
323
|
-
placeholder: "Search by
|
|
432
|
+
placeholder: "Search by swap ID or order ID",
|
|
324
433
|
value: searchQuery,
|
|
325
434
|
onChange: (event) => setSearchQuery(event.target.value),
|
|
326
435
|
className: "md:max-w-sm"
|
|
@@ -345,51 +454,50 @@ const ReturnsPage = () => {
|
|
|
345
454
|
ui.Button,
|
|
346
455
|
{
|
|
347
456
|
variant: "secondary",
|
|
348
|
-
onClick: () =>
|
|
457
|
+
onClick: () => loadSwaps(0, true),
|
|
349
458
|
children: "Try again"
|
|
350
459
|
}
|
|
351
460
|
) })
|
|
352
461
|
] }) : null,
|
|
353
|
-
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading
|
|
354
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "text-xl", children: "No
|
|
355
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "
|
|
462
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading swaps..." }) }) : items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
463
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "text-xl", children: "No swaps yet" }),
|
|
464
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Swap requests created by customers will appear here." })
|
|
356
465
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
357
466
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
358
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "
|
|
467
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Swap ID" }),
|
|
359
468
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
360
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
361
469
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
362
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "
|
|
470
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Difference Due" }),
|
|
363
471
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
364
472
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
365
473
|
] }) }),
|
|
366
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((
|
|
474
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((swap) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
367
475
|
"tr",
|
|
368
476
|
{
|
|
369
477
|
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
370
|
-
onClick: () => navigate(`/
|
|
478
|
+
onClick: () => navigate(`/swaps/${swap.id}`),
|
|
371
479
|
children: [
|
|
372
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
373
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children:
|
|
374
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
480
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: swap.id }) }) }),
|
|
481
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: swap.order_id }),
|
|
375
482
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
376
483
|
ui.Badge,
|
|
377
484
|
{
|
|
378
485
|
size: "2xsmall",
|
|
379
|
-
className: `uppercase ${getStatusBadgeClass$2(
|
|
380
|
-
children:
|
|
486
|
+
className: `uppercase ${getStatusBadgeClass$2(swap.status)}`,
|
|
487
|
+
children: swap.status.replace(/_/g, " ")
|
|
381
488
|
}
|
|
382
489
|
) }),
|
|
383
490
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
384
|
-
const amount =
|
|
491
|
+
const amount = swap.difference_due;
|
|
385
492
|
if (amount == null || amount === void 0) {
|
|
386
493
|
return "—";
|
|
387
494
|
}
|
|
388
495
|
const displayAmount = Number(amount) / 100;
|
|
389
|
-
const currency =
|
|
390
|
-
|
|
496
|
+
const currency = swap.currency_code || "$";
|
|
497
|
+
const sign = displayAmount >= 0 ? "+" : "";
|
|
498
|
+
return `${sign}${currency}${displayAmount.toFixed(2)}`;
|
|
391
499
|
})() }),
|
|
392
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(
|
|
500
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(swap.created_at).toLocaleDateString("en-US", {
|
|
393
501
|
year: "numeric",
|
|
394
502
|
month: "short",
|
|
395
503
|
day: "numeric",
|
|
@@ -404,14 +512,14 @@ const ReturnsPage = () => {
|
|
|
404
512
|
size: "small",
|
|
405
513
|
onClick: (e) => {
|
|
406
514
|
e.stopPropagation();
|
|
407
|
-
navigate(`/
|
|
515
|
+
navigate(`/swaps/${swap.id}`);
|
|
408
516
|
},
|
|
409
517
|
children: "View"
|
|
410
518
|
}
|
|
411
519
|
) })
|
|
412
520
|
]
|
|
413
521
|
},
|
|
414
|
-
|
|
522
|
+
swap.id
|
|
415
523
|
)) })
|
|
416
524
|
] }) }),
|
|
417
525
|
hasMore ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -419,14 +527,14 @@ const ReturnsPage = () => {
|
|
|
419
527
|
{
|
|
420
528
|
variant: "secondary",
|
|
421
529
|
isLoading: isFetchingMore,
|
|
422
|
-
onClick: () =>
|
|
530
|
+
onClick: () => loadSwaps(offset, false),
|
|
423
531
|
children: "Load more"
|
|
424
532
|
}
|
|
425
533
|
) }) : null
|
|
426
534
|
] }) });
|
|
427
535
|
};
|
|
428
536
|
const config$2 = adminSdk.defineRouteConfig({
|
|
429
|
-
label: "
|
|
537
|
+
label: "Swaps",
|
|
430
538
|
icon: icons.ArrowPath
|
|
431
539
|
});
|
|
432
540
|
const getStatusBadgeClass$1 = (status) => {
|
|
@@ -440,6 +548,12 @@ const getStatusBadgeClass$1 = (status) => {
|
|
|
440
548
|
if (statusLower === "rejected") {
|
|
441
549
|
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
442
550
|
}
|
|
551
|
+
if (statusLower === "received") {
|
|
552
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
553
|
+
}
|
|
554
|
+
if (statusLower === "refunded") {
|
|
555
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
556
|
+
}
|
|
443
557
|
if (statusLower === "completed") {
|
|
444
558
|
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
445
559
|
}
|
|
@@ -448,182 +562,134 @@ const getStatusBadgeClass$1 = (status) => {
|
|
|
448
562
|
}
|
|
449
563
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
450
564
|
};
|
|
451
|
-
const
|
|
565
|
+
const ReturnDetailPage = () => {
|
|
452
566
|
var _a, _b;
|
|
453
567
|
const navigate = reactRouterDom.useNavigate();
|
|
454
568
|
const { id } = reactRouterDom.useParams();
|
|
455
|
-
const [
|
|
456
|
-
const [order, setOrder] = react.useState(null);
|
|
457
|
-
const [selectedStatus, setSelectedStatus] = react.useState("");
|
|
569
|
+
const [returnOrder, setReturnOrder] = react.useState(null);
|
|
458
570
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
459
|
-
const [isUpdating, setIsUpdating] = react.useState(false);
|
|
460
571
|
const [isApproving, setIsApproving] = react.useState(false);
|
|
461
572
|
const [isRejecting, setIsRejecting] = react.useState(false);
|
|
462
573
|
const [error, setError] = react.useState(null);
|
|
463
574
|
const [updateError, setUpdateError] = react.useState(null);
|
|
464
575
|
const [updateSuccess, setUpdateSuccess] = react.useState(false);
|
|
465
|
-
const availableStatuses = ["requested", "approved", "rejected"];
|
|
466
576
|
react.useEffect(() => {
|
|
467
577
|
if (!id) {
|
|
468
|
-
navigate("/
|
|
578
|
+
navigate("/returns");
|
|
469
579
|
return;
|
|
470
580
|
}
|
|
471
|
-
const
|
|
581
|
+
const loadReturn = async () => {
|
|
472
582
|
try {
|
|
473
583
|
setIsLoading(true);
|
|
474
584
|
setError(null);
|
|
475
|
-
const response = await fetch(`/admin/
|
|
585
|
+
const response = await fetch(`/admin/returns/${id}`, {
|
|
476
586
|
credentials: "include"
|
|
477
587
|
});
|
|
478
588
|
if (!response.ok) {
|
|
479
589
|
const message = await response.text();
|
|
480
|
-
throw new Error(message || "Unable to load
|
|
590
|
+
throw new Error(message || "Unable to load return order");
|
|
481
591
|
}
|
|
482
592
|
const payload = await response.json();
|
|
483
|
-
|
|
484
|
-
setOrder(payload.order || null);
|
|
485
|
-
setSelectedStatus("");
|
|
593
|
+
setReturnOrder(payload.return);
|
|
486
594
|
} catch (loadError) {
|
|
487
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load
|
|
595
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return order";
|
|
488
596
|
setError(message);
|
|
489
597
|
} finally {
|
|
490
598
|
setIsLoading(false);
|
|
491
599
|
}
|
|
492
600
|
};
|
|
493
|
-
void
|
|
601
|
+
void loadReturn();
|
|
494
602
|
}, [id, navigate]);
|
|
495
|
-
const
|
|
496
|
-
if (!id
|
|
603
|
+
const handleApprove = async () => {
|
|
604
|
+
if (!id) {
|
|
497
605
|
return;
|
|
498
606
|
}
|
|
499
607
|
try {
|
|
500
|
-
|
|
608
|
+
setIsApproving(true);
|
|
501
609
|
setUpdateError(null);
|
|
502
610
|
setUpdateSuccess(false);
|
|
503
|
-
const response = await fetch(`/admin/
|
|
611
|
+
const response = await fetch(`/admin/returns/${id}/approve`, {
|
|
504
612
|
method: "POST",
|
|
505
613
|
headers: {
|
|
506
614
|
"Content-Type": "application/json"
|
|
507
615
|
},
|
|
508
|
-
credentials: "include"
|
|
509
|
-
body: JSON.stringify({ status: selectedStatus })
|
|
616
|
+
credentials: "include"
|
|
510
617
|
});
|
|
511
618
|
if (!response.ok) {
|
|
512
619
|
const message = await response.text();
|
|
513
|
-
throw new Error(message || "Unable to
|
|
620
|
+
throw new Error(message || "Unable to approve return");
|
|
514
621
|
}
|
|
515
622
|
const payload = await response.json();
|
|
516
|
-
|
|
517
|
-
setSelectedStatus("");
|
|
623
|
+
setReturnOrder(payload.return);
|
|
518
624
|
setUpdateSuccess(true);
|
|
625
|
+
const orderId = payload.return.order_id;
|
|
626
|
+
if (orderId) {
|
|
627
|
+
window.location.href = `/app/orders/${orderId}`;
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
519
630
|
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
520
|
-
const detailResponse = await fetch(`/admin/
|
|
631
|
+
const detailResponse = await fetch(`/admin/returns/${id}`, {
|
|
521
632
|
credentials: "include"
|
|
522
633
|
});
|
|
523
634
|
if (detailResponse.ok) {
|
|
524
635
|
const detailPayload = await detailResponse.json();
|
|
525
|
-
|
|
526
|
-
setOrder(detailPayload.order || null);
|
|
636
|
+
setReturnOrder(detailPayload.return);
|
|
527
637
|
}
|
|
528
|
-
} catch (
|
|
529
|
-
const message =
|
|
638
|
+
} catch (approveErr) {
|
|
639
|
+
const message = approveErr instanceof Error ? approveErr.message : "Unable to approve return";
|
|
530
640
|
setUpdateError(message);
|
|
531
641
|
} finally {
|
|
532
|
-
|
|
642
|
+
setIsApproving(false);
|
|
533
643
|
}
|
|
534
644
|
};
|
|
535
|
-
const
|
|
645
|
+
const handleReject = async () => {
|
|
536
646
|
if (!id) {
|
|
537
647
|
return;
|
|
538
648
|
}
|
|
539
649
|
try {
|
|
540
|
-
|
|
650
|
+
setIsRejecting(true);
|
|
541
651
|
setUpdateError(null);
|
|
542
652
|
setUpdateSuccess(false);
|
|
543
|
-
const response = await fetch(`/admin/
|
|
653
|
+
const response = await fetch(`/admin/returns/${id}/reject`, {
|
|
544
654
|
method: "POST",
|
|
545
655
|
headers: {
|
|
546
656
|
"Content-Type": "application/json"
|
|
547
657
|
},
|
|
548
|
-
credentials: "include"
|
|
658
|
+
credentials: "include",
|
|
659
|
+
body: JSON.stringify({ reason: "Rejected by admin" })
|
|
549
660
|
});
|
|
550
661
|
if (!response.ok) {
|
|
551
662
|
const message = await response.text();
|
|
552
|
-
throw new Error(message || "Unable to
|
|
663
|
+
throw new Error(message || "Unable to reject return");
|
|
553
664
|
}
|
|
554
665
|
const payload = await response.json();
|
|
555
|
-
|
|
556
|
-
setUpdateSuccess(true);
|
|
557
|
-
const orderId = payload.swap.order_id;
|
|
558
|
-
if (orderId) {
|
|
559
|
-
window.location.href = `/app/orders/${orderId}`;
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
563
|
-
const detailResponse = await fetch(`/admin/swaps/${id}`, {
|
|
564
|
-
credentials: "include"
|
|
565
|
-
});
|
|
566
|
-
if (detailResponse.ok) {
|
|
567
|
-
const detailPayload = await detailResponse.json();
|
|
568
|
-
setSwap(detailPayload.swap);
|
|
569
|
-
setOrder(detailPayload.order || null);
|
|
570
|
-
}
|
|
571
|
-
} catch (approveErr) {
|
|
572
|
-
const message = approveErr instanceof Error ? approveErr.message : "Unable to create exchange from swap";
|
|
573
|
-
setUpdateError(message);
|
|
574
|
-
} finally {
|
|
575
|
-
setIsApproving(false);
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
const handleReject = async () => {
|
|
579
|
-
if (!id) {
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
try {
|
|
583
|
-
setIsRejecting(true);
|
|
584
|
-
setUpdateError(null);
|
|
585
|
-
setUpdateSuccess(false);
|
|
586
|
-
const response = await fetch(`/admin/swaps/${id}/reject`, {
|
|
587
|
-
method: "POST",
|
|
588
|
-
headers: {
|
|
589
|
-
"Content-Type": "application/json"
|
|
590
|
-
},
|
|
591
|
-
credentials: "include",
|
|
592
|
-
body: JSON.stringify({ reason: "Rejected by admin" })
|
|
593
|
-
});
|
|
594
|
-
if (!response.ok) {
|
|
595
|
-
const message = await response.text();
|
|
596
|
-
throw new Error(message || "Unable to reject swap");
|
|
597
|
-
}
|
|
598
|
-
const payload = await response.json();
|
|
599
|
-
setSwap(payload.swap);
|
|
666
|
+
setReturnOrder(payload.return);
|
|
600
667
|
setUpdateSuccess(true);
|
|
601
668
|
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
602
|
-
const detailResponse = await fetch(`/admin/
|
|
669
|
+
const detailResponse = await fetch(`/admin/returns/${id}`, {
|
|
603
670
|
credentials: "include"
|
|
604
671
|
});
|
|
605
672
|
if (detailResponse.ok) {
|
|
606
673
|
const detailPayload = await detailResponse.json();
|
|
607
|
-
|
|
608
|
-
setOrder(detailPayload.order || null);
|
|
674
|
+
setReturnOrder(detailPayload.return);
|
|
609
675
|
}
|
|
610
676
|
} catch (updateErr) {
|
|
611
|
-
const message = updateErr instanceof Error ? updateErr.message : "Unable to reject
|
|
677
|
+
const message = updateErr instanceof Error ? updateErr.message : "Unable to reject return";
|
|
612
678
|
setUpdateError(message);
|
|
613
679
|
} finally {
|
|
614
680
|
setIsRejecting(false);
|
|
615
681
|
}
|
|
616
682
|
};
|
|
617
683
|
if (isLoading) {
|
|
618
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading
|
|
684
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading return order..." }) }) }) });
|
|
619
685
|
}
|
|
620
|
-
if (error || !
|
|
686
|
+
if (error || !returnOrder) {
|
|
621
687
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
622
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "plus", className: "text-ui-fg-error", children: error || "
|
|
623
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/
|
|
688
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Return order not found" }),
|
|
689
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/returns"), children: "Back to list" }) })
|
|
624
690
|
] }) }) });
|
|
625
691
|
}
|
|
626
|
-
const statusHistory = ((_a =
|
|
692
|
+
const statusHistory = ((_a = returnOrder.metadata) == null ? void 0 : _a.status_history) || [];
|
|
627
693
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: [
|
|
628
694
|
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
629
695
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -631,7 +697,7 @@ const SwapDetailPage = () => {
|
|
|
631
697
|
{
|
|
632
698
|
variant: "transparent",
|
|
633
699
|
size: "small",
|
|
634
|
-
onClick: () => navigate("/
|
|
700
|
+
onClick: () => navigate("/returns"),
|
|
635
701
|
className: "w-fit",
|
|
636
702
|
children: [
|
|
637
703
|
/* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, { className: "mr-2" }),
|
|
@@ -641,29 +707,29 @@ const SwapDetailPage = () => {
|
|
|
641
707
|
),
|
|
642
708
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:flex-row md:items-center md:justify-between", children: [
|
|
643
709
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
644
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
645
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children:
|
|
710
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Return Order Details" }),
|
|
711
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: returnOrder.id })
|
|
646
712
|
] }),
|
|
647
713
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
648
714
|
ui.Badge,
|
|
649
715
|
{
|
|
650
716
|
size: "small",
|
|
651
|
-
className: `uppercase ${getStatusBadgeClass$1(
|
|
652
|
-
children:
|
|
717
|
+
className: `uppercase ${getStatusBadgeClass$1(returnOrder.status)}`,
|
|
718
|
+
children: returnOrder.status.replace(/_/g, " ")
|
|
653
719
|
}
|
|
654
720
|
)
|
|
655
721
|
] })
|
|
656
722
|
] }),
|
|
657
|
-
|
|
723
|
+
returnOrder.status === "requested" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
658
724
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
659
725
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
660
726
|
ui.Button,
|
|
661
727
|
{
|
|
662
728
|
variant: "primary",
|
|
663
|
-
onClick:
|
|
729
|
+
onClick: handleApprove,
|
|
664
730
|
disabled: isApproving || isRejecting,
|
|
665
731
|
isLoading: isApproving,
|
|
666
|
-
children: "Approve &
|
|
732
|
+
children: "Approve & Process Return"
|
|
667
733
|
}
|
|
668
734
|
),
|
|
669
735
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -673,98 +739,62 @@ const SwapDetailPage = () => {
|
|
|
673
739
|
onClick: handleReject,
|
|
674
740
|
disabled: isApproving || isRejecting,
|
|
675
741
|
isLoading: isRejecting,
|
|
676
|
-
children: "Reject
|
|
677
|
-
}
|
|
678
|
-
)
|
|
679
|
-
] }),
|
|
680
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Approving will automatically create an exchange with return items and new items from the swap request" })
|
|
681
|
-
] }),
|
|
682
|
-
swap.status === "requested" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
683
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Update Status" }),
|
|
684
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-end", children: [
|
|
685
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
686
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "New Status" }),
|
|
687
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
688
|
-
"select",
|
|
689
|
-
{
|
|
690
|
-
value: selectedStatus,
|
|
691
|
-
onChange: (event) => setSelectedStatus(event.target.value),
|
|
692
|
-
className: "h-9 w-full rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
|
|
693
|
-
children: [
|
|
694
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select new status" }),
|
|
695
|
-
availableStatuses.filter((status) => status !== swap.status).map((status) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
696
|
-
]
|
|
697
|
-
}
|
|
698
|
-
)
|
|
699
|
-
] }),
|
|
700
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
701
|
-
ui.Button,
|
|
702
|
-
{
|
|
703
|
-
variant: "primary",
|
|
704
|
-
onClick: handleStatusUpdate,
|
|
705
|
-
disabled: !selectedStatus || isUpdating,
|
|
706
|
-
isLoading: isUpdating,
|
|
707
|
-
children: "Update Status"
|
|
742
|
+
children: "Reject Return"
|
|
708
743
|
}
|
|
709
744
|
)
|
|
710
745
|
] }),
|
|
711
|
-
|
|
712
|
-
updateSuccess && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-success", children: "Status updated successfully" })
|
|
746
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Approving will create a Medusa return entity and process the return request" })
|
|
713
747
|
] }),
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
748
|
+
(returnOrder.status === "approved" || returnOrder.status === "received" || returnOrder.status === "refunded") && returnOrder.medusa_return_id && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Receive item and process refund from the order detail page (same flow as admin-created returns)." }) }),
|
|
749
|
+
returnOrder.status === "approved" && returnOrder.medusa_return_id && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
750
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Information" }),
|
|
751
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
717
752
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
718
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
719
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
753
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Medusa Return ID" }),
|
|
754
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.medusa_return_id })
|
|
720
755
|
] }),
|
|
721
756
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
722
757
|
ui.Button,
|
|
723
758
|
{
|
|
724
759
|
variant: "secondary",
|
|
725
760
|
onClick: () => {
|
|
726
|
-
window.open(
|
|
761
|
+
window.open(
|
|
762
|
+
`/app/orders/${returnOrder.order_id}`,
|
|
763
|
+
"_blank"
|
|
764
|
+
);
|
|
727
765
|
},
|
|
728
|
-
children: "View
|
|
766
|
+
children: "View in Medusa"
|
|
729
767
|
}
|
|
730
768
|
) })
|
|
731
|
-
] })
|
|
769
|
+
] })
|
|
732
770
|
] }),
|
|
733
771
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
734
772
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
735
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "
|
|
773
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Details" }),
|
|
736
774
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
737
775
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
738
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
739
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
776
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Return ID" }),
|
|
777
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.id })
|
|
740
778
|
] }),
|
|
741
779
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
742
780
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Status" }),
|
|
743
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
744
|
-
] }),
|
|
745
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
746
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Difference Due" }),
|
|
747
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.difference_due != null ? `${swap.currency_code || "$"}${(Number(swap.difference_due) / 100).toFixed(2)}` : "—" })
|
|
781
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.status })
|
|
748
782
|
] }),
|
|
749
|
-
|
|
783
|
+
returnOrder.reason && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
750
784
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Reason" }),
|
|
751
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
785
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.reason })
|
|
752
786
|
] }),
|
|
753
|
-
|
|
787
|
+
returnOrder.note && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
754
788
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Note" }),
|
|
755
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
789
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.note })
|
|
756
790
|
] }),
|
|
757
791
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
758
792
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Created" }),
|
|
759
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(
|
|
793
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(returnOrder.created_at).toLocaleString() })
|
|
760
794
|
] }),
|
|
761
795
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
762
796
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Last Updated" }),
|
|
763
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(
|
|
764
|
-
] }),
|
|
765
|
-
swap.exchange_id && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
766
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
|
|
767
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.exchange_id })
|
|
797
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(returnOrder.updated_at).toLocaleString() })
|
|
768
798
|
] })
|
|
769
799
|
] })
|
|
770
800
|
] }),
|
|
@@ -794,31 +824,31 @@ const SwapDetailPage = () => {
|
|
|
794
824
|
)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "No status history available" })
|
|
795
825
|
] })
|
|
796
826
|
] }),
|
|
797
|
-
order && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
827
|
+
returnOrder.order && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
798
828
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Related Order Information" }),
|
|
799
829
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
800
830
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
801
831
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Order ID" }),
|
|
802
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: order.id })
|
|
832
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.order.id })
|
|
803
833
|
] }),
|
|
804
834
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
805
835
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Status" }),
|
|
806
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: order.status || "—" })
|
|
836
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: returnOrder.order.status || "—" })
|
|
807
837
|
] }),
|
|
808
838
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
809
839
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
|
|
810
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: ((_b = order.customer) == null ? void 0 : _b.email) || order.email || "—" })
|
|
840
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: ((_b = returnOrder.order.customer) == null ? void 0 : _b.email) || returnOrder.order.email || "—" })
|
|
811
841
|
] }),
|
|
812
|
-
order.total && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
842
|
+
returnOrder.order.total && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
813
843
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
814
844
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "font-medium", children: [
|
|
815
|
-
order.currency_code || "$",
|
|
816
|
-
(Number(order.total) / 100).toFixed(2)
|
|
845
|
+
returnOrder.order.currency_code || "$",
|
|
846
|
+
(Number(returnOrder.order.total) / 100).toFixed(2)
|
|
817
847
|
] })
|
|
818
848
|
] })
|
|
819
849
|
] })
|
|
820
850
|
] }),
|
|
821
|
-
|
|
851
|
+
returnOrder.return_items && returnOrder.return_items.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
822
852
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Items" }),
|
|
823
853
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
824
854
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
@@ -826,31 +856,20 @@ const SwapDetailPage = () => {
|
|
|
826
856
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" }),
|
|
827
857
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Reason" })
|
|
828
858
|
] }) }),
|
|
829
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children:
|
|
859
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: returnOrder.return_items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
830
860
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.id }),
|
|
831
861
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity }),
|
|
832
862
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.reason || "—" })
|
|
833
863
|
] }, item.id || index)) })
|
|
834
864
|
] }) })
|
|
835
865
|
] }),
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
839
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
840
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Variant ID" }),
|
|
841
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" })
|
|
842
|
-
] }) }),
|
|
843
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.new_items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
844
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.variant_id }),
|
|
845
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity })
|
|
846
|
-
] }, item.variant_id || index)) })
|
|
847
|
-
] }) })
|
|
848
|
-
] })
|
|
866
|
+
updateError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-ui-border-error bg-ui-bg-error-subtle p-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error", children: updateError }) }),
|
|
867
|
+
updateSuccess && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-ui-border-success bg-ui-bg-success-subtle p-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-success", children: "Action completed successfully" }) })
|
|
849
868
|
] }) });
|
|
850
869
|
};
|
|
851
870
|
const config$1 = adminSdk.defineRouteConfig({
|
|
852
|
-
label: "
|
|
853
|
-
icon: icons.
|
|
871
|
+
label: "Return Order Details",
|
|
872
|
+
icon: icons.CheckCircle
|
|
854
873
|
});
|
|
855
874
|
const getStatusBadgeClass = (status) => {
|
|
856
875
|
const statusLower = status.toLowerCase();
|
|
@@ -863,12 +882,6 @@ const getStatusBadgeClass = (status) => {
|
|
|
863
882
|
if (statusLower === "rejected") {
|
|
864
883
|
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
865
884
|
}
|
|
866
|
-
if (statusLower === "received") {
|
|
867
|
-
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
868
|
-
}
|
|
869
|
-
if (statusLower === "refunded") {
|
|
870
|
-
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
871
|
-
}
|
|
872
885
|
if (statusLower === "completed") {
|
|
873
886
|
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
874
887
|
}
|
|
@@ -877,45 +890,91 @@ const getStatusBadgeClass = (status) => {
|
|
|
877
890
|
}
|
|
878
891
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
879
892
|
};
|
|
880
|
-
const
|
|
893
|
+
const SwapDetailPage = () => {
|
|
881
894
|
var _a, _b;
|
|
882
895
|
const navigate = reactRouterDom.useNavigate();
|
|
883
896
|
const { id } = reactRouterDom.useParams();
|
|
884
|
-
const [
|
|
897
|
+
const [swap, setSwap] = react.useState(null);
|
|
898
|
+
const [order, setOrder] = react.useState(null);
|
|
899
|
+
const [selectedStatus, setSelectedStatus] = react.useState("");
|
|
885
900
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
901
|
+
const [isUpdating, setIsUpdating] = react.useState(false);
|
|
886
902
|
const [isApproving, setIsApproving] = react.useState(false);
|
|
887
903
|
const [isRejecting, setIsRejecting] = react.useState(false);
|
|
888
904
|
const [error, setError] = react.useState(null);
|
|
889
905
|
const [updateError, setUpdateError] = react.useState(null);
|
|
890
906
|
const [updateSuccess, setUpdateSuccess] = react.useState(false);
|
|
907
|
+
const availableStatuses = ["requested", "approved", "rejected"];
|
|
891
908
|
react.useEffect(() => {
|
|
892
909
|
if (!id) {
|
|
893
|
-
navigate("/
|
|
910
|
+
navigate("/swaps");
|
|
894
911
|
return;
|
|
895
912
|
}
|
|
896
|
-
const
|
|
913
|
+
const loadSwap = async () => {
|
|
897
914
|
try {
|
|
898
915
|
setIsLoading(true);
|
|
899
916
|
setError(null);
|
|
900
|
-
const response = await fetch(`/admin/
|
|
917
|
+
const response = await fetch(`/admin/swaps/${id}`, {
|
|
901
918
|
credentials: "include"
|
|
902
919
|
});
|
|
903
920
|
if (!response.ok) {
|
|
904
921
|
const message = await response.text();
|
|
905
|
-
throw new Error(message || "Unable to load
|
|
922
|
+
throw new Error(message || "Unable to load swap");
|
|
906
923
|
}
|
|
907
924
|
const payload = await response.json();
|
|
908
|
-
|
|
925
|
+
setSwap(payload.swap);
|
|
926
|
+
setOrder(payload.order || null);
|
|
927
|
+
setSelectedStatus("");
|
|
909
928
|
} catch (loadError) {
|
|
910
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load
|
|
929
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load swap";
|
|
911
930
|
setError(message);
|
|
912
931
|
} finally {
|
|
913
932
|
setIsLoading(false);
|
|
914
933
|
}
|
|
915
934
|
};
|
|
916
|
-
void
|
|
935
|
+
void loadSwap();
|
|
917
936
|
}, [id, navigate]);
|
|
918
|
-
const
|
|
937
|
+
const handleStatusUpdate = async () => {
|
|
938
|
+
if (!id || !selectedStatus) {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
setIsUpdating(true);
|
|
943
|
+
setUpdateError(null);
|
|
944
|
+
setUpdateSuccess(false);
|
|
945
|
+
const response = await fetch(`/admin/swaps/${id}/status`, {
|
|
946
|
+
method: "POST",
|
|
947
|
+
headers: {
|
|
948
|
+
"Content-Type": "application/json"
|
|
949
|
+
},
|
|
950
|
+
credentials: "include",
|
|
951
|
+
body: JSON.stringify({ status: selectedStatus })
|
|
952
|
+
});
|
|
953
|
+
if (!response.ok) {
|
|
954
|
+
const message = await response.text();
|
|
955
|
+
throw new Error(message || "Unable to update status");
|
|
956
|
+
}
|
|
957
|
+
const payload = await response.json();
|
|
958
|
+
setSwap(payload.swap);
|
|
959
|
+
setSelectedStatus("");
|
|
960
|
+
setUpdateSuccess(true);
|
|
961
|
+
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
962
|
+
const detailResponse = await fetch(`/admin/swaps/${id}`, {
|
|
963
|
+
credentials: "include"
|
|
964
|
+
});
|
|
965
|
+
if (detailResponse.ok) {
|
|
966
|
+
const detailPayload = await detailResponse.json();
|
|
967
|
+
setSwap(detailPayload.swap);
|
|
968
|
+
setOrder(detailPayload.order || null);
|
|
969
|
+
}
|
|
970
|
+
} catch (updateErr) {
|
|
971
|
+
const message = updateErr instanceof Error ? updateErr.message : "Unable to update status";
|
|
972
|
+
setUpdateError(message);
|
|
973
|
+
} finally {
|
|
974
|
+
setIsUpdating(false);
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
const handleAutoCreateExchange = async () => {
|
|
919
978
|
if (!id) {
|
|
920
979
|
return;
|
|
921
980
|
}
|
|
@@ -923,7 +982,7 @@ const ReturnDetailPage = () => {
|
|
|
923
982
|
setIsApproving(true);
|
|
924
983
|
setUpdateError(null);
|
|
925
984
|
setUpdateSuccess(false);
|
|
926
|
-
const response = await fetch(`/admin/
|
|
985
|
+
const response = await fetch(`/admin/swaps/${id}/create-exchange`, {
|
|
927
986
|
method: "POST",
|
|
928
987
|
headers: {
|
|
929
988
|
"Content-Type": "application/json"
|
|
@@ -932,26 +991,27 @@ const ReturnDetailPage = () => {
|
|
|
932
991
|
});
|
|
933
992
|
if (!response.ok) {
|
|
934
993
|
const message = await response.text();
|
|
935
|
-
throw new Error(message || "Unable to
|
|
994
|
+
throw new Error(message || "Unable to create exchange from swap");
|
|
936
995
|
}
|
|
937
996
|
const payload = await response.json();
|
|
938
|
-
|
|
997
|
+
setSwap(payload.swap);
|
|
939
998
|
setUpdateSuccess(true);
|
|
940
|
-
const orderId = payload.
|
|
999
|
+
const orderId = payload.swap.order_id;
|
|
941
1000
|
if (orderId) {
|
|
942
1001
|
window.location.href = `/app/orders/${orderId}`;
|
|
943
1002
|
return;
|
|
944
1003
|
}
|
|
945
1004
|
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
946
|
-
const detailResponse = await fetch(`/admin/
|
|
1005
|
+
const detailResponse = await fetch(`/admin/swaps/${id}`, {
|
|
947
1006
|
credentials: "include"
|
|
948
1007
|
});
|
|
949
1008
|
if (detailResponse.ok) {
|
|
950
1009
|
const detailPayload = await detailResponse.json();
|
|
951
|
-
|
|
1010
|
+
setSwap(detailPayload.swap);
|
|
1011
|
+
setOrder(detailPayload.order || null);
|
|
952
1012
|
}
|
|
953
1013
|
} catch (approveErr) {
|
|
954
|
-
const message = approveErr instanceof Error ? approveErr.message : "Unable to
|
|
1014
|
+
const message = approveErr instanceof Error ? approveErr.message : "Unable to create exchange from swap";
|
|
955
1015
|
setUpdateError(message);
|
|
956
1016
|
} finally {
|
|
957
1017
|
setIsApproving(false);
|
|
@@ -965,7 +1025,7 @@ const ReturnDetailPage = () => {
|
|
|
965
1025
|
setIsRejecting(true);
|
|
966
1026
|
setUpdateError(null);
|
|
967
1027
|
setUpdateSuccess(false);
|
|
968
|
-
const response = await fetch(`/admin/
|
|
1028
|
+
const response = await fetch(`/admin/swaps/${id}/reject`, {
|
|
969
1029
|
method: "POST",
|
|
970
1030
|
headers: {
|
|
971
1031
|
"Content-Type": "application/json"
|
|
@@ -975,36 +1035,37 @@ const ReturnDetailPage = () => {
|
|
|
975
1035
|
});
|
|
976
1036
|
if (!response.ok) {
|
|
977
1037
|
const message = await response.text();
|
|
978
|
-
throw new Error(message || "Unable to reject
|
|
1038
|
+
throw new Error(message || "Unable to reject swap");
|
|
979
1039
|
}
|
|
980
1040
|
const payload = await response.json();
|
|
981
|
-
|
|
1041
|
+
setSwap(payload.swap);
|
|
982
1042
|
setUpdateSuccess(true);
|
|
983
1043
|
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
984
|
-
const detailResponse = await fetch(`/admin/
|
|
1044
|
+
const detailResponse = await fetch(`/admin/swaps/${id}`, {
|
|
985
1045
|
credentials: "include"
|
|
986
1046
|
});
|
|
987
1047
|
if (detailResponse.ok) {
|
|
988
1048
|
const detailPayload = await detailResponse.json();
|
|
989
|
-
|
|
1049
|
+
setSwap(detailPayload.swap);
|
|
1050
|
+
setOrder(detailPayload.order || null);
|
|
990
1051
|
}
|
|
991
1052
|
} catch (updateErr) {
|
|
992
|
-
const message = updateErr instanceof Error ? updateErr.message : "Unable to reject
|
|
1053
|
+
const message = updateErr instanceof Error ? updateErr.message : "Unable to reject swap";
|
|
993
1054
|
setUpdateError(message);
|
|
994
1055
|
} finally {
|
|
995
1056
|
setIsRejecting(false);
|
|
996
1057
|
}
|
|
997
1058
|
};
|
|
998
1059
|
if (isLoading) {
|
|
999
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading
|
|
1060
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading swap..." }) }) }) });
|
|
1000
1061
|
}
|
|
1001
|
-
if (error || !
|
|
1062
|
+
if (error || !swap) {
|
|
1002
1063
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
1003
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "plus", className: "text-ui-fg-error", children: error || "
|
|
1004
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/
|
|
1064
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Swap not found" }),
|
|
1065
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/swaps"), children: "Back to list" }) })
|
|
1005
1066
|
] }) }) });
|
|
1006
1067
|
}
|
|
1007
|
-
const statusHistory = ((_a =
|
|
1068
|
+
const statusHistory = ((_a = swap.metadata) == null ? void 0 : _a.status_history) || [];
|
|
1008
1069
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: [
|
|
1009
1070
|
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
1010
1071
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1012,7 +1073,7 @@ const ReturnDetailPage = () => {
|
|
|
1012
1073
|
{
|
|
1013
1074
|
variant: "transparent",
|
|
1014
1075
|
size: "small",
|
|
1015
|
-
onClick: () => navigate("/
|
|
1076
|
+
onClick: () => navigate("/swaps"),
|
|
1016
1077
|
className: "w-fit",
|
|
1017
1078
|
children: [
|
|
1018
1079
|
/* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, { className: "mr-2" }),
|
|
@@ -1022,29 +1083,29 @@ const ReturnDetailPage = () => {
|
|
|
1022
1083
|
),
|
|
1023
1084
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:flex-row md:items-center md:justify-between", children: [
|
|
1024
1085
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1025
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
1026
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children:
|
|
1086
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Swap Details" }),
|
|
1087
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: swap.id })
|
|
1027
1088
|
] }),
|
|
1028
1089
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1029
1090
|
ui.Badge,
|
|
1030
1091
|
{
|
|
1031
1092
|
size: "small",
|
|
1032
|
-
className: `uppercase ${getStatusBadgeClass(
|
|
1033
|
-
children:
|
|
1093
|
+
className: `uppercase ${getStatusBadgeClass(swap.status)}`,
|
|
1094
|
+
children: swap.status.replace(/_/g, " ")
|
|
1034
1095
|
}
|
|
1035
1096
|
)
|
|
1036
1097
|
] })
|
|
1037
1098
|
] }),
|
|
1038
|
-
|
|
1099
|
+
swap.status === "requested" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
1039
1100
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
1040
1101
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1041
1102
|
ui.Button,
|
|
1042
1103
|
{
|
|
1043
1104
|
variant: "primary",
|
|
1044
|
-
onClick:
|
|
1105
|
+
onClick: handleAutoCreateExchange,
|
|
1045
1106
|
disabled: isApproving || isRejecting,
|
|
1046
1107
|
isLoading: isApproving,
|
|
1047
|
-
children: "Approve &
|
|
1108
|
+
children: "Approve & Create Exchange"
|
|
1048
1109
|
}
|
|
1049
1110
|
),
|
|
1050
1111
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1054,62 +1115,98 @@ const ReturnDetailPage = () => {
|
|
|
1054
1115
|
onClick: handleReject,
|
|
1055
1116
|
disabled: isApproving || isRejecting,
|
|
1056
1117
|
isLoading: isRejecting,
|
|
1057
|
-
children: "Reject
|
|
1118
|
+
children: "Reject Swap"
|
|
1058
1119
|
}
|
|
1059
1120
|
)
|
|
1060
1121
|
] }),
|
|
1061
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Approving will create
|
|
1122
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Approving will automatically create an exchange with return items and new items from the swap request" })
|
|
1062
1123
|
] }),
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1066
|
-
|
|
1124
|
+
swap.status === "requested" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
1125
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Update Status" }),
|
|
1126
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-end", children: [
|
|
1127
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
1128
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "New Status" }),
|
|
1129
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1130
|
+
"select",
|
|
1131
|
+
{
|
|
1132
|
+
value: selectedStatus,
|
|
1133
|
+
onChange: (event) => setSelectedStatus(event.target.value),
|
|
1134
|
+
className: "h-9 w-full rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
|
|
1135
|
+
children: [
|
|
1136
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select new status" }),
|
|
1137
|
+
availableStatuses.filter((status) => status !== swap.status).map((status) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
1138
|
+
]
|
|
1139
|
+
}
|
|
1140
|
+
)
|
|
1141
|
+
] }),
|
|
1142
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1143
|
+
ui.Button,
|
|
1144
|
+
{
|
|
1145
|
+
variant: "primary",
|
|
1146
|
+
onClick: handleStatusUpdate,
|
|
1147
|
+
disabled: !selectedStatus || isUpdating,
|
|
1148
|
+
isLoading: isUpdating,
|
|
1149
|
+
children: "Update Status"
|
|
1150
|
+
}
|
|
1151
|
+
)
|
|
1152
|
+
] }),
|
|
1153
|
+
updateError && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-error", children: updateError }),
|
|
1154
|
+
updateSuccess && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-success", children: "Status updated successfully" })
|
|
1155
|
+
] }),
|
|
1156
|
+
swap.status === "approved" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
1157
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Exchange Information" }),
|
|
1158
|
+
swap.exchange_id ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1067
1159
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1068
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
1069
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1160
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
|
|
1161
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.exchange_id })
|
|
1070
1162
|
] }),
|
|
1071
1163
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1072
1164
|
ui.Button,
|
|
1073
1165
|
{
|
|
1074
1166
|
variant: "secondary",
|
|
1075
1167
|
onClick: () => {
|
|
1076
|
-
window.open(
|
|
1077
|
-
`/app/orders/${returnOrder.order_id}`,
|
|
1078
|
-
"_blank"
|
|
1079
|
-
);
|
|
1168
|
+
window.open(`/app/orders/${swap.order_id}/exchanges/${swap.exchange_id}`, "_blank");
|
|
1080
1169
|
},
|
|
1081
|
-
children: "View
|
|
1170
|
+
children: "View Exchange"
|
|
1082
1171
|
}
|
|
1083
1172
|
) })
|
|
1084
|
-
] })
|
|
1173
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange is being created. Please refresh the page to see the exchange details." }) })
|
|
1085
1174
|
] }),
|
|
1086
1175
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
1087
1176
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
1088
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "
|
|
1177
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Swap Information" }),
|
|
1089
1178
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1090
1179
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1091
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
1092
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1180
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Swap ID" }),
|
|
1181
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.id })
|
|
1093
1182
|
] }),
|
|
1094
1183
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1095
1184
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Status" }),
|
|
1096
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1185
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.status })
|
|
1097
1186
|
] }),
|
|
1098
|
-
|
|
1187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1188
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Difference Due" }),
|
|
1189
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.difference_due != null ? `${swap.currency_code || "$"}${(Number(swap.difference_due) / 100).toFixed(2)}` : "—" })
|
|
1190
|
+
] }),
|
|
1191
|
+
swap.reason && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1099
1192
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Reason" }),
|
|
1100
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1193
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.reason })
|
|
1101
1194
|
] }),
|
|
1102
|
-
|
|
1195
|
+
swap.note && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1103
1196
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Note" }),
|
|
1104
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1197
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.note })
|
|
1105
1198
|
] }),
|
|
1106
1199
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1107
1200
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Created" }),
|
|
1108
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(
|
|
1201
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(swap.created_at).toLocaleString() })
|
|
1109
1202
|
] }),
|
|
1110
1203
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1111
1204
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Last Updated" }),
|
|
1112
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(
|
|
1205
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: new Date(swap.updated_at).toLocaleString() })
|
|
1206
|
+
] }),
|
|
1207
|
+
swap.exchange_id && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1208
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
|
|
1209
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: swap.exchange_id })
|
|
1113
1210
|
] })
|
|
1114
1211
|
] })
|
|
1115
1212
|
] }),
|
|
@@ -1139,31 +1236,31 @@ const ReturnDetailPage = () => {
|
|
|
1139
1236
|
)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "No status history available" })
|
|
1140
1237
|
] })
|
|
1141
1238
|
] }),
|
|
1142
|
-
|
|
1239
|
+
order && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
1143
1240
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Related Order Information" }),
|
|
1144
1241
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1145
1242
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1146
1243
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Order ID" }),
|
|
1147
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1244
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: order.id })
|
|
1148
1245
|
] }),
|
|
1149
1246
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1150
1247
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Status" }),
|
|
1151
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children:
|
|
1248
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: order.status || "—" })
|
|
1152
1249
|
] }),
|
|
1153
1250
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1154
1251
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
|
|
1155
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: ((_b =
|
|
1252
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: ((_b = order.customer) == null ? void 0 : _b.email) || order.email || "—" })
|
|
1156
1253
|
] }),
|
|
1157
|
-
|
|
1254
|
+
order.total && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1158
1255
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
1159
1256
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "font-medium", children: [
|
|
1160
|
-
|
|
1161
|
-
(Number(
|
|
1257
|
+
order.currency_code || "$",
|
|
1258
|
+
(Number(order.total) / 100).toFixed(2)
|
|
1162
1259
|
] })
|
|
1163
1260
|
] })
|
|
1164
1261
|
] })
|
|
1165
1262
|
] }),
|
|
1166
|
-
|
|
1263
|
+
swap.return_items && swap.return_items.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
1167
1264
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Items" }),
|
|
1168
1265
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
1169
1266
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
@@ -1171,66 +1268,82 @@ const ReturnDetailPage = () => {
|
|
|
1171
1268
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" }),
|
|
1172
1269
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Reason" })
|
|
1173
1270
|
] }) }),
|
|
1174
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children:
|
|
1271
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.return_items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
1175
1272
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.id }),
|
|
1176
1273
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity }),
|
|
1177
1274
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.reason || "—" })
|
|
1178
1275
|
] }, item.id || index)) })
|
|
1179
1276
|
] }) })
|
|
1180
1277
|
] }),
|
|
1181
|
-
|
|
1182
|
-
|
|
1278
|
+
swap.new_items && swap.new_items.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
1279
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "New Items" }),
|
|
1280
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
1281
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
1282
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Variant ID" }),
|
|
1283
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" })
|
|
1284
|
+
] }) }),
|
|
1285
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.new_items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
1286
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.variant_id }),
|
|
1287
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity })
|
|
1288
|
+
] }, item.variant_id || index)) })
|
|
1289
|
+
] }) })
|
|
1290
|
+
] })
|
|
1183
1291
|
] }) });
|
|
1184
1292
|
};
|
|
1185
1293
|
const config = adminSdk.defineRouteConfig({
|
|
1186
|
-
label: "
|
|
1187
|
-
icon: icons.
|
|
1294
|
+
label: "Swap Details",
|
|
1295
|
+
icon: icons.ArrowPath
|
|
1188
1296
|
});
|
|
1189
1297
|
const i18nTranslations0 = {};
|
|
1190
|
-
const widgetModule = { widgets: [
|
|
1298
|
+
const widgetModule = { widgets: [
|
|
1299
|
+
{
|
|
1300
|
+
Component: OrderReturnApprovalNoticeWidget,
|
|
1301
|
+
zone: ["order.details.before"]
|
|
1302
|
+
}
|
|
1303
|
+
] };
|
|
1191
1304
|
const routeModule = {
|
|
1192
1305
|
routes: [
|
|
1193
|
-
{
|
|
1194
|
-
Component: SwapsPage,
|
|
1195
|
-
path: "/swaps"
|
|
1196
|
-
},
|
|
1197
1306
|
{
|
|
1198
1307
|
Component: ReturnsPage,
|
|
1199
1308
|
path: "/returns"
|
|
1200
1309
|
},
|
|
1201
1310
|
{
|
|
1202
|
-
Component:
|
|
1203
|
-
path: "/swaps
|
|
1311
|
+
Component: SwapsPage,
|
|
1312
|
+
path: "/swaps"
|
|
1204
1313
|
},
|
|
1205
1314
|
{
|
|
1206
1315
|
Component: ReturnDetailPage,
|
|
1207
1316
|
path: "/returns/:id"
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
Component: SwapDetailPage,
|
|
1320
|
+
path: "/swaps/:id"
|
|
1208
1321
|
}
|
|
1209
1322
|
]
|
|
1210
1323
|
};
|
|
1211
1324
|
const menuItemModule = {
|
|
1212
1325
|
menuItems: [
|
|
1213
1326
|
{
|
|
1214
|
-
label: config$
|
|
1215
|
-
icon: config$
|
|
1327
|
+
label: config$3.label,
|
|
1328
|
+
icon: config$3.icon,
|
|
1216
1329
|
path: "/returns",
|
|
1217
1330
|
nested: void 0
|
|
1218
1331
|
},
|
|
1219
1332
|
{
|
|
1220
|
-
label: config$
|
|
1221
|
-
icon: config$
|
|
1333
|
+
label: config$2.label,
|
|
1334
|
+
icon: config$2.icon,
|
|
1222
1335
|
path: "/swaps",
|
|
1223
1336
|
nested: void 0
|
|
1224
1337
|
},
|
|
1225
1338
|
{
|
|
1226
|
-
label: config.label,
|
|
1227
|
-
icon: config.icon,
|
|
1339
|
+
label: config$1.label,
|
|
1340
|
+
icon: config$1.icon,
|
|
1228
1341
|
path: "/returns/:id",
|
|
1229
1342
|
nested: void 0
|
|
1230
1343
|
},
|
|
1231
1344
|
{
|
|
1232
|
-
label: config
|
|
1233
|
-
icon: config
|
|
1345
|
+
label: config.label,
|
|
1346
|
+
icon: config.icon,
|
|
1234
1347
|
path: "/swaps/:id",
|
|
1235
1348
|
nested: void 0
|
|
1236
1349
|
}
|