order-management 0.0.107 → 0.0.109
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 +2157 -2159
- package/.medusa/server/src/admin/index.mjs +2160 -2162
- package/.medusa/server/src/api/middlewares/inject-return-shipping.js +6 -1
- package/.medusa/server/src/api/store/guest-orders/[id]/returns/route.js +56 -46
- package/.medusa/server/src/api/store/guest-orders/[id]/swaps/route.js +55 -4
- package/.medusa/server/src/api/store/returns/route.js +44 -4
- package/.medusa/server/src/api/store/returns/validators.js +3 -1
- package/.medusa/server/src/api/store/swaps/route.js +55 -4
- package/.medusa/server/src/helpers/index.js +2 -1
- package/.medusa/server/src/helpers/return-channel.js +127 -0
- package/.medusa/server/src/subscribers/order-return-received.js +32 -2
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
|
-
import { useState, useEffect, useRef,
|
|
4
|
-
import { Text, Container, Heading, Badge, Button, Label, Select, Textarea,
|
|
5
|
-
import { CashSolid, PencilSquareSolid, Trash,
|
|
3
|
+
import { useState, useEffect, useRef, useMemo, useCallback } from "react";
|
|
4
|
+
import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Popover, clx, Input, Copy, Skeleton, Tooltip, toast } from "@medusajs/ui";
|
|
5
|
+
import { CashSolid, PencilSquareSolid, Trash, ChevronDownMini, Check, ArrowPath, InformationCircle, ExclamationCircle, MagnifierAlert, ChevronRightMini, CreditCard, Receipt, ArrowLeft, ClockSolid, ShieldCheck, SquareTwoStack, CheckCircle } from "@medusajs/icons";
|
|
6
6
|
import { useNavigate, useLocation, useSearchParams, useParams } from "react-router-dom";
|
|
7
7
|
function roundRectPath(ctx, x, y, w, h, r) {
|
|
8
8
|
ctx.beginPath();
|
|
@@ -605,7 +605,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
605
605
|
const mapping = context?.refund_mapping;
|
|
606
606
|
const mode = mapping?.refund_mode;
|
|
607
607
|
setEditRefundMode(
|
|
608
|
-
mode === "offline" || mode === "online" ? mode : ""
|
|
608
|
+
mode === "offline" || mode === "online" || mode === "wallet" ? mode : ""
|
|
609
609
|
);
|
|
610
610
|
setEditDetails(mapping?.details ?? "");
|
|
611
611
|
setEditImageUrls(mapping?.images ?? []);
|
|
@@ -653,7 +653,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
653
653
|
headers: { "Content-Type": "application/json" },
|
|
654
654
|
credentials: "include",
|
|
655
655
|
body: JSON.stringify({
|
|
656
|
-
refund_mode: editRefundMode === "offline" || editRefundMode === "online" ? editRefundMode : null,
|
|
656
|
+
refund_mode: editRefundMode === "offline" || editRefundMode === "online" || editRefundMode === "wallet" ? editRefundMode : null,
|
|
657
657
|
details: editDetails.trim() || null,
|
|
658
658
|
images: editImageUrls
|
|
659
659
|
})
|
|
@@ -713,18 +713,15 @@ const OrderRefundContextWidget = (props) => {
|
|
|
713
713
|
] }),
|
|
714
714
|
/* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2 border-t border-ui-border-base pt-3", children: [
|
|
715
715
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
716
|
-
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "
|
|
717
|
-
context.refund_mapping?.
|
|
716
|
+
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Refund destination" }),
|
|
717
|
+
context.refund_mapping?.refund_mode === "wallet" || context.refund_mapping?.is_refunded ? /* @__PURE__ */ jsx(Badge, { color: "green", children: "Customer wallet" }) : /* @__PURE__ */ jsx(Badge, { color: "blue", children: "Customer wallet" })
|
|
718
|
+
] }),
|
|
719
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "Refunds are credited to the customer's wallet when the return is received. Offline UPI/bank payout is no longer the primary path." }) }),
|
|
720
|
+
paymentDetail && /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
721
|
+
"Legacy linked ",
|
|
722
|
+
paymentDetail.type.toUpperCase(),
|
|
723
|
+
" on file (optional / historical)."
|
|
718
724
|
] }),
|
|
719
|
-
context.refund_mapping?.payment_id && !paymentDetail && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-orange-200 bg-orange-50 px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "The customer specified a payment method for this return, but that payment method has since been removed from their account. Ask the customer to update their refund payment method." }) }),
|
|
720
|
-
!context.refund_mapping?.payment_id && paymentDetail?.source === "default" && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "The customer did not specify a payment method for this return. Showing their default payment method." }) }),
|
|
721
|
-
!context.refund_mapping?.payment_id && !paymentDetail && orderPayment && !orderPayment.is_cod && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
722
|
-
"Refund will go to the original payment method (",
|
|
723
|
-
orderPayment.label,
|
|
724
|
-
")."
|
|
725
|
-
] }) }),
|
|
726
|
-
!context.refund_mapping?.payment_id && !paymentDetail && (context.is_cod || orderPayment?.is_cod) && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "This order was paid with Cash on Delivery. No stored bank/UPI refund destination." }) }),
|
|
727
|
-
!context.refund_mapping?.payment_id && !paymentDetail && !orderPayment && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "No payment method found for this customer." }) }),
|
|
728
725
|
paymentDetails.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: paymentDetails.map((detail) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
729
726
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
730
727
|
/* @__PURE__ */ jsx(Badge, { children: detail.type.toUpperCase() }),
|
|
@@ -786,8 +783,9 @@ const OrderRefundContextWidget = (props) => {
|
|
|
786
783
|
children: [
|
|
787
784
|
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Select mode" }) }),
|
|
788
785
|
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
789
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "
|
|
790
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "
|
|
786
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "wallet", children: "Wallet" }),
|
|
787
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "offline", children: "Offline (legacy)" }),
|
|
788
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "online", children: "Online (legacy)" })
|
|
791
789
|
] })
|
|
792
790
|
]
|
|
793
791
|
}
|
|
@@ -867,7 +865,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
867
865
|
] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
868
866
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
869
867
|
/* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted", children: "Refund mode" }),
|
|
870
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "block", children: context.refund_mapping.refund_mode === "offline" ? "Offline" : context.refund_mapping.refund_mode === "online" ? "Online" : context.refund_mapping.refund_mode || "—" })
|
|
868
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "block", children: context.refund_mapping.refund_mode === "wallet" ? "Wallet" : context.refund_mapping.refund_mode === "offline" ? "Offline" : context.refund_mapping.refund_mode === "online" ? "Online" : context.refund_mapping.refund_mode || "—" })
|
|
871
869
|
] }),
|
|
872
870
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
873
871
|
/* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted", children: "Details" }),
|
|
@@ -923,742 +921,6 @@ const OrderRefundContextWidget = (props) => {
|
|
|
923
921
|
defineWidgetConfig({
|
|
924
922
|
zone: "order.details.after"
|
|
925
923
|
});
|
|
926
|
-
const useDebounce$3 = (value, delay) => {
|
|
927
|
-
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
928
|
-
useEffect(() => {
|
|
929
|
-
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
930
|
-
return () => clearTimeout(handler);
|
|
931
|
-
}, [value, delay]);
|
|
932
|
-
return debouncedValue;
|
|
933
|
-
};
|
|
934
|
-
const getStatusBadgeClass$7 = (status) => {
|
|
935
|
-
const s2 = status.toLowerCase();
|
|
936
|
-
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
937
|
-
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
938
|
-
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
939
|
-
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
940
|
-
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
941
|
-
};
|
|
942
|
-
const PaymentsPage = () => {
|
|
943
|
-
const navigate = useNavigate();
|
|
944
|
-
const [items, setItems] = useState([]);
|
|
945
|
-
const [statusFilter, setStatusFilter] = useState("all");
|
|
946
|
-
const [orderIdSearch, setOrderIdSearch] = useState("");
|
|
947
|
-
const debouncedOrderId = useDebounce$3(orderIdSearch, 300);
|
|
948
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
949
|
-
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
950
|
-
const [error, setError] = useState(null);
|
|
951
|
-
const [offset, setOffset] = useState(0);
|
|
952
|
-
const [count, setCount] = useState(0);
|
|
953
|
-
const limit = 50;
|
|
954
|
-
const loadTransactions = useCallback(
|
|
955
|
-
async (nextOffset, replace) => {
|
|
956
|
-
try {
|
|
957
|
-
if (replace) setIsLoading(true);
|
|
958
|
-
else setIsFetchingMore(true);
|
|
959
|
-
setError(null);
|
|
960
|
-
const params = new URLSearchParams();
|
|
961
|
-
params.set("limit", String(limit));
|
|
962
|
-
params.set("offset", String(nextOffset));
|
|
963
|
-
if (statusFilter !== "all") params.set("status", statusFilter);
|
|
964
|
-
if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
|
|
965
|
-
const response = await fetch(
|
|
966
|
-
`/admin/payment-transactions?${params.toString()}`,
|
|
967
|
-
{ credentials: "include" }
|
|
968
|
-
);
|
|
969
|
-
if (!response.ok) {
|
|
970
|
-
const text = await response.text();
|
|
971
|
-
throw new Error(text || "Failed to load payment transactions");
|
|
972
|
-
}
|
|
973
|
-
const payload = await response.json();
|
|
974
|
-
const list = payload.transactions ?? [];
|
|
975
|
-
setCount(payload.count ?? 0);
|
|
976
|
-
setOffset(nextOffset + list.length);
|
|
977
|
-
setItems((prev) => replace ? list : [...prev, ...list]);
|
|
978
|
-
} catch (e) {
|
|
979
|
-
setError(e instanceof Error ? e.message : "Failed to load");
|
|
980
|
-
} finally {
|
|
981
|
-
setIsLoading(false);
|
|
982
|
-
setIsFetchingMore(false);
|
|
983
|
-
}
|
|
984
|
-
},
|
|
985
|
-
[statusFilter, debouncedOrderId]
|
|
986
|
-
);
|
|
987
|
-
useEffect(() => {
|
|
988
|
-
void loadTransactions(0, true);
|
|
989
|
-
}, [loadTransactions]);
|
|
990
|
-
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
991
|
-
const displayStatus = (t) => {
|
|
992
|
-
const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
|
|
993
|
-
return s2 !== "" ? s2 : "—";
|
|
994
|
-
};
|
|
995
|
-
const displayAmount = (t) => {
|
|
996
|
-
const code = (t.currency_code ?? "USD").toUpperCase();
|
|
997
|
-
return `${code} ${Number(t.amount)}`;
|
|
998
|
-
};
|
|
999
|
-
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: [
|
|
1000
|
-
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1001
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1002
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
|
|
1003
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
|
|
1004
|
-
] }),
|
|
1005
|
-
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
|
|
1006
|
-
] }),
|
|
1007
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1008
|
-
/* @__PURE__ */ jsx(
|
|
1009
|
-
Input,
|
|
1010
|
-
{
|
|
1011
|
-
placeholder: "Search by Order ID",
|
|
1012
|
-
value: orderIdSearch,
|
|
1013
|
-
onChange: (e) => setOrderIdSearch(e.target.value),
|
|
1014
|
-
className: "md:max-w-sm",
|
|
1015
|
-
"aria-label": "Search by order ID"
|
|
1016
|
-
}
|
|
1017
|
-
),
|
|
1018
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
|
|
1019
|
-
"select",
|
|
1020
|
-
{
|
|
1021
|
-
value: statusFilter,
|
|
1022
|
-
onChange: (e) => setStatusFilter(e.target.value),
|
|
1023
|
-
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",
|
|
1024
|
-
"aria-label": "Filter by status",
|
|
1025
|
-
children: [
|
|
1026
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
|
|
1027
|
-
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
1028
|
-
/* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
|
|
1029
|
-
/* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
|
|
1030
|
-
/* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
|
|
1031
|
-
/* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
|
|
1032
|
-
/* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
|
|
1033
|
-
]
|
|
1034
|
-
}
|
|
1035
|
-
) })
|
|
1036
|
-
] }),
|
|
1037
|
-
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
1038
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
1039
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
|
|
1040
|
-
] }) : null,
|
|
1041
|
-
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading payments…" }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
1042
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
|
|
1043
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
|
|
1044
|
-
] }) : /* @__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: [
|
|
1045
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1046
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
1047
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
|
|
1048
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
|
|
1049
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
1050
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
|
|
1051
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
1052
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
1053
|
-
] }) }),
|
|
1054
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
|
|
1055
|
-
"tr",
|
|
1056
|
-
{
|
|
1057
|
-
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
1058
|
-
onClick: () => navigate(`/payments/${t.payment_session_id}`),
|
|
1059
|
-
children: [
|
|
1060
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
|
|
1061
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
|
|
1062
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
|
|
1063
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
1064
|
-
Badge,
|
|
1065
|
-
{
|
|
1066
|
-
size: "2xsmall",
|
|
1067
|
-
className: `uppercase ${getStatusBadgeClass$7(displayStatus(t))}`,
|
|
1068
|
-
children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
|
|
1069
|
-
}
|
|
1070
|
-
) }),
|
|
1071
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
|
|
1072
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
|
|
1073
|
-
year: "numeric",
|
|
1074
|
-
month: "short",
|
|
1075
|
-
day: "numeric",
|
|
1076
|
-
hour: "numeric",
|
|
1077
|
-
minute: "2-digit",
|
|
1078
|
-
hour12: true
|
|
1079
|
-
}) }),
|
|
1080
|
-
/* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
|
|
1081
|
-
/* @__PURE__ */ jsx(
|
|
1082
|
-
Button,
|
|
1083
|
-
{
|
|
1084
|
-
variant: "transparent",
|
|
1085
|
-
size: "small",
|
|
1086
|
-
onClick: (e) => {
|
|
1087
|
-
e.stopPropagation();
|
|
1088
|
-
navigate(`/payments/${t.payment_session_id}`);
|
|
1089
|
-
},
|
|
1090
|
-
children: "View details"
|
|
1091
|
-
}
|
|
1092
|
-
),
|
|
1093
|
-
t.order_id ? /* @__PURE__ */ jsx(
|
|
1094
|
-
Button,
|
|
1095
|
-
{
|
|
1096
|
-
variant: "transparent",
|
|
1097
|
-
size: "small",
|
|
1098
|
-
onClick: (e) => {
|
|
1099
|
-
e.stopPropagation();
|
|
1100
|
-
navigate(`/orders/${t.order_id}`);
|
|
1101
|
-
},
|
|
1102
|
-
children: "Order"
|
|
1103
|
-
}
|
|
1104
|
-
) : null
|
|
1105
|
-
] })
|
|
1106
|
-
]
|
|
1107
|
-
},
|
|
1108
|
-
t.payment_session_id
|
|
1109
|
-
)) })
|
|
1110
|
-
] }) }),
|
|
1111
|
-
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1112
|
-
Button,
|
|
1113
|
-
{
|
|
1114
|
-
variant: "secondary",
|
|
1115
|
-
isLoading: isFetchingMore,
|
|
1116
|
-
onClick: () => loadTransactions(offset, false),
|
|
1117
|
-
children: "Load more"
|
|
1118
|
-
}
|
|
1119
|
-
) }) : null
|
|
1120
|
-
] }) });
|
|
1121
|
-
};
|
|
1122
|
-
const config$9 = defineRouteConfig({
|
|
1123
|
-
label: "Payments",
|
|
1124
|
-
icon: CreditCard
|
|
1125
|
-
});
|
|
1126
|
-
const useDebounce$2 = (value, delay) => {
|
|
1127
|
-
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
1128
|
-
useEffect(() => {
|
|
1129
|
-
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
1130
|
-
return () => clearTimeout(handler);
|
|
1131
|
-
}, [value, delay]);
|
|
1132
|
-
return debouncedValue;
|
|
1133
|
-
};
|
|
1134
|
-
const getStatusBadgeClass$6 = (status) => {
|
|
1135
|
-
const s2 = status.toLowerCase();
|
|
1136
|
-
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
1137
|
-
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
1138
|
-
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
1139
|
-
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
1140
|
-
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
1141
|
-
};
|
|
1142
|
-
const RefundsPage = () => {
|
|
1143
|
-
const navigate = useNavigate();
|
|
1144
|
-
const [items, setItems] = useState([]);
|
|
1145
|
-
const [orderIdSearch, setOrderIdSearch] = useState("");
|
|
1146
|
-
const debouncedOrderId = useDebounce$2(orderIdSearch, 300);
|
|
1147
|
-
const [paymentStatusFilter, setPaymentStatusFilter] = useState("all");
|
|
1148
|
-
const [providerSearch, setProviderSearch] = useState("");
|
|
1149
|
-
const debouncedProvider = useDebounce$2(providerSearch, 300);
|
|
1150
|
-
const [currencySearch, setCurrencySearch] = useState("");
|
|
1151
|
-
const debouncedCurrency = useDebounce$2(currencySearch, 300);
|
|
1152
|
-
const [dateFrom, setDateFrom] = useState("");
|
|
1153
|
-
const [dateTo, setDateTo] = useState("");
|
|
1154
|
-
const [amountMin, setAmountMin] = useState("");
|
|
1155
|
-
const [amountMax, setAmountMax] = useState("");
|
|
1156
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
1157
|
-
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
1158
|
-
const [error, setError] = useState(null);
|
|
1159
|
-
const [offset, setOffset] = useState(0);
|
|
1160
|
-
const [count, setCount] = useState(0);
|
|
1161
|
-
const limit = 50;
|
|
1162
|
-
const loadRefunds = useCallback(
|
|
1163
|
-
async (nextOffset, replace) => {
|
|
1164
|
-
try {
|
|
1165
|
-
if (replace) setIsLoading(true);
|
|
1166
|
-
else setIsFetchingMore(true);
|
|
1167
|
-
setError(null);
|
|
1168
|
-
const params = new URLSearchParams();
|
|
1169
|
-
params.set("limit", String(limit));
|
|
1170
|
-
params.set("offset", String(nextOffset));
|
|
1171
|
-
if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
|
|
1172
|
-
if (paymentStatusFilter !== "all") params.set("payment_status", paymentStatusFilter);
|
|
1173
|
-
if (debouncedProvider.trim()) params.set("provider_id", debouncedProvider.trim());
|
|
1174
|
-
if (debouncedCurrency.trim()) params.set("currency_code", debouncedCurrency.trim());
|
|
1175
|
-
if (dateFrom.trim()) params.set("date_from", dateFrom.trim());
|
|
1176
|
-
if (dateTo.trim()) params.set("date_to", dateTo.trim());
|
|
1177
|
-
const min = amountMin.trim() ? Number(amountMin) : void 0;
|
|
1178
|
-
const max = amountMax.trim() ? Number(amountMax) : void 0;
|
|
1179
|
-
if (min != null && !Number.isNaN(min)) params.set("amount_min", String(min));
|
|
1180
|
-
if (max != null && !Number.isNaN(max)) params.set("amount_max", String(max));
|
|
1181
|
-
const response = await fetch(`/admin/refunds?${params.toString()}`, {
|
|
1182
|
-
credentials: "include"
|
|
1183
|
-
});
|
|
1184
|
-
if (!response.ok) {
|
|
1185
|
-
const text = await response.text();
|
|
1186
|
-
throw new Error(text || "Failed to load refunds");
|
|
1187
|
-
}
|
|
1188
|
-
const payload = await response.json();
|
|
1189
|
-
const list = payload.refunds ?? [];
|
|
1190
|
-
setCount(payload.count ?? 0);
|
|
1191
|
-
setOffset(nextOffset + list.length);
|
|
1192
|
-
setItems((prev) => replace ? list : [...prev, ...list]);
|
|
1193
|
-
} catch (e) {
|
|
1194
|
-
setError(e instanceof Error ? e.message : "Failed to load");
|
|
1195
|
-
} finally {
|
|
1196
|
-
setIsLoading(false);
|
|
1197
|
-
setIsFetchingMore(false);
|
|
1198
|
-
}
|
|
1199
|
-
},
|
|
1200
|
-
[
|
|
1201
|
-
debouncedOrderId,
|
|
1202
|
-
paymentStatusFilter,
|
|
1203
|
-
debouncedProvider,
|
|
1204
|
-
debouncedCurrency,
|
|
1205
|
-
dateFrom,
|
|
1206
|
-
dateTo,
|
|
1207
|
-
amountMin,
|
|
1208
|
-
amountMax
|
|
1209
|
-
]
|
|
1210
|
-
);
|
|
1211
|
-
useEffect(() => {
|
|
1212
|
-
void loadRefunds(0, true);
|
|
1213
|
-
}, [loadRefunds]);
|
|
1214
|
-
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
1215
|
-
const displayAmount = (r) => {
|
|
1216
|
-
const code = (r.currency_code ?? "USD").toUpperCase();
|
|
1217
|
-
return `${code} ${Number(r.amount)}`;
|
|
1218
|
-
};
|
|
1219
|
-
const displayStatus = (r) => {
|
|
1220
|
-
const s2 = r.payment_status ?? "";
|
|
1221
|
-
return s2 !== "" ? s2 : "—";
|
|
1222
|
-
};
|
|
1223
|
-
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: [
|
|
1224
|
-
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1225
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1226
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refunds" }),
|
|
1227
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Refund records — amount, order, payment status" })
|
|
1228
|
-
] }),
|
|
1229
|
-
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadRefunds(0, true), children: "Refresh" })
|
|
1230
|
-
] }),
|
|
1231
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
1232
|
-
/* @__PURE__ */ jsx(
|
|
1233
|
-
Input,
|
|
1234
|
-
{
|
|
1235
|
-
placeholder: "Order ID",
|
|
1236
|
-
value: orderIdSearch,
|
|
1237
|
-
onChange: (e) => setOrderIdSearch(e.target.value),
|
|
1238
|
-
className: "md:max-w-[180px]",
|
|
1239
|
-
"aria-label": "Filter by order ID"
|
|
1240
|
-
}
|
|
1241
|
-
),
|
|
1242
|
-
/* @__PURE__ */ jsx(
|
|
1243
|
-
Input,
|
|
1244
|
-
{
|
|
1245
|
-
placeholder: "Provider",
|
|
1246
|
-
value: providerSearch,
|
|
1247
|
-
onChange: (e) => setProviderSearch(e.target.value),
|
|
1248
|
-
className: "md:max-w-[140px]",
|
|
1249
|
-
"aria-label": "Filter by provider"
|
|
1250
|
-
}
|
|
1251
|
-
),
|
|
1252
|
-
/* @__PURE__ */ jsx(
|
|
1253
|
-
Input,
|
|
1254
|
-
{
|
|
1255
|
-
placeholder: "Currency",
|
|
1256
|
-
value: currencySearch,
|
|
1257
|
-
onChange: (e) => setCurrencySearch(e.target.value),
|
|
1258
|
-
className: "md:max-w-[100px]",
|
|
1259
|
-
"aria-label": "Filter by currency"
|
|
1260
|
-
}
|
|
1261
|
-
),
|
|
1262
|
-
/* @__PURE__ */ jsxs(
|
|
1263
|
-
"select",
|
|
1264
|
-
{
|
|
1265
|
-
value: paymentStatusFilter,
|
|
1266
|
-
onChange: (e) => setPaymentStatusFilter(e.target.value),
|
|
1267
|
-
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-[160px]",
|
|
1268
|
-
"aria-label": "Filter by payment status",
|
|
1269
|
-
children: [
|
|
1270
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
|
|
1271
|
-
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
1272
|
-
/* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
|
|
1273
|
-
/* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
|
|
1274
|
-
/* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
|
|
1275
|
-
/* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
|
|
1276
|
-
/* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
|
|
1277
|
-
]
|
|
1278
|
-
}
|
|
1279
|
-
),
|
|
1280
|
-
/* @__PURE__ */ jsx(
|
|
1281
|
-
Input,
|
|
1282
|
-
{
|
|
1283
|
-
type: "date",
|
|
1284
|
-
placeholder: "From",
|
|
1285
|
-
value: dateFrom,
|
|
1286
|
-
onChange: (e) => setDateFrom(e.target.value),
|
|
1287
|
-
className: "md:max-w-[140px]",
|
|
1288
|
-
"aria-label": "Date from"
|
|
1289
|
-
}
|
|
1290
|
-
),
|
|
1291
|
-
/* @__PURE__ */ jsx(
|
|
1292
|
-
Input,
|
|
1293
|
-
{
|
|
1294
|
-
type: "date",
|
|
1295
|
-
placeholder: "To",
|
|
1296
|
-
value: dateTo,
|
|
1297
|
-
onChange: (e) => setDateTo(e.target.value),
|
|
1298
|
-
className: "md:max-w-[140px]",
|
|
1299
|
-
"aria-label": "Date to"
|
|
1300
|
-
}
|
|
1301
|
-
),
|
|
1302
|
-
/* @__PURE__ */ jsx(
|
|
1303
|
-
Input,
|
|
1304
|
-
{
|
|
1305
|
-
placeholder: "Amount min",
|
|
1306
|
-
value: amountMin,
|
|
1307
|
-
onChange: (e) => setAmountMin(e.target.value),
|
|
1308
|
-
type: "number",
|
|
1309
|
-
min: 0,
|
|
1310
|
-
className: "md:max-w-[100px]",
|
|
1311
|
-
"aria-label": "Refund amount minimum"
|
|
1312
|
-
}
|
|
1313
|
-
),
|
|
1314
|
-
/* @__PURE__ */ jsx(
|
|
1315
|
-
Input,
|
|
1316
|
-
{
|
|
1317
|
-
placeholder: "Amount max",
|
|
1318
|
-
value: amountMax,
|
|
1319
|
-
onChange: (e) => setAmountMax(e.target.value),
|
|
1320
|
-
type: "number",
|
|
1321
|
-
min: 0,
|
|
1322
|
-
className: "md:max-w-[100px]",
|
|
1323
|
-
"aria-label": "Refund amount maximum"
|
|
1324
|
-
}
|
|
1325
|
-
)
|
|
1326
|
-
] }) }),
|
|
1327
|
-
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
1328
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
1329
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadRefunds(0, true), children: "Try again" }) })
|
|
1330
|
-
] }) : null,
|
|
1331
|
-
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading refunds…" }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
1332
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No refunds yet" }),
|
|
1333
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Refund records will appear here." })
|
|
1334
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "w-full table-fixed divide-y divide-ui-border-base", style: { minWidth: 0 }, children: [
|
|
1335
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1336
|
-
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund ID" }),
|
|
1337
|
-
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
1338
|
-
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Payment ID" }),
|
|
1339
|
-
/* @__PURE__ */ jsx("th", { className: "w-[8%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
|
|
1340
|
-
/* @__PURE__ */ jsx("th", { className: "w-[6%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Currency" }),
|
|
1341
|
-
/* @__PURE__ */ jsx("th", { className: "w-[10%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
|
|
1342
|
-
/* @__PURE__ */ jsx("th", { className: "w-[10%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Payment Status" }),
|
|
1343
|
-
/* @__PURE__ */ jsx("th", { className: "w-[14%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Note" }),
|
|
1344
|
-
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
1345
|
-
/* @__PURE__ */ jsx("th", { className: "w-[8%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
1346
|
-
] }) }),
|
|
1347
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
|
|
1348
|
-
"tr",
|
|
1349
|
-
{
|
|
1350
|
-
className: "cursor-pointer hover:bg-ui-bg-subtle/60",
|
|
1351
|
-
onClick: () => navigate(`/refunds/${r.refund_id}`),
|
|
1352
|
-
children: [
|
|
1353
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-base", title: r.refund_id, children: r.refund_id }),
|
|
1354
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-medium text-ui-fg-base", title: r.order_id ?? void 0, children: r.order_id ?? "—" }),
|
|
1355
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-subtle", title: r.payment_id, children: r.payment_id }),
|
|
1356
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
|
|
1357
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
|
|
1358
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.provider_id || void 0, children: r.provider_id || "—" }),
|
|
1359
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
|
|
1360
|
-
Badge,
|
|
1361
|
-
{
|
|
1362
|
-
size: "2xsmall",
|
|
1363
|
-
className: `uppercase ${getStatusBadgeClass$6(displayStatus(r))}`,
|
|
1364
|
-
children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
|
|
1365
|
-
}
|
|
1366
|
-
) }),
|
|
1367
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
|
|
1368
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle text-xs", children: new Date(r.created_at).toLocaleDateString("en-US", {
|
|
1369
|
-
month: "short",
|
|
1370
|
-
day: "numeric",
|
|
1371
|
-
hour: "numeric",
|
|
1372
|
-
minute: "2-digit",
|
|
1373
|
-
hour12: true
|
|
1374
|
-
}) }),
|
|
1375
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
1376
|
-
/* @__PURE__ */ jsx(
|
|
1377
|
-
Button,
|
|
1378
|
-
{
|
|
1379
|
-
variant: "transparent",
|
|
1380
|
-
size: "small",
|
|
1381
|
-
onClick: (e) => {
|
|
1382
|
-
e.stopPropagation();
|
|
1383
|
-
navigate(`/refunds/${r.refund_id}`);
|
|
1384
|
-
},
|
|
1385
|
-
children: "Details"
|
|
1386
|
-
}
|
|
1387
|
-
),
|
|
1388
|
-
r.order_id ? /* @__PURE__ */ jsx(
|
|
1389
|
-
Button,
|
|
1390
|
-
{
|
|
1391
|
-
variant: "transparent",
|
|
1392
|
-
size: "small",
|
|
1393
|
-
onClick: (e) => {
|
|
1394
|
-
e.stopPropagation();
|
|
1395
|
-
navigate(`/orders/${r.order_id}`);
|
|
1396
|
-
},
|
|
1397
|
-
children: "Order"
|
|
1398
|
-
}
|
|
1399
|
-
) : null
|
|
1400
|
-
] }) })
|
|
1401
|
-
]
|
|
1402
|
-
},
|
|
1403
|
-
r.refund_id
|
|
1404
|
-
)) })
|
|
1405
|
-
] }) }),
|
|
1406
|
-
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1407
|
-
Button,
|
|
1408
|
-
{
|
|
1409
|
-
variant: "secondary",
|
|
1410
|
-
isLoading: isFetchingMore,
|
|
1411
|
-
onClick: () => loadRefunds(offset, false),
|
|
1412
|
-
children: "Load more"
|
|
1413
|
-
}
|
|
1414
|
-
) }) : null
|
|
1415
|
-
] }) });
|
|
1416
|
-
};
|
|
1417
|
-
const config$8 = defineRouteConfig({
|
|
1418
|
-
label: "Refunds",
|
|
1419
|
-
icon: Receipt
|
|
1420
|
-
});
|
|
1421
|
-
const useDebounce$1 = (value, delay) => {
|
|
1422
|
-
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
1423
|
-
useEffect(() => {
|
|
1424
|
-
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
1425
|
-
return () => clearTimeout(handler);
|
|
1426
|
-
}, [value, delay]);
|
|
1427
|
-
return debouncedValue;
|
|
1428
|
-
};
|
|
1429
|
-
const getStatusBadgeClass$5 = (status) => {
|
|
1430
|
-
const statusLower = status.toLowerCase();
|
|
1431
|
-
if (statusLower === "requested") {
|
|
1432
|
-
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
1433
|
-
}
|
|
1434
|
-
if (statusLower === "received") {
|
|
1435
|
-
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
1436
|
-
}
|
|
1437
|
-
if (statusLower === "requires_action") {
|
|
1438
|
-
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
1439
|
-
}
|
|
1440
|
-
if (statusLower === "completed") {
|
|
1441
|
-
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
1442
|
-
}
|
|
1443
|
-
if (statusLower === "canceled") {
|
|
1444
|
-
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
1445
|
-
}
|
|
1446
|
-
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
1447
|
-
};
|
|
1448
|
-
const ReturnsPage = () => {
|
|
1449
|
-
const navigate = useNavigate();
|
|
1450
|
-
const [items, setItems] = useState([]);
|
|
1451
|
-
const [statusFilter, setStatusFilter] = useState("all");
|
|
1452
|
-
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
1453
|
-
const [searchQuery, setSearchQuery] = useState("");
|
|
1454
|
-
const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
|
|
1455
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
1456
|
-
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
1457
|
-
const [error, setError] = useState(null);
|
|
1458
|
-
const [offset, setOffset] = useState(0);
|
|
1459
|
-
const [count, setCount] = useState(0);
|
|
1460
|
-
const limit = 50;
|
|
1461
|
-
const loadReturns = useCallback(
|
|
1462
|
-
async (nextOffset, replace = false) => {
|
|
1463
|
-
try {
|
|
1464
|
-
if (replace) {
|
|
1465
|
-
setIsLoading(true);
|
|
1466
|
-
} else {
|
|
1467
|
-
setIsFetchingMore(true);
|
|
1468
|
-
}
|
|
1469
|
-
setError(null);
|
|
1470
|
-
const params = new URLSearchParams();
|
|
1471
|
-
params.set("limit", String(limit));
|
|
1472
|
-
params.set("offset", String(nextOffset));
|
|
1473
|
-
if (statusFilter !== "all") {
|
|
1474
|
-
params.set("status", statusFilter);
|
|
1475
|
-
}
|
|
1476
|
-
if (debouncedSearchQuery.trim()) {
|
|
1477
|
-
params.set("q", debouncedSearchQuery.trim());
|
|
1478
|
-
}
|
|
1479
|
-
if (createdByFilter !== "all") {
|
|
1480
|
-
params.set("created_by", createdByFilter);
|
|
1481
|
-
}
|
|
1482
|
-
params.set("order", "created_at");
|
|
1483
|
-
const response = await fetch(
|
|
1484
|
-
`/admin/return?${params.toString()}`,
|
|
1485
|
-
{ credentials: "include" }
|
|
1486
|
-
);
|
|
1487
|
-
if (!response.ok) {
|
|
1488
|
-
const message = await response.text();
|
|
1489
|
-
throw new Error(message || "Unable to load return orders");
|
|
1490
|
-
}
|
|
1491
|
-
const payload = await response.json();
|
|
1492
|
-
setCount(payload.count ?? 0);
|
|
1493
|
-
setOffset(nextOffset + (payload.returns?.length ?? 0));
|
|
1494
|
-
setItems(
|
|
1495
|
-
(prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
|
|
1496
|
-
);
|
|
1497
|
-
} catch (loadError) {
|
|
1498
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
1499
|
-
setError(message);
|
|
1500
|
-
} finally {
|
|
1501
|
-
setIsLoading(false);
|
|
1502
|
-
setIsFetchingMore(false);
|
|
1503
|
-
}
|
|
1504
|
-
},
|
|
1505
|
-
[statusFilter, createdByFilter, debouncedSearchQuery]
|
|
1506
|
-
);
|
|
1507
|
-
useEffect(() => {
|
|
1508
|
-
void loadReturns(0, true);
|
|
1509
|
-
}, [statusFilter, createdByFilter, debouncedSearchQuery, loadReturns]);
|
|
1510
|
-
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
1511
|
-
const availableStatuses = useMemo(() => {
|
|
1512
|
-
const statuses = /* @__PURE__ */ new Set();
|
|
1513
|
-
items.forEach((item) => statuses.add(item.status));
|
|
1514
|
-
return Array.from(statuses).sort();
|
|
1515
|
-
}, [items]);
|
|
1516
|
-
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: [
|
|
1517
|
-
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1518
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1519
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Orders" }),
|
|
1520
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
|
|
1521
|
-
] }),
|
|
1522
|
-
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
|
|
1523
|
-
] }),
|
|
1524
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1525
|
-
/* @__PURE__ */ jsx(
|
|
1526
|
-
Input,
|
|
1527
|
-
{
|
|
1528
|
-
placeholder: "Search by return ID, order ID, or customer email",
|
|
1529
|
-
value: searchQuery,
|
|
1530
|
-
onChange: (event) => setSearchQuery(event.target.value),
|
|
1531
|
-
className: "md:max-w-sm"
|
|
1532
|
-
}
|
|
1533
|
-
),
|
|
1534
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
1535
|
-
/* @__PURE__ */ jsxs(
|
|
1536
|
-
"select",
|
|
1537
|
-
{
|
|
1538
|
-
value: createdByFilter,
|
|
1539
|
-
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
1540
|
-
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",
|
|
1541
|
-
children: [
|
|
1542
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
1543
|
-
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
1544
|
-
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
1545
|
-
]
|
|
1546
|
-
}
|
|
1547
|
-
),
|
|
1548
|
-
/* @__PURE__ */ jsxs(
|
|
1549
|
-
"select",
|
|
1550
|
-
{
|
|
1551
|
-
value: statusFilter,
|
|
1552
|
-
onChange: (event) => setStatusFilter(event.target.value),
|
|
1553
|
-
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",
|
|
1554
|
-
children: [
|
|
1555
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
1556
|
-
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
1557
|
-
]
|
|
1558
|
-
}
|
|
1559
|
-
)
|
|
1560
|
-
] })
|
|
1561
|
-
] }),
|
|
1562
|
-
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
1563
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
1564
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1565
|
-
Button,
|
|
1566
|
-
{
|
|
1567
|
-
variant: "secondary",
|
|
1568
|
-
onClick: () => loadReturns(0, true),
|
|
1569
|
-
children: "Try again"
|
|
1570
|
-
}
|
|
1571
|
-
) })
|
|
1572
|
-
] }) : null,
|
|
1573
|
-
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: [
|
|
1574
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
|
|
1575
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
|
|
1576
|
-
] }) : /* @__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: [
|
|
1577
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1578
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
|
|
1579
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
1580
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
1581
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
1582
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
|
|
1583
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
1584
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
1585
|
-
] }) }),
|
|
1586
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
|
|
1587
|
-
"tr",
|
|
1588
|
-
{
|
|
1589
|
-
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
1590
|
-
onClick: () => navigate(`/returns/${returnOrder.id}`),
|
|
1591
|
-
children: [
|
|
1592
|
-
/* @__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 }) }) }),
|
|
1593
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
|
|
1594
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
1595
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
1596
|
-
Badge,
|
|
1597
|
-
{
|
|
1598
|
-
size: "2xsmall",
|
|
1599
|
-
className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
|
|
1600
|
-
children: returnOrder.status.replace(/_/g, " ")
|
|
1601
|
-
}
|
|
1602
|
-
) }),
|
|
1603
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
1604
|
-
const calc = returnOrder.refund;
|
|
1605
|
-
if (calc?.is_processed && calc.final_refund_amount != null) {
|
|
1606
|
-
return formatRefundCurrency(
|
|
1607
|
-
calc.final_refund_amount,
|
|
1608
|
-
calc.currency_code || returnOrder.currency_code
|
|
1609
|
-
);
|
|
1610
|
-
}
|
|
1611
|
-
if (calc) {
|
|
1612
|
-
return "Pending";
|
|
1613
|
-
}
|
|
1614
|
-
if (returnOrder.refund_amount == null) {
|
|
1615
|
-
return "—";
|
|
1616
|
-
}
|
|
1617
|
-
return formatRefundCurrency(
|
|
1618
|
-
Number(returnOrder.refund_amount),
|
|
1619
|
-
returnOrder.currency_code
|
|
1620
|
-
);
|
|
1621
|
-
})() }),
|
|
1622
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
|
|
1623
|
-
year: "numeric",
|
|
1624
|
-
month: "short",
|
|
1625
|
-
day: "numeric",
|
|
1626
|
-
hour: "numeric",
|
|
1627
|
-
minute: "2-digit",
|
|
1628
|
-
hour12: true
|
|
1629
|
-
}) }),
|
|
1630
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
1631
|
-
Button,
|
|
1632
|
-
{
|
|
1633
|
-
variant: "transparent",
|
|
1634
|
-
size: "small",
|
|
1635
|
-
onClick: (e) => {
|
|
1636
|
-
e.stopPropagation();
|
|
1637
|
-
navigate(`/app/orders/${returnOrder.order_id}`);
|
|
1638
|
-
},
|
|
1639
|
-
children: "Go to order"
|
|
1640
|
-
}
|
|
1641
|
-
) })
|
|
1642
|
-
]
|
|
1643
|
-
},
|
|
1644
|
-
returnOrder.id
|
|
1645
|
-
)) })
|
|
1646
|
-
] }) }),
|
|
1647
|
-
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1648
|
-
Button,
|
|
1649
|
-
{
|
|
1650
|
-
variant: "secondary",
|
|
1651
|
-
isLoading: isFetchingMore,
|
|
1652
|
-
onClick: () => loadReturns(offset, false),
|
|
1653
|
-
children: "Load more"
|
|
1654
|
-
}
|
|
1655
|
-
) }) : null
|
|
1656
|
-
] }) });
|
|
1657
|
-
};
|
|
1658
|
-
const config$7 = defineRouteConfig({
|
|
1659
|
-
label: "Return Orders",
|
|
1660
|
-
icon: ArrowPath
|
|
1661
|
-
});
|
|
1662
924
|
const AUDITED_TABLE_NAMES = [
|
|
1663
925
|
"account_deletion_request",
|
|
1664
926
|
"account_holder",
|
|
@@ -2944,11 +2206,11 @@ const ErrorState = ({ onRetry, detail }) => /* @__PURE__ */ jsxs("div", { classN
|
|
|
2944
2206
|
/* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: detail }),
|
|
2945
2207
|
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", className: "mt-2", onClick: onRetry, children: "Try again" })
|
|
2946
2208
|
] });
|
|
2947
|
-
const config$
|
|
2209
|
+
const config$9 = defineRouteConfig({
|
|
2948
2210
|
label: "Deleted Records",
|
|
2949
2211
|
icon: Trash
|
|
2950
2212
|
});
|
|
2951
|
-
const useDebounce = (value, delay) => {
|
|
2213
|
+
const useDebounce$3 = (value, delay) => {
|
|
2952
2214
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2953
2215
|
useEffect(() => {
|
|
2954
2216
|
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
@@ -2956,210 +2218,476 @@ const useDebounce = (value, delay) => {
|
|
|
2956
2218
|
}, [value, delay]);
|
|
2957
2219
|
return debouncedValue;
|
|
2958
2220
|
};
|
|
2959
|
-
const getStatusBadgeClass$
|
|
2960
|
-
const
|
|
2961
|
-
if (
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
if (
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2221
|
+
const getStatusBadgeClass$7 = (status) => {
|
|
2222
|
+
const s2 = status.toLowerCase();
|
|
2223
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2224
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2225
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2226
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2227
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
2228
|
+
};
|
|
2229
|
+
const PaymentsPage = () => {
|
|
2230
|
+
const navigate = useNavigate();
|
|
2231
|
+
const [items, setItems] = useState([]);
|
|
2232
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
2233
|
+
const [orderIdSearch, setOrderIdSearch] = useState("");
|
|
2234
|
+
const debouncedOrderId = useDebounce$3(orderIdSearch, 300);
|
|
2235
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
2236
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
2237
|
+
const [error, setError] = useState(null);
|
|
2238
|
+
const [offset, setOffset] = useState(0);
|
|
2239
|
+
const [count, setCount] = useState(0);
|
|
2240
|
+
const limit = 50;
|
|
2241
|
+
const loadTransactions = useCallback(
|
|
2242
|
+
async (nextOffset, replace) => {
|
|
2243
|
+
try {
|
|
2244
|
+
if (replace) setIsLoading(true);
|
|
2245
|
+
else setIsFetchingMore(true);
|
|
2246
|
+
setError(null);
|
|
2247
|
+
const params = new URLSearchParams();
|
|
2248
|
+
params.set("limit", String(limit));
|
|
2249
|
+
params.set("offset", String(nextOffset));
|
|
2250
|
+
if (statusFilter !== "all") params.set("status", statusFilter);
|
|
2251
|
+
if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
|
|
2252
|
+
const response = await fetch(
|
|
2253
|
+
`/admin/payment-transactions?${params.toString()}`,
|
|
2254
|
+
{ credentials: "include" }
|
|
2255
|
+
);
|
|
2256
|
+
if (!response.ok) {
|
|
2257
|
+
const text = await response.text();
|
|
2258
|
+
throw new Error(text || "Failed to load payment transactions");
|
|
2259
|
+
}
|
|
2260
|
+
const payload = await response.json();
|
|
2261
|
+
const list = payload.transactions ?? [];
|
|
2262
|
+
setCount(payload.count ?? 0);
|
|
2263
|
+
setOffset(nextOffset + list.length);
|
|
2264
|
+
setItems((prev) => replace ? list : [...prev, ...list]);
|
|
2265
|
+
} catch (e) {
|
|
2266
|
+
setError(e instanceof Error ? e.message : "Failed to load");
|
|
2267
|
+
} finally {
|
|
2268
|
+
setIsLoading(false);
|
|
2269
|
+
setIsFetchingMore(false);
|
|
2270
|
+
}
|
|
2271
|
+
},
|
|
2272
|
+
[statusFilter, debouncedOrderId]
|
|
2273
|
+
);
|
|
2274
|
+
useEffect(() => {
|
|
2275
|
+
void loadTransactions(0, true);
|
|
2276
|
+
}, [loadTransactions]);
|
|
2277
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
2278
|
+
const displayStatus = (t) => {
|
|
2279
|
+
const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
|
|
2280
|
+
return s2 !== "" ? s2 : "—";
|
|
2281
|
+
};
|
|
2282
|
+
const displayAmount = (t) => {
|
|
2283
|
+
const code = (t.currency_code ?? "USD").toUpperCase();
|
|
2284
|
+
return `${code} ${Number(t.amount)}`;
|
|
2285
|
+
};
|
|
2286
|
+
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: [
|
|
2287
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2288
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2289
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
|
|
2290
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
|
|
2291
|
+
] }),
|
|
2292
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
|
|
2293
|
+
] }),
|
|
2294
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2295
|
+
/* @__PURE__ */ jsx(
|
|
2296
|
+
Input,
|
|
2297
|
+
{
|
|
2298
|
+
placeholder: "Search by Order ID",
|
|
2299
|
+
value: orderIdSearch,
|
|
2300
|
+
onChange: (e) => setOrderIdSearch(e.target.value),
|
|
2301
|
+
className: "md:max-w-sm",
|
|
2302
|
+
"aria-label": "Search by order ID"
|
|
2303
|
+
}
|
|
2304
|
+
),
|
|
2305
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
|
|
2306
|
+
"select",
|
|
2307
|
+
{
|
|
2308
|
+
value: statusFilter,
|
|
2309
|
+
onChange: (e) => setStatusFilter(e.target.value),
|
|
2310
|
+
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",
|
|
2311
|
+
"aria-label": "Filter by status",
|
|
2312
|
+
children: [
|
|
2313
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
|
|
2314
|
+
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
2315
|
+
/* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
|
|
2316
|
+
/* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
|
|
2317
|
+
/* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
|
|
2318
|
+
/* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
|
|
2319
|
+
/* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
|
|
2320
|
+
]
|
|
2321
|
+
}
|
|
2322
|
+
) })
|
|
2323
|
+
] }),
|
|
2324
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
2325
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
2326
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
|
|
2327
|
+
] }) : null,
|
|
2328
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading payments…" }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
2329
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
|
|
2330
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
|
|
2331
|
+
] }) : /* @__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: [
|
|
2332
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2333
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
2334
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
|
|
2335
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
|
|
2336
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
2337
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
|
|
2338
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
2339
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
2340
|
+
] }) }),
|
|
2341
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
|
|
2342
|
+
"tr",
|
|
2343
|
+
{
|
|
2344
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
2345
|
+
onClick: () => navigate(`/payments/${t.payment_session_id}`),
|
|
2346
|
+
children: [
|
|
2347
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
|
|
2348
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
|
|
2349
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
|
|
2350
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
2351
|
+
Badge,
|
|
2352
|
+
{
|
|
2353
|
+
size: "2xsmall",
|
|
2354
|
+
className: `uppercase ${getStatusBadgeClass$7(displayStatus(t))}`,
|
|
2355
|
+
children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
|
|
2356
|
+
}
|
|
2357
|
+
) }),
|
|
2358
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
|
|
2359
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
|
|
2360
|
+
year: "numeric",
|
|
2361
|
+
month: "short",
|
|
2362
|
+
day: "numeric",
|
|
2363
|
+
hour: "numeric",
|
|
2364
|
+
minute: "2-digit",
|
|
2365
|
+
hour12: true
|
|
2366
|
+
}) }),
|
|
2367
|
+
/* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
|
|
2368
|
+
/* @__PURE__ */ jsx(
|
|
2369
|
+
Button,
|
|
2370
|
+
{
|
|
2371
|
+
variant: "transparent",
|
|
2372
|
+
size: "small",
|
|
2373
|
+
onClick: (e) => {
|
|
2374
|
+
e.stopPropagation();
|
|
2375
|
+
navigate(`/payments/${t.payment_session_id}`);
|
|
2376
|
+
},
|
|
2377
|
+
children: "View details"
|
|
2378
|
+
}
|
|
2379
|
+
),
|
|
2380
|
+
t.order_id ? /* @__PURE__ */ jsx(
|
|
2381
|
+
Button,
|
|
2382
|
+
{
|
|
2383
|
+
variant: "transparent",
|
|
2384
|
+
size: "small",
|
|
2385
|
+
onClick: (e) => {
|
|
2386
|
+
e.stopPropagation();
|
|
2387
|
+
navigate(`/orders/${t.order_id}`);
|
|
2388
|
+
},
|
|
2389
|
+
children: "Order"
|
|
2390
|
+
}
|
|
2391
|
+
) : null
|
|
2392
|
+
] })
|
|
2393
|
+
]
|
|
2394
|
+
},
|
|
2395
|
+
t.payment_session_id
|
|
2396
|
+
)) })
|
|
2397
|
+
] }) }),
|
|
2398
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
2399
|
+
Button,
|
|
2400
|
+
{
|
|
2401
|
+
variant: "secondary",
|
|
2402
|
+
isLoading: isFetchingMore,
|
|
2403
|
+
onClick: () => loadTransactions(offset, false),
|
|
2404
|
+
children: "Load more"
|
|
2405
|
+
}
|
|
2406
|
+
) }) : null
|
|
2407
|
+
] }) });
|
|
2408
|
+
};
|
|
2409
|
+
const config$8 = defineRouteConfig({
|
|
2410
|
+
label: "Payments",
|
|
2411
|
+
icon: CreditCard
|
|
2412
|
+
});
|
|
2413
|
+
const useDebounce$2 = (value, delay) => {
|
|
2414
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2415
|
+
useEffect(() => {
|
|
2416
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
2417
|
+
return () => clearTimeout(handler);
|
|
2418
|
+
}, [value, delay]);
|
|
2419
|
+
return debouncedValue;
|
|
2420
|
+
};
|
|
2421
|
+
const getStatusBadgeClass$6 = (status) => {
|
|
2422
|
+
const s2 = status.toLowerCase();
|
|
2423
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2424
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2425
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2426
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2976
2427
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
2977
2428
|
};
|
|
2978
|
-
const
|
|
2429
|
+
const RefundsPage = () => {
|
|
2979
2430
|
const navigate = useNavigate();
|
|
2980
2431
|
const [items, setItems] = useState([]);
|
|
2981
|
-
const [
|
|
2982
|
-
const
|
|
2983
|
-
const [
|
|
2984
|
-
const
|
|
2432
|
+
const [orderIdSearch, setOrderIdSearch] = useState("");
|
|
2433
|
+
const debouncedOrderId = useDebounce$2(orderIdSearch, 300);
|
|
2434
|
+
const [paymentStatusFilter, setPaymentStatusFilter] = useState("all");
|
|
2435
|
+
const [providerSearch, setProviderSearch] = useState("");
|
|
2436
|
+
const debouncedProvider = useDebounce$2(providerSearch, 300);
|
|
2437
|
+
const [currencySearch, setCurrencySearch] = useState("");
|
|
2438
|
+
const debouncedCurrency = useDebounce$2(currencySearch, 300);
|
|
2439
|
+
const [dateFrom, setDateFrom] = useState("");
|
|
2440
|
+
const [dateTo, setDateTo] = useState("");
|
|
2441
|
+
const [amountMin, setAmountMin] = useState("");
|
|
2442
|
+
const [amountMax, setAmountMax] = useState("");
|
|
2985
2443
|
const [isLoading, setIsLoading] = useState(true);
|
|
2986
2444
|
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
2987
2445
|
const [error, setError] = useState(null);
|
|
2988
2446
|
const [offset, setOffset] = useState(0);
|
|
2989
2447
|
const [count, setCount] = useState(0);
|
|
2990
2448
|
const limit = 50;
|
|
2991
|
-
const
|
|
2992
|
-
async (nextOffset, replace
|
|
2449
|
+
const loadRefunds = useCallback(
|
|
2450
|
+
async (nextOffset, replace) => {
|
|
2993
2451
|
try {
|
|
2994
|
-
if (replace)
|
|
2995
|
-
|
|
2996
|
-
} else {
|
|
2997
|
-
setIsFetchingMore(true);
|
|
2998
|
-
}
|
|
2452
|
+
if (replace) setIsLoading(true);
|
|
2453
|
+
else setIsFetchingMore(true);
|
|
2999
2454
|
setError(null);
|
|
3000
2455
|
const params = new URLSearchParams();
|
|
3001
2456
|
params.set("limit", String(limit));
|
|
3002
2457
|
params.set("offset", String(nextOffset));
|
|
3003
|
-
if (
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
if (
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
);
|
|
2458
|
+
if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
|
|
2459
|
+
if (paymentStatusFilter !== "all") params.set("payment_status", paymentStatusFilter);
|
|
2460
|
+
if (debouncedProvider.trim()) params.set("provider_id", debouncedProvider.trim());
|
|
2461
|
+
if (debouncedCurrency.trim()) params.set("currency_code", debouncedCurrency.trim());
|
|
2462
|
+
if (dateFrom.trim()) params.set("date_from", dateFrom.trim());
|
|
2463
|
+
if (dateTo.trim()) params.set("date_to", dateTo.trim());
|
|
2464
|
+
const min = amountMin.trim() ? Number(amountMin) : void 0;
|
|
2465
|
+
const max = amountMax.trim() ? Number(amountMax) : void 0;
|
|
2466
|
+
if (min != null && !Number.isNaN(min)) params.set("amount_min", String(min));
|
|
2467
|
+
if (max != null && !Number.isNaN(max)) params.set("amount_max", String(max));
|
|
2468
|
+
const response = await fetch(`/admin/refunds?${params.toString()}`, {
|
|
2469
|
+
credentials: "include"
|
|
2470
|
+
});
|
|
3016
2471
|
if (!response.ok) {
|
|
3017
|
-
const
|
|
3018
|
-
throw new Error(
|
|
2472
|
+
const text = await response.text();
|
|
2473
|
+
throw new Error(text || "Failed to load refunds");
|
|
3019
2474
|
}
|
|
3020
2475
|
const payload = await response.json();
|
|
2476
|
+
const list = payload.refunds ?? [];
|
|
3021
2477
|
setCount(payload.count ?? 0);
|
|
3022
|
-
setOffset(nextOffset +
|
|
3023
|
-
setItems(
|
|
3024
|
-
|
|
3025
|
-
);
|
|
3026
|
-
} catch (loadError) {
|
|
3027
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
|
|
3028
|
-
setError(message);
|
|
2478
|
+
setOffset(nextOffset + list.length);
|
|
2479
|
+
setItems((prev) => replace ? list : [...prev, ...list]);
|
|
2480
|
+
} catch (e) {
|
|
2481
|
+
setError(e instanceof Error ? e.message : "Failed to load");
|
|
3029
2482
|
} finally {
|
|
3030
2483
|
setIsLoading(false);
|
|
3031
2484
|
setIsFetchingMore(false);
|
|
3032
2485
|
}
|
|
3033
2486
|
},
|
|
3034
|
-
[
|
|
2487
|
+
[
|
|
2488
|
+
debouncedOrderId,
|
|
2489
|
+
paymentStatusFilter,
|
|
2490
|
+
debouncedProvider,
|
|
2491
|
+
debouncedCurrency,
|
|
2492
|
+
dateFrom,
|
|
2493
|
+
dateTo,
|
|
2494
|
+
amountMin,
|
|
2495
|
+
amountMax
|
|
2496
|
+
]
|
|
3035
2497
|
);
|
|
3036
2498
|
useEffect(() => {
|
|
3037
|
-
void
|
|
3038
|
-
}, [
|
|
2499
|
+
void loadRefunds(0, true);
|
|
2500
|
+
}, [loadRefunds]);
|
|
3039
2501
|
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
3040
|
-
const
|
|
3041
|
-
const
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
2502
|
+
const displayAmount = (r) => {
|
|
2503
|
+
const code = (r.currency_code ?? "USD").toUpperCase();
|
|
2504
|
+
return `${code} ${Number(r.amount)}`;
|
|
2505
|
+
};
|
|
2506
|
+
const displayStatus = (r) => {
|
|
2507
|
+
const s2 = r.payment_status ?? "";
|
|
2508
|
+
return s2 !== "" ? s2 : "—";
|
|
2509
|
+
};
|
|
3045
2510
|
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: [
|
|
3046
2511
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
3047
2512
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3048
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "
|
|
3049
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
2513
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refunds" }),
|
|
2514
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Refund records — amount, order, payment status" })
|
|
3050
2515
|
] }),
|
|
3051
|
-
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () =>
|
|
2516
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadRefunds(0, true), children: "Refresh" })
|
|
3052
2517
|
] }),
|
|
3053
|
-
/* @__PURE__ */
|
|
2518
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
3054
2519
|
/* @__PURE__ */ jsx(
|
|
3055
2520
|
Input,
|
|
3056
2521
|
{
|
|
3057
|
-
placeholder: "
|
|
3058
|
-
value:
|
|
3059
|
-
onChange: (
|
|
3060
|
-
className: "md:max-w-
|
|
2522
|
+
placeholder: "Order ID",
|
|
2523
|
+
value: orderIdSearch,
|
|
2524
|
+
onChange: (e) => setOrderIdSearch(e.target.value),
|
|
2525
|
+
className: "md:max-w-[180px]",
|
|
2526
|
+
"aria-label": "Filter by order ID"
|
|
3061
2527
|
}
|
|
3062
2528
|
),
|
|
3063
|
-
/* @__PURE__ */
|
|
3064
|
-
|
|
3065
|
-
"select",
|
|
3066
|
-
{
|
|
3067
|
-
value: createdByFilter,
|
|
3068
|
-
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
3069
|
-
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",
|
|
3070
|
-
children: [
|
|
3071
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
3072
|
-
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
3073
|
-
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
3074
|
-
]
|
|
3075
|
-
}
|
|
3076
|
-
),
|
|
3077
|
-
/* @__PURE__ */ jsxs(
|
|
3078
|
-
"select",
|
|
3079
|
-
{
|
|
3080
|
-
value: statusFilter,
|
|
3081
|
-
onChange: (event) => setStatusFilter(event.target.value),
|
|
3082
|
-
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",
|
|
3083
|
-
children: [
|
|
3084
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
3085
|
-
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
3086
|
-
]
|
|
3087
|
-
}
|
|
3088
|
-
)
|
|
3089
|
-
] })
|
|
3090
|
-
] }),
|
|
3091
|
-
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3092
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3093
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
3094
|
-
Button,
|
|
2529
|
+
/* @__PURE__ */ jsx(
|
|
2530
|
+
Input,
|
|
3095
2531
|
{
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
2532
|
+
placeholder: "Provider",
|
|
2533
|
+
value: providerSearch,
|
|
2534
|
+
onChange: (e) => setProviderSearch(e.target.value),
|
|
2535
|
+
className: "md:max-w-[140px]",
|
|
2536
|
+
"aria-label": "Filter by provider"
|
|
3099
2537
|
}
|
|
3100
|
-
)
|
|
2538
|
+
),
|
|
2539
|
+
/* @__PURE__ */ jsx(
|
|
2540
|
+
Input,
|
|
2541
|
+
{
|
|
2542
|
+
placeholder: "Currency",
|
|
2543
|
+
value: currencySearch,
|
|
2544
|
+
onChange: (e) => setCurrencySearch(e.target.value),
|
|
2545
|
+
className: "md:max-w-[100px]",
|
|
2546
|
+
"aria-label": "Filter by currency"
|
|
2547
|
+
}
|
|
2548
|
+
),
|
|
2549
|
+
/* @__PURE__ */ jsxs(
|
|
2550
|
+
"select",
|
|
2551
|
+
{
|
|
2552
|
+
value: paymentStatusFilter,
|
|
2553
|
+
onChange: (e) => setPaymentStatusFilter(e.target.value),
|
|
2554
|
+
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-[160px]",
|
|
2555
|
+
"aria-label": "Filter by payment status",
|
|
2556
|
+
children: [
|
|
2557
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
|
|
2558
|
+
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
2559
|
+
/* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
|
|
2560
|
+
/* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
|
|
2561
|
+
/* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
|
|
2562
|
+
/* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
|
|
2563
|
+
/* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
|
|
2564
|
+
]
|
|
2565
|
+
}
|
|
2566
|
+
),
|
|
2567
|
+
/* @__PURE__ */ jsx(
|
|
2568
|
+
Input,
|
|
2569
|
+
{
|
|
2570
|
+
type: "date",
|
|
2571
|
+
placeholder: "From",
|
|
2572
|
+
value: dateFrom,
|
|
2573
|
+
onChange: (e) => setDateFrom(e.target.value),
|
|
2574
|
+
className: "md:max-w-[140px]",
|
|
2575
|
+
"aria-label": "Date from"
|
|
2576
|
+
}
|
|
2577
|
+
),
|
|
2578
|
+
/* @__PURE__ */ jsx(
|
|
2579
|
+
Input,
|
|
2580
|
+
{
|
|
2581
|
+
type: "date",
|
|
2582
|
+
placeholder: "To",
|
|
2583
|
+
value: dateTo,
|
|
2584
|
+
onChange: (e) => setDateTo(e.target.value),
|
|
2585
|
+
className: "md:max-w-[140px]",
|
|
2586
|
+
"aria-label": "Date to"
|
|
2587
|
+
}
|
|
2588
|
+
),
|
|
2589
|
+
/* @__PURE__ */ jsx(
|
|
2590
|
+
Input,
|
|
2591
|
+
{
|
|
2592
|
+
placeholder: "Amount min",
|
|
2593
|
+
value: amountMin,
|
|
2594
|
+
onChange: (e) => setAmountMin(e.target.value),
|
|
2595
|
+
type: "number",
|
|
2596
|
+
min: 0,
|
|
2597
|
+
className: "md:max-w-[100px]",
|
|
2598
|
+
"aria-label": "Refund amount minimum"
|
|
2599
|
+
}
|
|
2600
|
+
),
|
|
2601
|
+
/* @__PURE__ */ jsx(
|
|
2602
|
+
Input,
|
|
2603
|
+
{
|
|
2604
|
+
placeholder: "Amount max",
|
|
2605
|
+
value: amountMax,
|
|
2606
|
+
onChange: (e) => setAmountMax(e.target.value),
|
|
2607
|
+
type: "number",
|
|
2608
|
+
min: 0,
|
|
2609
|
+
className: "md:max-w-[100px]",
|
|
2610
|
+
"aria-label": "Refund amount maximum"
|
|
2611
|
+
}
|
|
2612
|
+
)
|
|
2613
|
+
] }) }),
|
|
2614
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
2615
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
2616
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadRefunds(0, true), children: "Try again" }) })
|
|
3101
2617
|
] }) : null,
|
|
3102
|
-
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading
|
|
3103
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No
|
|
3104
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "
|
|
3105
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "overflow-
|
|
2618
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading refunds…" }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
2619
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No refunds yet" }),
|
|
2620
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Refund records will appear here." })
|
|
2621
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "w-full table-fixed divide-y divide-ui-border-base", style: { minWidth: 0 }, children: [
|
|
3106
2622
|
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
3107
|
-
/* @__PURE__ */ jsx("th", { className: "px-
|
|
3108
|
-
/* @__PURE__ */ jsx("th", { className: "px-
|
|
3109
|
-
/* @__PURE__ */ jsx("th", { className: "px-
|
|
3110
|
-
/* @__PURE__ */ jsx("th", { className: "px-
|
|
3111
|
-
/* @__PURE__ */ jsx("th", { className: "px-
|
|
3112
|
-
/* @__PURE__ */ jsx("th", { className: "px-
|
|
2623
|
+
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund ID" }),
|
|
2624
|
+
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
2625
|
+
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Payment ID" }),
|
|
2626
|
+
/* @__PURE__ */ jsx("th", { className: "w-[8%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
|
|
2627
|
+
/* @__PURE__ */ jsx("th", { className: "w-[6%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Currency" }),
|
|
2628
|
+
/* @__PURE__ */ jsx("th", { className: "w-[10%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
|
|
2629
|
+
/* @__PURE__ */ jsx("th", { className: "w-[10%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Payment Status" }),
|
|
2630
|
+
/* @__PURE__ */ jsx("th", { className: "w-[14%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Note" }),
|
|
2631
|
+
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
2632
|
+
/* @__PURE__ */ jsx("th", { className: "w-[8%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
3113
2633
|
] }) }),
|
|
3114
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((
|
|
2634
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
|
|
3115
2635
|
"tr",
|
|
3116
2636
|
{
|
|
3117
|
-
className: "hover:bg-ui-bg-subtle/60
|
|
3118
|
-
onClick: () => navigate(`/
|
|
2637
|
+
className: "cursor-pointer hover:bg-ui-bg-subtle/60",
|
|
2638
|
+
onClick: () => navigate(`/refunds/${r.refund_id}`),
|
|
3119
2639
|
children: [
|
|
3120
|
-
/* @__PURE__ */ jsx("td", { className: "px-
|
|
3121
|
-
/* @__PURE__ */ jsx("td", { className: "px-
|
|
3122
|
-
/* @__PURE__ */ jsx("td", { className: "px-
|
|
2640
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-base", title: r.refund_id, children: r.refund_id }),
|
|
2641
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-medium text-ui-fg-base", title: r.order_id ?? void 0, children: r.order_id ?? "—" }),
|
|
2642
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-subtle", title: r.payment_id, children: r.payment_id }),
|
|
2643
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
|
|
2644
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
|
|
2645
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.provider_id || void 0, children: r.provider_id || "—" }),
|
|
2646
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
|
|
3123
2647
|
Badge,
|
|
3124
2648
|
{
|
|
3125
2649
|
size: "2xsmall",
|
|
3126
|
-
className: `uppercase ${getStatusBadgeClass$
|
|
3127
|
-
children:
|
|
2650
|
+
className: `uppercase ${getStatusBadgeClass$6(displayStatus(r))}`,
|
|
2651
|
+
children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
|
|
3128
2652
|
}
|
|
3129
2653
|
) }),
|
|
3130
|
-
/* @__PURE__ */ jsx("td", { className: "px-
|
|
3131
|
-
|
|
3132
|
-
if (amount == null || amount === void 0) {
|
|
3133
|
-
return "—";
|
|
3134
|
-
}
|
|
3135
|
-
const displayAmount = Number(amount) / 100;
|
|
3136
|
-
const currency = swap.currency_code || "$";
|
|
3137
|
-
const sign = displayAmount >= 0 ? "+" : "";
|
|
3138
|
-
return `${sign}${currency}${displayAmount.toFixed(2)}`;
|
|
3139
|
-
})() }),
|
|
3140
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(swap.created_at).toLocaleDateString("en-US", {
|
|
3141
|
-
year: "numeric",
|
|
2654
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
|
|
2655
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle text-xs", children: new Date(r.created_at).toLocaleDateString("en-US", {
|
|
3142
2656
|
month: "short",
|
|
3143
2657
|
day: "numeric",
|
|
3144
2658
|
hour: "numeric",
|
|
3145
2659
|
minute: "2-digit",
|
|
3146
2660
|
hour12: true
|
|
3147
2661
|
}) }),
|
|
3148
|
-
/* @__PURE__ */ jsx("td", { className: "px-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
e
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
2662
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
2663
|
+
/* @__PURE__ */ jsx(
|
|
2664
|
+
Button,
|
|
2665
|
+
{
|
|
2666
|
+
variant: "transparent",
|
|
2667
|
+
size: "small",
|
|
2668
|
+
onClick: (e) => {
|
|
2669
|
+
e.stopPropagation();
|
|
2670
|
+
navigate(`/refunds/${r.refund_id}`);
|
|
2671
|
+
},
|
|
2672
|
+
children: "Details"
|
|
2673
|
+
}
|
|
2674
|
+
),
|
|
2675
|
+
r.order_id ? /* @__PURE__ */ jsx(
|
|
2676
|
+
Button,
|
|
2677
|
+
{
|
|
2678
|
+
variant: "transparent",
|
|
2679
|
+
size: "small",
|
|
2680
|
+
onClick: (e) => {
|
|
2681
|
+
e.stopPropagation();
|
|
2682
|
+
navigate(`/orders/${r.order_id}`);
|
|
2683
|
+
},
|
|
2684
|
+
children: "Order"
|
|
2685
|
+
}
|
|
2686
|
+
) : null
|
|
2687
|
+
] }) })
|
|
3160
2688
|
]
|
|
3161
2689
|
},
|
|
3162
|
-
|
|
2690
|
+
r.refund_id
|
|
3163
2691
|
)) })
|
|
3164
2692
|
] }) }),
|
|
3165
2693
|
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
@@ -3167,326 +2695,266 @@ const SwapsPage = () => {
|
|
|
3167
2695
|
{
|
|
3168
2696
|
variant: "secondary",
|
|
3169
2697
|
isLoading: isFetchingMore,
|
|
3170
|
-
onClick: () =>
|
|
2698
|
+
onClick: () => loadRefunds(offset, false),
|
|
3171
2699
|
children: "Load more"
|
|
3172
2700
|
}
|
|
3173
2701
|
) }) : null
|
|
3174
2702
|
] }) });
|
|
3175
2703
|
};
|
|
3176
|
-
const config$
|
|
3177
|
-
label: "
|
|
3178
|
-
icon:
|
|
2704
|
+
const config$7 = defineRouteConfig({
|
|
2705
|
+
label: "Refunds",
|
|
2706
|
+
icon: Receipt
|
|
3179
2707
|
});
|
|
3180
|
-
const
|
|
3181
|
-
const
|
|
3182
|
-
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3183
|
-
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
3184
|
-
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
3185
|
-
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
3186
|
-
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3187
|
-
};
|
|
3188
|
-
const PaymentDetailPage = () => {
|
|
3189
|
-
const navigate = useNavigate();
|
|
3190
|
-
const params = useParams();
|
|
3191
|
-
const id = params?.id?.trim();
|
|
3192
|
-
const [detail, setDetail] = useState(null);
|
|
3193
|
-
const [loading, setLoading] = useState(!!id);
|
|
3194
|
-
const [error, setError] = useState(null);
|
|
2708
|
+
const useDebounce$1 = (value, delay) => {
|
|
2709
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
3195
2710
|
useEffect(() => {
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
let cancelled = false;
|
|
3201
|
-
setLoading(true);
|
|
3202
|
-
setError(null);
|
|
3203
|
-
fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
|
|
3204
|
-
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
3205
|
-
return res.json();
|
|
3206
|
-
}).then((data) => {
|
|
3207
|
-
if (!cancelled) setDetail(data);
|
|
3208
|
-
}).catch((e) => {
|
|
3209
|
-
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
3210
|
-
}).finally(() => {
|
|
3211
|
-
if (!cancelled) setLoading(false);
|
|
3212
|
-
});
|
|
3213
|
-
return () => {
|
|
3214
|
-
cancelled = true;
|
|
3215
|
-
};
|
|
3216
|
-
}, [id]);
|
|
3217
|
-
const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
|
|
3218
|
-
const sessionStatusRaw = detail?.session_status ?? "—";
|
|
3219
|
-
const paymentStatusRaw = detail?.payment_id != null ? detail?.payment_status ?? "—" : "—";
|
|
3220
|
-
const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
|
|
3221
|
-
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 p-6", children: [
|
|
3222
|
-
/* @__PURE__ */ jsx("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3223
|
-
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
|
|
3224
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
|
|
3225
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
|
|
3226
|
-
] }) }),
|
|
3227
|
-
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3228
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3229
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
|
|
3230
|
-
] }) : loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading…" }) }) : detail ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
3231
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6 flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3232
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3233
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
|
|
3234
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
|
|
3235
|
-
Button,
|
|
3236
|
-
{
|
|
3237
|
-
variant: "transparent",
|
|
3238
|
-
size: "small",
|
|
3239
|
-
onClick: () => navigate(`/orders/${detail.order_id}`),
|
|
3240
|
-
children: detail.order_id
|
|
3241
|
-
}
|
|
3242
|
-
) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
|
|
3243
|
-
] }),
|
|
3244
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3245
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
3246
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
|
|
3247
|
-
] }),
|
|
3248
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3249
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
3250
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
|
|
3251
|
-
] }),
|
|
3252
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3253
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
3254
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
3255
|
-
Badge,
|
|
3256
|
-
{
|
|
3257
|
-
size: "2xsmall",
|
|
3258
|
-
className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
|
|
3259
|
-
children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
|
|
3260
|
-
}
|
|
3261
|
-
) })
|
|
3262
|
-
] }),
|
|
3263
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3264
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
|
|
3265
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
|
|
3266
|
-
] }),
|
|
3267
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3268
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
|
|
3269
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
|
|
3270
|
-
] }),
|
|
3271
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3272
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
|
|
3273
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
|
|
3274
|
-
] }),
|
|
3275
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3276
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
|
|
3277
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
|
|
3278
|
-
year: "numeric",
|
|
3279
|
-
month: "short",
|
|
3280
|
-
day: "numeric",
|
|
3281
|
-
hour: "numeric",
|
|
3282
|
-
minute: "2-digit",
|
|
3283
|
-
hour12: true
|
|
3284
|
-
}) })
|
|
3285
|
-
] })
|
|
3286
|
-
] }) }),
|
|
3287
|
-
Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3288
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
|
|
3289
|
-
/* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.data, null, 2) })
|
|
3290
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No provider data for this session." }) })
|
|
3291
|
-
] }) : null
|
|
3292
|
-
] }) });
|
|
2711
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
2712
|
+
return () => clearTimeout(handler);
|
|
2713
|
+
}, [value, delay]);
|
|
2714
|
+
return debouncedValue;
|
|
3293
2715
|
};
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
if (
|
|
3303
|
-
|
|
2716
|
+
const getStatusBadgeClass$5 = (status) => {
|
|
2717
|
+
const statusLower = status.toLowerCase();
|
|
2718
|
+
if (statusLower === "requested") {
|
|
2719
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2720
|
+
}
|
|
2721
|
+
if (statusLower === "received") {
|
|
2722
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2723
|
+
}
|
|
2724
|
+
if (statusLower === "requires_action") {
|
|
2725
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2726
|
+
}
|
|
2727
|
+
if (statusLower === "completed") {
|
|
2728
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2729
|
+
}
|
|
2730
|
+
if (statusLower === "canceled") {
|
|
2731
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
2732
|
+
}
|
|
3304
2733
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3305
2734
|
};
|
|
3306
|
-
const
|
|
3307
|
-
return String(value);
|
|
3308
|
-
};
|
|
3309
|
-
const RefundDetailPage = () => {
|
|
2735
|
+
const ReturnsPage = () => {
|
|
3310
2736
|
const navigate = useNavigate();
|
|
3311
|
-
const
|
|
3312
|
-
const
|
|
3313
|
-
const [
|
|
3314
|
-
const [
|
|
2737
|
+
const [items, setItems] = useState([]);
|
|
2738
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
2739
|
+
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
2740
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
2741
|
+
const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
|
|
2742
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
2743
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
3315
2744
|
const [error, setError] = useState(null);
|
|
3316
|
-
const [
|
|
2745
|
+
const [offset, setOffset] = useState(0);
|
|
2746
|
+
const [count, setCount] = useState(0);
|
|
2747
|
+
const limit = 50;
|
|
2748
|
+
const loadReturns = useCallback(
|
|
2749
|
+
async (nextOffset, replace = false) => {
|
|
2750
|
+
try {
|
|
2751
|
+
if (replace) {
|
|
2752
|
+
setIsLoading(true);
|
|
2753
|
+
} else {
|
|
2754
|
+
setIsFetchingMore(true);
|
|
2755
|
+
}
|
|
2756
|
+
setError(null);
|
|
2757
|
+
const params = new URLSearchParams();
|
|
2758
|
+
params.set("limit", String(limit));
|
|
2759
|
+
params.set("offset", String(nextOffset));
|
|
2760
|
+
if (statusFilter !== "all") {
|
|
2761
|
+
params.set("status", statusFilter);
|
|
2762
|
+
}
|
|
2763
|
+
if (debouncedSearchQuery.trim()) {
|
|
2764
|
+
params.set("q", debouncedSearchQuery.trim());
|
|
2765
|
+
}
|
|
2766
|
+
if (createdByFilter !== "all") {
|
|
2767
|
+
params.set("created_by", createdByFilter);
|
|
2768
|
+
}
|
|
2769
|
+
params.set("order", "created_at");
|
|
2770
|
+
const response = await fetch(
|
|
2771
|
+
`/admin/return?${params.toString()}`,
|
|
2772
|
+
{ credentials: "include" }
|
|
2773
|
+
);
|
|
2774
|
+
if (!response.ok) {
|
|
2775
|
+
const message = await response.text();
|
|
2776
|
+
throw new Error(message || "Unable to load return orders");
|
|
2777
|
+
}
|
|
2778
|
+
const payload = await response.json();
|
|
2779
|
+
setCount(payload.count ?? 0);
|
|
2780
|
+
setOffset(nextOffset + (payload.returns?.length ?? 0));
|
|
2781
|
+
setItems(
|
|
2782
|
+
(prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
|
|
2783
|
+
);
|
|
2784
|
+
} catch (loadError) {
|
|
2785
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
2786
|
+
setError(message);
|
|
2787
|
+
} finally {
|
|
2788
|
+
setIsLoading(false);
|
|
2789
|
+
setIsFetchingMore(false);
|
|
2790
|
+
}
|
|
2791
|
+
},
|
|
2792
|
+
[statusFilter, createdByFilter, debouncedSearchQuery]
|
|
2793
|
+
);
|
|
3317
2794
|
useEffect(() => {
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
/* @__PURE__ */
|
|
3345
|
-
|
|
3346
|
-
|
|
2795
|
+
void loadReturns(0, true);
|
|
2796
|
+
}, [statusFilter, createdByFilter, debouncedSearchQuery, loadReturns]);
|
|
2797
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
2798
|
+
const availableStatuses = useMemo(() => {
|
|
2799
|
+
const statuses = /* @__PURE__ */ new Set();
|
|
2800
|
+
items.forEach((item) => statuses.add(item.status));
|
|
2801
|
+
return Array.from(statuses).sort();
|
|
2802
|
+
}, [items]);
|
|
2803
|
+
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: [
|
|
2804
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2805
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2806
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Orders" }),
|
|
2807
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
|
|
2808
|
+
] }),
|
|
2809
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
|
|
2810
|
+
] }),
|
|
2811
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2812
|
+
/* @__PURE__ */ jsx(
|
|
2813
|
+
Input,
|
|
2814
|
+
{
|
|
2815
|
+
placeholder: "Search by return ID, order ID, or customer email",
|
|
2816
|
+
value: searchQuery,
|
|
2817
|
+
onChange: (event) => setSearchQuery(event.target.value),
|
|
2818
|
+
className: "md:max-w-sm"
|
|
2819
|
+
}
|
|
2820
|
+
),
|
|
2821
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
2822
|
+
/* @__PURE__ */ jsxs(
|
|
2823
|
+
"select",
|
|
2824
|
+
{
|
|
2825
|
+
value: createdByFilter,
|
|
2826
|
+
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
2827
|
+
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",
|
|
2828
|
+
children: [
|
|
2829
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
2830
|
+
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
2831
|
+
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
2832
|
+
]
|
|
2833
|
+
}
|
|
2834
|
+
),
|
|
2835
|
+
/* @__PURE__ */ jsxs(
|
|
2836
|
+
"select",
|
|
2837
|
+
{
|
|
2838
|
+
value: statusFilter,
|
|
2839
|
+
onChange: (event) => setStatusFilter(event.target.value),
|
|
2840
|
+
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",
|
|
2841
|
+
children: [
|
|
2842
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
2843
|
+
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
2844
|
+
]
|
|
2845
|
+
}
|
|
2846
|
+
)
|
|
2847
|
+
] })
|
|
2848
|
+
] }),
|
|
3347
2849
|
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3348
2850
|
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3349
|
-
/* @__PURE__ */ jsx(
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
/* @__PURE__ */ jsx(
|
|
3379
|
-
/* @__PURE__ */ jsx(
|
|
3380
|
-
|
|
3381
|
-
] })
|
|
3382
|
-
] }),
|
|
3383
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3384
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
|
|
3385
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3386
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3387
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
|
|
3388
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
|
|
3389
|
-
] }),
|
|
3390
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3391
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
|
|
3392
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
|
|
3393
|
-
] }),
|
|
3394
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3395
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
|
|
3396
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
|
|
3397
|
-
] }),
|
|
3398
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3399
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
3400
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
|
|
3401
|
-
] }),
|
|
3402
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3403
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
3404
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
2851
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
2852
|
+
Button,
|
|
2853
|
+
{
|
|
2854
|
+
variant: "secondary",
|
|
2855
|
+
onClick: () => loadReturns(0, true),
|
|
2856
|
+
children: "Try again"
|
|
2857
|
+
}
|
|
2858
|
+
) })
|
|
2859
|
+
] }) : null,
|
|
2860
|
+
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: [
|
|
2861
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
|
|
2862
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
|
|
2863
|
+
] }) : /* @__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: [
|
|
2864
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2865
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
|
|
2866
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
2867
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
2868
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
2869
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
|
|
2870
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
2871
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
2872
|
+
] }) }),
|
|
2873
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
|
|
2874
|
+
"tr",
|
|
2875
|
+
{
|
|
2876
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
2877
|
+
onClick: () => navigate(`/returns/${returnOrder.id}`),
|
|
2878
|
+
children: [
|
|
2879
|
+
/* @__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 }) }) }),
|
|
2880
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
|
|
2881
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
2882
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3405
2883
|
Badge,
|
|
3406
2884
|
{
|
|
3407
2885
|
size: "2xsmall",
|
|
3408
|
-
className: `uppercase ${getStatusBadgeClass$
|
|
3409
|
-
children:
|
|
3410
|
-
}
|
|
3411
|
-
) })
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
2886
|
+
className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
|
|
2887
|
+
children: returnOrder.status.replace(/_/g, " ")
|
|
2888
|
+
}
|
|
2889
|
+
) }),
|
|
2890
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
2891
|
+
const calc = returnOrder.refund;
|
|
2892
|
+
if (calc?.is_processed && calc.final_refund_amount != null) {
|
|
2893
|
+
return formatRefundCurrency(
|
|
2894
|
+
calc.final_refund_amount,
|
|
2895
|
+
calc.currency_code || returnOrder.currency_code
|
|
2896
|
+
);
|
|
2897
|
+
}
|
|
2898
|
+
if (calc) {
|
|
2899
|
+
return "Pending";
|
|
2900
|
+
}
|
|
2901
|
+
if (returnOrder.refund_amount == null) {
|
|
2902
|
+
return "—";
|
|
2903
|
+
}
|
|
2904
|
+
return formatRefundCurrency(
|
|
2905
|
+
Number(returnOrder.refund_amount),
|
|
2906
|
+
returnOrder.currency_code
|
|
2907
|
+
);
|
|
2908
|
+
})() }),
|
|
2909
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
|
|
2910
|
+
year: "numeric",
|
|
2911
|
+
month: "short",
|
|
2912
|
+
day: "numeric",
|
|
2913
|
+
hour: "numeric",
|
|
2914
|
+
minute: "2-digit",
|
|
2915
|
+
hour12: true
|
|
2916
|
+
}) }),
|
|
2917
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3438
2918
|
Button,
|
|
3439
2919
|
{
|
|
3440
2920
|
variant: "transparent",
|
|
3441
2921
|
size: "small",
|
|
3442
|
-
onClick: () =>
|
|
3443
|
-
|
|
2922
|
+
onClick: (e) => {
|
|
2923
|
+
e.stopPropagation();
|
|
2924
|
+
navigate(`/app/orders/${returnOrder.order_id}`);
|
|
2925
|
+
},
|
|
2926
|
+
children: "Go to order"
|
|
3444
2927
|
}
|
|
3445
2928
|
) })
|
|
3446
|
-
]
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
|
|
3461
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
|
|
3462
|
-
] }) : null
|
|
3463
|
-
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
|
|
3464
|
-
] }),
|
|
3465
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3466
|
-
/* @__PURE__ */ jsxs(
|
|
3467
|
-
"button",
|
|
3468
|
-
{
|
|
3469
|
-
type: "button",
|
|
3470
|
-
className: "flex w-full items-center justify-between text-left",
|
|
3471
|
-
onClick: () => setGatewayExpanded((prev) => !prev),
|
|
3472
|
-
"aria-expanded": gatewayExpanded,
|
|
3473
|
-
"aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
|
|
3474
|
-
children: [
|
|
3475
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
|
|
3476
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
|
|
3477
|
-
]
|
|
3478
|
-
}
|
|
3479
|
-
),
|
|
3480
|
-
gatewayExpanded && /* @__PURE__ */ jsx("div", { className: "mt-4", children: hasGatewayData ? /* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.payment.payment_data, null, 2) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No gateway payload for this payment." }) })
|
|
3481
|
-
] })
|
|
3482
|
-
] }) : null
|
|
2929
|
+
]
|
|
2930
|
+
},
|
|
2931
|
+
returnOrder.id
|
|
2932
|
+
)) })
|
|
2933
|
+
] }) }),
|
|
2934
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
2935
|
+
Button,
|
|
2936
|
+
{
|
|
2937
|
+
variant: "secondary",
|
|
2938
|
+
isLoading: isFetchingMore,
|
|
2939
|
+
onClick: () => loadReturns(offset, false),
|
|
2940
|
+
children: "Load more"
|
|
2941
|
+
}
|
|
2942
|
+
) }) : null
|
|
3483
2943
|
] }) });
|
|
3484
2944
|
};
|
|
3485
|
-
const config$
|
|
3486
|
-
label: "
|
|
3487
|
-
icon:
|
|
2945
|
+
const config$6 = defineRouteConfig({
|
|
2946
|
+
label: "Return Orders",
|
|
2947
|
+
icon: ArrowPath
|
|
3488
2948
|
});
|
|
3489
|
-
const
|
|
2949
|
+
const useDebounce = (value, delay) => {
|
|
2950
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2951
|
+
useEffect(() => {
|
|
2952
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
2953
|
+
return () => clearTimeout(handler);
|
|
2954
|
+
}, [value, delay]);
|
|
2955
|
+
return debouncedValue;
|
|
2956
|
+
};
|
|
2957
|
+
const getStatusBadgeClass$4 = (status) => {
|
|
3490
2958
|
const statusLower = status.toLowerCase();
|
|
3491
2959
|
if (statusLower === "requested") {
|
|
3492
2960
|
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
@@ -3497,12 +2965,6 @@ const getStatusBadgeClass$1 = (status) => {
|
|
|
3497
2965
|
if (statusLower === "rejected") {
|
|
3498
2966
|
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
3499
2967
|
}
|
|
3500
|
-
if (statusLower === "received") {
|
|
3501
|
-
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
3502
|
-
}
|
|
3503
|
-
if (statusLower === "refunded") {
|
|
3504
|
-
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3505
|
-
}
|
|
3506
2968
|
if (statusLower === "completed") {
|
|
3507
2969
|
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3508
2970
|
}
|
|
@@ -3511,1005 +2973,1541 @@ const getStatusBadgeClass$1 = (status) => {
|
|
|
3511
2973
|
}
|
|
3512
2974
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3513
2975
|
};
|
|
3514
|
-
const
|
|
2976
|
+
const SwapsPage = () => {
|
|
3515
2977
|
const navigate = useNavigate();
|
|
3516
|
-
const
|
|
3517
|
-
const [
|
|
2978
|
+
const [items, setItems] = useState([]);
|
|
2979
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
2980
|
+
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
2981
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
2982
|
+
const debouncedSearchQuery = useDebounce(searchQuery, 300);
|
|
3518
2983
|
const [isLoading, setIsLoading] = useState(true);
|
|
3519
|
-
const [
|
|
2984
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
3520
2985
|
const [error, setError] = useState(null);
|
|
3521
|
-
const [
|
|
3522
|
-
const [
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
return;
|
|
3527
|
-
}
|
|
3528
|
-
const loadReturn = async () => {
|
|
2986
|
+
const [offset, setOffset] = useState(0);
|
|
2987
|
+
const [count, setCount] = useState(0);
|
|
2988
|
+
const limit = 50;
|
|
2989
|
+
const loadSwaps = useCallback(
|
|
2990
|
+
async (nextOffset, replace = false) => {
|
|
3529
2991
|
try {
|
|
3530
|
-
|
|
2992
|
+
if (replace) {
|
|
2993
|
+
setIsLoading(true);
|
|
2994
|
+
} else {
|
|
2995
|
+
setIsFetchingMore(true);
|
|
2996
|
+
}
|
|
3531
2997
|
setError(null);
|
|
3532
|
-
const
|
|
3533
|
-
|
|
3534
|
-
|
|
2998
|
+
const params = new URLSearchParams();
|
|
2999
|
+
params.set("limit", String(limit));
|
|
3000
|
+
params.set("offset", String(nextOffset));
|
|
3001
|
+
if (statusFilter !== "all") {
|
|
3002
|
+
params.set("status", statusFilter);
|
|
3003
|
+
}
|
|
3004
|
+
if (debouncedSearchQuery.trim()) {
|
|
3005
|
+
params.set("order_id", debouncedSearchQuery.trim());
|
|
3006
|
+
}
|
|
3007
|
+
if (createdByFilter !== "all") {
|
|
3008
|
+
params.set("created_by", createdByFilter);
|
|
3009
|
+
}
|
|
3010
|
+
const response = await fetch(
|
|
3011
|
+
`/admin/swaps?${params.toString()}`,
|
|
3012
|
+
{ credentials: "include" }
|
|
3013
|
+
);
|
|
3535
3014
|
if (!response.ok) {
|
|
3536
3015
|
const message = await response.text();
|
|
3537
|
-
throw new Error(message || "Unable to load
|
|
3016
|
+
throw new Error(message || "Unable to load swaps");
|
|
3538
3017
|
}
|
|
3539
3018
|
const payload = await response.json();
|
|
3540
|
-
|
|
3019
|
+
setCount(payload.count ?? 0);
|
|
3020
|
+
setOffset(nextOffset + (payload.swaps?.length ?? 0));
|
|
3021
|
+
setItems(
|
|
3022
|
+
(prev) => replace ? payload.swaps ?? [] : [...prev, ...payload.swaps ?? []]
|
|
3023
|
+
);
|
|
3541
3024
|
} catch (loadError) {
|
|
3542
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load
|
|
3025
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
|
|
3543
3026
|
setError(message);
|
|
3544
3027
|
} finally {
|
|
3545
3028
|
setIsLoading(false);
|
|
3029
|
+
setIsFetchingMore(false);
|
|
3546
3030
|
}
|
|
3547
|
-
}
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
},
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
})
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
credentials: "include"
|
|
3576
|
-
});
|
|
3577
|
-
if (detailResponse.ok) {
|
|
3578
|
-
const detailPayload = await detailResponse.json();
|
|
3579
|
-
setReturnOrder(detailPayload.return);
|
|
3580
|
-
}
|
|
3581
|
-
} catch (updateErr) {
|
|
3582
|
-
const message = updateErr instanceof Error ? updateErr.message : "Unable to reject return";
|
|
3583
|
-
setUpdateError(message);
|
|
3584
|
-
} finally {
|
|
3585
|
-
setIsRejecting(false);
|
|
3586
|
-
}
|
|
3587
|
-
};
|
|
3588
|
-
if (isLoading) {
|
|
3589
|
-
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..." }) }) }) });
|
|
3590
|
-
}
|
|
3591
|
-
if (error || !returnOrder) {
|
|
3592
|
-
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: [
|
|
3593
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Return order not found" }),
|
|
3594
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/returns"), children: "Back to list" }) })
|
|
3595
|
-
] }) }) });
|
|
3596
|
-
}
|
|
3597
|
-
const statusHistory = returnOrder.metadata?.status_history || [];
|
|
3598
|
-
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: [
|
|
3599
|
-
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
3600
|
-
/* @__PURE__ */ jsxs(
|
|
3601
|
-
Button,
|
|
3602
|
-
{
|
|
3603
|
-
variant: "transparent",
|
|
3604
|
-
size: "small",
|
|
3605
|
-
onClick: () => navigate("/returns"),
|
|
3606
|
-
className: "w-fit",
|
|
3607
|
-
children: [
|
|
3608
|
-
/* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2" }),
|
|
3609
|
-
"Back to list"
|
|
3610
|
-
]
|
|
3031
|
+
},
|
|
3032
|
+
[statusFilter, createdByFilter, debouncedSearchQuery]
|
|
3033
|
+
);
|
|
3034
|
+
useEffect(() => {
|
|
3035
|
+
void loadSwaps(0, true);
|
|
3036
|
+
}, [statusFilter, createdByFilter, debouncedSearchQuery, loadSwaps]);
|
|
3037
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
3038
|
+
const availableStatuses = useMemo(() => {
|
|
3039
|
+
const statuses = /* @__PURE__ */ new Set();
|
|
3040
|
+
items.forEach((item) => statuses.add(item.status));
|
|
3041
|
+
return Array.from(statuses).sort();
|
|
3042
|
+
}, [items]);
|
|
3043
|
+
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: [
|
|
3044
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
3045
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3046
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Exchanges" }),
|
|
3047
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer exchange requests" })
|
|
3048
|
+
] }),
|
|
3049
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadSwaps(0, true), children: "Refresh" })
|
|
3050
|
+
] }),
|
|
3051
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
3052
|
+
/* @__PURE__ */ jsx(
|
|
3053
|
+
Input,
|
|
3054
|
+
{
|
|
3055
|
+
placeholder: "Search by swap ID or order ID",
|
|
3056
|
+
value: searchQuery,
|
|
3057
|
+
onChange: (event) => setSearchQuery(event.target.value),
|
|
3058
|
+
className: "md:max-w-sm"
|
|
3611
3059
|
}
|
|
3612
3060
|
),
|
|
3613
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
3614
|
-
/* @__PURE__ */ jsxs(
|
|
3615
|
-
|
|
3616
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: returnOrder.id })
|
|
3617
|
-
] }),
|
|
3618
|
-
/* @__PURE__ */ jsx(
|
|
3619
|
-
Badge,
|
|
3061
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
3062
|
+
/* @__PURE__ */ jsxs(
|
|
3063
|
+
"select",
|
|
3620
3064
|
{
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3065
|
+
value: createdByFilter,
|
|
3066
|
+
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
3067
|
+
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",
|
|
3068
|
+
children: [
|
|
3069
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
3070
|
+
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
3071
|
+
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
3072
|
+
]
|
|
3073
|
+
}
|
|
3074
|
+
),
|
|
3075
|
+
/* @__PURE__ */ jsxs(
|
|
3076
|
+
"select",
|
|
3077
|
+
{
|
|
3078
|
+
value: statusFilter,
|
|
3079
|
+
onChange: (event) => setStatusFilter(event.target.value),
|
|
3080
|
+
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",
|
|
3081
|
+
children: [
|
|
3082
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
3083
|
+
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
3084
|
+
]
|
|
3624
3085
|
}
|
|
3625
3086
|
)
|
|
3626
3087
|
] })
|
|
3627
3088
|
] }),
|
|
3628
|
-
|
|
3629
|
-
/* @__PURE__ */ jsx("
|
|
3089
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3090
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3091
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
3630
3092
|
Button,
|
|
3631
3093
|
{
|
|
3632
|
-
variant: "
|
|
3633
|
-
onClick:
|
|
3634
|
-
|
|
3635
|
-
isLoading: isRejecting,
|
|
3636
|
-
children: "Reject (Cancel) Return"
|
|
3094
|
+
variant: "secondary",
|
|
3095
|
+
onClick: () => loadSwaps(0, true),
|
|
3096
|
+
children: "Try again"
|
|
3637
3097
|
}
|
|
3638
|
-
) })
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
/* @__PURE__ */
|
|
3645
|
-
/* @__PURE__ */
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
/* @__PURE__ */ jsx("
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
},
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
/* @__PURE__ */ jsx(
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
/* @__PURE__ */ jsx(
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3098
|
+
) })
|
|
3099
|
+
] }) : null,
|
|
3100
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading swaps..." }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
3101
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No exchanges yet" }),
|
|
3102
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Exchange requests created by customers will appear here." })
|
|
3103
|
+
] }) : /* @__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: [
|
|
3104
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
3105
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Exchange ID" }),
|
|
3106
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
3107
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
3108
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Difference Due" }),
|
|
3109
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
3110
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
3111
|
+
] }) }),
|
|
3112
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((swap) => /* @__PURE__ */ jsxs(
|
|
3113
|
+
"tr",
|
|
3114
|
+
{
|
|
3115
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
3116
|
+
onClick: () => navigate(`/swaps/${swap.id}`),
|
|
3117
|
+
children: [
|
|
3118
|
+
/* @__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: swap.id }) }) }),
|
|
3119
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: swap.order_id }),
|
|
3120
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3121
|
+
Badge,
|
|
3122
|
+
{
|
|
3123
|
+
size: "2xsmall",
|
|
3124
|
+
className: `uppercase ${getStatusBadgeClass$4(swap.status)}`,
|
|
3125
|
+
children: swap.status.replace(/_/g, " ")
|
|
3126
|
+
}
|
|
3127
|
+
) }),
|
|
3128
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
3129
|
+
const amount = swap.difference_due;
|
|
3130
|
+
if (amount == null || amount === void 0) {
|
|
3131
|
+
return "—";
|
|
3132
|
+
}
|
|
3133
|
+
const displayAmount = Number(amount) / 100;
|
|
3134
|
+
const currency = swap.currency_code || "$";
|
|
3135
|
+
const sign = displayAmount >= 0 ? "+" : "";
|
|
3136
|
+
return `${sign}${currency}${displayAmount.toFixed(2)}`;
|
|
3137
|
+
})() }),
|
|
3138
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(swap.created_at).toLocaleDateString("en-US", {
|
|
3139
|
+
year: "numeric",
|
|
3140
|
+
month: "short",
|
|
3141
|
+
day: "numeric",
|
|
3142
|
+
hour: "numeric",
|
|
3143
|
+
minute: "2-digit",
|
|
3144
|
+
hour12: true
|
|
3145
|
+
}) }),
|
|
3146
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3147
|
+
Button,
|
|
3148
|
+
{
|
|
3149
|
+
variant: "transparent",
|
|
3150
|
+
size: "small",
|
|
3151
|
+
onClick: (e) => {
|
|
3152
|
+
e.stopPropagation();
|
|
3153
|
+
navigate(`/app/orders/${swap.order_id}`);
|
|
3154
|
+
},
|
|
3155
|
+
children: "Go to order"
|
|
3156
|
+
}
|
|
3157
|
+
) })
|
|
3158
|
+
]
|
|
3159
|
+
},
|
|
3160
|
+
swap.id
|
|
3161
|
+
)) })
|
|
3162
|
+
] }) }),
|
|
3163
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
3164
|
+
Button,
|
|
3165
|
+
{
|
|
3166
|
+
variant: "secondary",
|
|
3167
|
+
isLoading: isFetchingMore,
|
|
3168
|
+
onClick: () => loadSwaps(offset, false),
|
|
3169
|
+
children: "Load more"
|
|
3170
|
+
}
|
|
3171
|
+
) }) : null
|
|
3172
|
+
] }) });
|
|
3173
|
+
};
|
|
3174
|
+
const config$5 = defineRouteConfig({
|
|
3175
|
+
label: "Exchanges",
|
|
3176
|
+
icon: ArrowPath
|
|
3177
|
+
});
|
|
3178
|
+
const MASKED_VALUE = "••••••••••••";
|
|
3179
|
+
const SENSITIVE_KEY_PATTERNS = [
|
|
3180
|
+
/password|passwd|passphrase/i,
|
|
3181
|
+
/secret/i,
|
|
3182
|
+
/token/i,
|
|
3183
|
+
/api_?key$/i,
|
|
3184
|
+
/private_?key/i,
|
|
3185
|
+
/access_?key/i,
|
|
3186
|
+
/(^|_)hash(ed)?($|_)/i,
|
|
3187
|
+
/(^|_)salt$/i,
|
|
3188
|
+
/^cvv$|^cvc$|security_code/i,
|
|
3189
|
+
/card_?number/i,
|
|
3190
|
+
/account_?number/i,
|
|
3191
|
+
/credential/i,
|
|
3192
|
+
/authorization/i,
|
|
3193
|
+
/recovery_?code/i,
|
|
3194
|
+
/(^|_)otp($|_)/i,
|
|
3195
|
+
/verification_?code/i,
|
|
3196
|
+
/^code_hash$/i,
|
|
3197
|
+
/webhook_?signature/i
|
|
3198
|
+
];
|
|
3199
|
+
const TABLE_SENSITIVE_KEYS = {
|
|
3200
|
+
otp_verification: /* @__PURE__ */ new Set(["code", "value"]),
|
|
3201
|
+
auth_verification: /* @__PURE__ */ new Set(["code", "value"]),
|
|
3202
|
+
auth_mfa_factor: /* @__PURE__ */ new Set(["value", "config"])
|
|
3203
|
+
};
|
|
3204
|
+
const SAFE_KEYS = /* @__PURE__ */ new Set([
|
|
3205
|
+
"token_type",
|
|
3206
|
+
"redacted",
|
|
3207
|
+
"api_key_id",
|
|
3208
|
+
"token_id",
|
|
3209
|
+
"notification_token_id"
|
|
3210
|
+
]);
|
|
3211
|
+
function isSensitiveKey(key) {
|
|
3212
|
+
const normalized = key.trim().toLowerCase();
|
|
3213
|
+
if (SAFE_KEYS.has(normalized)) return false;
|
|
3214
|
+
return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
3215
|
+
}
|
|
3216
|
+
const FULLY_SECRET_TABLES = /* @__PURE__ */ new Set(["auth_mfa_recovery_code", "auth_password_reset_token"]);
|
|
3217
|
+
const ALWAYS_VISIBLE_KEYS = /* @__PURE__ */ new Set(["id", "created_at", "updated_at", "deleted_at", "expires_at", "used_at"]);
|
|
3218
|
+
function maskValue(value, ctx, depth) {
|
|
3219
|
+
if (Array.isArray(value)) return value.map((item) => maskValue(item, ctx, depth + 1));
|
|
3220
|
+
if (value !== null && typeof value === "object") {
|
|
3221
|
+
const out = {};
|
|
3222
|
+
for (const [key, inner] of Object.entries(value)) {
|
|
3223
|
+
const topLevel = depth === 0;
|
|
3224
|
+
const secret = inner !== null && inner !== void 0 && inner !== "" && (isSensitiveKey(key) || topLevel && ctx.tableKeys?.has(key.toLowerCase()) === true || topLevel && ctx.maskAll && !ALWAYS_VISIBLE_KEYS.has(key) && !key.endsWith("_id"));
|
|
3225
|
+
if (secret) {
|
|
3226
|
+
ctx.count += 1;
|
|
3227
|
+
out[key] = MASKED_VALUE;
|
|
3228
|
+
} else {
|
|
3229
|
+
out[key] = maskValue(inner, ctx, depth + 1);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
return out;
|
|
3233
|
+
}
|
|
3234
|
+
return value;
|
|
3235
|
+
}
|
|
3236
|
+
function maskSensitiveData(data, tableName) {
|
|
3237
|
+
const ctx = {
|
|
3238
|
+
count: 0,
|
|
3239
|
+
maskAll: tableName ? FULLY_SECRET_TABLES.has(tableName) : false,
|
|
3240
|
+
tableKeys: tableName ? TABLE_SENSITIVE_KEYS[tableName] : void 0
|
|
3241
|
+
};
|
|
3242
|
+
const value = maskValue(data, ctx, 0);
|
|
3243
|
+
return { value, maskedCount: ctx.count };
|
|
3244
|
+
}
|
|
3245
|
+
const AUTO_EXPAND_DEPTH = 1;
|
|
3246
|
+
const LONG_STRING = 200;
|
|
3247
|
+
const JsonViewer = ({ data }) => {
|
|
3248
|
+
const [generation, setGeneration] = useState(0);
|
|
3249
|
+
const [expandAll, setExpandAll] = useState(null);
|
|
3250
|
+
const setAll = (value) => {
|
|
3251
|
+
setExpandAll(value);
|
|
3252
|
+
setGeneration((g) => g + 1);
|
|
3253
|
+
};
|
|
3254
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3255
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
3256
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => setAll(true), children: "Expand all" }),
|
|
3257
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => setAll(false), children: "Collapse all" })
|
|
3719
3258
|
] }),
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
/* @__PURE__ */
|
|
3736
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Payment method" }),
|
|
3737
|
-
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.order_payment?.label || "—" })
|
|
3738
|
-
] }),
|
|
3739
|
-
returnOrder.order.total && /* @__PURE__ */ jsxs("div", { children: [
|
|
3740
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
3741
|
-
/* @__PURE__ */ jsxs(Text, { className: "font-medium", children: [
|
|
3742
|
-
returnOrder.order.currency_code || "$",
|
|
3743
|
-
(Number(returnOrder.order.total) / 100).toFixed(2)
|
|
3744
|
-
] })
|
|
3745
|
-
] })
|
|
3259
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-[560px] overflow-auto rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 font-mono text-xs leading-5", children: /* @__PURE__ */ jsx(JsonNode, { value: data, depth: 0, forceExpand: expandAll }, generation) })
|
|
3260
|
+
] });
|
|
3261
|
+
};
|
|
3262
|
+
const JsonNode = ({ name, value, depth, forceExpand }) => {
|
|
3263
|
+
const isContainer = value !== null && typeof value === "object";
|
|
3264
|
+
const [open, setOpen] = useState(forceExpand ?? depth < AUTO_EXPAND_DEPTH);
|
|
3265
|
+
const label = name !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-ui-fg-subtle", children: [
|
|
3266
|
+
name,
|
|
3267
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: ": " })
|
|
3268
|
+
] }) : null;
|
|
3269
|
+
if (!isContainer) {
|
|
3270
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start", style: { paddingLeft: depth ? 16 : 0 }, children: [
|
|
3271
|
+
/* @__PURE__ */ jsx("span", { className: "w-4 shrink-0" }),
|
|
3272
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 break-words [overflow-wrap:anywhere]", children: [
|
|
3273
|
+
label,
|
|
3274
|
+
/* @__PURE__ */ jsx(Primitive, { value })
|
|
3746
3275
|
] })
|
|
3747
|
-
] })
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3276
|
+
] });
|
|
3277
|
+
}
|
|
3278
|
+
const entries = Array.isArray(value) ? value.map((v, i) => [String(i), v]) : Object.entries(value);
|
|
3279
|
+
const [openBracket, closeBracket] = Array.isArray(value) ? ["[", "]"] : ["{", "}"];
|
|
3280
|
+
const summary = Array.isArray(value) ? `${entries.length} items` : `${entries.length} keys`;
|
|
3281
|
+
return /* @__PURE__ */ jsxs("div", { style: { paddingLeft: depth ? 16 : 0 }, children: [
|
|
3282
|
+
/* @__PURE__ */ jsxs(
|
|
3283
|
+
"button",
|
|
3284
|
+
{
|
|
3285
|
+
type: "button",
|
|
3286
|
+
onClick: () => setOpen((o) => !o),
|
|
3287
|
+
className: "flex items-start text-left hover:bg-ui-bg-base-hover",
|
|
3288
|
+
"aria-expanded": open,
|
|
3289
|
+
children: [
|
|
3290
|
+
/* @__PURE__ */ jsx("span", { className: "flex w-4 shrink-0 items-center pt-0.5 text-ui-fg-muted", children: entries.length ? open ? /* @__PURE__ */ jsx(ChevronDownMini, {}) : /* @__PURE__ */ jsx(ChevronRightMini, {}) : null }),
|
|
3291
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
3292
|
+
label,
|
|
3293
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: openBracket }),
|
|
3294
|
+
!open || entries.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3295
|
+
entries.length ? /* @__PURE__ */ jsx("span", { className: "px-1 italic text-ui-fg-muted", children: summary }) : null,
|
|
3296
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: closeBracket })
|
|
3297
|
+
] }) : null
|
|
3298
|
+
] })
|
|
3299
|
+
]
|
|
3300
|
+
}
|
|
3301
|
+
),
|
|
3302
|
+
open && entries.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3303
|
+
entries.map(([key, child]) => /* @__PURE__ */ jsx(JsonNode, { name: key, value: child, depth: depth + 1, forceExpand }, key)),
|
|
3304
|
+
/* @__PURE__ */ jsx("div", { style: { paddingLeft: 16 }, className: "text-ui-fg-muted", children: closeBracket })
|
|
3305
|
+
] }) : null
|
|
3306
|
+
] });
|
|
3307
|
+
};
|
|
3308
|
+
const Primitive = ({ value }) => {
|
|
3309
|
+
const [showFull, setShowFull] = useState(false);
|
|
3310
|
+
if (value === MASKED_VALUE) {
|
|
3311
|
+
return /* @__PURE__ */ jsx("span", { className: "rounded bg-ui-tag-orange-bg px-1 text-ui-tag-orange-text", title: "Hidden for security", children: MASKED_VALUE });
|
|
3312
|
+
}
|
|
3313
|
+
if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "null" });
|
|
3314
|
+
if (typeof value === "boolean") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-purple-text", children: String(value) });
|
|
3315
|
+
if (typeof value === "number") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-blue-text", children: value });
|
|
3316
|
+
const text = String(value);
|
|
3317
|
+
const truncated = !showFull && text.length > LONG_STRING;
|
|
3318
|
+
return /* @__PURE__ */ jsxs("span", { className: clx("text-ui-tag-green-text"), children: [
|
|
3319
|
+
'"',
|
|
3320
|
+
truncated ? `${text.slice(0, LONG_STRING)}…` : text,
|
|
3321
|
+
'"',
|
|
3322
|
+
text.length > LONG_STRING ? /* @__PURE__ */ jsx(
|
|
3323
|
+
"button",
|
|
3324
|
+
{
|
|
3325
|
+
type: "button",
|
|
3326
|
+
onClick: () => setShowFull((s2) => !s2),
|
|
3327
|
+
className: "ml-1 font-sans text-ui-fg-interactive hover:underline",
|
|
3328
|
+
children: showFull ? "show less" : `show all (${text.length} chars)`
|
|
3329
|
+
}
|
|
3330
|
+
) : null
|
|
3331
|
+
] });
|
|
3332
|
+
};
|
|
3333
|
+
const GUIDANCE = {
|
|
3334
|
+
orders: {
|
|
3335
|
+
headline: "Order data affects customers, payments and reports.",
|
|
3336
|
+
recreate: "Orders can’t be recreated identically from the admin. If this deletion was not intended, ask a developer to restore it from a database backup using the snapshot on this page.",
|
|
3337
|
+
adminSection: { label: "Go to Orders", path: "/orders" }
|
|
3338
|
+
},
|
|
3339
|
+
carts: {
|
|
3340
|
+
headline: "Carts are usually cleaned up automatically.",
|
|
3341
|
+
recreate: "No action is normally needed. Customers can simply add items to a new cart."
|
|
3342
|
+
},
|
|
3343
|
+
customers: {
|
|
3344
|
+
headline: "Customer data may be needed for orders, support and compliance.",
|
|
3345
|
+
recreate: "If it was deleted by mistake, recreate it from Customers using the values shown above. A recreated customer gets a new ID and must reset their password.",
|
|
3346
|
+
adminSection: { label: "Go to Customers", path: "/customers" }
|
|
3347
|
+
},
|
|
3348
|
+
catalog: {
|
|
3349
|
+
headline: "Catalog changes affect what customers can see and buy.",
|
|
3350
|
+
recreate: "If it was deleted by mistake, recreate it from Products using the values shown above. It will get a new ID.",
|
|
3351
|
+
adminSection: { label: "Go to Products", path: "/products" }
|
|
3352
|
+
},
|
|
3353
|
+
pricing: {
|
|
3354
|
+
headline: "Pricing and promotions affect what customers pay.",
|
|
3355
|
+
recreate: "If it was deleted by mistake, recreate it from Promotions or Price Lists using the values shown above.",
|
|
3356
|
+
adminSection: { label: "Go to Promotions", path: "/promotions" }
|
|
3357
|
+
},
|
|
3358
|
+
payments: {
|
|
3359
|
+
headline: "Payment records are financial data.",
|
|
3360
|
+
recreate: "Do not recreate payment records by hand—this can make balances inconsistent. If this deletion was not expected, escalate to a developer or your finance team."
|
|
3361
|
+
},
|
|
3362
|
+
fulfillment: {
|
|
3363
|
+
headline: "Shipping and fulfillment settings affect checkout and delivery.",
|
|
3364
|
+
recreate: "If it was deleted by mistake, recreate it from Settings → Locations & Shipping using the values shown above.",
|
|
3365
|
+
adminSection: { label: "Go to Settings", path: "/settings" }
|
|
3366
|
+
},
|
|
3367
|
+
inventory: {
|
|
3368
|
+
headline: "Inventory changes can affect stock levels and availability.",
|
|
3369
|
+
recreate: "If it was deleted by mistake, recreate it from Inventory using the values shown above and re-check stock quantities.",
|
|
3370
|
+
adminSection: { label: "Go to Inventory", path: "/inventory" }
|
|
3371
|
+
},
|
|
3372
|
+
wallet: {
|
|
3373
|
+
headline: "Wallet and credit records are financial data.",
|
|
3374
|
+
recreate: "Do not recreate balances by hand. If this deletion was not expected, escalate to a developer or your finance team so balances can be verified."
|
|
3375
|
+
},
|
|
3376
|
+
access: {
|
|
3377
|
+
headline: "Access records control who can sign in.",
|
|
3378
|
+
recreate: "Secrets such as passwords and keys can’t be restored. Re-invite the user or create a new API key if access is still needed.",
|
|
3379
|
+
adminSection: { label: "Go to Settings", path: "/settings" }
|
|
3380
|
+
},
|
|
3381
|
+
store: {
|
|
3382
|
+
headline: "Store settings affect regions, currencies and taxes.",
|
|
3383
|
+
recreate: "If it was deleted by mistake, recreate it from Settings using the values shown above.",
|
|
3384
|
+
adminSection: { label: "Go to Settings", path: "/settings" }
|
|
3385
|
+
},
|
|
3386
|
+
engagement: {
|
|
3387
|
+
headline: "Customer-generated content.",
|
|
3388
|
+
recreate: "These usually can’t be recreated on the customer’s behalf. Keep the snapshot on this page if you need a record of it."
|
|
3389
|
+
},
|
|
3390
|
+
notifications: {
|
|
3391
|
+
headline: "Notification records are usually cleaned up automatically.",
|
|
3392
|
+
recreate: "No action is normally needed."
|
|
3393
|
+
},
|
|
3394
|
+
system: {
|
|
3395
|
+
headline: "Internal system data, usually removed automatically by the platform.",
|
|
3396
|
+
recreate: "No action is normally needed. If you suspect a problem, share this page with a developer."
|
|
3397
|
+
}
|
|
3398
|
+
};
|
|
3399
|
+
function getNextSteps(category) {
|
|
3400
|
+
return GUIDANCE[category];
|
|
3401
|
+
}
|
|
3402
|
+
const RELATED_LINKS = [
|
|
3403
|
+
{ key: "order_id", label: "Order", path: (id) => `/orders/${id}`, selfTables: ["order"] },
|
|
3404
|
+
{ key: "customer_id", label: "Customer", path: (id) => `/customers/${id}`, selfTables: ["customer"] },
|
|
3405
|
+
{ key: "product_id", label: "Product", path: (id) => `/products/${id}`, selfTables: ["product"] }
|
|
3406
|
+
];
|
|
3407
|
+
function getRelatedLinks(tableName, oldData) {
|
|
3408
|
+
if (!oldData) return [];
|
|
3409
|
+
return RELATED_LINKS.flatMap((link) => {
|
|
3410
|
+
const id = oldData[link.key];
|
|
3411
|
+
if (link.selfTables.includes(tableName) || typeof id !== "string" || !id.trim()) return [];
|
|
3412
|
+
return [{ label: link.label, id, path: link.path(id) }];
|
|
3413
|
+
});
|
|
3414
|
+
}
|
|
3415
|
+
const fullName = (row) => {
|
|
3416
|
+
const parts = [row.first_name, row.last_name].filter(
|
|
3417
|
+
(part) => typeof part === "string" && part.trim() !== ""
|
|
3418
|
+
);
|
|
3419
|
+
return parts.length ? parts.join(" ") : void 0;
|
|
3420
|
+
};
|
|
3421
|
+
const addressLine = (row) => {
|
|
3422
|
+
const parts = [row.address_1, row.address_2, row.city, row.province, row.postal_code, row.country_code].filter((part) => typeof part === "string" && part.trim() !== "").map((part) => part.trim());
|
|
3423
|
+
return parts.length ? parts.join(", ") : void 0;
|
|
3424
|
+
};
|
|
3425
|
+
const NAME = { key: "name", label: "Name", derive: fullName };
|
|
3426
|
+
const ADDRESS = { key: "address", label: "Address", derive: addressLine };
|
|
3427
|
+
const CREATED = { key: "created_at", label: "Created", kind: "date" };
|
|
3428
|
+
const ENTITY_FIELDS = {
|
|
3429
|
+
order: [
|
|
3430
|
+
{ key: "display_id", label: "Order number" },
|
|
3431
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3432
|
+
{ key: "email", label: "Customer email" },
|
|
3433
|
+
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
3434
|
+
{ key: "currency_code", label: "Currency" },
|
|
3435
|
+
{ key: "region_id", label: "Region ID", kind: "id" },
|
|
3436
|
+
{ key: "sales_channel_id", label: "Sales channel ID", kind: "id" },
|
|
3437
|
+
{ key: "canceled_at", label: "Canceled", kind: "date" },
|
|
3438
|
+
CREATED
|
|
3439
|
+
],
|
|
3440
|
+
order_line_item: [
|
|
3441
|
+
{ key: "title", label: "Item" },
|
|
3442
|
+
{ key: "variant_title", label: "Variant" },
|
|
3443
|
+
{ key: "variant_sku", label: "SKU" },
|
|
3444
|
+
{ key: "unit_price", label: "Unit price", kind: "money" },
|
|
3445
|
+
{ key: "product_id", label: "Product ID", kind: "id" },
|
|
3446
|
+
{ key: "variant_id", label: "Variant ID", kind: "id" },
|
|
3447
|
+
CREATED
|
|
3448
|
+
],
|
|
3449
|
+
cart_line_item: [
|
|
3450
|
+
{ key: "title", label: "Item" },
|
|
3451
|
+
{ key: "variant_sku", label: "SKU" },
|
|
3452
|
+
{ key: "quantity", label: "Quantity", kind: "number" },
|
|
3453
|
+
{ key: "unit_price", label: "Unit price", kind: "money" },
|
|
3454
|
+
{ key: "cart_id", label: "Cart ID", kind: "id" },
|
|
3455
|
+
{ key: "variant_id", label: "Variant ID", kind: "id" },
|
|
3456
|
+
CREATED
|
|
3457
|
+
],
|
|
3458
|
+
cart: [
|
|
3459
|
+
{ key: "email", label: "Email" },
|
|
3460
|
+
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
3461
|
+
{ key: "currency_code", label: "Currency" },
|
|
3462
|
+
{ key: "region_id", label: "Region ID", kind: "id" },
|
|
3463
|
+
{ key: "completed_at", label: "Completed", kind: "date" },
|
|
3464
|
+
CREATED
|
|
3465
|
+
],
|
|
3466
|
+
customer: [
|
|
3467
|
+
NAME,
|
|
3468
|
+
{ key: "email", label: "Email" },
|
|
3469
|
+
{ key: "phone", label: "Phone" },
|
|
3470
|
+
{ key: "company_name", label: "Company" },
|
|
3471
|
+
{ key: "has_account", label: "Registered account", kind: "boolean" },
|
|
3472
|
+
CREATED
|
|
3473
|
+
],
|
|
3474
|
+
customer_address: [
|
|
3475
|
+
{ key: "address_name", label: "Label" },
|
|
3476
|
+
NAME,
|
|
3477
|
+
ADDRESS,
|
|
3478
|
+
{ key: "phone", label: "Phone" },
|
|
3479
|
+
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
3480
|
+
{ key: "is_default_shipping", label: "Default shipping", kind: "boolean" },
|
|
3481
|
+
CREATED
|
|
3482
|
+
],
|
|
3483
|
+
order_address: [NAME, ADDRESS, { key: "phone", label: "Phone" }, CREATED],
|
|
3484
|
+
cart_address: [NAME, ADDRESS, { key: "phone", label: "Phone" }, CREATED],
|
|
3485
|
+
product: [
|
|
3486
|
+
{ key: "title", label: "Title" },
|
|
3487
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3488
|
+
{ key: "handle", label: "Handle" },
|
|
3489
|
+
{ key: "subtitle", label: "Subtitle" },
|
|
3490
|
+
{ key: "collection_id", label: "Collection ID", kind: "id" },
|
|
3491
|
+
{ key: "is_giftcard", label: "Gift card", kind: "boolean" },
|
|
3492
|
+
CREATED
|
|
3493
|
+
],
|
|
3494
|
+
product_variant: [
|
|
3495
|
+
{ key: "title", label: "Title" },
|
|
3496
|
+
{ key: "sku", label: "SKU" },
|
|
3497
|
+
{ key: "barcode", label: "Barcode" },
|
|
3498
|
+
{ key: "product_id", label: "Product ID", kind: "id" },
|
|
3499
|
+
{ key: "manage_inventory", label: "Manages inventory", kind: "boolean" },
|
|
3500
|
+
CREATED
|
|
3501
|
+
],
|
|
3502
|
+
product_category: [
|
|
3503
|
+
{ key: "name", label: "Name" },
|
|
3504
|
+
{ key: "handle", label: "Handle" },
|
|
3505
|
+
{ key: "is_active", label: "Active", kind: "boolean" },
|
|
3506
|
+
{ key: "parent_category_id", label: "Parent category ID", kind: "id" },
|
|
3507
|
+
CREATED
|
|
3508
|
+
],
|
|
3509
|
+
product_collection: [{ key: "title", label: "Title" }, { key: "handle", label: "Handle" }, CREATED],
|
|
3510
|
+
payment: [
|
|
3511
|
+
{ key: "amount", label: "Amount", kind: "money" },
|
|
3512
|
+
{ key: "currency_code", label: "Currency" },
|
|
3513
|
+
{ key: "provider_id", label: "Provider" },
|
|
3514
|
+
{ key: "captured_at", label: "Captured", kind: "date" },
|
|
3515
|
+
{ key: "canceled_at", label: "Canceled", kind: "date" },
|
|
3516
|
+
{ key: "payment_collection_id", label: "Payment collection ID", kind: "id" },
|
|
3517
|
+
CREATED
|
|
3518
|
+
],
|
|
3519
|
+
payment_session: [
|
|
3520
|
+
{ key: "amount", label: "Amount", kind: "money" },
|
|
3521
|
+
{ key: "currency_code", label: "Currency" },
|
|
3522
|
+
{ key: "provider_id", label: "Provider" },
|
|
3523
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3524
|
+
{ key: "payment_collection_id", label: "Payment collection ID", kind: "id" },
|
|
3525
|
+
CREATED
|
|
3526
|
+
],
|
|
3527
|
+
payment_collection: [
|
|
3528
|
+
{ key: "amount", label: "Amount", kind: "money" },
|
|
3529
|
+
{ key: "currency_code", label: "Currency" },
|
|
3530
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3531
|
+
CREATED
|
|
3532
|
+
],
|
|
3533
|
+
refund: [
|
|
3534
|
+
{ key: "amount", label: "Amount", kind: "money" },
|
|
3535
|
+
{ key: "payment_id", label: "Payment ID", kind: "id" },
|
|
3536
|
+
{ key: "refund_reason_id", label: "Refund reason ID", kind: "id" },
|
|
3537
|
+
{ key: "note", label: "Note" },
|
|
3538
|
+
{ key: "created_by", label: "Created by" },
|
|
3539
|
+
CREATED
|
|
3540
|
+
],
|
|
3541
|
+
return: [
|
|
3542
|
+
{ key: "display_id", label: "Return number" },
|
|
3543
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3544
|
+
{ key: "order_id", label: "Order ID", kind: "id" },
|
|
3545
|
+
{ key: "refund_amount", label: "Refund amount", kind: "money" },
|
|
3546
|
+
{ key: "received_at", label: "Received", kind: "date" },
|
|
3547
|
+
CREATED
|
|
3548
|
+
],
|
|
3549
|
+
payment_detail: [
|
|
3550
|
+
{ key: "type", label: "Method type" },
|
|
3551
|
+
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
3552
|
+
{ key: "is_default", label: "Default method", kind: "boolean" },
|
|
3553
|
+
CREATED
|
|
3554
|
+
],
|
|
3555
|
+
user: [NAME, { key: "email", label: "Email" }, CREATED],
|
|
3556
|
+
invite: [
|
|
3557
|
+
{ key: "email", label: "Email" },
|
|
3558
|
+
{ key: "accepted", label: "Accepted", kind: "boolean" },
|
|
3559
|
+
{ key: "expires_at", label: "Expires", kind: "date" },
|
|
3560
|
+
CREATED
|
|
3561
|
+
],
|
|
3562
|
+
api_key: [
|
|
3563
|
+
{ key: "title", label: "Title" },
|
|
3564
|
+
{ key: "type", label: "Type" },
|
|
3565
|
+
{ key: "redacted", label: "Key (redacted)" },
|
|
3566
|
+
{ key: "revoked_at", label: "Revoked", kind: "date" },
|
|
3567
|
+
CREATED
|
|
3568
|
+
],
|
|
3569
|
+
promotion: [
|
|
3570
|
+
{ key: "code", label: "Promotion code" },
|
|
3571
|
+
{ key: "type", label: "Type" },
|
|
3572
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3573
|
+
{ key: "is_automatic", label: "Automatic", kind: "boolean" },
|
|
3574
|
+
CREATED
|
|
3575
|
+
],
|
|
3576
|
+
fulfillment: [
|
|
3577
|
+
{ key: "provider_id", label: "Provider" },
|
|
3578
|
+
{ key: "location_id", label: "Location ID", kind: "id" },
|
|
3579
|
+
{ key: "shipped_at", label: "Shipped", kind: "date" },
|
|
3580
|
+
{ key: "delivered_at", label: "Delivered", kind: "date" },
|
|
3581
|
+
{ key: "canceled_at", label: "Canceled", kind: "date" },
|
|
3582
|
+
CREATED
|
|
3583
|
+
],
|
|
3584
|
+
inventory_item: [
|
|
3585
|
+
{ key: "sku", label: "SKU" },
|
|
3586
|
+
{ key: "title", label: "Title" },
|
|
3587
|
+
{ key: "requires_shipping", label: "Requires shipping", kind: "boolean" },
|
|
3588
|
+
CREATED
|
|
3589
|
+
],
|
|
3590
|
+
inventory_level: [
|
|
3591
|
+
{ key: "inventory_item_id", label: "Inventory item ID", kind: "id" },
|
|
3592
|
+
{ key: "location_id", label: "Location ID", kind: "id" },
|
|
3593
|
+
{ key: "stocked_quantity", label: "Stocked", kind: "number" },
|
|
3594
|
+
{ key: "reserved_quantity", label: "Reserved", kind: "number" },
|
|
3595
|
+
CREATED
|
|
3596
|
+
],
|
|
3597
|
+
review: [
|
|
3598
|
+
{ key: "title", label: "Title" },
|
|
3599
|
+
{ key: "rating", label: "Rating", kind: "number" },
|
|
3600
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3601
|
+
{ key: "product_id", label: "Product ID", kind: "id" },
|
|
3602
|
+
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
3603
|
+
CREATED
|
|
3604
|
+
]
|
|
3766
3605
|
};
|
|
3767
|
-
const
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
}
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
/^code_hash$/i,
|
|
3790
|
-
/webhook_?signature/i
|
|
3606
|
+
const GENERIC_FIELDS = [
|
|
3607
|
+
{ key: "display_id", label: "Number" },
|
|
3608
|
+
{ key: "title", label: "Title" },
|
|
3609
|
+
{ key: "name", label: "Name" },
|
|
3610
|
+
NAME,
|
|
3611
|
+
{ key: "email", label: "Email" },
|
|
3612
|
+
{ key: "phone", label: "Phone" },
|
|
3613
|
+
{ key: "handle", label: "Handle" },
|
|
3614
|
+
{ key: "sku", label: "SKU" },
|
|
3615
|
+
{ key: "code", label: "Code" },
|
|
3616
|
+
{ key: "status", label: "Status", kind: "status" },
|
|
3617
|
+
{ key: "type", label: "Type" },
|
|
3618
|
+
{ key: "amount", label: "Amount", kind: "money" },
|
|
3619
|
+
{ key: "quantity", label: "Quantity", kind: "number" },
|
|
3620
|
+
{ key: "currency_code", label: "Currency" },
|
|
3621
|
+
{ key: "order_id", label: "Order ID", kind: "id" },
|
|
3622
|
+
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
3623
|
+
{ key: "product_id", label: "Product ID", kind: "id" },
|
|
3624
|
+
{ key: "payment_id", label: "Payment ID", kind: "id" },
|
|
3625
|
+
{ key: "provider_id", label: "Provider" },
|
|
3626
|
+
CREATED,
|
|
3627
|
+
{ key: "updated_at", label: "Last updated", kind: "date" }
|
|
3791
3628
|
];
|
|
3792
|
-
const
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
"
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
const ALWAYS_VISIBLE_KEYS = /* @__PURE__ */ new Set(["id", "created_at", "updated_at", "deleted_at", "expires_at", "used_at"]);
|
|
3811
|
-
function maskValue(value, ctx, depth) {
|
|
3812
|
-
if (Array.isArray(value)) return value.map((item) => maskValue(item, ctx, depth + 1));
|
|
3813
|
-
if (value !== null && typeof value === "object") {
|
|
3814
|
-
const out = {};
|
|
3815
|
-
for (const [key, inner] of Object.entries(value)) {
|
|
3816
|
-
const topLevel = depth === 0;
|
|
3817
|
-
const secret = inner !== null && inner !== void 0 && inner !== "" && (isSensitiveKey(key) || topLevel && ctx.tableKeys?.has(key.toLowerCase()) === true || topLevel && ctx.maskAll && !ALWAYS_VISIBLE_KEYS.has(key) && !key.endsWith("_id"));
|
|
3818
|
-
if (secret) {
|
|
3819
|
-
ctx.count += 1;
|
|
3820
|
-
out[key] = MASKED_VALUE;
|
|
3821
|
-
} else {
|
|
3822
|
-
out[key] = maskValue(inner, ctx, depth + 1);
|
|
3823
|
-
}
|
|
3629
|
+
const MAX_GENERIC_FIELDS = 8;
|
|
3630
|
+
function amountOf(value) {
|
|
3631
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3632
|
+
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
|
|
3633
|
+
if (value !== null && typeof value === "object" && "value" in value) {
|
|
3634
|
+
return amountOf(value.value);
|
|
3635
|
+
}
|
|
3636
|
+
return null;
|
|
3637
|
+
}
|
|
3638
|
+
function formatValue(raw, kind, row) {
|
|
3639
|
+
if (raw === null || raw === void 0 || raw === "") return null;
|
|
3640
|
+
if (raw === MASKED_VALUE) return { value: MASKED_VALUE, kind: "masked" };
|
|
3641
|
+
switch (kind) {
|
|
3642
|
+
case "money": {
|
|
3643
|
+
const amount = amountOf(raw);
|
|
3644
|
+
if (amount === null) return null;
|
|
3645
|
+
const currency = typeof row.currency_code === "string" ? row.currency_code : null;
|
|
3646
|
+
return { value: formatMoney(amount, currency), kind };
|
|
3824
3647
|
}
|
|
3825
|
-
|
|
3648
|
+
case "date":
|
|
3649
|
+
return typeof raw === "string" || raw instanceof Date ? { value: formatDate(raw), kind } : null;
|
|
3650
|
+
case "boolean":
|
|
3651
|
+
return { value: raw === true || raw === "true" ? "Yes" : "No", kind };
|
|
3652
|
+
case "number": {
|
|
3653
|
+
const n = amountOf(raw);
|
|
3654
|
+
return n === null ? null : { value: formatNumber(n), kind };
|
|
3655
|
+
}
|
|
3656
|
+
case "status":
|
|
3657
|
+
return { value: String(raw).replace(/_/g, " "), kind };
|
|
3658
|
+
default:
|
|
3659
|
+
if (typeof raw === "object") return null;
|
|
3660
|
+
if (typeof raw === "string" && raw.length > 160) return { value: `${raw.slice(0, 157)}…`, kind };
|
|
3661
|
+
return { value: String(raw), kind };
|
|
3826
3662
|
}
|
|
3827
|
-
return value;
|
|
3828
3663
|
}
|
|
3829
|
-
function
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
const
|
|
3836
|
-
|
|
3664
|
+
function summarizeOldData(tableName, oldData) {
|
|
3665
|
+
if (!oldData) return [];
|
|
3666
|
+
const { value: row } = maskSensitiveData(oldData, tableName);
|
|
3667
|
+
const specific = ENTITY_FIELDS[tableName];
|
|
3668
|
+
const specs = specific ?? GENERIC_FIELDS;
|
|
3669
|
+
const fields = [];
|
|
3670
|
+
const seenLabels = /* @__PURE__ */ new Set();
|
|
3671
|
+
for (const spec of specs) {
|
|
3672
|
+
const raw = spec.derive ? spec.derive(row) : row[spec.key];
|
|
3673
|
+
const formatted = formatValue(raw, spec.kind ?? "text", row);
|
|
3674
|
+
if (!formatted || seenLabels.has(spec.label)) continue;
|
|
3675
|
+
seenLabels.add(spec.label);
|
|
3676
|
+
const value = spec.key === "currency_code" ? formatted.value.toUpperCase() : formatted.value;
|
|
3677
|
+
fields.push({ key: spec.key, label: spec.label, value, kind: formatted.kind });
|
|
3678
|
+
if (!specific && fields.length >= MAX_GENERIC_FIELDS) break;
|
|
3679
|
+
}
|
|
3680
|
+
return fields;
|
|
3837
3681
|
}
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3682
|
+
function readLastListSearch() {
|
|
3683
|
+
try {
|
|
3684
|
+
return window.sessionStorage.getItem(LAST_LIST_URL_KEY) ?? "";
|
|
3685
|
+
} catch {
|
|
3686
|
+
return "";
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
const DeletedRecordDetailPage = () => {
|
|
3690
|
+
const navigate = useNavigate();
|
|
3691
|
+
const location = useLocation();
|
|
3692
|
+
const { id = "" } = useParams();
|
|
3693
|
+
const [state, setState] = useState({ status: "loading" });
|
|
3694
|
+
const [reloadToken, setReloadToken] = useState(0);
|
|
3695
|
+
const cameFromList = location.state?.fromList === true;
|
|
3696
|
+
const goBack = () => {
|
|
3697
|
+
if (cameFromList) navigate(-1);
|
|
3698
|
+
else navigate(`/deleted-records-audit${readLastListSearch()}`);
|
|
3846
3699
|
};
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3700
|
+
useEffect(() => {
|
|
3701
|
+
const controller = new AbortController();
|
|
3702
|
+
setState({ status: "loading" });
|
|
3703
|
+
fetchAuditDetail(id, controller.signal).then((audit) => setState({ status: "ready", audit })).catch((e) => {
|
|
3704
|
+
if (controller.signal.aborted) return;
|
|
3705
|
+
setState({
|
|
3706
|
+
status: "error",
|
|
3707
|
+
message: e instanceof Error ? e.message : "Unknown error",
|
|
3708
|
+
notFound: e instanceof AuditApiError && e.status === 404
|
|
3709
|
+
});
|
|
3710
|
+
});
|
|
3711
|
+
return () => controller.abort();
|
|
3712
|
+
}, [id, reloadToken]);
|
|
3713
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-3 md:p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-4 md:p-6", children: [
|
|
3714
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "transparent", size: "small", onClick: goBack, className: "-ml-2", children: [
|
|
3715
|
+
/* @__PURE__ */ jsx(ArrowLeft, {}),
|
|
3716
|
+
"Back to Deleted Records"
|
|
3717
|
+
] }) }),
|
|
3718
|
+
state.status === "loading" ? /* @__PURE__ */ jsx(DetailSkeleton, {}) : state.status === "error" ? /* @__PURE__ */ jsx(
|
|
3719
|
+
DetailError,
|
|
3720
|
+
{
|
|
3721
|
+
notFound: state.notFound,
|
|
3722
|
+
message: state.message,
|
|
3723
|
+
onRetry: () => setReloadToken((t) => t + 1),
|
|
3724
|
+
onBack: goBack
|
|
3725
|
+
}
|
|
3726
|
+
) : /* @__PURE__ */ jsx(DetailContent, { audit: state.audit })
|
|
3727
|
+
] }) });
|
|
3854
3728
|
};
|
|
3855
|
-
const
|
|
3856
|
-
const
|
|
3857
|
-
const
|
|
3858
|
-
const
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3729
|
+
const DetailContent = ({ audit }) => {
|
|
3730
|
+
const navigate = useNavigate();
|
|
3731
|
+
const entity = getEntityInfo(audit.table_name);
|
|
3732
|
+
const source = describeSource(audit.source);
|
|
3733
|
+
const summary = useMemo(() => summarizeOldData(audit.table_name, audit.old_data), [audit]);
|
|
3734
|
+
const masked = useMemo(() => maskSensitiveData(audit.old_data, audit.table_name), [audit]);
|
|
3735
|
+
const guidance = getNextSteps(entity.category.id);
|
|
3736
|
+
const related = getRelatedLinks(audit.table_name, audit.old_data);
|
|
3737
|
+
const [showRaw, setShowRaw] = useState(false);
|
|
3738
|
+
const copyJson = async () => {
|
|
3739
|
+
try {
|
|
3740
|
+
await navigator.clipboard.writeText(JSON.stringify(masked.value, null, 2));
|
|
3741
|
+
toast.success("Record data copied", {
|
|
3742
|
+
description: masked.maskedCount ? "Sensitive values were left hidden." : void 0
|
|
3743
|
+
});
|
|
3744
|
+
} catch {
|
|
3745
|
+
toast.error("Couldn’t copy to clipboard");
|
|
3746
|
+
}
|
|
3747
|
+
};
|
|
3748
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3749
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
3750
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
3751
|
+
/* @__PURE__ */ jsxs(Badge, { size: "small", color: "red", children: [
|
|
3752
|
+
/* @__PURE__ */ jsx(Trash, {}),
|
|
3753
|
+
"Deleted"
|
|
3754
|
+
] }),
|
|
3755
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: entity.category.label })
|
|
3756
|
+
] }),
|
|
3757
|
+
/* @__PURE__ */ jsxs(Heading, { level: "h1", children: [
|
|
3758
|
+
"Deleted ",
|
|
3759
|
+
entity.label
|
|
3760
|
+
] }),
|
|
3761
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3762
|
+
/* @__PURE__ */ jsx(CopyableId, { value: audit.record_id, emptyLabel: "This record type has no ID column", className: "text-sm" }),
|
|
3763
|
+
/* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
3764
|
+
"Database table: ",
|
|
3765
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: audit.table_name })
|
|
3766
|
+
] })
|
|
3868
3767
|
] })
|
|
3869
|
-
] })
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3768
|
+
] }),
|
|
3769
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-ui-tag-orange-border bg-ui-tag-orange-bg px-4 py-3", children: [
|
|
3770
|
+
/* @__PURE__ */ jsx(InformationCircle, { className: "mt-0.5 shrink-0 text-ui-tag-orange-icon" }),
|
|
3771
|
+
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-tag-orange-text", children: [
|
|
3772
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "This is a historical snapshot" }),
|
|
3773
|
+
" captured immediately before deletion. The record no longer exists in the database, so changes elsewhere in the admin are not reflected here."
|
|
3774
|
+
] })
|
|
3775
|
+
] }),
|
|
3776
|
+
/* @__PURE__ */ jsx(Section, { title: "Deletion information", children: /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: [
|
|
3777
|
+
/* @__PURE__ */ jsx(Field, { label: "Deleted", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
3778
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: formatExactDateTime(audit.occurred_at) }),
|
|
3779
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-ui-fg-muted", children: [
|
|
3780
|
+
/* @__PURE__ */ jsx(ClockSolid, { className: "size-3" }),
|
|
3781
|
+
formatRelativeTime(audit.occurred_at)
|
|
3782
|
+
] })
|
|
3783
|
+
] }) }),
|
|
3784
|
+
/* @__PURE__ */ jsx(Field, { label: "Deleted by", children: audit.deleted_by ? /* @__PURE__ */ jsx("span", { className: "break-all text-sm text-ui-fg-base", children: audit.deleted_by }) : /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-muted", children: "Not recorded" }) }),
|
|
3785
|
+
/* @__PURE__ */ jsx(Field, { label: "Source", children: source.kind === "unknown" ? /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-muted", children: "Unknown" }) : /* @__PURE__ */ jsx(Badge, { size: "small", color: sourceBadgeColor(source.kind), children: source.label }) }),
|
|
3786
|
+
/* @__PURE__ */ jsx(Field, { label: "Action", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Permanently deleted" }) })
|
|
3787
|
+
] }) }),
|
|
3788
|
+
/* @__PURE__ */ jsx(
|
|
3789
|
+
Section,
|
|
3877
3790
|
{
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
className: "
|
|
3881
|
-
"aria-expanded": open,
|
|
3882
|
-
children: [
|
|
3883
|
-
/* @__PURE__ */ jsx("span", { className: "flex w-4 shrink-0 items-center pt-0.5 text-ui-fg-muted", children: entries.length ? open ? /* @__PURE__ */ jsx(ChevronDownMini, {}) : /* @__PURE__ */ jsx(ChevronRightMini, {}) : null }),
|
|
3884
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
3885
|
-
label,
|
|
3886
|
-
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: openBracket }),
|
|
3887
|
-
!open || entries.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3888
|
-
entries.length ? /* @__PURE__ */ jsx("span", { className: "px-1 italic text-ui-fg-muted", children: summary }) : null,
|
|
3889
|
-
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: closeBracket })
|
|
3890
|
-
] }) : null
|
|
3891
|
-
] })
|
|
3892
|
-
]
|
|
3791
|
+
title: "Record summary",
|
|
3792
|
+
description: `Key details of this ${entity.label.toLowerCase()} at the moment it was deleted.`,
|
|
3793
|
+
children: summary.length ? /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: summary.map((field) => /* @__PURE__ */ jsx(Field, { label: field.label, children: field.kind === "id" ? /* @__PURE__ */ jsx(CopyableId, { value: field.value }) : field.kind === "status" ? /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", className: "capitalize", children: field.value }) : field.kind === "masked" ? /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-muted", children: "Hidden for security" }) : /* @__PURE__ */ jsx("span", { className: "break-words text-sm text-ui-fg-base", children: field.value }) }, field.label)) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No key details could be extracted for this record type. See the original record data below." })
|
|
3893
3794
|
}
|
|
3894
3795
|
),
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
/* @__PURE__ */ jsx("div", { style: { paddingLeft: 16 }, className: "text-ui-fg-muted", children: closeBracket })
|
|
3898
|
-
] }) : null
|
|
3899
|
-
] });
|
|
3900
|
-
};
|
|
3901
|
-
const Primitive = ({ value }) => {
|
|
3902
|
-
const [showFull, setShowFull] = useState(false);
|
|
3903
|
-
if (value === MASKED_VALUE) {
|
|
3904
|
-
return /* @__PURE__ */ jsx("span", { className: "rounded bg-ui-tag-orange-bg px-1 text-ui-tag-orange-text", title: "Hidden for security", children: MASKED_VALUE });
|
|
3905
|
-
}
|
|
3906
|
-
if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "null" });
|
|
3907
|
-
if (typeof value === "boolean") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-purple-text", children: String(value) });
|
|
3908
|
-
if (typeof value === "number") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-blue-text", children: value });
|
|
3909
|
-
const text = String(value);
|
|
3910
|
-
const truncated = !showFull && text.length > LONG_STRING;
|
|
3911
|
-
return /* @__PURE__ */ jsxs("span", { className: clx("text-ui-tag-green-text"), children: [
|
|
3912
|
-
'"',
|
|
3913
|
-
truncated ? `${text.slice(0, LONG_STRING)}…` : text,
|
|
3914
|
-
'"',
|
|
3915
|
-
text.length > LONG_STRING ? /* @__PURE__ */ jsx(
|
|
3916
|
-
"button",
|
|
3796
|
+
/* @__PURE__ */ jsx(
|
|
3797
|
+
Section,
|
|
3917
3798
|
{
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3799
|
+
title: "Original record data",
|
|
3800
|
+
description: "The complete data captured before deletion.",
|
|
3801
|
+
actions: showRaw && audit.old_data ? /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: copyJson, children: [
|
|
3802
|
+
/* @__PURE__ */ jsx(SquareTwoStack, {}),
|
|
3803
|
+
"Copy JSON"
|
|
3804
|
+
] }) : null,
|
|
3805
|
+
children: audit.old_data ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
3806
|
+
masked.maskedCount > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3807
|
+
/* @__PURE__ */ jsx(ShieldCheck, { className: "shrink-0 text-ui-fg-muted" }),
|
|
3808
|
+
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
|
|
3809
|
+
masked.maskedCount,
|
|
3810
|
+
" sensitive ",
|
|
3811
|
+
masked.maskedCount === 1 ? "value is" : "values are",
|
|
3812
|
+
" hidden for security (passwords, tokens, card or account numbers)."
|
|
3813
|
+
] })
|
|
3814
|
+
] }) : null,
|
|
3815
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: () => setShowRaw((s2) => !s2), "aria-expanded": showRaw, children: [
|
|
3816
|
+
showRaw ? /* @__PURE__ */ jsx(ChevronDownMini, {}) : /* @__PURE__ */ jsx(ChevronRightMini, {}),
|
|
3817
|
+
showRaw ? "Hide full record" : "View full record"
|
|
3818
|
+
] }) }),
|
|
3819
|
+
showRaw ? /* @__PURE__ */ jsx(JsonViewer, { data: masked.value }) : null
|
|
3820
|
+
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No data was captured for this deletion." })
|
|
3922
3821
|
}
|
|
3923
|
-
)
|
|
3822
|
+
),
|
|
3823
|
+
/* @__PURE__ */ jsx(Section, { title: "What you can do now", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
3824
|
+
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-base", children: [
|
|
3825
|
+
"This record was permanently deleted. ",
|
|
3826
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Automatic restoration is not available" }),
|
|
3827
|
+
" ",
|
|
3828
|
+
"from this screen."
|
|
3829
|
+
] }),
|
|
3830
|
+
/* @__PURE__ */ jsxs("ol", { className: "flex list-decimal flex-col gap-3 pl-5 text-sm text-ui-fg-subtle marker:text-ui-fg-muted", children: [
|
|
3831
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
3832
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Check whether this was expected." }),
|
|
3833
|
+
" ",
|
|
3834
|
+
audit.deleted_by || source.kind !== "unknown" ? "Confirm with the person or system shown above." : `Who deleted it wasn’t recorded—check with your team or integrations active around ${formatExactDateTime(audit.occurred_at)}.`,
|
|
3835
|
+
" ",
|
|
3836
|
+
guidance.headline
|
|
3837
|
+
] }),
|
|
3838
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
3839
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "If it needs to come back:" }),
|
|
3840
|
+
" ",
|
|
3841
|
+
guidance.recreate
|
|
3842
|
+
] }),
|
|
3843
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
3844
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Need the details?" }),
|
|
3845
|
+
" Use “View full record” above to see or copy everything that was stored. Sensitive values stay hidden."
|
|
3846
|
+
] })
|
|
3847
|
+
] }),
|
|
3848
|
+
guidance.adminSection || related.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
3849
|
+
guidance.adminSection ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => navigate(guidance.adminSection.path), children: guidance.adminSection.label }) : null,
|
|
3850
|
+
related.map((link) => /* @__PURE__ */ jsxs(
|
|
3851
|
+
Button,
|
|
3852
|
+
{
|
|
3853
|
+
variant: "transparent",
|
|
3854
|
+
size: "small",
|
|
3855
|
+
onClick: () => navigate(link.path),
|
|
3856
|
+
title: `Opens ${link.label.toLowerCase()} ${link.id} if it still exists`,
|
|
3857
|
+
children: [
|
|
3858
|
+
"Open related ",
|
|
3859
|
+
link.label.toLowerCase(),
|
|
3860
|
+
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
3861
|
+
]
|
|
3862
|
+
},
|
|
3863
|
+
link.path
|
|
3864
|
+
))
|
|
3865
|
+
] }) : null,
|
|
3866
|
+
related.length ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "Related records open only if they haven’t been deleted too." }) : null
|
|
3867
|
+
] }) })
|
|
3924
3868
|
] });
|
|
3925
3869
|
};
|
|
3926
|
-
const
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
},
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
},
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
}
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3870
|
+
const Section = ({
|
|
3871
|
+
title,
|
|
3872
|
+
description,
|
|
3873
|
+
actions,
|
|
3874
|
+
children
|
|
3875
|
+
}) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4 rounded-lg border border-ui-border-base p-5", children: [
|
|
3876
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [
|
|
3877
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
3878
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
|
|
3879
|
+
description ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: description }) : null
|
|
3880
|
+
] }),
|
|
3881
|
+
actions
|
|
3882
|
+
] }),
|
|
3883
|
+
children
|
|
3884
|
+
] });
|
|
3885
|
+
const Field = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
|
|
3886
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: label }),
|
|
3887
|
+
/* @__PURE__ */ jsx("dd", { className: "min-w-0", children })
|
|
3888
|
+
] });
|
|
3889
|
+
const DetailSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "aria-busy": "true", children: [
|
|
3890
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
3891
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" }),
|
|
3892
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-64" }),
|
|
3893
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
|
|
3894
|
+
] }),
|
|
3895
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-14 w-full" }),
|
|
3896
|
+
Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 rounded-lg border border-ui-border-base p-5", children: [
|
|
3897
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" }),
|
|
3898
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: Array.from({ length: 4 }).map((__, j) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
3899
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" }),
|
|
3900
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-36" })
|
|
3901
|
+
] }, j)) })
|
|
3902
|
+
] }, i))
|
|
3903
|
+
] });
|
|
3904
|
+
const DetailError = ({
|
|
3905
|
+
notFound,
|
|
3906
|
+
message,
|
|
3907
|
+
onRetry,
|
|
3908
|
+
onBack
|
|
3909
|
+
}) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 rounded-lg border border-ui-border-base px-6 py-12 text-center", children: [
|
|
3910
|
+
/* @__PURE__ */ jsx(ExclamationCircle, { className: clx(notFound ? "text-ui-fg-muted" : "text-ui-fg-error") }),
|
|
3911
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", children: notFound ? "Audit entry not found" : "Unable to load this deleted record" }),
|
|
3912
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "max-w-md text-ui-fg-subtle", children: notFound ? "This audit entry doesn’t exist. The link may be incorrect." : "We couldn’t retrieve the audit entry right now. Check your connection and try again." }),
|
|
3913
|
+
!notFound ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: message }) : null,
|
|
3914
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
|
|
3915
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: onBack, children: "Back to Deleted Records" }),
|
|
3916
|
+
!notFound ? /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: onRetry, children: "Try again" }) : null
|
|
3917
|
+
] })
|
|
3918
|
+
] });
|
|
3919
|
+
const config$4 = defineRouteConfig({});
|
|
3920
|
+
const getStatusBadgeClass$3 = (status) => {
|
|
3921
|
+
const s2 = status.toLowerCase();
|
|
3922
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3923
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
3924
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
3925
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
3926
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3927
|
+
};
|
|
3928
|
+
const PaymentDetailPage = () => {
|
|
3929
|
+
const navigate = useNavigate();
|
|
3930
|
+
const params = useParams();
|
|
3931
|
+
const id = params?.id?.trim();
|
|
3932
|
+
const [detail, setDetail] = useState(null);
|
|
3933
|
+
const [loading, setLoading] = useState(!!id);
|
|
3934
|
+
const [error, setError] = useState(null);
|
|
3935
|
+
useEffect(() => {
|
|
3936
|
+
if (!id) {
|
|
3937
|
+
setLoading(false);
|
|
3938
|
+
return;
|
|
3939
|
+
}
|
|
3940
|
+
let cancelled = false;
|
|
3941
|
+
setLoading(true);
|
|
3942
|
+
setError(null);
|
|
3943
|
+
fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
|
|
3944
|
+
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
3945
|
+
return res.json();
|
|
3946
|
+
}).then((data) => {
|
|
3947
|
+
if (!cancelled) setDetail(data);
|
|
3948
|
+
}).catch((e) => {
|
|
3949
|
+
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
3950
|
+
}).finally(() => {
|
|
3951
|
+
if (!cancelled) setLoading(false);
|
|
3952
|
+
});
|
|
3953
|
+
return () => {
|
|
3954
|
+
cancelled = true;
|
|
3955
|
+
};
|
|
3956
|
+
}, [id]);
|
|
3957
|
+
const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
|
|
3958
|
+
const sessionStatusRaw = detail?.session_status ?? "—";
|
|
3959
|
+
const paymentStatusRaw = detail?.payment_id != null ? detail?.payment_status ?? "—" : "—";
|
|
3960
|
+
const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
|
|
3961
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 p-6", children: [
|
|
3962
|
+
/* @__PURE__ */ jsx("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3963
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
|
|
3964
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
|
|
3965
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
|
|
3966
|
+
] }) }),
|
|
3967
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3968
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3969
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
|
|
3970
|
+
] }) : loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading…" }) }) : detail ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
3971
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6 flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3972
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3973
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
|
|
3974
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
|
|
3975
|
+
Button,
|
|
3976
|
+
{
|
|
3977
|
+
variant: "transparent",
|
|
3978
|
+
size: "small",
|
|
3979
|
+
onClick: () => navigate(`/orders/${detail.order_id}`),
|
|
3980
|
+
children: detail.order_id
|
|
3981
|
+
}
|
|
3982
|
+
) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
|
|
3983
|
+
] }),
|
|
3984
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3985
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
3986
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
|
|
3987
|
+
] }),
|
|
3988
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3989
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
3990
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
|
|
3991
|
+
] }),
|
|
3992
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3993
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
3994
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
3995
|
+
Badge,
|
|
3996
|
+
{
|
|
3997
|
+
size: "2xsmall",
|
|
3998
|
+
className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
|
|
3999
|
+
children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
|
|
4000
|
+
}
|
|
4001
|
+
) })
|
|
4002
|
+
] }),
|
|
4003
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4004
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
|
|
4005
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
|
|
4006
|
+
] }),
|
|
4007
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4008
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
|
|
4009
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
|
|
4010
|
+
] }),
|
|
4011
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4012
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
|
|
4013
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
|
|
4014
|
+
] }),
|
|
4015
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4016
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
|
|
4017
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
|
|
4018
|
+
year: "numeric",
|
|
4019
|
+
month: "short",
|
|
4020
|
+
day: "numeric",
|
|
4021
|
+
hour: "numeric",
|
|
4022
|
+
minute: "2-digit",
|
|
4023
|
+
hour12: true
|
|
4024
|
+
}) })
|
|
4025
|
+
] })
|
|
4026
|
+
] }) }),
|
|
4027
|
+
Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4028
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
|
|
4029
|
+
/* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.data, null, 2) })
|
|
4030
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No provider data for this session." }) })
|
|
4031
|
+
] }) : null
|
|
4032
|
+
] }) });
|
|
3991
4033
|
};
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
if (
|
|
4002
|
-
return
|
|
4003
|
-
const id = oldData[link.key];
|
|
4004
|
-
if (link.selfTables.includes(tableName) || typeof id !== "string" || !id.trim()) return [];
|
|
4005
|
-
return [{ label: link.label, id, path: link.path(id) }];
|
|
4006
|
-
});
|
|
4007
|
-
}
|
|
4008
|
-
const fullName = (row) => {
|
|
4009
|
-
const parts = [row.first_name, row.last_name].filter(
|
|
4010
|
-
(part) => typeof part === "string" && part.trim() !== ""
|
|
4011
|
-
);
|
|
4012
|
-
return parts.length ? parts.join(" ") : void 0;
|
|
4034
|
+
const config$3 = defineRouteConfig({
|
|
4035
|
+
label: "Payment details",
|
|
4036
|
+
icon: CreditCard
|
|
4037
|
+
});
|
|
4038
|
+
const getStatusBadgeClass$2 = (status) => {
|
|
4039
|
+
const s2 = status.toLowerCase();
|
|
4040
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
4041
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
4042
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
4043
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
4044
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
4013
4045
|
};
|
|
4014
|
-
const
|
|
4015
|
-
|
|
4016
|
-
return parts.length ? parts.join(", ") : void 0;
|
|
4046
|
+
const formatAmount = (value) => {
|
|
4047
|
+
return String(value);
|
|
4017
4048
|
};
|
|
4018
|
-
const
|
|
4019
|
-
const
|
|
4020
|
-
const
|
|
4021
|
-
const
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
{
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
{ key: "status", label: "Status", kind: "status" },
|
|
4194
|
-
{ key: "product_id", label: "Product ID", kind: "id" },
|
|
4195
|
-
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
4196
|
-
CREATED
|
|
4197
|
-
]
|
|
4049
|
+
const RefundDetailPage = () => {
|
|
4050
|
+
const navigate = useNavigate();
|
|
4051
|
+
const params = useParams();
|
|
4052
|
+
const id = params?.id?.trim();
|
|
4053
|
+
const [detail, setDetail] = useState(null);
|
|
4054
|
+
const [loading, setLoading] = useState(!!id);
|
|
4055
|
+
const [error, setError] = useState(null);
|
|
4056
|
+
const [gatewayExpanded, setGatewayExpanded] = useState(false);
|
|
4057
|
+
useEffect(() => {
|
|
4058
|
+
if (!id) {
|
|
4059
|
+
setLoading(false);
|
|
4060
|
+
return;
|
|
4061
|
+
}
|
|
4062
|
+
let cancelled = false;
|
|
4063
|
+
setLoading(true);
|
|
4064
|
+
setError(null);
|
|
4065
|
+
fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
|
|
4066
|
+
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
4067
|
+
return res.json();
|
|
4068
|
+
}).then((data) => {
|
|
4069
|
+
if (!cancelled) setDetail(data);
|
|
4070
|
+
}).catch((e) => {
|
|
4071
|
+
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
4072
|
+
}).finally(() => {
|
|
4073
|
+
if (!cancelled) setLoading(false);
|
|
4074
|
+
});
|
|
4075
|
+
return () => {
|
|
4076
|
+
cancelled = true;
|
|
4077
|
+
};
|
|
4078
|
+
}, [id]);
|
|
4079
|
+
const paymentStatus = detail?.payment?.status ?? "—";
|
|
4080
|
+
const hasGatewayData = detail?.payment?.payment_data && typeof detail.payment.payment_data === "object" && Object.keys(detail.payment.payment_data).length > 0;
|
|
4081
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 p-6", children: [
|
|
4082
|
+
/* @__PURE__ */ jsx("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
4083
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
|
|
4084
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
|
|
4085
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
|
|
4086
|
+
] }) }),
|
|
4087
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
4088
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
4089
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
|
|
4090
|
+
] }) : loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading…" }) }) : detail ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
4091
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4092
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
|
|
4093
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4094
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4095
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund ID" }),
|
|
4096
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.id })
|
|
4097
|
+
] }),
|
|
4098
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4099
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
4100
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.refund.amount) })
|
|
4101
|
+
] }),
|
|
4102
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4103
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Note" }),
|
|
4104
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.refund.note ?? "—" })
|
|
4105
|
+
] }),
|
|
4106
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4107
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created at" }),
|
|
4108
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.refund.created_at).toLocaleDateString("en-US", {
|
|
4109
|
+
year: "numeric",
|
|
4110
|
+
month: "short",
|
|
4111
|
+
day: "numeric",
|
|
4112
|
+
hour: "numeric",
|
|
4113
|
+
minute: "2-digit",
|
|
4114
|
+
hour12: true
|
|
4115
|
+
}) })
|
|
4116
|
+
] }),
|
|
4117
|
+
detail.refund.created_by ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4118
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created by" }),
|
|
4119
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.created_by })
|
|
4120
|
+
] }) : null
|
|
4121
|
+
] })
|
|
4122
|
+
] }),
|
|
4123
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4124
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
|
|
4125
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4126
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4127
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
|
|
4128
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
|
|
4129
|
+
] }),
|
|
4130
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4131
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
|
|
4132
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
|
|
4133
|
+
] }),
|
|
4134
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4135
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
|
|
4136
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
|
|
4137
|
+
] }),
|
|
4138
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4139
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
4140
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
|
|
4141
|
+
] }),
|
|
4142
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4143
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
4144
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
4145
|
+
Badge,
|
|
4146
|
+
{
|
|
4147
|
+
size: "2xsmall",
|
|
4148
|
+
className: `uppercase ${getStatusBadgeClass$2(paymentStatus)}`,
|
|
4149
|
+
children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
|
|
4150
|
+
}
|
|
4151
|
+
) })
|
|
4152
|
+
] }),
|
|
4153
|
+
detail.computed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4154
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4155
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Full refund" }),
|
|
4156
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.computed.is_full_refund ? "Yes" : "No" })
|
|
4157
|
+
] }),
|
|
4158
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4159
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Remaining refundable" }),
|
|
4160
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.computed.remaining_refundable_amount) })
|
|
4161
|
+
] }),
|
|
4162
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4163
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund %" }),
|
|
4164
|
+
/* @__PURE__ */ jsxs(Text, { className: "mt-1 block", children: [
|
|
4165
|
+
detail.computed.refund_percentage.toFixed(1),
|
|
4166
|
+
"%"
|
|
4167
|
+
] })
|
|
4168
|
+
] })
|
|
4169
|
+
] }) : null
|
|
4170
|
+
] })
|
|
4171
|
+
] }),
|
|
4172
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4173
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Order summary" }),
|
|
4174
|
+
detail.order ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4175
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4176
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order" }),
|
|
4177
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
4178
|
+
Button,
|
|
4179
|
+
{
|
|
4180
|
+
variant: "transparent",
|
|
4181
|
+
size: "small",
|
|
4182
|
+
onClick: () => navigate(`/orders/${detail.order.order_id}`),
|
|
4183
|
+
children: detail.order.order_number ?? detail.order.order_id
|
|
4184
|
+
}
|
|
4185
|
+
) })
|
|
4186
|
+
] }),
|
|
4187
|
+
detail.order.total != null ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4188
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Total" }),
|
|
4189
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.order.total) })
|
|
4190
|
+
] }) : null,
|
|
4191
|
+
detail.order.customer_id ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4192
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Customer ID" }),
|
|
4193
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.order.customer_id })
|
|
4194
|
+
] }) : null,
|
|
4195
|
+
detail.order.region ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4196
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Region" }),
|
|
4197
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.region })
|
|
4198
|
+
] }) : null,
|
|
4199
|
+
detail.order.fulfillment_status ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4200
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
|
|
4201
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
|
|
4202
|
+
] }) : null
|
|
4203
|
+
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
|
|
4204
|
+
] }),
|
|
4205
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4206
|
+
/* @__PURE__ */ jsxs(
|
|
4207
|
+
"button",
|
|
4208
|
+
{
|
|
4209
|
+
type: "button",
|
|
4210
|
+
className: "flex w-full items-center justify-between text-left",
|
|
4211
|
+
onClick: () => setGatewayExpanded((prev) => !prev),
|
|
4212
|
+
"aria-expanded": gatewayExpanded,
|
|
4213
|
+
"aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
|
|
4214
|
+
children: [
|
|
4215
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
|
|
4216
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
|
|
4217
|
+
]
|
|
4218
|
+
}
|
|
4219
|
+
),
|
|
4220
|
+
gatewayExpanded && /* @__PURE__ */ jsx("div", { className: "mt-4", children: hasGatewayData ? /* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.payment.payment_data, null, 2) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No gateway payload for this payment." }) })
|
|
4221
|
+
] })
|
|
4222
|
+
] }) : null
|
|
4223
|
+
] }) });
|
|
4198
4224
|
};
|
|
4199
|
-
const
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
{ key: "sku", label: "SKU" },
|
|
4208
|
-
{ key: "code", label: "Code" },
|
|
4209
|
-
{ key: "status", label: "Status", kind: "status" },
|
|
4210
|
-
{ key: "type", label: "Type" },
|
|
4211
|
-
{ key: "amount", label: "Amount", kind: "money" },
|
|
4212
|
-
{ key: "quantity", label: "Quantity", kind: "number" },
|
|
4213
|
-
{ key: "currency_code", label: "Currency" },
|
|
4214
|
-
{ key: "order_id", label: "Order ID", kind: "id" },
|
|
4215
|
-
{ key: "customer_id", label: "Customer ID", kind: "id" },
|
|
4216
|
-
{ key: "product_id", label: "Product ID", kind: "id" },
|
|
4217
|
-
{ key: "payment_id", label: "Payment ID", kind: "id" },
|
|
4218
|
-
{ key: "provider_id", label: "Provider" },
|
|
4219
|
-
CREATED,
|
|
4220
|
-
{ key: "updated_at", label: "Last updated", kind: "date" }
|
|
4221
|
-
];
|
|
4222
|
-
const MAX_GENERIC_FIELDS = 8;
|
|
4223
|
-
function amountOf(value) {
|
|
4224
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4225
|
-
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
|
|
4226
|
-
if (value !== null && typeof value === "object" && "value" in value) {
|
|
4227
|
-
return amountOf(value.value);
|
|
4225
|
+
const config$2 = defineRouteConfig({
|
|
4226
|
+
label: "Refund details",
|
|
4227
|
+
icon: Receipt
|
|
4228
|
+
});
|
|
4229
|
+
const getStatusBadgeClass$1 = (status) => {
|
|
4230
|
+
const statusLower = status.toLowerCase();
|
|
4231
|
+
if (statusLower === "requested") {
|
|
4232
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
4228
4233
|
}
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
function formatValue(raw, kind, row) {
|
|
4232
|
-
if (raw === null || raw === void 0 || raw === "") return null;
|
|
4233
|
-
if (raw === MASKED_VALUE) return { value: MASKED_VALUE, kind: "masked" };
|
|
4234
|
-
switch (kind) {
|
|
4235
|
-
case "money": {
|
|
4236
|
-
const amount = amountOf(raw);
|
|
4237
|
-
if (amount === null) return null;
|
|
4238
|
-
const currency = typeof row.currency_code === "string" ? row.currency_code : null;
|
|
4239
|
-
return { value: formatMoney(amount, currency), kind };
|
|
4240
|
-
}
|
|
4241
|
-
case "date":
|
|
4242
|
-
return typeof raw === "string" || raw instanceof Date ? { value: formatDate(raw), kind } : null;
|
|
4243
|
-
case "boolean":
|
|
4244
|
-
return { value: raw === true || raw === "true" ? "Yes" : "No", kind };
|
|
4245
|
-
case "number": {
|
|
4246
|
-
const n = amountOf(raw);
|
|
4247
|
-
return n === null ? null : { value: formatNumber(n), kind };
|
|
4248
|
-
}
|
|
4249
|
-
case "status":
|
|
4250
|
-
return { value: String(raw).replace(/_/g, " "), kind };
|
|
4251
|
-
default:
|
|
4252
|
-
if (typeof raw === "object") return null;
|
|
4253
|
-
if (typeof raw === "string" && raw.length > 160) return { value: `${raw.slice(0, 157)}…`, kind };
|
|
4254
|
-
return { value: String(raw), kind };
|
|
4234
|
+
if (statusLower === "approved") {
|
|
4235
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
4255
4236
|
}
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
if (!oldData) return [];
|
|
4259
|
-
const { value: row } = maskSensitiveData(oldData, tableName);
|
|
4260
|
-
const specific = ENTITY_FIELDS[tableName];
|
|
4261
|
-
const specs = specific ?? GENERIC_FIELDS;
|
|
4262
|
-
const fields = [];
|
|
4263
|
-
const seenLabels = /* @__PURE__ */ new Set();
|
|
4264
|
-
for (const spec of specs) {
|
|
4265
|
-
const raw = spec.derive ? spec.derive(row) : row[spec.key];
|
|
4266
|
-
const formatted = formatValue(raw, spec.kind ?? "text", row);
|
|
4267
|
-
if (!formatted || seenLabels.has(spec.label)) continue;
|
|
4268
|
-
seenLabels.add(spec.label);
|
|
4269
|
-
const value = spec.key === "currency_code" ? formatted.value.toUpperCase() : formatted.value;
|
|
4270
|
-
fields.push({ key: spec.key, label: spec.label, value, kind: formatted.kind });
|
|
4271
|
-
if (!specific && fields.length >= MAX_GENERIC_FIELDS) break;
|
|
4237
|
+
if (statusLower === "rejected") {
|
|
4238
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
4272
4239
|
}
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
return
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4240
|
+
if (statusLower === "received") {
|
|
4241
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
4242
|
+
}
|
|
4243
|
+
if (statusLower === "refunded") {
|
|
4244
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
4245
|
+
}
|
|
4246
|
+
if (statusLower === "completed") {
|
|
4247
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
4280
4248
|
}
|
|
4281
|
-
|
|
4282
|
-
|
|
4249
|
+
if (statusLower === "cancelled") {
|
|
4250
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
4251
|
+
}
|
|
4252
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
4253
|
+
};
|
|
4254
|
+
const ReturnDetailPage = () => {
|
|
4283
4255
|
const navigate = useNavigate();
|
|
4284
|
-
const
|
|
4285
|
-
const
|
|
4286
|
-
const [
|
|
4287
|
-
const [
|
|
4288
|
-
const
|
|
4289
|
-
const
|
|
4290
|
-
|
|
4291
|
-
else navigate(`/deleted-records-audit${readLastListSearch()}`);
|
|
4292
|
-
};
|
|
4256
|
+
const { id } = useParams();
|
|
4257
|
+
const [returnOrder, setReturnOrder] = useState(null);
|
|
4258
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
4259
|
+
const [isRejecting, setIsRejecting] = useState(false);
|
|
4260
|
+
const [error, setError] = useState(null);
|
|
4261
|
+
const [updateError, setUpdateError] = useState(null);
|
|
4262
|
+
const [updateSuccess, setUpdateSuccess] = useState(false);
|
|
4293
4263
|
useEffect(() => {
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
onRetry: () => setReloadToken((t) => t + 1),
|
|
4317
|
-
onBack: goBack
|
|
4264
|
+
if (!id) {
|
|
4265
|
+
navigate("/returns");
|
|
4266
|
+
return;
|
|
4267
|
+
}
|
|
4268
|
+
const loadReturn = async () => {
|
|
4269
|
+
try {
|
|
4270
|
+
setIsLoading(true);
|
|
4271
|
+
setError(null);
|
|
4272
|
+
const response = await fetch(`/admin/return/${id}`, {
|
|
4273
|
+
credentials: "include"
|
|
4274
|
+
});
|
|
4275
|
+
if (!response.ok) {
|
|
4276
|
+
const message = await response.text();
|
|
4277
|
+
throw new Error(message || "Unable to load return order");
|
|
4278
|
+
}
|
|
4279
|
+
const payload = await response.json();
|
|
4280
|
+
setReturnOrder(payload.return);
|
|
4281
|
+
} catch (loadError) {
|
|
4282
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return order";
|
|
4283
|
+
setError(message);
|
|
4284
|
+
} finally {
|
|
4285
|
+
setIsLoading(false);
|
|
4318
4286
|
}
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
};
|
|
4322
|
-
const
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
const summary = useMemo(() => summarizeOldData(audit.table_name, audit.old_data), [audit]);
|
|
4327
|
-
const masked = useMemo(() => maskSensitiveData(audit.old_data, audit.table_name), [audit]);
|
|
4328
|
-
const guidance = getNextSteps(entity.category.id);
|
|
4329
|
-
const related = getRelatedLinks(audit.table_name, audit.old_data);
|
|
4330
|
-
const [showRaw, setShowRaw] = useState(false);
|
|
4331
|
-
const copyJson = async () => {
|
|
4287
|
+
};
|
|
4288
|
+
void loadReturn();
|
|
4289
|
+
}, [id, navigate]);
|
|
4290
|
+
const handleReject = async () => {
|
|
4291
|
+
if (!id) {
|
|
4292
|
+
return;
|
|
4293
|
+
}
|
|
4332
4294
|
try {
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4295
|
+
setIsRejecting(true);
|
|
4296
|
+
setUpdateError(null);
|
|
4297
|
+
setUpdateSuccess(false);
|
|
4298
|
+
const response = await fetch(`/admin/return/${id}/reject`, {
|
|
4299
|
+
method: "POST",
|
|
4300
|
+
headers: {
|
|
4301
|
+
"Content-Type": "application/json"
|
|
4302
|
+
},
|
|
4303
|
+
credentials: "include",
|
|
4304
|
+
body: JSON.stringify({ reason: "Rejected by admin" })
|
|
4336
4305
|
});
|
|
4337
|
-
|
|
4338
|
-
|
|
4306
|
+
if (!response.ok) {
|
|
4307
|
+
const message = await response.text();
|
|
4308
|
+
throw new Error(message || "Unable to reject return");
|
|
4309
|
+
}
|
|
4310
|
+
const payload = await response.json();
|
|
4311
|
+
setReturnOrder(payload.return);
|
|
4312
|
+
setUpdateSuccess(true);
|
|
4313
|
+
setTimeout(() => setUpdateSuccess(false), 3e3);
|
|
4314
|
+
const detailResponse = await fetch(`/admin/return/${id}`, {
|
|
4315
|
+
credentials: "include"
|
|
4316
|
+
});
|
|
4317
|
+
if (detailResponse.ok) {
|
|
4318
|
+
const detailPayload = await detailResponse.json();
|
|
4319
|
+
setReturnOrder(detailPayload.return);
|
|
4320
|
+
}
|
|
4321
|
+
} catch (updateErr) {
|
|
4322
|
+
const message = updateErr instanceof Error ? updateErr.message : "Unable to reject return";
|
|
4323
|
+
setUpdateError(message);
|
|
4324
|
+
} finally {
|
|
4325
|
+
setIsRejecting(false);
|
|
4339
4326
|
}
|
|
4340
4327
|
};
|
|
4341
|
-
|
|
4328
|
+
if (isLoading) {
|
|
4329
|
+
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..." }) }) }) });
|
|
4330
|
+
}
|
|
4331
|
+
if (error || !returnOrder) {
|
|
4332
|
+
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: [
|
|
4333
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Return order not found" }),
|
|
4334
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/returns"), children: "Back to list" }) })
|
|
4335
|
+
] }) }) });
|
|
4336
|
+
}
|
|
4337
|
+
const statusHistory = returnOrder.metadata?.status_history || [];
|
|
4338
|
+
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: [
|
|
4342
4339
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
4343
|
-
/* @__PURE__ */ jsxs(
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
"
|
|
4340
|
+
/* @__PURE__ */ jsxs(
|
|
4341
|
+
Button,
|
|
4342
|
+
{
|
|
4343
|
+
variant: "transparent",
|
|
4344
|
+
size: "small",
|
|
4345
|
+
onClick: () => navigate("/returns"),
|
|
4346
|
+
className: "w-fit",
|
|
4347
|
+
children: [
|
|
4348
|
+
/* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2" }),
|
|
4349
|
+
"Back to list"
|
|
4350
|
+
]
|
|
4351
|
+
}
|
|
4352
|
+
),
|
|
4353
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 md:flex-row md:items-center md:justify-between", children: [
|
|
4354
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
4355
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Order Details" }),
|
|
4356
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: returnOrder.id })
|
|
4347
4357
|
] }),
|
|
4348
|
-
/* @__PURE__ */ jsx(
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
/* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
4357
|
-
"Database table: ",
|
|
4358
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono", children: audit.table_name })
|
|
4359
|
-
] })
|
|
4360
|
-
] })
|
|
4361
|
-
] }),
|
|
4362
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-ui-tag-orange-border bg-ui-tag-orange-bg px-4 py-3", children: [
|
|
4363
|
-
/* @__PURE__ */ jsx(InformationCircle, { className: "mt-0.5 shrink-0 text-ui-tag-orange-icon" }),
|
|
4364
|
-
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-tag-orange-text", children: [
|
|
4365
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "This is a historical snapshot" }),
|
|
4366
|
-
" captured immediately before deletion. The record no longer exists in the database, so changes elsewhere in the admin are not reflected here."
|
|
4358
|
+
/* @__PURE__ */ jsx(
|
|
4359
|
+
Badge,
|
|
4360
|
+
{
|
|
4361
|
+
size: "small",
|
|
4362
|
+
className: `uppercase ${getStatusBadgeClass$1(returnOrder.status)}`,
|
|
4363
|
+
children: returnOrder.status.replace(/_/g, " ")
|
|
4364
|
+
}
|
|
4365
|
+
)
|
|
4367
4366
|
] })
|
|
4368
4367
|
] }),
|
|
4369
|
-
|
|
4370
|
-
/* @__PURE__ */ jsx(
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
/* @__PURE__ */ jsx(
|
|
4390
|
-
Section,
|
|
4391
|
-
{
|
|
4392
|
-
title: "Original record data",
|
|
4393
|
-
description: "The complete data captured before deletion.",
|
|
4394
|
-
actions: showRaw && audit.old_data ? /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: copyJson, children: [
|
|
4395
|
-
/* @__PURE__ */ jsx(SquareTwoStack, {}),
|
|
4396
|
-
"Copy JSON"
|
|
4397
|
-
] }) : null,
|
|
4398
|
-
children: audit.old_data ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
4399
|
-
masked.maskedCount > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4400
|
-
/* @__PURE__ */ jsx(ShieldCheck, { className: "shrink-0 text-ui-fg-muted" }),
|
|
4401
|
-
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
|
|
4402
|
-
masked.maskedCount,
|
|
4403
|
-
" sensitive ",
|
|
4404
|
-
masked.maskedCount === 1 ? "value is" : "values are",
|
|
4405
|
-
" hidden for security (passwords, tokens, card or account numbers)."
|
|
4406
|
-
] })
|
|
4407
|
-
] }) : null,
|
|
4408
|
-
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: () => setShowRaw((s2) => !s2), "aria-expanded": showRaw, children: [
|
|
4409
|
-
showRaw ? /* @__PURE__ */ jsx(ChevronDownMini, {}) : /* @__PURE__ */ jsx(ChevronRightMini, {}),
|
|
4410
|
-
showRaw ? "Hide full record" : "View full record"
|
|
4411
|
-
] }) }),
|
|
4412
|
-
showRaw ? /* @__PURE__ */ jsx(JsonViewer, { data: masked.value }) : null
|
|
4413
|
-
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No data was captured for this deletion." })
|
|
4414
|
-
}
|
|
4415
|
-
),
|
|
4416
|
-
/* @__PURE__ */ jsx(Section, { title: "What you can do now", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
4417
|
-
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-base", children: [
|
|
4418
|
-
"This record was permanently deleted. ",
|
|
4419
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Automatic restoration is not available" }),
|
|
4420
|
-
" ",
|
|
4421
|
-
"from this screen."
|
|
4422
|
-
] }),
|
|
4423
|
-
/* @__PURE__ */ jsxs("ol", { className: "flex list-decimal flex-col gap-3 pl-5 text-sm text-ui-fg-subtle marker:text-ui-fg-muted", children: [
|
|
4424
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
4425
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Check whether this was expected." }),
|
|
4426
|
-
" ",
|
|
4427
|
-
audit.deleted_by || source.kind !== "unknown" ? "Confirm with the person or system shown above." : `Who deleted it wasn’t recorded—check with your team or integrations active around ${formatExactDateTime(audit.occurred_at)}.`,
|
|
4428
|
-
" ",
|
|
4429
|
-
guidance.headline
|
|
4430
|
-
] }),
|
|
4431
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
4432
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "If it needs to come back:" }),
|
|
4433
|
-
" ",
|
|
4434
|
-
guidance.recreate
|
|
4368
|
+
returnOrder.status === "requested" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
4369
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsx(
|
|
4370
|
+
Button,
|
|
4371
|
+
{
|
|
4372
|
+
variant: "danger",
|
|
4373
|
+
onClick: handleReject,
|
|
4374
|
+
disabled: isRejecting,
|
|
4375
|
+
isLoading: isRejecting,
|
|
4376
|
+
children: "Reject (Cancel) Return"
|
|
4377
|
+
}
|
|
4378
|
+
) }),
|
|
4379
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: 'Cancel this return request. Use "Mark as received" when items are received.' })
|
|
4380
|
+
] }),
|
|
4381
|
+
returnOrder.refund ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: /* @__PURE__ */ jsx(RefundCalculationBlock, { refund: returnOrder.refund }) }) : null,
|
|
4382
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
4383
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Information" }),
|
|
4384
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
4385
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4386
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Return ID" }),
|
|
4387
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.id })
|
|
4435
4388
|
] }),
|
|
4436
|
-
/* @__PURE__ */
|
|
4437
|
-
|
|
4438
|
-
|
|
4389
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
4390
|
+
Button,
|
|
4391
|
+
{
|
|
4392
|
+
variant: "secondary",
|
|
4393
|
+
onClick: () => {
|
|
4394
|
+
window.open(
|
|
4395
|
+
`/app/orders/${returnOrder.order_id}`,
|
|
4396
|
+
"_blank"
|
|
4397
|
+
);
|
|
4398
|
+
},
|
|
4399
|
+
children: "View order"
|
|
4400
|
+
}
|
|
4401
|
+
) })
|
|
4402
|
+
] })
|
|
4403
|
+
] }),
|
|
4404
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
4405
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
4406
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Details" }),
|
|
4407
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
4408
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4409
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Return ID" }),
|
|
4410
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.id })
|
|
4411
|
+
] }),
|
|
4412
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4413
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Status" }),
|
|
4414
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.status })
|
|
4415
|
+
] }),
|
|
4416
|
+
returnOrder.reason && /* @__PURE__ */ jsxs("div", { children: [
|
|
4417
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Reason" }),
|
|
4418
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.reason })
|
|
4419
|
+
] }),
|
|
4420
|
+
returnOrder.note && /* @__PURE__ */ jsxs("div", { children: [
|
|
4421
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Note" }),
|
|
4422
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.note })
|
|
4423
|
+
] }),
|
|
4424
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4425
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Created" }),
|
|
4426
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(returnOrder.created_at).toLocaleString() })
|
|
4427
|
+
] }),
|
|
4428
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4429
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Last Updated" }),
|
|
4430
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(returnOrder.updated_at).toLocaleString() })
|
|
4431
|
+
] })
|
|
4439
4432
|
] })
|
|
4440
4433
|
] }),
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4434
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
4435
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Status History" }),
|
|
4436
|
+
statusHistory.length > 0 ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: statusHistory.map((entry, index) => /* @__PURE__ */ jsx(
|
|
4437
|
+
"div",
|
|
4445
4438
|
{
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4439
|
+
className: "flex items-center justify-between border-b border-ui-border-subtle pb-2 last:border-0",
|
|
4440
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
4441
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
|
|
4442
|
+
Badge,
|
|
4443
|
+
{
|
|
4444
|
+
size: "2xsmall",
|
|
4445
|
+
className: `uppercase ${getStatusBadgeClass$1(entry.status)}`,
|
|
4446
|
+
children: entry.status.replace(/_/g, " ")
|
|
4447
|
+
}
|
|
4448
|
+
) }),
|
|
4449
|
+
/* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
|
|
4450
|
+
new Date(entry.timestamp).toLocaleString(),
|
|
4451
|
+
entry.admin_id && ` by ${entry.admin_id}`,
|
|
4452
|
+
entry.reason && ` - ${entry.reason}`
|
|
4453
|
+
] })
|
|
4454
|
+
] })
|
|
4455
4455
|
},
|
|
4456
|
-
|
|
4457
|
-
))
|
|
4458
|
-
] })
|
|
4459
|
-
related.length ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "Related records open only if they haven’t been deleted too." }) : null
|
|
4460
|
-
] }) })
|
|
4461
|
-
] });
|
|
4462
|
-
};
|
|
4463
|
-
const Section = ({
|
|
4464
|
-
title,
|
|
4465
|
-
description,
|
|
4466
|
-
actions,
|
|
4467
|
-
children
|
|
4468
|
-
}) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4 rounded-lg border border-ui-border-base p-5", children: [
|
|
4469
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [
|
|
4470
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
4471
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
|
|
4472
|
-
description ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: description }) : null
|
|
4456
|
+
index
|
|
4457
|
+
)) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No status history available" })
|
|
4458
|
+
] })
|
|
4473
4459
|
] }),
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4460
|
+
returnOrder.order && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
4461
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Related Order Information" }),
|
|
4462
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
4463
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4464
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order ID" }),
|
|
4465
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.id })
|
|
4466
|
+
] }),
|
|
4467
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4468
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Status" }),
|
|
4469
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.status || "—" })
|
|
4470
|
+
] }),
|
|
4471
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4472
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
|
|
4473
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.customer?.email || returnOrder.order.email || "—" })
|
|
4474
|
+
] }),
|
|
4475
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4476
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Payment method" }),
|
|
4477
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.order_payment?.label || "—" })
|
|
4478
|
+
] }),
|
|
4479
|
+
returnOrder.order.total && /* @__PURE__ */ jsxs("div", { children: [
|
|
4480
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
4481
|
+
/* @__PURE__ */ jsxs(Text, { className: "font-medium", children: [
|
|
4482
|
+
returnOrder.order.currency_code || "$",
|
|
4483
|
+
(Number(returnOrder.order.total) / 100).toFixed(2)
|
|
4484
|
+
] })
|
|
4485
|
+
] })
|
|
4486
|
+
] })
|
|
4487
|
+
] }),
|
|
4488
|
+
returnOrder.return_items && returnOrder.return_items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
4489
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Items" }),
|
|
4490
|
+
/* @__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: [
|
|
4491
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
4492
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Item ID" }),
|
|
4493
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" }),
|
|
4494
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Reason" })
|
|
4495
|
+
] }) }),
|
|
4496
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: returnOrder.return_items.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
4497
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.id }),
|
|
4498
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity }),
|
|
4499
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.reason || "—" })
|
|
4500
|
+
] }, item.id || index)) })
|
|
4501
|
+
] }) })
|
|
4502
|
+
] }),
|
|
4503
|
+
updateError && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-ui-border-error bg-ui-bg-error-subtle p-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error", children: updateError }) }),
|
|
4504
|
+
updateSuccess && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-ui-border-success bg-ui-bg-success-subtle p-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-success", children: "Action completed successfully" }) })
|
|
4505
|
+
] }) });
|
|
4506
|
+
};
|
|
4507
|
+
const config$1 = defineRouteConfig({
|
|
4508
|
+
label: "Return Order Details",
|
|
4509
|
+
icon: CheckCircle
|
|
4510
|
+
});
|
|
4513
4511
|
const getStatusBadgeClass = (status) => {
|
|
4514
4512
|
const statusLower = status.toLowerCase();
|
|
4515
4513
|
if (statusLower === "requested") {
|
|
@@ -4803,24 +4801,24 @@ const widgetModule = { widgets: [
|
|
|
4803
4801
|
] };
|
|
4804
4802
|
const routeModule = {
|
|
4805
4803
|
routes: [
|
|
4804
|
+
{
|
|
4805
|
+
Component: DeletedRecordsPage,
|
|
4806
|
+
path: "/deleted-records-audit",
|
|
4807
|
+
handle: { label: config$9.label, translationNs: config$9.translationNs }
|
|
4808
|
+
},
|
|
4806
4809
|
{
|
|
4807
4810
|
Component: PaymentsPage,
|
|
4808
4811
|
path: "/payments",
|
|
4809
|
-
handle: { label: config$
|
|
4812
|
+
handle: { label: config$8.label, translationNs: config$8.translationNs }
|
|
4810
4813
|
},
|
|
4811
4814
|
{
|
|
4812
4815
|
Component: RefundsPage,
|
|
4813
4816
|
path: "/refunds",
|
|
4814
|
-
handle: { label: config$
|
|
4817
|
+
handle: { label: config$7.label, translationNs: config$7.translationNs }
|
|
4815
4818
|
},
|
|
4816
4819
|
{
|
|
4817
4820
|
Component: ReturnsPage,
|
|
4818
4821
|
path: "/returns",
|
|
4819
|
-
handle: { label: config$7.label, translationNs: config$7.translationNs }
|
|
4820
|
-
},
|
|
4821
|
-
{
|
|
4822
|
-
Component: DeletedRecordsPage,
|
|
4823
|
-
path: "/deleted-records-audit",
|
|
4824
4822
|
handle: { label: config$6.label, translationNs: config$6.translationNs }
|
|
4825
4823
|
},
|
|
4826
4824
|
{
|
|
@@ -4828,24 +4826,24 @@ const routeModule = {
|
|
|
4828
4826
|
path: "/swaps",
|
|
4829
4827
|
handle: { label: config$5.label, translationNs: config$5.translationNs }
|
|
4830
4828
|
},
|
|
4829
|
+
{
|
|
4830
|
+
Component: DeletedRecordDetailPage,
|
|
4831
|
+
path: "/deleted-records-audit/:id",
|
|
4832
|
+
handle: { label: config$4.label, translationNs: config$4.translationNs }
|
|
4833
|
+
},
|
|
4831
4834
|
{
|
|
4832
4835
|
Component: PaymentDetailPage,
|
|
4833
4836
|
path: "/payments/:id",
|
|
4834
|
-
handle: { label: config$
|
|
4837
|
+
handle: { label: config$3.label, translationNs: config$3.translationNs }
|
|
4835
4838
|
},
|
|
4836
4839
|
{
|
|
4837
4840
|
Component: RefundDetailPage,
|
|
4838
4841
|
path: "/refunds/:id",
|
|
4839
|
-
handle: { label: config$
|
|
4842
|
+
handle: { label: config$2.label, translationNs: config$2.translationNs }
|
|
4840
4843
|
},
|
|
4841
4844
|
{
|
|
4842
4845
|
Component: ReturnDetailPage,
|
|
4843
4846
|
path: "/returns/:id",
|
|
4844
|
-
handle: { label: config$2.label, translationNs: config$2.translationNs }
|
|
4845
|
-
},
|
|
4846
|
-
{
|
|
4847
|
-
Component: DeletedRecordDetailPage,
|
|
4848
|
-
path: "/deleted-records-audit/:id",
|
|
4849
4847
|
handle: { label: config$1.label, translationNs: config$1.translationNs }
|
|
4850
4848
|
},
|
|
4851
4849
|
{
|
|
@@ -4858,16 +4856,16 @@ const routeModule = {
|
|
|
4858
4856
|
const menuItemModule = {
|
|
4859
4857
|
menuItems: [
|
|
4860
4858
|
{
|
|
4861
|
-
label: config$
|
|
4862
|
-
icon: config$
|
|
4859
|
+
label: config$9.label,
|
|
4860
|
+
icon: config$9.icon,
|
|
4863
4861
|
path: "/deleted-records-audit",
|
|
4864
4862
|
nested: void 0,
|
|
4865
4863
|
rank: void 0,
|
|
4866
4864
|
translationNs: void 0
|
|
4867
4865
|
},
|
|
4868
4866
|
{
|
|
4869
|
-
label: config$
|
|
4870
|
-
icon: config$
|
|
4867
|
+
label: config$8.label,
|
|
4868
|
+
icon: config$8.icon,
|
|
4871
4869
|
path: "/payments",
|
|
4872
4870
|
nested: void 0,
|
|
4873
4871
|
rank: void 0,
|
|
@@ -4876,15 +4874,15 @@ const menuItemModule = {
|
|
|
4876
4874
|
{
|
|
4877
4875
|
label: config$7.label,
|
|
4878
4876
|
icon: config$7.icon,
|
|
4879
|
-
path: "/
|
|
4877
|
+
path: "/refunds",
|
|
4880
4878
|
nested: void 0,
|
|
4881
4879
|
rank: void 0,
|
|
4882
4880
|
translationNs: void 0
|
|
4883
4881
|
},
|
|
4884
4882
|
{
|
|
4885
|
-
label: config$
|
|
4886
|
-
icon: config$
|
|
4887
|
-
path: "/
|
|
4883
|
+
label: config$6.label,
|
|
4884
|
+
icon: config$6.icon,
|
|
4885
|
+
path: "/returns",
|
|
4888
4886
|
nested: void 0,
|
|
4889
4887
|
rank: void 0,
|
|
4890
4888
|
translationNs: void 0
|
|
@@ -4898,8 +4896,8 @@ const menuItemModule = {
|
|
|
4898
4896
|
translationNs: void 0
|
|
4899
4897
|
},
|
|
4900
4898
|
{
|
|
4901
|
-
label: config$
|
|
4902
|
-
icon: config$
|
|
4899
|
+
label: config$3.label,
|
|
4900
|
+
icon: config$3.icon,
|
|
4903
4901
|
path: "/payments/:id",
|
|
4904
4902
|
nested: void 0,
|
|
4905
4903
|
rank: void 0,
|
|
@@ -4908,15 +4906,15 @@ const menuItemModule = {
|
|
|
4908
4906
|
{
|
|
4909
4907
|
label: config$2.label,
|
|
4910
4908
|
icon: config$2.icon,
|
|
4911
|
-
path: "/
|
|
4909
|
+
path: "/refunds/:id",
|
|
4912
4910
|
nested: void 0,
|
|
4913
4911
|
rank: void 0,
|
|
4914
4912
|
translationNs: void 0
|
|
4915
4913
|
},
|
|
4916
4914
|
{
|
|
4917
|
-
label: config$
|
|
4918
|
-
icon: config$
|
|
4919
|
-
path: "/
|
|
4915
|
+
label: config$1.label,
|
|
4916
|
+
icon: config$1.icon,
|
|
4917
|
+
path: "/returns/:id",
|
|
4920
4918
|
nested: void 0,
|
|
4921
4919
|
rank: void 0,
|
|
4922
4920
|
translationNs: void 0
|