order-management 0.0.9 → 0.0.11
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 +542 -2
- package/.medusa/server/src/admin/index.mjs +542 -2
- package/.medusa/server/src/api/admin/returns/[id]/route.js +112 -0
- package/.medusa/server/src/api/admin/returns/[id]/status/route.js +118 -0
- package/.medusa/server/src/api/admin/returns/route.js +193 -0
- package/.medusa/server/src/api/admin/returns/validators.js +25 -0
- package/.medusa/server/src/subscribers/send-order-email.js +46 -131
- package/.medusa/server/src/types/order-management-options.js +3 -0
- package/.medusa/server/src/utils/resolve-options.js +55 -0
- package/.medusa/server/src/utils/template.js +78 -0
- package/README.md +142 -0
- package/package.json +1 -1
|
@@ -1,10 +1,550 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
3
|
+
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
4
|
+
import { Container, Heading, Text, Button, Input, Badge } from "@medusajs/ui";
|
|
5
|
+
import { ArrowPath, ArrowLeft } from "@medusajs/icons";
|
|
6
|
+
import { useNavigate, useParams } from "react-router-dom";
|
|
7
|
+
const useDebounce = (value, delay) => {
|
|
8
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
11
|
+
return () => clearTimeout(handler);
|
|
12
|
+
}, [value, delay]);
|
|
13
|
+
return debouncedValue;
|
|
14
|
+
};
|
|
15
|
+
const getStatusBadgeClass$1 = (status) => {
|
|
16
|
+
const statusLower = status.toLowerCase();
|
|
17
|
+
if (statusLower === "requested") {
|
|
18
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
19
|
+
}
|
|
20
|
+
if (statusLower === "received") {
|
|
21
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
22
|
+
}
|
|
23
|
+
if (statusLower === "requires_action") {
|
|
24
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
25
|
+
}
|
|
26
|
+
if (statusLower === "completed") {
|
|
27
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
28
|
+
}
|
|
29
|
+
if (statusLower === "canceled") {
|
|
30
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
31
|
+
}
|
|
32
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
33
|
+
};
|
|
34
|
+
const ReturnsPage = () => {
|
|
35
|
+
const navigate = useNavigate();
|
|
36
|
+
const [items, setItems] = useState([]);
|
|
37
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
38
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
39
|
+
const debouncedSearchQuery = useDebounce(searchQuery, 300);
|
|
40
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
41
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
42
|
+
const [error, setError] = useState(null);
|
|
43
|
+
const [offset, setOffset] = useState(0);
|
|
44
|
+
const [count, setCount] = useState(0);
|
|
45
|
+
const limit = 50;
|
|
46
|
+
const loadReturns = useCallback(
|
|
47
|
+
async (nextOffset, replace = false) => {
|
|
48
|
+
var _a;
|
|
49
|
+
try {
|
|
50
|
+
if (replace) {
|
|
51
|
+
setIsLoading(true);
|
|
52
|
+
} else {
|
|
53
|
+
setIsFetchingMore(true);
|
|
54
|
+
}
|
|
55
|
+
setError(null);
|
|
56
|
+
const params = new URLSearchParams();
|
|
57
|
+
params.set("limit", String(limit));
|
|
58
|
+
params.set("offset", String(nextOffset));
|
|
59
|
+
if (statusFilter !== "all") {
|
|
60
|
+
params.set("status", statusFilter);
|
|
61
|
+
}
|
|
62
|
+
if (debouncedSearchQuery.trim()) {
|
|
63
|
+
params.set("q", debouncedSearchQuery.trim());
|
|
64
|
+
}
|
|
65
|
+
params.set("order", "created_at");
|
|
66
|
+
params.set("order_direction", "DESC");
|
|
67
|
+
const response = await fetch(
|
|
68
|
+
`/admin/returns?${params.toString()}`,
|
|
69
|
+
{ credentials: "include" }
|
|
70
|
+
);
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
const message = await response.text();
|
|
73
|
+
throw new Error(message || "Unable to load return orders");
|
|
74
|
+
}
|
|
75
|
+
const payload = await response.json();
|
|
76
|
+
setCount(payload.count ?? 0);
|
|
77
|
+
setOffset(nextOffset + (((_a = payload.returns) == null ? void 0 : _a.length) ?? 0));
|
|
78
|
+
setItems(
|
|
79
|
+
(prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
|
|
80
|
+
);
|
|
81
|
+
} catch (loadError) {
|
|
82
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
83
|
+
setError(message);
|
|
84
|
+
} finally {
|
|
85
|
+
setIsLoading(false);
|
|
86
|
+
setIsFetchingMore(false);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
[statusFilter, debouncedSearchQuery]
|
|
90
|
+
);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
void loadReturns(0, true);
|
|
93
|
+
}, [statusFilter, debouncedSearchQuery, loadReturns]);
|
|
94
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
95
|
+
const availableStatuses = useMemo(() => {
|
|
96
|
+
const statuses = /* @__PURE__ */ new Set();
|
|
97
|
+
items.forEach((item) => statuses.add(item.status));
|
|
98
|
+
return Array.from(statuses).sort();
|
|
99
|
+
}, [items]);
|
|
100
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-6", children: [
|
|
101
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
103
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Orders" }),
|
|
104
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
110
|
+
Input,
|
|
111
|
+
{
|
|
112
|
+
placeholder: "Search by return ID, order ID, or customer email",
|
|
113
|
+
value: searchQuery,
|
|
114
|
+
onChange: (event) => setSearchQuery(event.target.value),
|
|
115
|
+
className: "md:max-w-sm"
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
|
|
119
|
+
"select",
|
|
120
|
+
{
|
|
121
|
+
value: statusFilter,
|
|
122
|
+
onChange: (event) => setStatusFilter(event.target.value),
|
|
123
|
+
className: "h-9 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 md:max-w-xs",
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
126
|
+
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace("_", " ").toUpperCase() }, status))
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
) })
|
|
130
|
+
] }),
|
|
131
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
132
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
133
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
134
|
+
Button,
|
|
135
|
+
{
|
|
136
|
+
variant: "secondary",
|
|
137
|
+
onClick: () => loadReturns(0, true),
|
|
138
|
+
children: "Try again"
|
|
139
|
+
}
|
|
140
|
+
) })
|
|
141
|
+
] }) : null,
|
|
142
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading return orders..." }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
143
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
|
|
144
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
|
|
145
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
146
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
147
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
|
|
148
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
149
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
150
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
151
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
|
|
152
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
153
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
154
|
+
] }) }),
|
|
155
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
|
|
156
|
+
"tr",
|
|
157
|
+
{
|
|
158
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
159
|
+
onClick: () => navigate(`/returns/${returnOrder.id}`),
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: /* @__PURE__ */ jsx("span", { children: returnOrder.id }) }) }),
|
|
162
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
|
|
163
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
164
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
165
|
+
Badge,
|
|
166
|
+
{
|
|
167
|
+
size: "2xsmall",
|
|
168
|
+
className: `uppercase ${getStatusBadgeClass$1(returnOrder.status)}`,
|
|
169
|
+
children: returnOrder.status.replace("_", " ")
|
|
170
|
+
}
|
|
171
|
+
) }),
|
|
172
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.refund_amount ? `$${Number(returnOrder.refund_amount).toFixed(2)}` : "—" }),
|
|
173
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleString() }),
|
|
174
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
175
|
+
Button,
|
|
176
|
+
{
|
|
177
|
+
variant: "transparent",
|
|
178
|
+
size: "small",
|
|
179
|
+
onClick: (e) => {
|
|
180
|
+
e.stopPropagation();
|
|
181
|
+
navigate(`/returns/${returnOrder.id}`);
|
|
182
|
+
},
|
|
183
|
+
children: "View"
|
|
184
|
+
}
|
|
185
|
+
) })
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
returnOrder.id
|
|
189
|
+
)) })
|
|
190
|
+
] }) }),
|
|
191
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
192
|
+
Button,
|
|
193
|
+
{
|
|
194
|
+
variant: "secondary",
|
|
195
|
+
isLoading: isFetchingMore,
|
|
196
|
+
onClick: () => loadReturns(offset, false),
|
|
197
|
+
children: "Load more"
|
|
198
|
+
}
|
|
199
|
+
) }) : null
|
|
200
|
+
] }) });
|
|
201
|
+
};
|
|
202
|
+
const config$1 = defineRouteConfig({
|
|
203
|
+
label: "Return Orders",
|
|
204
|
+
icon: ArrowPath
|
|
205
|
+
});
|
|
206
|
+
const getStatusBadgeClass = (status) => {
|
|
207
|
+
const statusLower = status.toLowerCase();
|
|
208
|
+
if (statusLower === "requested") {
|
|
209
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
210
|
+
}
|
|
211
|
+
if (statusLower === "received") {
|
|
212
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
213
|
+
}
|
|
214
|
+
if (statusLower === "requires_action") {
|
|
215
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
216
|
+
}
|
|
217
|
+
if (statusLower === "completed") {
|
|
218
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
219
|
+
}
|
|
220
|
+
if (statusLower === "canceled") {
|
|
221
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
222
|
+
}
|
|
223
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
224
|
+
};
|
|
225
|
+
const ReturnDetailPage = () => {
|
|
226
|
+
var _a, _b, _c;
|
|
227
|
+
const navigate = useNavigate();
|
|
228
|
+
const { id } = useParams();
|
|
229
|
+
const [returnOrder, setReturnOrder] = useState(null);
|
|
230
|
+
const [selectedStatus, setSelectedStatus] = useState("");
|
|
231
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
232
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
233
|
+
const [error, setError] = useState(null);
|
|
234
|
+
const [updateError, setUpdateError] = useState(null);
|
|
235
|
+
const [updateSuccess, setUpdateSuccess] = useState(false);
|
|
236
|
+
const availableStatuses = [
|
|
237
|
+
"requested",
|
|
238
|
+
"received",
|
|
239
|
+
"requires_action",
|
|
240
|
+
"completed",
|
|
241
|
+
"canceled"
|
|
242
|
+
];
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (!id) {
|
|
245
|
+
navigate("/returns");
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const loadReturn = async () => {
|
|
249
|
+
try {
|
|
250
|
+
setIsLoading(true);
|
|
251
|
+
setError(null);
|
|
252
|
+
const response = await fetch(`/admin/returns/${id}`, {
|
|
253
|
+
credentials: "include"
|
|
254
|
+
});
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
const message = await response.text();
|
|
257
|
+
throw new Error(message || "Unable to load return order");
|
|
258
|
+
}
|
|
259
|
+
const payload = await response.json();
|
|
260
|
+
setReturnOrder(payload.return);
|
|
261
|
+
setSelectedStatus("");
|
|
262
|
+
} catch (loadError) {
|
|
263
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return order";
|
|
264
|
+
setError(message);
|
|
265
|
+
} finally {
|
|
266
|
+
setIsLoading(false);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
void loadReturn();
|
|
270
|
+
}, [id, navigate]);
|
|
271
|
+
const handleStatusUpdate = async () => {
|
|
272
|
+
if (!id || !selectedStatus) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
setIsUpdating(true);
|
|
277
|
+
setUpdateError(null);
|
|
278
|
+
setUpdateSuccess(false);
|
|
279
|
+
const response = await fetch(`/admin/returns/${id}/status`, {
|
|
280
|
+
method: "POST",
|
|
281
|
+
headers: {
|
|
282
|
+
"Content-Type": "application/json"
|
|
283
|
+
},
|
|
284
|
+
credentials: "include",
|
|
285
|
+
body: JSON.stringify({ status: selectedStatus })
|
|
286
|
+
});
|
|
287
|
+
if (!response.ok) {
|
|
288
|
+
const message = await response.text();
|
|
289
|
+
throw new Error(message || "Unable to update status");
|
|
290
|
+
}
|
|
291
|
+
const payload = await response.json();
|
|
292
|
+
setReturnOrder(payload.return);
|
|
293
|
+
setSelectedStatus("");
|
|
294
|
+
setUpdateSuccess(true);
|
|
295
|
+
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
296
|
+
const detailResponse = await fetch(`/admin/returns/${id}`, {
|
|
297
|
+
credentials: "include"
|
|
298
|
+
});
|
|
299
|
+
if (detailResponse.ok) {
|
|
300
|
+
const detailPayload = await detailResponse.json();
|
|
301
|
+
setReturnOrder(detailPayload.return);
|
|
302
|
+
}
|
|
303
|
+
} catch (updateErr) {
|
|
304
|
+
const message = updateErr instanceof Error ? updateErr.message : "Unable to update status";
|
|
305
|
+
setUpdateError(message);
|
|
306
|
+
} finally {
|
|
307
|
+
setIsUpdating(false);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
if (isLoading) {
|
|
311
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsx(Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading return order..." }) }) }) });
|
|
312
|
+
}
|
|
313
|
+
if (error || !returnOrder) {
|
|
314
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsx(Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
315
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Return order not found" }),
|
|
316
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/returns"), children: "Back to list" }) })
|
|
317
|
+
] }) }) });
|
|
318
|
+
}
|
|
319
|
+
const statusHistory = ((_a = returnOrder.metadata) == null ? void 0 : _a.status_history) || [];
|
|
320
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: [
|
|
321
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
322
|
+
/* @__PURE__ */ jsxs(
|
|
323
|
+
Button,
|
|
324
|
+
{
|
|
325
|
+
variant: "transparent",
|
|
326
|
+
size: "small",
|
|
327
|
+
onClick: () => navigate("/returns"),
|
|
328
|
+
className: "w-fit",
|
|
329
|
+
children: [
|
|
330
|
+
/* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2" }),
|
|
331
|
+
"Back to list"
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
),
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 md:flex-row md:items-center md:justify-between", children: [
|
|
336
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
337
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Order Details" }),
|
|
338
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: returnOrder.id })
|
|
339
|
+
] }),
|
|
340
|
+
/* @__PURE__ */ jsx(
|
|
341
|
+
Badge,
|
|
342
|
+
{
|
|
343
|
+
size: "small",
|
|
344
|
+
className: `uppercase ${getStatusBadgeClass(returnOrder.status)}`,
|
|
345
|
+
children: returnOrder.status.replace("_", " ")
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
] })
|
|
349
|
+
] }),
|
|
350
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
351
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Update Status" }),
|
|
352
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-end", children: [
|
|
353
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
354
|
+
/* @__PURE__ */ jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "New Status" }),
|
|
355
|
+
/* @__PURE__ */ jsxs(
|
|
356
|
+
"select",
|
|
357
|
+
{
|
|
358
|
+
value: selectedStatus,
|
|
359
|
+
onChange: (event) => setSelectedStatus(event.target.value),
|
|
360
|
+
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",
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Select new status" }),
|
|
363
|
+
availableStatuses.filter((status) => status !== returnOrder.status).map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace("_", " ").toUpperCase() }, status))
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
)
|
|
367
|
+
] }),
|
|
368
|
+
/* @__PURE__ */ jsx(
|
|
369
|
+
Button,
|
|
370
|
+
{
|
|
371
|
+
variant: "primary",
|
|
372
|
+
onClick: handleStatusUpdate,
|
|
373
|
+
disabled: !selectedStatus || isUpdating,
|
|
374
|
+
isLoading: isUpdating,
|
|
375
|
+
children: "Update Status"
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
] }),
|
|
379
|
+
updateError && /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-error", children: updateError }),
|
|
380
|
+
updateSuccess && /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-success", children: "Status updated successfully" })
|
|
381
|
+
] }),
|
|
382
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
383
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
384
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Information" }),
|
|
385
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
386
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
387
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Return ID" }),
|
|
388
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.id })
|
|
389
|
+
] }),
|
|
390
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
391
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Status" }),
|
|
392
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.status })
|
|
393
|
+
] }),
|
|
394
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
395
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Refund Amount" }),
|
|
396
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.refund_amount ? `${((_b = returnOrder.order) == null ? void 0 : _b.currency_code) || "$"}${Number(returnOrder.refund_amount).toFixed(2)}` : "—" })
|
|
397
|
+
] }),
|
|
398
|
+
returnOrder.reason && /* @__PURE__ */ jsxs("div", { children: [
|
|
399
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Reason" }),
|
|
400
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.reason })
|
|
401
|
+
] }),
|
|
402
|
+
returnOrder.note && /* @__PURE__ */ jsxs("div", { children: [
|
|
403
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Note" }),
|
|
404
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.note })
|
|
405
|
+
] }),
|
|
406
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
407
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Created" }),
|
|
408
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(returnOrder.created_at).toLocaleString() })
|
|
409
|
+
] }),
|
|
410
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
411
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Last Updated" }),
|
|
412
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(returnOrder.updated_at).toLocaleString() })
|
|
413
|
+
] })
|
|
414
|
+
] })
|
|
415
|
+
] }),
|
|
416
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
417
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Status History" }),
|
|
418
|
+
statusHistory.length > 0 ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: statusHistory.map((entry, index) => /* @__PURE__ */ jsx(
|
|
419
|
+
"div",
|
|
420
|
+
{
|
|
421
|
+
className: "flex items-center justify-between border-b border-ui-border-subtle pb-2 last:border-0",
|
|
422
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
423
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
424
|
+
/* @__PURE__ */ jsx(
|
|
425
|
+
Badge,
|
|
426
|
+
{
|
|
427
|
+
size: "2xsmall",
|
|
428
|
+
className: `uppercase ${getStatusBadgeClass(entry.to)}`,
|
|
429
|
+
children: entry.to.replace("_", " ")
|
|
430
|
+
}
|
|
431
|
+
),
|
|
432
|
+
entry.from && /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
|
|
433
|
+
"from ",
|
|
434
|
+
entry.from.replace("_", " ")
|
|
435
|
+
] })
|
|
436
|
+
] }),
|
|
437
|
+
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
|
|
438
|
+
new Date(entry.changed_at).toLocaleString(),
|
|
439
|
+
entry.changed_by && ` by ${entry.changed_by}`
|
|
440
|
+
] })
|
|
441
|
+
] })
|
|
442
|
+
},
|
|
443
|
+
index
|
|
444
|
+
)) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No status history available" })
|
|
445
|
+
] })
|
|
446
|
+
] }),
|
|
447
|
+
returnOrder.order && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
448
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Related Order Information" }),
|
|
449
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
450
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
451
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
452
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order ID" }),
|
|
453
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.id })
|
|
454
|
+
] }),
|
|
455
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
456
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Status" }),
|
|
457
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.status || "—" })
|
|
458
|
+
] }),
|
|
459
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
460
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
|
|
461
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: ((_c = returnOrder.order.customer) == null ? void 0 : _c.email) || returnOrder.order.email || "—" })
|
|
462
|
+
] }),
|
|
463
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
464
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
465
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.total ? `${returnOrder.order.currency_code || "$"}${Number(returnOrder.order.total).toFixed(2)}` : "—" })
|
|
466
|
+
] })
|
|
467
|
+
] }),
|
|
468
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
469
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
470
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Subtotal" }),
|
|
471
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.subtotal ? `${returnOrder.order.currency_code || "$"}${Number(returnOrder.order.subtotal).toFixed(2)}` : "—" })
|
|
472
|
+
] }),
|
|
473
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
474
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Tax Total" }),
|
|
475
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.tax_total ? `${returnOrder.order.currency_code || "$"}${Number(returnOrder.order.tax_total).toFixed(2)}` : "—" })
|
|
476
|
+
] }),
|
|
477
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
478
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Shipping Total" }),
|
|
479
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.shipping_total ? `${returnOrder.order.currency_code || "$"}${Number(returnOrder.order.shipping_total).toFixed(2)}` : "—" })
|
|
480
|
+
] }),
|
|
481
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
482
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Created" }),
|
|
483
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.created_at ? new Date(returnOrder.order.created_at).toLocaleString() : "—" })
|
|
484
|
+
] })
|
|
485
|
+
] })
|
|
486
|
+
] })
|
|
487
|
+
] }),
|
|
488
|
+
returnOrder.items && returnOrder.items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
489
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Items" }),
|
|
490
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
491
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
492
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Item" }),
|
|
493
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" })
|
|
494
|
+
] }) }),
|
|
495
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: returnOrder.items.map((item) => {
|
|
496
|
+
var _a2, _b2;
|
|
497
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
498
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: ((_a2 = item.item) == null ? void 0 : _a2.title) || ((_b2 = item.item) == null ? void 0 : _b2.id) || item.id }),
|
|
499
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity })
|
|
500
|
+
] }, item.id);
|
|
501
|
+
}) })
|
|
502
|
+
] }) })
|
|
503
|
+
] }),
|
|
504
|
+
returnOrder.metadata && Object.keys(returnOrder.metadata).filter(
|
|
505
|
+
(key) => key !== "status_history"
|
|
506
|
+
).length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
507
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Metadata" }),
|
|
508
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: Object.entries(returnOrder.metadata).filter(([key]) => key !== "status_history").map(([key, value]) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
509
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: key }),
|
|
510
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "font-medium", children: typeof value === "string" ? value : JSON.stringify(value) })
|
|
511
|
+
] }, key)) })
|
|
512
|
+
] })
|
|
513
|
+
] }) });
|
|
514
|
+
};
|
|
515
|
+
const config = defineRouteConfig({
|
|
516
|
+
label: "Return Order Details",
|
|
517
|
+
icon: ArrowPath
|
|
518
|
+
});
|
|
1
519
|
const i18nTranslations0 = {};
|
|
2
520
|
const widgetModule = { widgets: [] };
|
|
3
521
|
const routeModule = {
|
|
4
|
-
routes: [
|
|
522
|
+
routes: [
|
|
523
|
+
{
|
|
524
|
+
Component: ReturnsPage,
|
|
525
|
+
path: "/returns"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
Component: ReturnDetailPage,
|
|
529
|
+
path: "/returns/:id"
|
|
530
|
+
}
|
|
531
|
+
]
|
|
5
532
|
};
|
|
6
533
|
const menuItemModule = {
|
|
7
|
-
menuItems: [
|
|
534
|
+
menuItems: [
|
|
535
|
+
{
|
|
536
|
+
label: config$1.label,
|
|
537
|
+
icon: config$1.icon,
|
|
538
|
+
path: "/returns",
|
|
539
|
+
nested: void 0
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
label: config.label,
|
|
543
|
+
icon: config.icon,
|
|
544
|
+
path: "/returns/:id",
|
|
545
|
+
nested: void 0
|
|
546
|
+
}
|
|
547
|
+
]
|
|
8
548
|
};
|
|
9
549
|
const formModule = { customFields: {} };
|
|
10
550
|
const displayModule = {
|