order-management 0.0.100 → 0.0.101

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.
@@ -3,9 +3,9 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
5
5
  import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
6
- import { useState, useEffect, useRef, useCallback, useMemo } from "react";
7
- import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Input, Popover, clx, Copy, Skeleton, Tooltip, toast } from "@medusajs/ui";
8
- import { CashSolid, PencilSquareSolid, Trash, CreditCard, Receipt, ChevronDownMini, Check, ArrowPath, InformationCircle, ChevronRightMini, MagnifierAlert, ExclamationCircle, ArrowLeft, ClockSolid, SquareTwoStack, ShieldCheck, CheckCircle } from "@medusajs/icons";
6
+ import { useState, useEffect, useRef, useMemo, useCallback } from "react";
7
+ import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Popover, clx, Input, Copy, Skeleton, Tooltip, toast } from "@medusajs/ui";
8
+ import { CashSolid, PencilSquareSolid, Trash, ChevronDownMini, Check, ArrowPath, InformationCircle, ChevronRightMini, MagnifierAlert, ExclamationCircle, CreditCard, ArrowLeft, ClockSolid, SquareTwoStack, ShieldCheck, Receipt, CheckCircle } from "@medusajs/icons";
9
9
  import { useNavigate, useLocation, useSearchParams, useParams } from "react-router-dom";
10
10
  function roundRectPath(ctx, x, y, w, h, r) {
11
11
  ctx.beginPath();
@@ -935,501 +935,6 @@ const OrderRefundContextWidget = (props) => {
935
935
  defineWidgetConfig({
936
936
  zone: "order.details.after"
937
937
  });
938
- const useDebounce$3 = (value, delay) => {
939
- const [debouncedValue, setDebouncedValue] = useState(value);
940
- useEffect(() => {
941
- const handler = setTimeout(() => setDebouncedValue(value), delay);
942
- return () => clearTimeout(handler);
943
- }, [value, delay]);
944
- return debouncedValue;
945
- };
946
- const getStatusBadgeClass$7 = (status) => {
947
- const s2 = status.toLowerCase();
948
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
949
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
950
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
951
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
952
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
953
- };
954
- const PaymentsPage = () => {
955
- const navigate = useNavigate();
956
- const [items, setItems] = useState([]);
957
- const [statusFilter, setStatusFilter] = useState("all");
958
- const [orderIdSearch, setOrderIdSearch] = useState("");
959
- const debouncedOrderId = useDebounce$3(orderIdSearch, 300);
960
- const [isLoading, setIsLoading] = useState(true);
961
- const [isFetchingMore, setIsFetchingMore] = useState(false);
962
- const [error, setError] = useState(null);
963
- const [offset, setOffset] = useState(0);
964
- const [count, setCount] = useState(0);
965
- const limit = 50;
966
- const loadTransactions = useCallback(
967
- async (nextOffset, replace) => {
968
- try {
969
- if (replace) setIsLoading(true);
970
- else setIsFetchingMore(true);
971
- setError(null);
972
- const params = new URLSearchParams();
973
- params.set("limit", String(limit));
974
- params.set("offset", String(nextOffset));
975
- if (statusFilter !== "all") params.set("status", statusFilter);
976
- if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
977
- const response = await fetch(
978
- `/admin/payment-transactions?${params.toString()}`,
979
- { credentials: "include" }
980
- );
981
- if (!response.ok) {
982
- const text = await response.text();
983
- throw new Error(text || "Failed to load payment transactions");
984
- }
985
- const payload = await response.json();
986
- const list = payload.transactions ?? [];
987
- setCount(payload.count ?? 0);
988
- setOffset(nextOffset + list.length);
989
- setItems((prev) => replace ? list : [...prev, ...list]);
990
- } catch (e) {
991
- setError(e instanceof Error ? e.message : "Failed to load");
992
- } finally {
993
- setIsLoading(false);
994
- setIsFetchingMore(false);
995
- }
996
- },
997
- [statusFilter, debouncedOrderId]
998
- );
999
- useEffect(() => {
1000
- void loadTransactions(0, true);
1001
- }, [loadTransactions]);
1002
- const hasMore = useMemo(() => offset < count, [offset, count]);
1003
- const displayStatus = (t) => {
1004
- const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
1005
- return s2 !== "" ? s2 : "—";
1006
- };
1007
- const displayAmount = (t) => {
1008
- const code = (t.currency_code ?? "USD").toUpperCase();
1009
- return `${code} ${Number(t.amount)}`;
1010
- };
1011
- 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: [
1012
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
1013
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1014
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
1015
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
1016
- ] }),
1017
- /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
1018
- ] }),
1019
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
1020
- /* @__PURE__ */ jsx(
1021
- Input,
1022
- {
1023
- placeholder: "Search by Order ID",
1024
- value: orderIdSearch,
1025
- onChange: (e) => setOrderIdSearch(e.target.value),
1026
- className: "md:max-w-sm",
1027
- "aria-label": "Search by order ID"
1028
- }
1029
- ),
1030
- /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
1031
- "select",
1032
- {
1033
- value: statusFilter,
1034
- onChange: (e) => setStatusFilter(e.target.value),
1035
- 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",
1036
- "aria-label": "Filter by status",
1037
- children: [
1038
- /* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
1039
- /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
1040
- /* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
1041
- /* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
1042
- /* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
1043
- /* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
1044
- /* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
1045
- ]
1046
- }
1047
- ) })
1048
- ] }),
1049
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
1050
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
1051
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
1052
- ] }) : null,
1053
- 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: [
1054
- /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
1055
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
1056
- ] }) : /* @__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: [
1057
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
1058
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
1059
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
1060
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
1061
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
1062
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
1063
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
1064
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
1065
- ] }) }),
1066
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
1067
- "tr",
1068
- {
1069
- className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
1070
- onClick: () => navigate(`/payments/${t.payment_session_id}`),
1071
- children: [
1072
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
1073
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
1074
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
1075
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
1076
- Badge,
1077
- {
1078
- size: "2xsmall",
1079
- className: `uppercase ${getStatusBadgeClass$7(displayStatus(t))}`,
1080
- children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
1081
- }
1082
- ) }),
1083
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
1084
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
1085
- year: "numeric",
1086
- month: "short",
1087
- day: "numeric",
1088
- hour: "numeric",
1089
- minute: "2-digit",
1090
- hour12: true
1091
- }) }),
1092
- /* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
1093
- /* @__PURE__ */ jsx(
1094
- Button,
1095
- {
1096
- variant: "transparent",
1097
- size: "small",
1098
- onClick: (e) => {
1099
- e.stopPropagation();
1100
- navigate(`/payments/${t.payment_session_id}`);
1101
- },
1102
- children: "View details"
1103
- }
1104
- ),
1105
- t.order_id ? /* @__PURE__ */ jsx(
1106
- Button,
1107
- {
1108
- variant: "transparent",
1109
- size: "small",
1110
- onClick: (e) => {
1111
- e.stopPropagation();
1112
- navigate(`/orders/${t.order_id}`);
1113
- },
1114
- children: "Order"
1115
- }
1116
- ) : null
1117
- ] })
1118
- ]
1119
- },
1120
- t.payment_session_id
1121
- )) })
1122
- ] }) }),
1123
- hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
1124
- Button,
1125
- {
1126
- variant: "secondary",
1127
- isLoading: isFetchingMore,
1128
- onClick: () => loadTransactions(offset, false),
1129
- children: "Load more"
1130
- }
1131
- ) }) : null
1132
- ] }) });
1133
- };
1134
- const config$8 = defineRouteConfig({
1135
- label: "Payments",
1136
- icon: CreditCard
1137
- });
1138
- const useDebounce$2 = (value, delay) => {
1139
- const [debouncedValue, setDebouncedValue] = useState(value);
1140
- useEffect(() => {
1141
- const handler = setTimeout(() => setDebouncedValue(value), delay);
1142
- return () => clearTimeout(handler);
1143
- }, [value, delay]);
1144
- return debouncedValue;
1145
- };
1146
- const getStatusBadgeClass$6 = (status) => {
1147
- const s2 = status.toLowerCase();
1148
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
1149
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
1150
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
1151
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
1152
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
1153
- };
1154
- const RefundsPage = () => {
1155
- const navigate = useNavigate();
1156
- const [items, setItems] = useState([]);
1157
- const [orderIdSearch, setOrderIdSearch] = useState("");
1158
- const debouncedOrderId = useDebounce$2(orderIdSearch, 300);
1159
- const [paymentStatusFilter, setPaymentStatusFilter] = useState("all");
1160
- const [providerSearch, setProviderSearch] = useState("");
1161
- const debouncedProvider = useDebounce$2(providerSearch, 300);
1162
- const [currencySearch, setCurrencySearch] = useState("");
1163
- const debouncedCurrency = useDebounce$2(currencySearch, 300);
1164
- const [dateFrom, setDateFrom] = useState("");
1165
- const [dateTo, setDateTo] = useState("");
1166
- const [amountMin, setAmountMin] = useState("");
1167
- const [amountMax, setAmountMax] = useState("");
1168
- const [isLoading, setIsLoading] = useState(true);
1169
- const [isFetchingMore, setIsFetchingMore] = useState(false);
1170
- const [error, setError] = useState(null);
1171
- const [offset, setOffset] = useState(0);
1172
- const [count, setCount] = useState(0);
1173
- const limit = 50;
1174
- const loadRefunds = useCallback(
1175
- async (nextOffset, replace) => {
1176
- try {
1177
- if (replace) setIsLoading(true);
1178
- else setIsFetchingMore(true);
1179
- setError(null);
1180
- const params = new URLSearchParams();
1181
- params.set("limit", String(limit));
1182
- params.set("offset", String(nextOffset));
1183
- if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
1184
- if (paymentStatusFilter !== "all") params.set("payment_status", paymentStatusFilter);
1185
- if (debouncedProvider.trim()) params.set("provider_id", debouncedProvider.trim());
1186
- if (debouncedCurrency.trim()) params.set("currency_code", debouncedCurrency.trim());
1187
- if (dateFrom.trim()) params.set("date_from", dateFrom.trim());
1188
- if (dateTo.trim()) params.set("date_to", dateTo.trim());
1189
- const min = amountMin.trim() ? Number(amountMin) : void 0;
1190
- const max = amountMax.trim() ? Number(amountMax) : void 0;
1191
- if (min != null && !Number.isNaN(min)) params.set("amount_min", String(min));
1192
- if (max != null && !Number.isNaN(max)) params.set("amount_max", String(max));
1193
- const response = await fetch(`/admin/refunds?${params.toString()}`, {
1194
- credentials: "include"
1195
- });
1196
- if (!response.ok) {
1197
- const text = await response.text();
1198
- throw new Error(text || "Failed to load refunds");
1199
- }
1200
- const payload = await response.json();
1201
- const list = payload.refunds ?? [];
1202
- setCount(payload.count ?? 0);
1203
- setOffset(nextOffset + list.length);
1204
- setItems((prev) => replace ? list : [...prev, ...list]);
1205
- } catch (e) {
1206
- setError(e instanceof Error ? e.message : "Failed to load");
1207
- } finally {
1208
- setIsLoading(false);
1209
- setIsFetchingMore(false);
1210
- }
1211
- },
1212
- [
1213
- debouncedOrderId,
1214
- paymentStatusFilter,
1215
- debouncedProvider,
1216
- debouncedCurrency,
1217
- dateFrom,
1218
- dateTo,
1219
- amountMin,
1220
- amountMax
1221
- ]
1222
- );
1223
- useEffect(() => {
1224
- void loadRefunds(0, true);
1225
- }, [loadRefunds]);
1226
- const hasMore = useMemo(() => offset < count, [offset, count]);
1227
- const displayAmount = (r) => {
1228
- const code = (r.currency_code ?? "USD").toUpperCase();
1229
- return `${code} ${Number(r.amount)}`;
1230
- };
1231
- const displayStatus = (r) => {
1232
- const s2 = r.payment_status ?? "";
1233
- return s2 !== "" ? s2 : "—";
1234
- };
1235
- 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: [
1236
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
1237
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1238
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refunds" }),
1239
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Refund records — amount, order, payment status" })
1240
- ] }),
1241
- /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadRefunds(0, true), children: "Refresh" })
1242
- ] }),
1243
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
1244
- /* @__PURE__ */ jsx(
1245
- Input,
1246
- {
1247
- placeholder: "Order ID",
1248
- value: orderIdSearch,
1249
- onChange: (e) => setOrderIdSearch(e.target.value),
1250
- className: "md:max-w-[180px]",
1251
- "aria-label": "Filter by order ID"
1252
- }
1253
- ),
1254
- /* @__PURE__ */ jsx(
1255
- Input,
1256
- {
1257
- placeholder: "Provider",
1258
- value: providerSearch,
1259
- onChange: (e) => setProviderSearch(e.target.value),
1260
- className: "md:max-w-[140px]",
1261
- "aria-label": "Filter by provider"
1262
- }
1263
- ),
1264
- /* @__PURE__ */ jsx(
1265
- Input,
1266
- {
1267
- placeholder: "Currency",
1268
- value: currencySearch,
1269
- onChange: (e) => setCurrencySearch(e.target.value),
1270
- className: "md:max-w-[100px]",
1271
- "aria-label": "Filter by currency"
1272
- }
1273
- ),
1274
- /* @__PURE__ */ jsxs(
1275
- "select",
1276
- {
1277
- value: paymentStatusFilter,
1278
- onChange: (e) => setPaymentStatusFilter(e.target.value),
1279
- 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]",
1280
- "aria-label": "Filter by payment status",
1281
- children: [
1282
- /* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
1283
- /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
1284
- /* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
1285
- /* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
1286
- /* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
1287
- /* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
1288
- /* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
1289
- ]
1290
- }
1291
- ),
1292
- /* @__PURE__ */ jsx(
1293
- Input,
1294
- {
1295
- type: "date",
1296
- placeholder: "From",
1297
- value: dateFrom,
1298
- onChange: (e) => setDateFrom(e.target.value),
1299
- className: "md:max-w-[140px]",
1300
- "aria-label": "Date from"
1301
- }
1302
- ),
1303
- /* @__PURE__ */ jsx(
1304
- Input,
1305
- {
1306
- type: "date",
1307
- placeholder: "To",
1308
- value: dateTo,
1309
- onChange: (e) => setDateTo(e.target.value),
1310
- className: "md:max-w-[140px]",
1311
- "aria-label": "Date to"
1312
- }
1313
- ),
1314
- /* @__PURE__ */ jsx(
1315
- Input,
1316
- {
1317
- placeholder: "Amount min",
1318
- value: amountMin,
1319
- onChange: (e) => setAmountMin(e.target.value),
1320
- type: "number",
1321
- min: 0,
1322
- className: "md:max-w-[100px]",
1323
- "aria-label": "Refund amount minimum"
1324
- }
1325
- ),
1326
- /* @__PURE__ */ jsx(
1327
- Input,
1328
- {
1329
- placeholder: "Amount max",
1330
- value: amountMax,
1331
- onChange: (e) => setAmountMax(e.target.value),
1332
- type: "number",
1333
- min: 0,
1334
- className: "md:max-w-[100px]",
1335
- "aria-label": "Refund amount maximum"
1336
- }
1337
- )
1338
- ] }) }),
1339
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
1340
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
1341
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadRefunds(0, true), children: "Try again" }) })
1342
- ] }) : null,
1343
- 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: [
1344
- /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No refunds yet" }),
1345
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Refund records will appear here." })
1346
- ] }) : /* @__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: [
1347
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
1348
- /* @__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" }),
1349
- /* @__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" }),
1350
- /* @__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" }),
1351
- /* @__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" }),
1352
- /* @__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" }),
1353
- /* @__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" }),
1354
- /* @__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" }),
1355
- /* @__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" }),
1356
- /* @__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" }),
1357
- /* @__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" })
1358
- ] }) }),
1359
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
1360
- "tr",
1361
- {
1362
- className: "cursor-pointer hover:bg-ui-bg-subtle/60",
1363
- onClick: () => navigate(`/refunds/${r.refund_id}`),
1364
- children: [
1365
- /* @__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 }),
1366
- /* @__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 ?? "—" }),
1367
- /* @__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 }),
1368
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
1369
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
1370
- /* @__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 || "—" }),
1371
- /* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
1372
- Badge,
1373
- {
1374
- size: "2xsmall",
1375
- className: `uppercase ${getStatusBadgeClass$6(displayStatus(r))}`,
1376
- children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
1377
- }
1378
- ) }),
1379
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
1380
- /* @__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", {
1381
- month: "short",
1382
- day: "numeric",
1383
- hour: "numeric",
1384
- minute: "2-digit",
1385
- hour12: true
1386
- }) }),
1387
- /* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
1388
- /* @__PURE__ */ jsx(
1389
- Button,
1390
- {
1391
- variant: "transparent",
1392
- size: "small",
1393
- onClick: (e) => {
1394
- e.stopPropagation();
1395
- navigate(`/refunds/${r.refund_id}`);
1396
- },
1397
- children: "Details"
1398
- }
1399
- ),
1400
- r.order_id ? /* @__PURE__ */ jsx(
1401
- Button,
1402
- {
1403
- variant: "transparent",
1404
- size: "small",
1405
- onClick: (e) => {
1406
- e.stopPropagation();
1407
- navigate(`/orders/${r.order_id}`);
1408
- },
1409
- children: "Order"
1410
- }
1411
- ) : null
1412
- ] }) })
1413
- ]
1414
- },
1415
- r.refund_id
1416
- )) })
1417
- ] }) }),
1418
- hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
1419
- Button,
1420
- {
1421
- variant: "secondary",
1422
- isLoading: isFetchingMore,
1423
- onClick: () => loadRefunds(offset, false),
1424
- children: "Load more"
1425
- }
1426
- ) }) : null
1427
- ] }) });
1428
- };
1429
- const config$7 = defineRouteConfig({
1430
- label: "Refunds",
1431
- icon: Receipt
1432
- });
1433
938
  const AUDITED_TABLE_NAMES = [
1434
939
  "account_deletion_request",
1435
940
  "account_holder",
@@ -2721,11 +2226,211 @@ const ErrorState = ({ onRetry, detail }) => /* @__PURE__ */ jsxs("div", { classN
2721
2226
  /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: detail }),
2722
2227
  /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", className: "mt-2", onClick: onRetry, children: "Try again" })
2723
2228
  ] });
2724
- const config$6 = defineRouteConfig({
2229
+ const config$8 = defineRouteConfig({
2725
2230
  label: "Deleted Records",
2726
2231
  icon: Trash
2727
2232
  });
2728
- const useDebounce$1 = (value, delay) => {
2233
+ const useDebounce$3 = (value, delay) => {
2234
+ const [debouncedValue, setDebouncedValue] = useState(value);
2235
+ useEffect(() => {
2236
+ const handler = setTimeout(() => setDebouncedValue(value), delay);
2237
+ return () => clearTimeout(handler);
2238
+ }, [value, delay]);
2239
+ return debouncedValue;
2240
+ };
2241
+ const getStatusBadgeClass$7 = (status) => {
2242
+ const s2 = status.toLowerCase();
2243
+ if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
2244
+ if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
2245
+ if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
2246
+ if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
2247
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
2248
+ };
2249
+ const PaymentsPage = () => {
2250
+ const navigate = useNavigate();
2251
+ const [items, setItems] = useState([]);
2252
+ const [statusFilter, setStatusFilter] = useState("all");
2253
+ const [orderIdSearch, setOrderIdSearch] = useState("");
2254
+ const debouncedOrderId = useDebounce$3(orderIdSearch, 300);
2255
+ const [isLoading, setIsLoading] = useState(true);
2256
+ const [isFetchingMore, setIsFetchingMore] = useState(false);
2257
+ const [error, setError] = useState(null);
2258
+ const [offset, setOffset] = useState(0);
2259
+ const [count, setCount] = useState(0);
2260
+ const limit = 50;
2261
+ const loadTransactions = useCallback(
2262
+ async (nextOffset, replace) => {
2263
+ try {
2264
+ if (replace) setIsLoading(true);
2265
+ else setIsFetchingMore(true);
2266
+ setError(null);
2267
+ const params = new URLSearchParams();
2268
+ params.set("limit", String(limit));
2269
+ params.set("offset", String(nextOffset));
2270
+ if (statusFilter !== "all") params.set("status", statusFilter);
2271
+ if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
2272
+ const response = await fetch(
2273
+ `/admin/payment-transactions?${params.toString()}`,
2274
+ { credentials: "include" }
2275
+ );
2276
+ if (!response.ok) {
2277
+ const text = await response.text();
2278
+ throw new Error(text || "Failed to load payment transactions");
2279
+ }
2280
+ const payload = await response.json();
2281
+ const list = payload.transactions ?? [];
2282
+ setCount(payload.count ?? 0);
2283
+ setOffset(nextOffset + list.length);
2284
+ setItems((prev) => replace ? list : [...prev, ...list]);
2285
+ } catch (e) {
2286
+ setError(e instanceof Error ? e.message : "Failed to load");
2287
+ } finally {
2288
+ setIsLoading(false);
2289
+ setIsFetchingMore(false);
2290
+ }
2291
+ },
2292
+ [statusFilter, debouncedOrderId]
2293
+ );
2294
+ useEffect(() => {
2295
+ void loadTransactions(0, true);
2296
+ }, [loadTransactions]);
2297
+ const hasMore = useMemo(() => offset < count, [offset, count]);
2298
+ const displayStatus = (t) => {
2299
+ const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
2300
+ return s2 !== "" ? s2 : "—";
2301
+ };
2302
+ const displayAmount = (t) => {
2303
+ const code = (t.currency_code ?? "USD").toUpperCase();
2304
+ return `${code} ${Number(t.amount)}`;
2305
+ };
2306
+ 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: [
2307
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
2308
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2309
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
2310
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
2311
+ ] }),
2312
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
2313
+ ] }),
2314
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
2315
+ /* @__PURE__ */ jsx(
2316
+ Input,
2317
+ {
2318
+ placeholder: "Search by Order ID",
2319
+ value: orderIdSearch,
2320
+ onChange: (e) => setOrderIdSearch(e.target.value),
2321
+ className: "md:max-w-sm",
2322
+ "aria-label": "Search by order ID"
2323
+ }
2324
+ ),
2325
+ /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
2326
+ "select",
2327
+ {
2328
+ value: statusFilter,
2329
+ onChange: (e) => setStatusFilter(e.target.value),
2330
+ 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",
2331
+ "aria-label": "Filter by status",
2332
+ children: [
2333
+ /* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
2334
+ /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
2335
+ /* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
2336
+ /* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
2337
+ /* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
2338
+ /* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
2339
+ /* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
2340
+ ]
2341
+ }
2342
+ ) })
2343
+ ] }),
2344
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2345
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2346
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
2347
+ ] }) : null,
2348
+ 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: [
2349
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
2350
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
2351
+ ] }) : /* @__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: [
2352
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2353
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
2354
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
2355
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
2356
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
2357
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
2358
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
2359
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
2360
+ ] }) }),
2361
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
2362
+ "tr",
2363
+ {
2364
+ className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
2365
+ onClick: () => navigate(`/payments/${t.payment_session_id}`),
2366
+ children: [
2367
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
2368
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
2369
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
2370
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
2371
+ Badge,
2372
+ {
2373
+ size: "2xsmall",
2374
+ className: `uppercase ${getStatusBadgeClass$7(displayStatus(t))}`,
2375
+ children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
2376
+ }
2377
+ ) }),
2378
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
2379
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
2380
+ year: "numeric",
2381
+ month: "short",
2382
+ day: "numeric",
2383
+ hour: "numeric",
2384
+ minute: "2-digit",
2385
+ hour12: true
2386
+ }) }),
2387
+ /* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
2388
+ /* @__PURE__ */ jsx(
2389
+ Button,
2390
+ {
2391
+ variant: "transparent",
2392
+ size: "small",
2393
+ onClick: (e) => {
2394
+ e.stopPropagation();
2395
+ navigate(`/payments/${t.payment_session_id}`);
2396
+ },
2397
+ children: "View details"
2398
+ }
2399
+ ),
2400
+ t.order_id ? /* @__PURE__ */ jsx(
2401
+ Button,
2402
+ {
2403
+ variant: "transparent",
2404
+ size: "small",
2405
+ onClick: (e) => {
2406
+ e.stopPropagation();
2407
+ navigate(`/orders/${t.order_id}`);
2408
+ },
2409
+ children: "Order"
2410
+ }
2411
+ ) : null
2412
+ ] })
2413
+ ]
2414
+ },
2415
+ t.payment_session_id
2416
+ )) })
2417
+ ] }) }),
2418
+ hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
2419
+ Button,
2420
+ {
2421
+ variant: "secondary",
2422
+ isLoading: isFetchingMore,
2423
+ onClick: () => loadTransactions(offset, false),
2424
+ children: "Load more"
2425
+ }
2426
+ ) }) : null
2427
+ ] }) });
2428
+ };
2429
+ const config$7 = defineRouteConfig({
2430
+ label: "Payments",
2431
+ icon: CreditCard
2432
+ });
2433
+ const useDebounce$2 = (value, delay) => {
2729
2434
  const [debouncedValue, setDebouncedValue] = useState(value);
2730
2435
  useEffect(() => {
2731
2436
  const handler = setTimeout(() => setDebouncedValue(value), delay);
@@ -2733,7 +2438,7 @@ const useDebounce$1 = (value, delay) => {
2733
2438
  }, [value, delay]);
2734
2439
  return debouncedValue;
2735
2440
  };
2736
- const getStatusBadgeClass$5 = (status) => {
2441
+ const getStatusBadgeClass$6 = (status) => {
2737
2442
  const statusLower = status.toLowerCase();
2738
2443
  if (statusLower === "requested") {
2739
2444
  return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
@@ -2758,7 +2463,7 @@ const ReturnsPage = () => {
2758
2463
  const [statusFilter, setStatusFilter] = useState("all");
2759
2464
  const [createdByFilter, setCreatedByFilter] = useState("all");
2760
2465
  const [searchQuery, setSearchQuery] = useState("");
2761
- const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
2466
+ const debouncedSearchQuery = useDebounce$2(searchQuery, 300);
2762
2467
  const [isLoading, setIsLoading] = useState(true);
2763
2468
  const [isFetchingMore, setIsFetchingMore] = useState(false);
2764
2469
  const [error, setError] = useState(null);
@@ -2866,1392 +2571,1774 @@ const ReturnsPage = () => {
2866
2571
  }
2867
2572
  )
2868
2573
  ] })
2869
- ] }),
2870
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2871
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2872
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
2873
- Button,
2874
- {
2875
- variant: "secondary",
2876
- onClick: () => loadReturns(0, true),
2877
- children: "Try again"
2878
- }
2879
- ) })
2880
- ] }) : null,
2881
- 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: [
2882
- /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
2883
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
2884
- ] }) : /* @__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: [
2885
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2886
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
2887
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
2888
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
2889
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
2890
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
2891
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
2892
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
2893
- ] }) }),
2894
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
2895
- "tr",
2896
- {
2897
- className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
2898
- onClick: () => navigate(`/returns/${returnOrder.id}`),
2899
- children: [
2900
- /* @__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 }) }) }),
2901
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
2902
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
2903
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
2904
- Badge,
2905
- {
2906
- size: "2xsmall",
2907
- className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
2908
- children: returnOrder.status.replace(/_/g, " ")
2909
- }
2910
- ) }),
2911
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
2912
- const calc = returnOrder.refund;
2913
- if ((calc == null ? void 0 : calc.is_processed) && calc.final_refund_amount != null) {
2914
- return formatRefundCurrency(
2915
- calc.final_refund_amount,
2916
- calc.currency_code || returnOrder.currency_code
2917
- );
2918
- }
2919
- if (calc) {
2920
- return "Pending";
2921
- }
2922
- if (returnOrder.refund_amount == null) {
2923
- return "—";
2924
- }
2925
- return formatRefundCurrency(
2926
- Number(returnOrder.refund_amount),
2927
- returnOrder.currency_code
2928
- );
2929
- })() }),
2930
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
2931
- year: "numeric",
2932
- month: "short",
2933
- day: "numeric",
2934
- hour: "numeric",
2935
- minute: "2-digit",
2936
- hour12: true
2937
- }) }),
2938
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
2939
- Button,
2940
- {
2941
- variant: "transparent",
2942
- size: "small",
2943
- onClick: (e) => {
2944
- e.stopPropagation();
2945
- navigate(`/app/orders/${returnOrder.order_id}`);
2946
- },
2947
- children: "Go to order"
2948
- }
2949
- ) })
2950
- ]
2951
- },
2952
- returnOrder.id
2953
- )) })
2954
- ] }) }),
2955
- hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
2956
- Button,
2574
+ ] }),
2575
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2576
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2577
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
2578
+ Button,
2579
+ {
2580
+ variant: "secondary",
2581
+ onClick: () => loadReturns(0, true),
2582
+ children: "Try again"
2583
+ }
2584
+ ) })
2585
+ ] }) : null,
2586
+ 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: [
2587
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
2588
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
2589
+ ] }) : /* @__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: [
2590
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2591
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
2592
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
2593
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
2594
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
2595
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
2596
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
2597
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
2598
+ ] }) }),
2599
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
2600
+ "tr",
2601
+ {
2602
+ className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
2603
+ onClick: () => navigate(`/returns/${returnOrder.id}`),
2604
+ children: [
2605
+ /* @__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 }) }) }),
2606
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
2607
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
2608
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
2609
+ Badge,
2610
+ {
2611
+ size: "2xsmall",
2612
+ className: `uppercase ${getStatusBadgeClass$6(returnOrder.status)}`,
2613
+ children: returnOrder.status.replace(/_/g, " ")
2614
+ }
2615
+ ) }),
2616
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
2617
+ const calc = returnOrder.refund;
2618
+ if ((calc == null ? void 0 : calc.is_processed) && calc.final_refund_amount != null) {
2619
+ return formatRefundCurrency(
2620
+ calc.final_refund_amount,
2621
+ calc.currency_code || returnOrder.currency_code
2622
+ );
2623
+ }
2624
+ if (calc) {
2625
+ return "Pending";
2626
+ }
2627
+ if (returnOrder.refund_amount == null) {
2628
+ return "—";
2629
+ }
2630
+ return formatRefundCurrency(
2631
+ Number(returnOrder.refund_amount),
2632
+ returnOrder.currency_code
2633
+ );
2634
+ })() }),
2635
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
2636
+ year: "numeric",
2637
+ month: "short",
2638
+ day: "numeric",
2639
+ hour: "numeric",
2640
+ minute: "2-digit",
2641
+ hour12: true
2642
+ }) }),
2643
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
2644
+ Button,
2645
+ {
2646
+ variant: "transparent",
2647
+ size: "small",
2648
+ onClick: (e) => {
2649
+ e.stopPropagation();
2650
+ navigate(`/app/orders/${returnOrder.order_id}`);
2651
+ },
2652
+ children: "Go to order"
2653
+ }
2654
+ ) })
2655
+ ]
2656
+ },
2657
+ returnOrder.id
2658
+ )) })
2659
+ ] }) }),
2660
+ hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
2661
+ Button,
2662
+ {
2663
+ variant: "secondary",
2664
+ isLoading: isFetchingMore,
2665
+ onClick: () => loadReturns(offset, false),
2666
+ children: "Load more"
2667
+ }
2668
+ ) }) : null
2669
+ ] }) });
2670
+ };
2671
+ const config$6 = defineRouteConfig({
2672
+ label: "Return Orders",
2673
+ icon: ArrowPath
2674
+ });
2675
+ const MASKED_VALUE = "••••••••••••";
2676
+ const SENSITIVE_KEY_PATTERNS = [
2677
+ /password|passwd|passphrase/i,
2678
+ /secret/i,
2679
+ /token/i,
2680
+ /api_?key$/i,
2681
+ /private_?key/i,
2682
+ /access_?key/i,
2683
+ /(^|_)hash(ed)?($|_)/i,
2684
+ /(^|_)salt$/i,
2685
+ /^cvv$|^cvc$|security_code/i,
2686
+ /card_?number/i,
2687
+ /account_?number/i,
2688
+ /credential/i,
2689
+ /authorization/i,
2690
+ /recovery_?code/i,
2691
+ /(^|_)otp($|_)/i,
2692
+ /verification_?code/i,
2693
+ /^code_hash$/i,
2694
+ /webhook_?signature/i
2695
+ ];
2696
+ const TABLE_SENSITIVE_KEYS = {
2697
+ otp_verification: /* @__PURE__ */ new Set(["code", "value"]),
2698
+ auth_verification: /* @__PURE__ */ new Set(["code", "value"]),
2699
+ auth_mfa_factor: /* @__PURE__ */ new Set(["value", "config"])
2700
+ };
2701
+ const SAFE_KEYS = /* @__PURE__ */ new Set([
2702
+ "token_type",
2703
+ "redacted",
2704
+ "api_key_id",
2705
+ "token_id",
2706
+ "notification_token_id"
2707
+ ]);
2708
+ function isSensitiveKey(key) {
2709
+ const normalized = key.trim().toLowerCase();
2710
+ if (SAFE_KEYS.has(normalized)) return false;
2711
+ return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(normalized));
2712
+ }
2713
+ const FULLY_SECRET_TABLES = /* @__PURE__ */ new Set(["auth_mfa_recovery_code", "auth_password_reset_token"]);
2714
+ const ALWAYS_VISIBLE_KEYS = /* @__PURE__ */ new Set(["id", "created_at", "updated_at", "deleted_at", "expires_at", "used_at"]);
2715
+ function maskValue(value, ctx, depth) {
2716
+ var _a;
2717
+ if (Array.isArray(value)) return value.map((item) => maskValue(item, ctx, depth + 1));
2718
+ if (value !== null && typeof value === "object") {
2719
+ const out = {};
2720
+ for (const [key, inner] of Object.entries(value)) {
2721
+ const topLevel = depth === 0;
2722
+ const secret = inner !== null && inner !== void 0 && inner !== "" && (isSensitiveKey(key) || topLevel && ((_a = ctx.tableKeys) == null ? void 0 : _a.has(key.toLowerCase())) === true || topLevel && ctx.maskAll && !ALWAYS_VISIBLE_KEYS.has(key) && !key.endsWith("_id"));
2723
+ if (secret) {
2724
+ ctx.count += 1;
2725
+ out[key] = MASKED_VALUE;
2726
+ } else {
2727
+ out[key] = maskValue(inner, ctx, depth + 1);
2728
+ }
2729
+ }
2730
+ return out;
2731
+ }
2732
+ return value;
2733
+ }
2734
+ function maskSensitiveData(data, tableName) {
2735
+ const ctx = {
2736
+ count: 0,
2737
+ maskAll: tableName ? FULLY_SECRET_TABLES.has(tableName) : false,
2738
+ tableKeys: tableName ? TABLE_SENSITIVE_KEYS[tableName] : void 0
2739
+ };
2740
+ const value = maskValue(data, ctx, 0);
2741
+ return { value, maskedCount: ctx.count };
2742
+ }
2743
+ const AUTO_EXPAND_DEPTH = 1;
2744
+ const LONG_STRING = 200;
2745
+ const JsonViewer = ({ data }) => {
2746
+ const [generation, setGeneration] = useState(0);
2747
+ const [expandAll, setExpandAll] = useState(null);
2748
+ const setAll = (value) => {
2749
+ setExpandAll(value);
2750
+ setGeneration((g) => g + 1);
2751
+ };
2752
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2753
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2754
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => setAll(true), children: "Expand all" }),
2755
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => setAll(false), children: "Collapse all" })
2756
+ ] }),
2757
+ /* @__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) })
2758
+ ] });
2759
+ };
2760
+ const JsonNode = ({ name, value, depth, forceExpand }) => {
2761
+ const isContainer = value !== null && typeof value === "object";
2762
+ const [open, setOpen] = useState(forceExpand ?? depth < AUTO_EXPAND_DEPTH);
2763
+ const label = name !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-ui-fg-subtle", children: [
2764
+ name,
2765
+ /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: ": " })
2766
+ ] }) : null;
2767
+ if (!isContainer) {
2768
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start", style: { paddingLeft: depth ? 16 : 0 }, children: [
2769
+ /* @__PURE__ */ jsx("span", { className: "w-4 shrink-0" }),
2770
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 break-words [overflow-wrap:anywhere]", children: [
2771
+ label,
2772
+ /* @__PURE__ */ jsx(Primitive, { value })
2773
+ ] })
2774
+ ] });
2775
+ }
2776
+ const entries = Array.isArray(value) ? value.map((v, i) => [String(i), v]) : Object.entries(value);
2777
+ const [openBracket, closeBracket] = Array.isArray(value) ? ["[", "]"] : ["{", "}"];
2778
+ const summary = Array.isArray(value) ? `${entries.length} items` : `${entries.length} keys`;
2779
+ return /* @__PURE__ */ jsxs("div", { style: { paddingLeft: depth ? 16 : 0 }, children: [
2780
+ /* @__PURE__ */ jsxs(
2781
+ "button",
2957
2782
  {
2958
- variant: "secondary",
2959
- isLoading: isFetchingMore,
2960
- onClick: () => loadReturns(offset, false),
2961
- children: "Load more"
2783
+ type: "button",
2784
+ onClick: () => setOpen((o) => !o),
2785
+ className: "flex items-start text-left hover:bg-ui-bg-base-hover",
2786
+ "aria-expanded": open,
2787
+ children: [
2788
+ /* @__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 }),
2789
+ /* @__PURE__ */ jsxs("span", { children: [
2790
+ label,
2791
+ /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: openBracket }),
2792
+ !open || entries.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2793
+ entries.length ? /* @__PURE__ */ jsx("span", { className: "px-1 italic text-ui-fg-muted", children: summary }) : null,
2794
+ /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: closeBracket })
2795
+ ] }) : null
2796
+ ] })
2797
+ ]
2962
2798
  }
2963
- ) }) : null
2964
- ] }) });
2799
+ ),
2800
+ open && entries.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
2801
+ entries.map(([key, child]) => /* @__PURE__ */ jsx(JsonNode, { name: key, value: child, depth: depth + 1, forceExpand }, key)),
2802
+ /* @__PURE__ */ jsx("div", { style: { paddingLeft: 16 }, className: "text-ui-fg-muted", children: closeBracket })
2803
+ ] }) : null
2804
+ ] });
2965
2805
  };
2966
- const config$5 = defineRouteConfig({
2967
- label: "Return Orders",
2968
- icon: ArrowPath
2969
- });
2970
- const useDebounce = (value, delay) => {
2971
- const [debouncedValue, setDebouncedValue] = useState(value);
2972
- useEffect(() => {
2973
- const handler = setTimeout(() => setDebouncedValue(value), delay);
2974
- return () => clearTimeout(handler);
2975
- }, [value, delay]);
2976
- return debouncedValue;
2806
+ const Primitive = ({ value }) => {
2807
+ const [showFull, setShowFull] = useState(false);
2808
+ if (value === MASKED_VALUE) {
2809
+ 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 });
2810
+ }
2811
+ if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "null" });
2812
+ if (typeof value === "boolean") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-purple-text", children: String(value) });
2813
+ if (typeof value === "number") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-blue-text", children: value });
2814
+ const text = String(value);
2815
+ const truncated = !showFull && text.length > LONG_STRING;
2816
+ return /* @__PURE__ */ jsxs("span", { className: clx("text-ui-tag-green-text"), children: [
2817
+ '"',
2818
+ truncated ? `${text.slice(0, LONG_STRING)}…` : text,
2819
+ '"',
2820
+ text.length > LONG_STRING ? /* @__PURE__ */ jsx(
2821
+ "button",
2822
+ {
2823
+ type: "button",
2824
+ onClick: () => setShowFull((s2) => !s2),
2825
+ className: "ml-1 font-sans text-ui-fg-interactive hover:underline",
2826
+ children: showFull ? "show less" : `show all (${text.length} chars)`
2827
+ }
2828
+ ) : null
2829
+ ] });
2830
+ };
2831
+ const GUIDANCE = {
2832
+ orders: {
2833
+ headline: "Order data affects customers, payments and reports.",
2834
+ 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.",
2835
+ adminSection: { label: "Go to Orders", path: "/orders" }
2836
+ },
2837
+ carts: {
2838
+ headline: "Carts are usually cleaned up automatically.",
2839
+ recreate: "No action is normally needed. Customers can simply add items to a new cart."
2840
+ },
2841
+ customers: {
2842
+ headline: "Customer data may be needed for orders, support and compliance.",
2843
+ 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.",
2844
+ adminSection: { label: "Go to Customers", path: "/customers" }
2845
+ },
2846
+ catalog: {
2847
+ headline: "Catalog changes affect what customers can see and buy.",
2848
+ recreate: "If it was deleted by mistake, recreate it from Products using the values shown above. It will get a new ID.",
2849
+ adminSection: { label: "Go to Products", path: "/products" }
2850
+ },
2851
+ pricing: {
2852
+ headline: "Pricing and promotions affect what customers pay.",
2853
+ recreate: "If it was deleted by mistake, recreate it from Promotions or Price Lists using the values shown above.",
2854
+ adminSection: { label: "Go to Promotions", path: "/promotions" }
2855
+ },
2856
+ payments: {
2857
+ headline: "Payment records are financial data.",
2858
+ 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."
2859
+ },
2860
+ fulfillment: {
2861
+ headline: "Shipping and fulfillment settings affect checkout and delivery.",
2862
+ recreate: "If it was deleted by mistake, recreate it from Settings → Locations & Shipping using the values shown above.",
2863
+ adminSection: { label: "Go to Settings", path: "/settings" }
2864
+ },
2865
+ inventory: {
2866
+ headline: "Inventory changes can affect stock levels and availability.",
2867
+ recreate: "If it was deleted by mistake, recreate it from Inventory using the values shown above and re-check stock quantities.",
2868
+ adminSection: { label: "Go to Inventory", path: "/inventory" }
2869
+ },
2870
+ wallet: {
2871
+ headline: "Wallet and credit records are financial data.",
2872
+ 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."
2873
+ },
2874
+ access: {
2875
+ headline: "Access records control who can sign in.",
2876
+ 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.",
2877
+ adminSection: { label: "Go to Settings", path: "/settings" }
2878
+ },
2879
+ store: {
2880
+ headline: "Store settings affect regions, currencies and taxes.",
2881
+ recreate: "If it was deleted by mistake, recreate it from Settings using the values shown above.",
2882
+ adminSection: { label: "Go to Settings", path: "/settings" }
2883
+ },
2884
+ engagement: {
2885
+ headline: "Customer-generated content.",
2886
+ 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."
2887
+ },
2888
+ notifications: {
2889
+ headline: "Notification records are usually cleaned up automatically.",
2890
+ recreate: "No action is normally needed."
2891
+ },
2892
+ system: {
2893
+ headline: "Internal system data, usually removed automatically by the platform.",
2894
+ recreate: "No action is normally needed. If you suspect a problem, share this page with a developer."
2895
+ }
2896
+ };
2897
+ function getNextSteps(category) {
2898
+ return GUIDANCE[category];
2899
+ }
2900
+ const RELATED_LINKS = [
2901
+ { key: "order_id", label: "Order", path: (id) => `/orders/${id}`, selfTables: ["order"] },
2902
+ { key: "customer_id", label: "Customer", path: (id) => `/customers/${id}`, selfTables: ["customer"] },
2903
+ { key: "product_id", label: "Product", path: (id) => `/products/${id}`, selfTables: ["product"] }
2904
+ ];
2905
+ function getRelatedLinks(tableName, oldData) {
2906
+ if (!oldData) return [];
2907
+ return RELATED_LINKS.flatMap((link) => {
2908
+ const id = oldData[link.key];
2909
+ if (link.selfTables.includes(tableName) || typeof id !== "string" || !id.trim()) return [];
2910
+ return [{ label: link.label, id, path: link.path(id) }];
2911
+ });
2912
+ }
2913
+ const fullName = (row) => {
2914
+ const parts = [row.first_name, row.last_name].filter(
2915
+ (part) => typeof part === "string" && part.trim() !== ""
2916
+ );
2917
+ return parts.length ? parts.join(" ") : void 0;
2918
+ };
2919
+ const addressLine = (row) => {
2920
+ 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());
2921
+ return parts.length ? parts.join(", ") : void 0;
2922
+ };
2923
+ const NAME = { key: "name", label: "Name", derive: fullName };
2924
+ const ADDRESS = { key: "address", label: "Address", derive: addressLine };
2925
+ const CREATED = { key: "created_at", label: "Created", kind: "date" };
2926
+ const ENTITY_FIELDS = {
2927
+ order: [
2928
+ { key: "display_id", label: "Order number" },
2929
+ { key: "status", label: "Status", kind: "status" },
2930
+ { key: "email", label: "Customer email" },
2931
+ { key: "customer_id", label: "Customer ID", kind: "id" },
2932
+ { key: "currency_code", label: "Currency" },
2933
+ { key: "region_id", label: "Region ID", kind: "id" },
2934
+ { key: "sales_channel_id", label: "Sales channel ID", kind: "id" },
2935
+ { key: "canceled_at", label: "Canceled", kind: "date" },
2936
+ CREATED
2937
+ ],
2938
+ order_line_item: [
2939
+ { key: "title", label: "Item" },
2940
+ { key: "variant_title", label: "Variant" },
2941
+ { key: "variant_sku", label: "SKU" },
2942
+ { key: "unit_price", label: "Unit price", kind: "money" },
2943
+ { key: "product_id", label: "Product ID", kind: "id" },
2944
+ { key: "variant_id", label: "Variant ID", kind: "id" },
2945
+ CREATED
2946
+ ],
2947
+ cart_line_item: [
2948
+ { key: "title", label: "Item" },
2949
+ { key: "variant_sku", label: "SKU" },
2950
+ { key: "quantity", label: "Quantity", kind: "number" },
2951
+ { key: "unit_price", label: "Unit price", kind: "money" },
2952
+ { key: "cart_id", label: "Cart ID", kind: "id" },
2953
+ { key: "variant_id", label: "Variant ID", kind: "id" },
2954
+ CREATED
2955
+ ],
2956
+ cart: [
2957
+ { key: "email", label: "Email" },
2958
+ { key: "customer_id", label: "Customer ID", kind: "id" },
2959
+ { key: "currency_code", label: "Currency" },
2960
+ { key: "region_id", label: "Region ID", kind: "id" },
2961
+ { key: "completed_at", label: "Completed", kind: "date" },
2962
+ CREATED
2963
+ ],
2964
+ customer: [
2965
+ NAME,
2966
+ { key: "email", label: "Email" },
2967
+ { key: "phone", label: "Phone" },
2968
+ { key: "company_name", label: "Company" },
2969
+ { key: "has_account", label: "Registered account", kind: "boolean" },
2970
+ CREATED
2971
+ ],
2972
+ customer_address: [
2973
+ { key: "address_name", label: "Label" },
2974
+ NAME,
2975
+ ADDRESS,
2976
+ { key: "phone", label: "Phone" },
2977
+ { key: "customer_id", label: "Customer ID", kind: "id" },
2978
+ { key: "is_default_shipping", label: "Default shipping", kind: "boolean" },
2979
+ CREATED
2980
+ ],
2981
+ order_address: [NAME, ADDRESS, { key: "phone", label: "Phone" }, CREATED],
2982
+ cart_address: [NAME, ADDRESS, { key: "phone", label: "Phone" }, CREATED],
2983
+ product: [
2984
+ { key: "title", label: "Title" },
2985
+ { key: "status", label: "Status", kind: "status" },
2986
+ { key: "handle", label: "Handle" },
2987
+ { key: "subtitle", label: "Subtitle" },
2988
+ { key: "collection_id", label: "Collection ID", kind: "id" },
2989
+ { key: "is_giftcard", label: "Gift card", kind: "boolean" },
2990
+ CREATED
2991
+ ],
2992
+ product_variant: [
2993
+ { key: "title", label: "Title" },
2994
+ { key: "sku", label: "SKU" },
2995
+ { key: "barcode", label: "Barcode" },
2996
+ { key: "product_id", label: "Product ID", kind: "id" },
2997
+ { key: "manage_inventory", label: "Manages inventory", kind: "boolean" },
2998
+ CREATED
2999
+ ],
3000
+ product_category: [
3001
+ { key: "name", label: "Name" },
3002
+ { key: "handle", label: "Handle" },
3003
+ { key: "is_active", label: "Active", kind: "boolean" },
3004
+ { key: "parent_category_id", label: "Parent category ID", kind: "id" },
3005
+ CREATED
3006
+ ],
3007
+ product_collection: [{ key: "title", label: "Title" }, { key: "handle", label: "Handle" }, CREATED],
3008
+ payment: [
3009
+ { key: "amount", label: "Amount", kind: "money" },
3010
+ { key: "currency_code", label: "Currency" },
3011
+ { key: "provider_id", label: "Provider" },
3012
+ { key: "captured_at", label: "Captured", kind: "date" },
3013
+ { key: "canceled_at", label: "Canceled", kind: "date" },
3014
+ { key: "payment_collection_id", label: "Payment collection ID", kind: "id" },
3015
+ CREATED
3016
+ ],
3017
+ payment_session: [
3018
+ { key: "amount", label: "Amount", kind: "money" },
3019
+ { key: "currency_code", label: "Currency" },
3020
+ { key: "provider_id", label: "Provider" },
3021
+ { key: "status", label: "Status", kind: "status" },
3022
+ { key: "payment_collection_id", label: "Payment collection ID", kind: "id" },
3023
+ CREATED
3024
+ ],
3025
+ payment_collection: [
3026
+ { key: "amount", label: "Amount", kind: "money" },
3027
+ { key: "currency_code", label: "Currency" },
3028
+ { key: "status", label: "Status", kind: "status" },
3029
+ CREATED
3030
+ ],
3031
+ refund: [
3032
+ { key: "amount", label: "Amount", kind: "money" },
3033
+ { key: "payment_id", label: "Payment ID", kind: "id" },
3034
+ { key: "refund_reason_id", label: "Refund reason ID", kind: "id" },
3035
+ { key: "note", label: "Note" },
3036
+ { key: "created_by", label: "Created by" },
3037
+ CREATED
3038
+ ],
3039
+ return: [
3040
+ { key: "display_id", label: "Return number" },
3041
+ { key: "status", label: "Status", kind: "status" },
3042
+ { key: "order_id", label: "Order ID", kind: "id" },
3043
+ { key: "refund_amount", label: "Refund amount", kind: "money" },
3044
+ { key: "received_at", label: "Received", kind: "date" },
3045
+ CREATED
3046
+ ],
3047
+ payment_detail: [
3048
+ { key: "type", label: "Method type" },
3049
+ { key: "customer_id", label: "Customer ID", kind: "id" },
3050
+ { key: "is_default", label: "Default method", kind: "boolean" },
3051
+ CREATED
3052
+ ],
3053
+ user: [NAME, { key: "email", label: "Email" }, CREATED],
3054
+ invite: [
3055
+ { key: "email", label: "Email" },
3056
+ { key: "accepted", label: "Accepted", kind: "boolean" },
3057
+ { key: "expires_at", label: "Expires", kind: "date" },
3058
+ CREATED
3059
+ ],
3060
+ api_key: [
3061
+ { key: "title", label: "Title" },
3062
+ { key: "type", label: "Type" },
3063
+ { key: "redacted", label: "Key (redacted)" },
3064
+ { key: "revoked_at", label: "Revoked", kind: "date" },
3065
+ CREATED
3066
+ ],
3067
+ promotion: [
3068
+ { key: "code", label: "Promotion code" },
3069
+ { key: "type", label: "Type" },
3070
+ { key: "status", label: "Status", kind: "status" },
3071
+ { key: "is_automatic", label: "Automatic", kind: "boolean" },
3072
+ CREATED
3073
+ ],
3074
+ fulfillment: [
3075
+ { key: "provider_id", label: "Provider" },
3076
+ { key: "location_id", label: "Location ID", kind: "id" },
3077
+ { key: "shipped_at", label: "Shipped", kind: "date" },
3078
+ { key: "delivered_at", label: "Delivered", kind: "date" },
3079
+ { key: "canceled_at", label: "Canceled", kind: "date" },
3080
+ CREATED
3081
+ ],
3082
+ inventory_item: [
3083
+ { key: "sku", label: "SKU" },
3084
+ { key: "title", label: "Title" },
3085
+ { key: "requires_shipping", label: "Requires shipping", kind: "boolean" },
3086
+ CREATED
3087
+ ],
3088
+ inventory_level: [
3089
+ { key: "inventory_item_id", label: "Inventory item ID", kind: "id" },
3090
+ { key: "location_id", label: "Location ID", kind: "id" },
3091
+ { key: "stocked_quantity", label: "Stocked", kind: "number" },
3092
+ { key: "reserved_quantity", label: "Reserved", kind: "number" },
3093
+ CREATED
3094
+ ],
3095
+ review: [
3096
+ { key: "title", label: "Title" },
3097
+ { key: "rating", label: "Rating", kind: "number" },
3098
+ { key: "status", label: "Status", kind: "status" },
3099
+ { key: "product_id", label: "Product ID", kind: "id" },
3100
+ { key: "customer_id", label: "Customer ID", kind: "id" },
3101
+ CREATED
3102
+ ]
2977
3103
  };
2978
- const getStatusBadgeClass$4 = (status) => {
2979
- const statusLower = status.toLowerCase();
2980
- if (statusLower === "requested") {
2981
- return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
2982
- }
2983
- if (statusLower === "approved") {
2984
- return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3104
+ const GENERIC_FIELDS = [
3105
+ { key: "display_id", label: "Number" },
3106
+ { key: "title", label: "Title" },
3107
+ { key: "name", label: "Name" },
3108
+ NAME,
3109
+ { key: "email", label: "Email" },
3110
+ { key: "phone", label: "Phone" },
3111
+ { key: "handle", label: "Handle" },
3112
+ { key: "sku", label: "SKU" },
3113
+ { key: "code", label: "Code" },
3114
+ { key: "status", label: "Status", kind: "status" },
3115
+ { key: "type", label: "Type" },
3116
+ { key: "amount", label: "Amount", kind: "money" },
3117
+ { key: "quantity", label: "Quantity", kind: "number" },
3118
+ { key: "currency_code", label: "Currency" },
3119
+ { key: "order_id", label: "Order ID", kind: "id" },
3120
+ { key: "customer_id", label: "Customer ID", kind: "id" },
3121
+ { key: "product_id", label: "Product ID", kind: "id" },
3122
+ { key: "payment_id", label: "Payment ID", kind: "id" },
3123
+ { key: "provider_id", label: "Provider" },
3124
+ CREATED,
3125
+ { key: "updated_at", label: "Last updated", kind: "date" }
3126
+ ];
3127
+ const MAX_GENERIC_FIELDS = 8;
3128
+ function amountOf(value) {
3129
+ if (typeof value === "number" && Number.isFinite(value)) return value;
3130
+ if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
3131
+ if (value !== null && typeof value === "object" && "value" in value) {
3132
+ return amountOf(value.value);
2985
3133
  }
2986
- if (statusLower === "rejected") {
2987
- return "bg-ui-tag-red-bg text-ui-tag-red-text";
3134
+ return null;
3135
+ }
3136
+ function formatValue(raw, kind, row) {
3137
+ if (raw === null || raw === void 0 || raw === "") return null;
3138
+ if (raw === MASKED_VALUE) return { value: MASKED_VALUE, kind: "masked" };
3139
+ switch (kind) {
3140
+ case "money": {
3141
+ const amount = amountOf(raw);
3142
+ if (amount === null) return null;
3143
+ const currency = typeof row.currency_code === "string" ? row.currency_code : null;
3144
+ return { value: formatMoney(amount, currency), kind };
3145
+ }
3146
+ case "date":
3147
+ return typeof raw === "string" || raw instanceof Date ? { value: formatDate(raw), kind } : null;
3148
+ case "boolean":
3149
+ return { value: raw === true || raw === "true" ? "Yes" : "No", kind };
3150
+ case "number": {
3151
+ const n = amountOf(raw);
3152
+ return n === null ? null : { value: formatNumber(n), kind };
3153
+ }
3154
+ case "status":
3155
+ return { value: String(raw).replace(/_/g, " "), kind };
3156
+ default:
3157
+ if (typeof raw === "object") return null;
3158
+ if (typeof raw === "string" && raw.length > 160) return { value: `${raw.slice(0, 157)}…`, kind };
3159
+ return { value: String(raw), kind };
2988
3160
  }
2989
- if (statusLower === "completed") {
2990
- return "bg-ui-tag-green-bg text-ui-tag-green-text";
3161
+ }
3162
+ function summarizeOldData(tableName, oldData) {
3163
+ if (!oldData) return [];
3164
+ const { value: row } = maskSensitiveData(oldData, tableName);
3165
+ const specific = ENTITY_FIELDS[tableName];
3166
+ const specs = specific ?? GENERIC_FIELDS;
3167
+ const fields = [];
3168
+ const seenLabels = /* @__PURE__ */ new Set();
3169
+ for (const spec of specs) {
3170
+ const raw = spec.derive ? spec.derive(row) : row[spec.key];
3171
+ const formatted = formatValue(raw, spec.kind ?? "text", row);
3172
+ if (!formatted || seenLabels.has(spec.label)) continue;
3173
+ seenLabels.add(spec.label);
3174
+ const value = spec.key === "currency_code" ? formatted.value.toUpperCase() : formatted.value;
3175
+ fields.push({ key: spec.key, label: spec.label, value, kind: formatted.kind });
3176
+ if (!specific && fields.length >= MAX_GENERIC_FIELDS) break;
2991
3177
  }
2992
- if (statusLower === "cancelled") {
2993
- return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
3178
+ return fields;
3179
+ }
3180
+ function readLastListSearch() {
3181
+ try {
3182
+ return window.sessionStorage.getItem(LAST_LIST_URL_KEY) ?? "";
3183
+ } catch {
3184
+ return "";
2994
3185
  }
2995
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
2996
- };
2997
- const SwapsPage = () => {
2998
- const navigate = useNavigate();
2999
- const [items, setItems] = useState([]);
3000
- const [statusFilter, setStatusFilter] = useState("all");
3001
- const [createdByFilter, setCreatedByFilter] = useState("all");
3002
- const [searchQuery, setSearchQuery] = useState("");
3003
- const debouncedSearchQuery = useDebounce(searchQuery, 300);
3004
- const [isLoading, setIsLoading] = useState(true);
3005
- const [isFetchingMore, setIsFetchingMore] = useState(false);
3006
- const [error, setError] = useState(null);
3007
- const [offset, setOffset] = useState(0);
3008
- const [count, setCount] = useState(0);
3009
- const limit = 50;
3010
- const loadSwaps = useCallback(
3011
- async (nextOffset, replace = false) => {
3012
- var _a;
3013
- try {
3014
- if (replace) {
3015
- setIsLoading(true);
3016
- } else {
3017
- setIsFetchingMore(true);
3018
- }
3019
- setError(null);
3020
- const params = new URLSearchParams();
3021
- params.set("limit", String(limit));
3022
- params.set("offset", String(nextOffset));
3023
- if (statusFilter !== "all") {
3024
- params.set("status", statusFilter);
3025
- }
3026
- if (debouncedSearchQuery.trim()) {
3027
- params.set("order_id", debouncedSearchQuery.trim());
3028
- }
3029
- if (createdByFilter !== "all") {
3030
- params.set("created_by", createdByFilter);
3031
- }
3032
- const response = await fetch(
3033
- `/admin/swaps?${params.toString()}`,
3034
- { credentials: "include" }
3035
- );
3036
- if (!response.ok) {
3037
- const message = await response.text();
3038
- throw new Error(message || "Unable to load swaps");
3039
- }
3040
- const payload = await response.json();
3041
- setCount(payload.count ?? 0);
3042
- setOffset(nextOffset + (((_a = payload.swaps) == null ? void 0 : _a.length) ?? 0));
3043
- setItems(
3044
- (prev) => replace ? payload.swaps ?? [] : [...prev, ...payload.swaps ?? []]
3045
- );
3046
- } catch (loadError) {
3047
- const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
3048
- setError(message);
3049
- } finally {
3050
- setIsLoading(false);
3051
- setIsFetchingMore(false);
3052
- }
3053
- },
3054
- [statusFilter, createdByFilter, debouncedSearchQuery]
3055
- );
3056
- useEffect(() => {
3057
- void loadSwaps(0, true);
3058
- }, [statusFilter, createdByFilter, debouncedSearchQuery, loadSwaps]);
3059
- const hasMore = useMemo(() => offset < count, [offset, count]);
3060
- const availableStatuses = useMemo(() => {
3061
- const statuses = /* @__PURE__ */ new Set();
3062
- items.forEach((item) => statuses.add(item.status));
3063
- return Array.from(statuses).sort();
3064
- }, [items]);
3065
- 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: [
3066
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
3067
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3068
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Exchanges" }),
3069
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer exchange requests" })
3070
- ] }),
3071
- /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadSwaps(0, true), children: "Refresh" })
3072
- ] }),
3073
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
3074
- /* @__PURE__ */ jsx(
3075
- Input,
3076
- {
3077
- placeholder: "Search by swap ID or order ID",
3078
- value: searchQuery,
3079
- onChange: (event) => setSearchQuery(event.target.value),
3080
- className: "md:max-w-sm"
3081
- }
3082
- ),
3083
- /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
3084
- /* @__PURE__ */ jsxs(
3085
- "select",
3086
- {
3087
- value: createdByFilter,
3088
- onChange: (event) => setCreatedByFilter(event.target.value),
3089
- 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",
3090
- children: [
3091
- /* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
3092
- /* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
3093
- /* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
3094
- ]
3095
- }
3096
- ),
3097
- /* @__PURE__ */ jsxs(
3098
- "select",
3099
- {
3100
- value: statusFilter,
3101
- onChange: (event) => setStatusFilter(event.target.value),
3102
- 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",
3103
- children: [
3104
- /* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
3105
- availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
3106
- ]
3107
- }
3108
- )
3109
- ] })
3110
- ] }),
3111
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3112
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3113
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
3114
- Button,
3115
- {
3116
- variant: "secondary",
3117
- onClick: () => loadSwaps(0, true),
3118
- children: "Try again"
3119
- }
3120
- ) })
3121
- ] }) : null,
3122
- 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: [
3123
- /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No exchanges yet" }),
3124
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Exchange requests created by customers will appear here." })
3125
- ] }) : /* @__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: [
3126
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3127
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Exchange ID" }),
3128
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
3129
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
3130
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Difference Due" }),
3131
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
3132
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
3133
- ] }) }),
3134
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((swap) => /* @__PURE__ */ jsxs(
3135
- "tr",
3136
- {
3137
- className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
3138
- onClick: () => navigate(`/swaps/${swap.id}`),
3139
- children: [
3140
- /* @__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 }) }) }),
3141
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: swap.order_id }),
3142
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
3143
- Badge,
3144
- {
3145
- size: "2xsmall",
3146
- className: `uppercase ${getStatusBadgeClass$4(swap.status)}`,
3147
- children: swap.status.replace(/_/g, " ")
3148
- }
3149
- ) }),
3150
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
3151
- const amount = swap.difference_due;
3152
- if (amount == null || amount === void 0) {
3153
- return "—";
3154
- }
3155
- const displayAmount = Number(amount) / 100;
3156
- const currency = swap.currency_code || "$";
3157
- const sign = displayAmount >= 0 ? "+" : "";
3158
- return `${sign}${currency}${displayAmount.toFixed(2)}`;
3159
- })() }),
3160
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(swap.created_at).toLocaleDateString("en-US", {
3161
- year: "numeric",
3162
- month: "short",
3163
- day: "numeric",
3164
- hour: "numeric",
3165
- minute: "2-digit",
3166
- hour12: true
3167
- }) }),
3168
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
3169
- Button,
3170
- {
3171
- variant: "transparent",
3172
- size: "small",
3173
- onClick: (e) => {
3174
- e.stopPropagation();
3175
- navigate(`/app/orders/${swap.order_id}`);
3176
- },
3177
- children: "Go to order"
3178
- }
3179
- ) })
3180
- ]
3181
- },
3182
- swap.id
3183
- )) })
3184
- ] }) }),
3185
- hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
3186
- Button,
3187
- {
3188
- variant: "secondary",
3189
- isLoading: isFetchingMore,
3190
- onClick: () => loadSwaps(offset, false),
3191
- children: "Load more"
3192
- }
3193
- ) }) : null
3194
- ] }) });
3195
- };
3196
- const config$4 = defineRouteConfig({
3197
- label: "Exchanges",
3198
- icon: ArrowPath
3199
- });
3200
- const getStatusBadgeClass$3 = (status) => {
3201
- const s2 = status.toLowerCase();
3202
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
3203
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3204
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
3205
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3206
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
3207
- };
3208
- const PaymentDetailPage = () => {
3186
+ }
3187
+ const DeletedRecordDetailPage = () => {
3209
3188
  var _a;
3210
3189
  const navigate = useNavigate();
3211
- const params = useParams();
3212
- const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
3213
- const [detail, setDetail] = useState(null);
3214
- const [loading, setLoading] = useState(!!id);
3215
- const [error, setError] = useState(null);
3216
- useEffect(() => {
3217
- if (!id) {
3218
- setLoading(false);
3219
- return;
3220
- }
3221
- let cancelled = false;
3222
- setLoading(true);
3223
- setError(null);
3224
- fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
3225
- if (!res.ok) throw new Error(res.statusText || "Failed to load");
3226
- return res.json();
3227
- }).then((data) => {
3228
- if (!cancelled) setDetail(data);
3229
- }).catch((e) => {
3230
- if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
3231
- }).finally(() => {
3232
- if (!cancelled) setLoading(false);
3190
+ const location = useLocation();
3191
+ const { id = "" } = useParams();
3192
+ const [state, setState] = useState({ status: "loading" });
3193
+ const [reloadToken, setReloadToken] = useState(0);
3194
+ const cameFromList = ((_a = location.state) == null ? void 0 : _a.fromList) === true;
3195
+ const goBack = () => {
3196
+ if (cameFromList) navigate(-1);
3197
+ else navigate(`/deleted-records-audit${readLastListSearch()}`);
3198
+ };
3199
+ useEffect(() => {
3200
+ const controller = new AbortController();
3201
+ setState({ status: "loading" });
3202
+ fetchAuditDetail(id, controller.signal).then((audit) => setState({ status: "ready", audit })).catch((e) => {
3203
+ if (controller.signal.aborted) return;
3204
+ setState({
3205
+ status: "error",
3206
+ message: e instanceof Error ? e.message : "Unknown error",
3207
+ notFound: e instanceof AuditApiError && e.status === 404
3208
+ });
3233
3209
  });
3234
- return () => {
3235
- cancelled = true;
3236
- };
3237
- }, [id]);
3238
- const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
3239
- const sessionStatusRaw = (detail == null ? void 0 : detail.session_status) ?? "—";
3240
- const paymentStatusRaw = (detail == null ? void 0 : detail.payment_id) != null ? (detail == null ? void 0 : detail.payment_status) ?? "—" : "—";
3241
- const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
3242
- 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: [
3243
- /* @__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: [
3244
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
3245
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
3246
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
3210
+ return () => controller.abort();
3211
+ }, [id, reloadToken]);
3212
+ 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: [
3213
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "transparent", size: "small", onClick: goBack, className: "-ml-2", children: [
3214
+ /* @__PURE__ */ jsx(ArrowLeft, {}),
3215
+ "Back to Deleted Records"
3247
3216
  ] }) }),
3248
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3249
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3250
- /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
3251
- ] }) : 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: [
3252
- /* @__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: [
3253
- /* @__PURE__ */ jsxs("div", { children: [
3254
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
3255
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
3256
- Button,
3257
- {
3258
- variant: "transparent",
3259
- size: "small",
3260
- onClick: () => navigate(`/orders/${detail.order_id}`),
3261
- children: detail.order_id
3262
- }
3263
- ) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
3264
- ] }),
3265
- /* @__PURE__ */ jsxs("div", { children: [
3266
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
3267
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
3268
- ] }),
3269
- /* @__PURE__ */ jsxs("div", { children: [
3270
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
3271
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
3272
- ] }),
3273
- /* @__PURE__ */ jsxs("div", { children: [
3274
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
3275
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
3276
- Badge,
3277
- {
3278
- size: "2xsmall",
3279
- className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
3280
- children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
3281
- }
3282
- ) })
3283
- ] }),
3284
- /* @__PURE__ */ jsxs("div", { children: [
3285
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
3286
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
3287
- ] }),
3288
- /* @__PURE__ */ jsxs("div", { children: [
3289
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
3290
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
3291
- ] }),
3292
- /* @__PURE__ */ jsxs("div", { children: [
3293
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
3294
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
3295
- ] }),
3296
- /* @__PURE__ */ jsxs("div", { children: [
3297
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
3298
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
3299
- year: "numeric",
3300
- month: "short",
3301
- day: "numeric",
3302
- hour: "numeric",
3303
- minute: "2-digit",
3304
- hour12: true
3305
- }) })
3306
- ] })
3307
- ] }) }),
3308
- Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
3309
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
3310
- /* @__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) })
3311
- ] }) : /* @__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." }) })
3312
- ] }) : null
3217
+ state.status === "loading" ? /* @__PURE__ */ jsx(DetailSkeleton, {}) : state.status === "error" ? /* @__PURE__ */ jsx(
3218
+ DetailError,
3219
+ {
3220
+ notFound: state.notFound,
3221
+ message: state.message,
3222
+ onRetry: () => setReloadToken((t) => t + 1),
3223
+ onBack: goBack
3224
+ }
3225
+ ) : /* @__PURE__ */ jsx(DetailContent, { audit: state.audit })
3313
3226
  ] }) });
3314
3227
  };
3315
- const config$3 = defineRouteConfig({
3316
- label: "Payment details",
3317
- icon: CreditCard
3318
- });
3319
- const getStatusBadgeClass$2 = (status) => {
3320
- const s2 = status.toLowerCase();
3321
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
3322
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3323
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
3324
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3325
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
3326
- };
3327
- const formatAmount = (value) => {
3328
- return String(value);
3329
- };
3330
- const RefundDetailPage = () => {
3331
- var _a, _b, _c;
3228
+ const DetailContent = ({ audit }) => {
3332
3229
  const navigate = useNavigate();
3333
- const params = useParams();
3334
- const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
3335
- const [detail, setDetail] = useState(null);
3336
- const [loading, setLoading] = useState(!!id);
3337
- const [error, setError] = useState(null);
3338
- const [gatewayExpanded, setGatewayExpanded] = useState(false);
3339
- useEffect(() => {
3340
- if (!id) {
3341
- setLoading(false);
3342
- return;
3230
+ const entity = getEntityInfo(audit.table_name);
3231
+ const source = describeSource(audit.source);
3232
+ const summary = useMemo(() => summarizeOldData(audit.table_name, audit.old_data), [audit]);
3233
+ const masked = useMemo(() => maskSensitiveData(audit.old_data, audit.table_name), [audit]);
3234
+ const guidance = getNextSteps(entity.category.id);
3235
+ const related = getRelatedLinks(audit.table_name, audit.old_data);
3236
+ const [showRaw, setShowRaw] = useState(false);
3237
+ const copyJson = async () => {
3238
+ try {
3239
+ await navigator.clipboard.writeText(JSON.stringify(masked.value, null, 2));
3240
+ toast.success("Record data copied", {
3241
+ description: masked.maskedCount ? "Sensitive values were left hidden." : void 0
3242
+ });
3243
+ } catch {
3244
+ toast.error("Couldn’t copy to clipboard");
3343
3245
  }
3344
- let cancelled = false;
3345
- setLoading(true);
3346
- setError(null);
3347
- fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
3348
- if (!res.ok) throw new Error(res.statusText || "Failed to load");
3349
- return res.json();
3350
- }).then((data) => {
3351
- if (!cancelled) setDetail(data);
3352
- }).catch((e) => {
3353
- if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
3354
- }).finally(() => {
3355
- if (!cancelled) setLoading(false);
3356
- });
3357
- return () => {
3358
- cancelled = true;
3359
- };
3360
- }, [id]);
3361
- const paymentStatus = ((_b = detail == null ? void 0 : detail.payment) == null ? void 0 : _b.status) ?? "—";
3362
- const hasGatewayData = ((_c = detail == null ? void 0 : detail.payment) == null ? void 0 : _c.payment_data) && typeof detail.payment.payment_data === "object" && Object.keys(detail.payment.payment_data).length > 0;
3363
- 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: [
3364
- /* @__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: [
3365
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
3366
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
3367
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
3368
- ] }) }),
3369
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3370
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3371
- /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
3372
- ] }) : 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: [
3373
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
3374
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
3375
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
3376
- /* @__PURE__ */ jsxs("div", { children: [
3377
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund ID" }),
3378
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.id })
3379
- ] }),
3380
- /* @__PURE__ */ jsxs("div", { children: [
3381
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
3382
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.refund.amount) })
3383
- ] }),
3384
- /* @__PURE__ */ jsxs("div", { children: [
3385
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Note" }),
3386
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.refund.note ?? "—" })
3387
- ] }),
3388
- /* @__PURE__ */ jsxs("div", { children: [
3389
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created at" }),
3390
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.refund.created_at).toLocaleDateString("en-US", {
3391
- year: "numeric",
3392
- month: "short",
3393
- day: "numeric",
3394
- hour: "numeric",
3395
- minute: "2-digit",
3396
- hour12: true
3397
- }) })
3398
- ] }),
3399
- detail.refund.created_by ? /* @__PURE__ */ jsxs("div", { children: [
3400
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created by" }),
3401
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.created_by })
3402
- ] }) : null
3403
- ] })
3404
- ] }),
3405
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
3406
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
3407
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
3408
- /* @__PURE__ */ jsxs("div", { children: [
3409
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
3410
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
3411
- ] }),
3412
- /* @__PURE__ */ jsxs("div", { children: [
3413
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
3414
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
3415
- ] }),
3416
- /* @__PURE__ */ jsxs("div", { children: [
3417
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
3418
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
3419
- ] }),
3420
- /* @__PURE__ */ jsxs("div", { children: [
3421
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
3422
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
3423
- ] }),
3424
- /* @__PURE__ */ jsxs("div", { children: [
3425
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
3426
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
3427
- Badge,
3428
- {
3429
- size: "2xsmall",
3430
- className: `uppercase ${getStatusBadgeClass$2(paymentStatus)}`,
3431
- children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
3432
- }
3433
- ) })
3434
- ] }),
3435
- detail.computed ? /* @__PURE__ */ jsxs(Fragment, { children: [
3436
- /* @__PURE__ */ jsxs("div", { children: [
3437
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Full refund" }),
3438
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.computed.is_full_refund ? "Yes" : "No" })
3439
- ] }),
3440
- /* @__PURE__ */ jsxs("div", { children: [
3441
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Remaining refundable" }),
3442
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.computed.remaining_refundable_amount) })
3443
- ] }),
3444
- /* @__PURE__ */ jsxs("div", { children: [
3445
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund %" }),
3446
- /* @__PURE__ */ jsxs(Text, { className: "mt-1 block", children: [
3447
- detail.computed.refund_percentage.toFixed(1),
3448
- "%"
3449
- ] })
3450
- ] })
3451
- ] }) : null
3452
- ] })
3246
+ };
3247
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3248
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
3249
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3250
+ /* @__PURE__ */ jsxs(Badge, { size: "small", color: "red", children: [
3251
+ /* @__PURE__ */ jsx(Trash, {}),
3252
+ "Deleted"
3253
+ ] }),
3254
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: entity.category.label })
3453
3255
  ] }),
3454
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
3455
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Order summary" }),
3456
- detail.order ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
3457
- /* @__PURE__ */ jsxs("div", { children: [
3458
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order" }),
3459
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
3460
- Button,
3461
- {
3462
- variant: "transparent",
3463
- size: "small",
3464
- onClick: () => navigate(`/orders/${detail.order.order_id}`),
3465
- children: detail.order.order_number ?? detail.order.order_id
3466
- }
3467
- ) })
3468
- ] }),
3469
- detail.order.total != null ? /* @__PURE__ */ jsxs("div", { children: [
3470
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Total" }),
3471
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.order.total) })
3472
- ] }) : null,
3473
- detail.order.customer_id ? /* @__PURE__ */ jsxs("div", { children: [
3474
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Customer ID" }),
3475
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.order.customer_id })
3476
- ] }) : null,
3477
- detail.order.region ? /* @__PURE__ */ jsxs("div", { children: [
3478
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Region" }),
3479
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.region })
3256
+ /* @__PURE__ */ jsxs(Heading, { level: "h1", children: [
3257
+ "Deleted ",
3258
+ entity.label
3259
+ ] }),
3260
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3261
+ /* @__PURE__ */ jsx(CopyableId, { value: audit.record_id, emptyLabel: "This record type has no ID column", className: "text-sm" }),
3262
+ /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
3263
+ "Database table: ",
3264
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: audit.table_name })
3265
+ ] })
3266
+ ] })
3267
+ ] }),
3268
+ /* @__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: [
3269
+ /* @__PURE__ */ jsx(InformationCircle, { className: "mt-0.5 shrink-0 text-ui-tag-orange-icon" }),
3270
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-tag-orange-text", children: [
3271
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "This is a historical snapshot" }),
3272
+ " captured immediately before deletion. The record no longer exists in the database, so changes elsewhere in the admin are not reflected here."
3273
+ ] })
3274
+ ] }),
3275
+ /* @__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: [
3276
+ /* @__PURE__ */ jsx(Field, { label: "Deleted", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3277
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: formatExactDateTime(audit.occurred_at) }),
3278
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-ui-fg-muted", children: [
3279
+ /* @__PURE__ */ jsx(ClockSolid, { className: "size-3" }),
3280
+ formatRelativeTime(audit.occurred_at)
3281
+ ] })
3282
+ ] }) }),
3283
+ /* @__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" }) }),
3284
+ /* @__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 }) }),
3285
+ /* @__PURE__ */ jsx(Field, { label: "Action", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Permanently deleted" }) })
3286
+ ] }) }),
3287
+ /* @__PURE__ */ jsx(
3288
+ Section,
3289
+ {
3290
+ title: "Record summary",
3291
+ description: `Key details of this ${entity.label.toLowerCase()} at the moment it was deleted.`,
3292
+ 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." })
3293
+ }
3294
+ ),
3295
+ /* @__PURE__ */ jsx(
3296
+ Section,
3297
+ {
3298
+ title: "Original record data",
3299
+ description: "The complete data captured before deletion.",
3300
+ actions: showRaw && audit.old_data ? /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: copyJson, children: [
3301
+ /* @__PURE__ */ jsx(SquareTwoStack, {}),
3302
+ "Copy JSON"
3303
+ ] }) : null,
3304
+ children: audit.old_data ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3305
+ masked.maskedCount > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3306
+ /* @__PURE__ */ jsx(ShieldCheck, { className: "shrink-0 text-ui-fg-muted" }),
3307
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
3308
+ masked.maskedCount,
3309
+ " sensitive ",
3310
+ masked.maskedCount === 1 ? "value is" : "values are",
3311
+ " hidden for security (passwords, tokens, card or account numbers)."
3312
+ ] })
3480
3313
  ] }) : null,
3481
- detail.order.fulfillment_status ? /* @__PURE__ */ jsxs("div", { children: [
3482
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
3483
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
3484
- ] }) : null
3485
- ] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
3314
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: () => setShowRaw((s2) => !s2), "aria-expanded": showRaw, children: [
3315
+ showRaw ? /* @__PURE__ */ jsx(ChevronDownMini, {}) : /* @__PURE__ */ jsx(ChevronRightMini, {}),
3316
+ showRaw ? "Hide full record" : "View full record"
3317
+ ] }) }),
3318
+ showRaw ? /* @__PURE__ */ jsx(JsonViewer, { data: masked.value }) : null
3319
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No data was captured for this deletion." })
3320
+ }
3321
+ ),
3322
+ /* @__PURE__ */ jsx(Section, { title: "What you can do now", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3323
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-base", children: [
3324
+ "This record was permanently deleted. ",
3325
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Automatic restoration is not available" }),
3326
+ " ",
3327
+ "from this screen."
3486
3328
  ] }),
3487
- /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
3488
- /* @__PURE__ */ jsxs(
3489
- "button",
3329
+ /* @__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: [
3330
+ /* @__PURE__ */ jsxs("li", { children: [
3331
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Check whether this was expected." }),
3332
+ " ",
3333
+ 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)}.`,
3334
+ " ",
3335
+ guidance.headline
3336
+ ] }),
3337
+ /* @__PURE__ */ jsxs("li", { children: [
3338
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "If it needs to come back:" }),
3339
+ " ",
3340
+ guidance.recreate
3341
+ ] }),
3342
+ /* @__PURE__ */ jsxs("li", { children: [
3343
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Need the details?" }),
3344
+ " Use “View full record” above to see or copy everything that was stored. Sensitive values stay hidden."
3345
+ ] })
3346
+ ] }),
3347
+ guidance.adminSection || related.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
3348
+ guidance.adminSection ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => navigate(guidance.adminSection.path), children: guidance.adminSection.label }) : null,
3349
+ related.map((link) => /* @__PURE__ */ jsxs(
3350
+ Button,
3490
3351
  {
3491
- type: "button",
3492
- className: "flex w-full items-center justify-between text-left",
3493
- onClick: () => setGatewayExpanded((prev) => !prev),
3494
- "aria-expanded": gatewayExpanded,
3495
- "aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
3352
+ variant: "transparent",
3353
+ size: "small",
3354
+ onClick: () => navigate(link.path),
3355
+ title: `Opens ${link.label.toLowerCase()} ${link.id} if it still exists`,
3496
3356
  children: [
3497
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
3498
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
3357
+ "Open related ",
3358
+ link.label.toLowerCase(),
3359
+ /* @__PURE__ */ jsx(ChevronRightMini, {})
3499
3360
  ]
3500
- }
3501
- ),
3502
- 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." }) })
3503
- ] })
3504
- ] }) : null
3505
- ] }) });
3506
- };
3507
- const config$2 = defineRouteConfig({
3508
- label: "Refund details",
3509
- icon: Receipt
3510
- });
3511
- const MASKED_VALUE = "••••••••••••";
3512
- const SENSITIVE_KEY_PATTERNS = [
3513
- /password|passwd|passphrase/i,
3514
- /secret/i,
3515
- /token/i,
3516
- /api_?key$/i,
3517
- /private_?key/i,
3518
- /access_?key/i,
3519
- /(^|_)hash(ed)?($|_)/i,
3520
- /(^|_)salt$/i,
3521
- /^cvv$|^cvc$|security_code/i,
3522
- /card_?number/i,
3523
- /account_?number/i,
3524
- /credential/i,
3525
- /authorization/i,
3526
- /recovery_?code/i,
3527
- /(^|_)otp($|_)/i,
3528
- /verification_?code/i,
3529
- /^code_hash$/i,
3530
- /webhook_?signature/i
3531
- ];
3532
- const TABLE_SENSITIVE_KEYS = {
3533
- otp_verification: /* @__PURE__ */ new Set(["code", "value"]),
3534
- auth_verification: /* @__PURE__ */ new Set(["code", "value"]),
3535
- auth_mfa_factor: /* @__PURE__ */ new Set(["value", "config"])
3361
+ },
3362
+ link.path
3363
+ ))
3364
+ ] }) : null,
3365
+ 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
3366
+ ] }) })
3367
+ ] });
3536
3368
  };
3537
- const SAFE_KEYS = /* @__PURE__ */ new Set([
3538
- "token_type",
3539
- "redacted",
3540
- "api_key_id",
3541
- "token_id",
3542
- "notification_token_id"
3543
- ]);
3544
- function isSensitiveKey(key) {
3545
- const normalized = key.trim().toLowerCase();
3546
- if (SAFE_KEYS.has(normalized)) return false;
3547
- return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(normalized));
3548
- }
3549
- const FULLY_SECRET_TABLES = /* @__PURE__ */ new Set(["auth_mfa_recovery_code", "auth_password_reset_token"]);
3550
- const ALWAYS_VISIBLE_KEYS = /* @__PURE__ */ new Set(["id", "created_at", "updated_at", "deleted_at", "expires_at", "used_at"]);
3551
- function maskValue(value, ctx, depth) {
3552
- var _a;
3553
- if (Array.isArray(value)) return value.map((item) => maskValue(item, ctx, depth + 1));
3554
- if (value !== null && typeof value === "object") {
3555
- const out = {};
3556
- for (const [key, inner] of Object.entries(value)) {
3557
- const topLevel = depth === 0;
3558
- const secret = inner !== null && inner !== void 0 && inner !== "" && (isSensitiveKey(key) || topLevel && ((_a = ctx.tableKeys) == null ? void 0 : _a.has(key.toLowerCase())) === true || topLevel && ctx.maskAll && !ALWAYS_VISIBLE_KEYS.has(key) && !key.endsWith("_id"));
3559
- if (secret) {
3560
- ctx.count += 1;
3561
- out[key] = MASKED_VALUE;
3562
- } else {
3563
- out[key] = maskValue(inner, ctx, depth + 1);
3564
- }
3565
- }
3566
- return out;
3567
- }
3568
- return value;
3569
- }
3570
- function maskSensitiveData(data, tableName) {
3571
- const ctx = {
3572
- count: 0,
3573
- maskAll: tableName ? FULLY_SECRET_TABLES.has(tableName) : false,
3574
- tableKeys: tableName ? TABLE_SENSITIVE_KEYS[tableName] : void 0
3575
- };
3576
- const value = maskValue(data, ctx, 0);
3577
- return { value, maskedCount: ctx.count };
3578
- }
3579
- const AUTO_EXPAND_DEPTH = 1;
3580
- const LONG_STRING = 200;
3581
- const JsonViewer = ({ data }) => {
3582
- const [generation, setGeneration] = useState(0);
3583
- const [expandAll, setExpandAll] = useState(null);
3584
- const setAll = (value) => {
3585
- setExpandAll(value);
3586
- setGeneration((g) => g + 1);
3587
- };
3588
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3589
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3590
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => setAll(true), children: "Expand all" }),
3591
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => setAll(false), children: "Collapse all" })
3369
+ const Section = ({
3370
+ title,
3371
+ description,
3372
+ actions,
3373
+ children
3374
+ }) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4 rounded-lg border border-ui-border-base p-5", children: [
3375
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [
3376
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
3377
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
3378
+ description ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: description }) : null
3592
3379
  ] }),
3593
- /* @__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) })
3594
- ] });
3380
+ actions
3381
+ ] }),
3382
+ children
3383
+ ] });
3384
+ const Field = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
3385
+ /* @__PURE__ */ jsx("dt", { className: "text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: label }),
3386
+ /* @__PURE__ */ jsx("dd", { className: "min-w-0", children })
3387
+ ] });
3388
+ const DetailSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "aria-busy": "true", children: [
3389
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3390
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" }),
3391
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-64" }),
3392
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
3393
+ ] }),
3394
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-14 w-full" }),
3395
+ 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: [
3396
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" }),
3397
+ /* @__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: [
3398
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" }),
3399
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-36" })
3400
+ ] }, j)) })
3401
+ ] }, i))
3402
+ ] });
3403
+ const DetailError = ({
3404
+ notFound,
3405
+ message,
3406
+ onRetry,
3407
+ onBack
3408
+ }) => /* @__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: [
3409
+ /* @__PURE__ */ jsx(ExclamationCircle, { className: clx(notFound ? "text-ui-fg-muted" : "text-ui-fg-error") }),
3410
+ /* @__PURE__ */ jsx(Heading, { level: "h3", children: notFound ? "Audit entry not found" : "Unable to load this deleted record" }),
3411
+ /* @__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." }),
3412
+ !notFound ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: message }) : null,
3413
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
3414
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: onBack, children: "Back to Deleted Records" }),
3415
+ !notFound ? /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: onRetry, children: "Try again" }) : null
3416
+ ] })
3417
+ ] });
3418
+ defineRouteConfig({});
3419
+ const useDebounce$1 = (value, delay) => {
3420
+ const [debouncedValue, setDebouncedValue] = useState(value);
3421
+ useEffect(() => {
3422
+ const handler = setTimeout(() => setDebouncedValue(value), delay);
3423
+ return () => clearTimeout(handler);
3424
+ }, [value, delay]);
3425
+ return debouncedValue;
3595
3426
  };
3596
- const JsonNode = ({ name, value, depth, forceExpand }) => {
3597
- const isContainer = value !== null && typeof value === "object";
3598
- const [open, setOpen] = useState(forceExpand ?? depth < AUTO_EXPAND_DEPTH);
3599
- const label = name !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-ui-fg-subtle", children: [
3600
- name,
3601
- /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: ": " })
3602
- ] }) : null;
3603
- if (!isContainer) {
3604
- return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start", style: { paddingLeft: depth ? 16 : 0 }, children: [
3605
- /* @__PURE__ */ jsx("span", { className: "w-4 shrink-0" }),
3606
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 break-words [overflow-wrap:anywhere]", children: [
3607
- label,
3608
- /* @__PURE__ */ jsx(Primitive, { value })
3609
- ] })
3610
- ] });
3427
+ const getStatusBadgeClass$5 = (status) => {
3428
+ const statusLower = status.toLowerCase();
3429
+ if (statusLower === "requested") {
3430
+ return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3611
3431
  }
3612
- const entries = Array.isArray(value) ? value.map((v, i) => [String(i), v]) : Object.entries(value);
3613
- const [openBracket, closeBracket] = Array.isArray(value) ? ["[", "]"] : ["{", "}"];
3614
- const summary = Array.isArray(value) ? `${entries.length} items` : `${entries.length} keys`;
3615
- return /* @__PURE__ */ jsxs("div", { style: { paddingLeft: depth ? 16 : 0 }, children: [
3616
- /* @__PURE__ */ jsxs(
3617
- "button",
3618
- {
3619
- type: "button",
3620
- onClick: () => setOpen((o) => !o),
3621
- className: "flex items-start text-left hover:bg-ui-bg-base-hover",
3622
- "aria-expanded": open,
3623
- children: [
3624
- /* @__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 }),
3625
- /* @__PURE__ */ jsxs("span", { children: [
3626
- label,
3627
- /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: openBracket }),
3628
- !open || entries.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
3629
- entries.length ? /* @__PURE__ */ jsx("span", { className: "px-1 italic text-ui-fg-muted", children: summary }) : null,
3630
- /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: closeBracket })
3631
- ] }) : null
3632
- ] })
3633
- ]
3634
- }
3635
- ),
3636
- open && entries.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
3637
- entries.map(([key, child]) => /* @__PURE__ */ jsx(JsonNode, { name: key, value: child, depth: depth + 1, forceExpand }, key)),
3638
- /* @__PURE__ */ jsx("div", { style: { paddingLeft: 16 }, className: "text-ui-fg-muted", children: closeBracket })
3639
- ] }) : null
3640
- ] });
3641
- };
3642
- const Primitive = ({ value }) => {
3643
- const [showFull, setShowFull] = useState(false);
3644
- if (value === MASKED_VALUE) {
3645
- 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 });
3432
+ if (statusLower === "approved") {
3433
+ return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3646
3434
  }
3647
- if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "null" });
3648
- if (typeof value === "boolean") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-purple-text", children: String(value) });
3649
- if (typeof value === "number") return /* @__PURE__ */ jsx("span", { className: "text-ui-tag-blue-text", children: value });
3650
- const text = String(value);
3651
- const truncated = !showFull && text.length > LONG_STRING;
3652
- return /* @__PURE__ */ jsxs("span", { className: clx("text-ui-tag-green-text"), children: [
3653
- '"',
3654
- truncated ? `${text.slice(0, LONG_STRING)}…` : text,
3655
- '"',
3656
- text.length > LONG_STRING ? /* @__PURE__ */ jsx(
3657
- "button",
3658
- {
3659
- type: "button",
3660
- onClick: () => setShowFull((s2) => !s2),
3661
- className: "ml-1 font-sans text-ui-fg-interactive hover:underline",
3662
- children: showFull ? "show less" : `show all (${text.length} chars)`
3663
- }
3664
- ) : null
3665
- ] });
3666
- };
3667
- const GUIDANCE = {
3668
- orders: {
3669
- headline: "Order data affects customers, payments and reports.",
3670
- 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.",
3671
- adminSection: { label: "Go to Orders", path: "/orders" }
3672
- },
3673
- carts: {
3674
- headline: "Carts are usually cleaned up automatically.",
3675
- recreate: "No action is normally needed. Customers can simply add items to a new cart."
3676
- },
3677
- customers: {
3678
- headline: "Customer data may be needed for orders, support and compliance.",
3679
- 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.",
3680
- adminSection: { label: "Go to Customers", path: "/customers" }
3681
- },
3682
- catalog: {
3683
- headline: "Catalog changes affect what customers can see and buy.",
3684
- recreate: "If it was deleted by mistake, recreate it from Products using the values shown above. It will get a new ID.",
3685
- adminSection: { label: "Go to Products", path: "/products" }
3686
- },
3687
- pricing: {
3688
- headline: "Pricing and promotions affect what customers pay.",
3689
- recreate: "If it was deleted by mistake, recreate it from Promotions or Price Lists using the values shown above.",
3690
- adminSection: { label: "Go to Promotions", path: "/promotions" }
3691
- },
3692
- payments: {
3693
- headline: "Payment records are financial data.",
3694
- 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."
3695
- },
3696
- fulfillment: {
3697
- headline: "Shipping and fulfillment settings affect checkout and delivery.",
3698
- recreate: "If it was deleted by mistake, recreate it from Settings → Locations & Shipping using the values shown above.",
3699
- adminSection: { label: "Go to Settings", path: "/settings" }
3700
- },
3701
- inventory: {
3702
- headline: "Inventory changes can affect stock levels and availability.",
3703
- recreate: "If it was deleted by mistake, recreate it from Inventory using the values shown above and re-check stock quantities.",
3704
- adminSection: { label: "Go to Inventory", path: "/inventory" }
3705
- },
3706
- wallet: {
3707
- headline: "Wallet and credit records are financial data.",
3708
- 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."
3709
- },
3710
- access: {
3711
- headline: "Access records control who can sign in.",
3712
- 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.",
3713
- adminSection: { label: "Go to Settings", path: "/settings" }
3714
- },
3715
- store: {
3716
- headline: "Store settings affect regions, currencies and taxes.",
3717
- recreate: "If it was deleted by mistake, recreate it from Settings using the values shown above.",
3718
- adminSection: { label: "Go to Settings", path: "/settings" }
3719
- },
3720
- engagement: {
3721
- headline: "Customer-generated content.",
3722
- 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."
3723
- },
3724
- notifications: {
3725
- headline: "Notification records are usually cleaned up automatically.",
3726
- recreate: "No action is normally needed."
3727
- },
3728
- system: {
3729
- headline: "Internal system data, usually removed automatically by the platform.",
3730
- recreate: "No action is normally needed. If you suspect a problem, share this page with a developer."
3435
+ if (statusLower === "rejected") {
3436
+ return "bg-ui-tag-red-bg text-ui-tag-red-text";
3437
+ }
3438
+ if (statusLower === "completed") {
3439
+ return "bg-ui-tag-green-bg text-ui-tag-green-text";
3440
+ }
3441
+ if (statusLower === "cancelled") {
3442
+ return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
3731
3443
  }
3444
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
3732
3445
  };
3733
- function getNextSteps(category) {
3734
- return GUIDANCE[category];
3735
- }
3736
- const RELATED_LINKS = [
3737
- { key: "order_id", label: "Order", path: (id) => `/orders/${id}`, selfTables: ["order"] },
3738
- { key: "customer_id", label: "Customer", path: (id) => `/customers/${id}`, selfTables: ["customer"] },
3739
- { key: "product_id", label: "Product", path: (id) => `/products/${id}`, selfTables: ["product"] }
3740
- ];
3741
- function getRelatedLinks(tableName, oldData) {
3742
- if (!oldData) return [];
3743
- return RELATED_LINKS.flatMap((link) => {
3744
- const id = oldData[link.key];
3745
- if (link.selfTables.includes(tableName) || typeof id !== "string" || !id.trim()) return [];
3746
- return [{ label: link.label, id, path: link.path(id) }];
3747
- });
3748
- }
3749
- const fullName = (row) => {
3750
- const parts = [row.first_name, row.last_name].filter(
3751
- (part) => typeof part === "string" && part.trim() !== ""
3446
+ const SwapsPage = () => {
3447
+ const navigate = useNavigate();
3448
+ const [items, setItems] = useState([]);
3449
+ const [statusFilter, setStatusFilter] = useState("all");
3450
+ const [createdByFilter, setCreatedByFilter] = useState("all");
3451
+ const [searchQuery, setSearchQuery] = useState("");
3452
+ const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
3453
+ const [isLoading, setIsLoading] = useState(true);
3454
+ const [isFetchingMore, setIsFetchingMore] = useState(false);
3455
+ const [error, setError] = useState(null);
3456
+ const [offset, setOffset] = useState(0);
3457
+ const [count, setCount] = useState(0);
3458
+ const limit = 50;
3459
+ const loadSwaps = useCallback(
3460
+ async (nextOffset, replace = false) => {
3461
+ var _a;
3462
+ try {
3463
+ if (replace) {
3464
+ setIsLoading(true);
3465
+ } else {
3466
+ setIsFetchingMore(true);
3467
+ }
3468
+ setError(null);
3469
+ const params = new URLSearchParams();
3470
+ params.set("limit", String(limit));
3471
+ params.set("offset", String(nextOffset));
3472
+ if (statusFilter !== "all") {
3473
+ params.set("status", statusFilter);
3474
+ }
3475
+ if (debouncedSearchQuery.trim()) {
3476
+ params.set("order_id", debouncedSearchQuery.trim());
3477
+ }
3478
+ if (createdByFilter !== "all") {
3479
+ params.set("created_by", createdByFilter);
3480
+ }
3481
+ const response = await fetch(
3482
+ `/admin/swaps?${params.toString()}`,
3483
+ { credentials: "include" }
3484
+ );
3485
+ if (!response.ok) {
3486
+ const message = await response.text();
3487
+ throw new Error(message || "Unable to load swaps");
3488
+ }
3489
+ const payload = await response.json();
3490
+ setCount(payload.count ?? 0);
3491
+ setOffset(nextOffset + (((_a = payload.swaps) == null ? void 0 : _a.length) ?? 0));
3492
+ setItems(
3493
+ (prev) => replace ? payload.swaps ?? [] : [...prev, ...payload.swaps ?? []]
3494
+ );
3495
+ } catch (loadError) {
3496
+ const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
3497
+ setError(message);
3498
+ } finally {
3499
+ setIsLoading(false);
3500
+ setIsFetchingMore(false);
3501
+ }
3502
+ },
3503
+ [statusFilter, createdByFilter, debouncedSearchQuery]
3752
3504
  );
3753
- return parts.length ? parts.join(" ") : void 0;
3754
- };
3755
- const addressLine = (row) => {
3756
- 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());
3757
- return parts.length ? parts.join(", ") : void 0;
3758
- };
3759
- const NAME = { key: "name", label: "Name", derive: fullName };
3760
- const ADDRESS = { key: "address", label: "Address", derive: addressLine };
3761
- const CREATED = { key: "created_at", label: "Created", kind: "date" };
3762
- const ENTITY_FIELDS = {
3763
- order: [
3764
- { key: "display_id", label: "Order number" },
3765
- { key: "status", label: "Status", kind: "status" },
3766
- { key: "email", label: "Customer email" },
3767
- { key: "customer_id", label: "Customer ID", kind: "id" },
3768
- { key: "currency_code", label: "Currency" },
3769
- { key: "region_id", label: "Region ID", kind: "id" },
3770
- { key: "sales_channel_id", label: "Sales channel ID", kind: "id" },
3771
- { key: "canceled_at", label: "Canceled", kind: "date" },
3772
- CREATED
3773
- ],
3774
- order_line_item: [
3775
- { key: "title", label: "Item" },
3776
- { key: "variant_title", label: "Variant" },
3777
- { key: "variant_sku", label: "SKU" },
3778
- { key: "unit_price", label: "Unit price", kind: "money" },
3779
- { key: "product_id", label: "Product ID", kind: "id" },
3780
- { key: "variant_id", label: "Variant ID", kind: "id" },
3781
- CREATED
3782
- ],
3783
- cart_line_item: [
3784
- { key: "title", label: "Item" },
3785
- { key: "variant_sku", label: "SKU" },
3786
- { key: "quantity", label: "Quantity", kind: "number" },
3787
- { key: "unit_price", label: "Unit price", kind: "money" },
3788
- { key: "cart_id", label: "Cart ID", kind: "id" },
3789
- { key: "variant_id", label: "Variant ID", kind: "id" },
3790
- CREATED
3791
- ],
3792
- cart: [
3793
- { key: "email", label: "Email" },
3794
- { key: "customer_id", label: "Customer ID", kind: "id" },
3795
- { key: "currency_code", label: "Currency" },
3796
- { key: "region_id", label: "Region ID", kind: "id" },
3797
- { key: "completed_at", label: "Completed", kind: "date" },
3798
- CREATED
3799
- ],
3800
- customer: [
3801
- NAME,
3802
- { key: "email", label: "Email" },
3803
- { key: "phone", label: "Phone" },
3804
- { key: "company_name", label: "Company" },
3805
- { key: "has_account", label: "Registered account", kind: "boolean" },
3806
- CREATED
3807
- ],
3808
- customer_address: [
3809
- { key: "address_name", label: "Label" },
3810
- NAME,
3811
- ADDRESS,
3812
- { key: "phone", label: "Phone" },
3813
- { key: "customer_id", label: "Customer ID", kind: "id" },
3814
- { key: "is_default_shipping", label: "Default shipping", kind: "boolean" },
3815
- CREATED
3816
- ],
3817
- order_address: [NAME, ADDRESS, { key: "phone", label: "Phone" }, CREATED],
3818
- cart_address: [NAME, ADDRESS, { key: "phone", label: "Phone" }, CREATED],
3819
- product: [
3820
- { key: "title", label: "Title" },
3821
- { key: "status", label: "Status", kind: "status" },
3822
- { key: "handle", label: "Handle" },
3823
- { key: "subtitle", label: "Subtitle" },
3824
- { key: "collection_id", label: "Collection ID", kind: "id" },
3825
- { key: "is_giftcard", label: "Gift card", kind: "boolean" },
3826
- CREATED
3827
- ],
3828
- product_variant: [
3829
- { key: "title", label: "Title" },
3830
- { key: "sku", label: "SKU" },
3831
- { key: "barcode", label: "Barcode" },
3832
- { key: "product_id", label: "Product ID", kind: "id" },
3833
- { key: "manage_inventory", label: "Manages inventory", kind: "boolean" },
3834
- CREATED
3835
- ],
3836
- product_category: [
3837
- { key: "name", label: "Name" },
3838
- { key: "handle", label: "Handle" },
3839
- { key: "is_active", label: "Active", kind: "boolean" },
3840
- { key: "parent_category_id", label: "Parent category ID", kind: "id" },
3841
- CREATED
3842
- ],
3843
- product_collection: [{ key: "title", label: "Title" }, { key: "handle", label: "Handle" }, CREATED],
3844
- payment: [
3845
- { key: "amount", label: "Amount", kind: "money" },
3846
- { key: "currency_code", label: "Currency" },
3847
- { key: "provider_id", label: "Provider" },
3848
- { key: "captured_at", label: "Captured", kind: "date" },
3849
- { key: "canceled_at", label: "Canceled", kind: "date" },
3850
- { key: "payment_collection_id", label: "Payment collection ID", kind: "id" },
3851
- CREATED
3852
- ],
3853
- payment_session: [
3854
- { key: "amount", label: "Amount", kind: "money" },
3855
- { key: "currency_code", label: "Currency" },
3856
- { key: "provider_id", label: "Provider" },
3857
- { key: "status", label: "Status", kind: "status" },
3858
- { key: "payment_collection_id", label: "Payment collection ID", kind: "id" },
3859
- CREATED
3860
- ],
3861
- payment_collection: [
3862
- { key: "amount", label: "Amount", kind: "money" },
3863
- { key: "currency_code", label: "Currency" },
3864
- { key: "status", label: "Status", kind: "status" },
3865
- CREATED
3866
- ],
3867
- refund: [
3868
- { key: "amount", label: "Amount", kind: "money" },
3869
- { key: "payment_id", label: "Payment ID", kind: "id" },
3870
- { key: "refund_reason_id", label: "Refund reason ID", kind: "id" },
3871
- { key: "note", label: "Note" },
3872
- { key: "created_by", label: "Created by" },
3873
- CREATED
3874
- ],
3875
- return: [
3876
- { key: "display_id", label: "Return number" },
3877
- { key: "status", label: "Status", kind: "status" },
3878
- { key: "order_id", label: "Order ID", kind: "id" },
3879
- { key: "refund_amount", label: "Refund amount", kind: "money" },
3880
- { key: "received_at", label: "Received", kind: "date" },
3881
- CREATED
3882
- ],
3883
- payment_detail: [
3884
- { key: "type", label: "Method type" },
3885
- { key: "customer_id", label: "Customer ID", kind: "id" },
3886
- { key: "is_default", label: "Default method", kind: "boolean" },
3887
- CREATED
3888
- ],
3889
- user: [NAME, { key: "email", label: "Email" }, CREATED],
3890
- invite: [
3891
- { key: "email", label: "Email" },
3892
- { key: "accepted", label: "Accepted", kind: "boolean" },
3893
- { key: "expires_at", label: "Expires", kind: "date" },
3894
- CREATED
3895
- ],
3896
- api_key: [
3897
- { key: "title", label: "Title" },
3898
- { key: "type", label: "Type" },
3899
- { key: "redacted", label: "Key (redacted)" },
3900
- { key: "revoked_at", label: "Revoked", kind: "date" },
3901
- CREATED
3902
- ],
3903
- promotion: [
3904
- { key: "code", label: "Promotion code" },
3905
- { key: "type", label: "Type" },
3906
- { key: "status", label: "Status", kind: "status" },
3907
- { key: "is_automatic", label: "Automatic", kind: "boolean" },
3908
- CREATED
3909
- ],
3910
- fulfillment: [
3911
- { key: "provider_id", label: "Provider" },
3912
- { key: "location_id", label: "Location ID", kind: "id" },
3913
- { key: "shipped_at", label: "Shipped", kind: "date" },
3914
- { key: "delivered_at", label: "Delivered", kind: "date" },
3915
- { key: "canceled_at", label: "Canceled", kind: "date" },
3916
- CREATED
3917
- ],
3918
- inventory_item: [
3919
- { key: "sku", label: "SKU" },
3920
- { key: "title", label: "Title" },
3921
- { key: "requires_shipping", label: "Requires shipping", kind: "boolean" },
3922
- CREATED
3923
- ],
3924
- inventory_level: [
3925
- { key: "inventory_item_id", label: "Inventory item ID", kind: "id" },
3926
- { key: "location_id", label: "Location ID", kind: "id" },
3927
- { key: "stocked_quantity", label: "Stocked", kind: "number" },
3928
- { key: "reserved_quantity", label: "Reserved", kind: "number" },
3929
- CREATED
3930
- ],
3931
- review: [
3932
- { key: "title", label: "Title" },
3933
- { key: "rating", label: "Rating", kind: "number" },
3934
- { key: "status", label: "Status", kind: "status" },
3935
- { key: "product_id", label: "Product ID", kind: "id" },
3936
- { key: "customer_id", label: "Customer ID", kind: "id" },
3937
- CREATED
3938
- ]
3505
+ useEffect(() => {
3506
+ void loadSwaps(0, true);
3507
+ }, [statusFilter, createdByFilter, debouncedSearchQuery, loadSwaps]);
3508
+ const hasMore = useMemo(() => offset < count, [offset, count]);
3509
+ const availableStatuses = useMemo(() => {
3510
+ const statuses = /* @__PURE__ */ new Set();
3511
+ items.forEach((item) => statuses.add(item.status));
3512
+ return Array.from(statuses).sort();
3513
+ }, [items]);
3514
+ 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: [
3515
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
3516
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3517
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Exchanges" }),
3518
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer exchange requests" })
3519
+ ] }),
3520
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadSwaps(0, true), children: "Refresh" })
3521
+ ] }),
3522
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
3523
+ /* @__PURE__ */ jsx(
3524
+ Input,
3525
+ {
3526
+ placeholder: "Search by swap ID or order ID",
3527
+ value: searchQuery,
3528
+ onChange: (event) => setSearchQuery(event.target.value),
3529
+ className: "md:max-w-sm"
3530
+ }
3531
+ ),
3532
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
3533
+ /* @__PURE__ */ jsxs(
3534
+ "select",
3535
+ {
3536
+ value: createdByFilter,
3537
+ onChange: (event) => setCreatedByFilter(event.target.value),
3538
+ 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",
3539
+ children: [
3540
+ /* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
3541
+ /* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
3542
+ /* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
3543
+ ]
3544
+ }
3545
+ ),
3546
+ /* @__PURE__ */ jsxs(
3547
+ "select",
3548
+ {
3549
+ value: statusFilter,
3550
+ onChange: (event) => setStatusFilter(event.target.value),
3551
+ 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",
3552
+ children: [
3553
+ /* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
3554
+ availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
3555
+ ]
3556
+ }
3557
+ )
3558
+ ] })
3559
+ ] }),
3560
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3561
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3562
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
3563
+ Button,
3564
+ {
3565
+ variant: "secondary",
3566
+ onClick: () => loadSwaps(0, true),
3567
+ children: "Try again"
3568
+ }
3569
+ ) })
3570
+ ] }) : null,
3571
+ 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: [
3572
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No exchanges yet" }),
3573
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Exchange requests created by customers will appear here." })
3574
+ ] }) : /* @__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: [
3575
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3576
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Exchange ID" }),
3577
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
3578
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
3579
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Difference Due" }),
3580
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
3581
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
3582
+ ] }) }),
3583
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((swap) => /* @__PURE__ */ jsxs(
3584
+ "tr",
3585
+ {
3586
+ className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
3587
+ onClick: () => navigate(`/swaps/${swap.id}`),
3588
+ children: [
3589
+ /* @__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 }) }) }),
3590
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: swap.order_id }),
3591
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
3592
+ Badge,
3593
+ {
3594
+ size: "2xsmall",
3595
+ className: `uppercase ${getStatusBadgeClass$5(swap.status)}`,
3596
+ children: swap.status.replace(/_/g, " ")
3597
+ }
3598
+ ) }),
3599
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
3600
+ const amount = swap.difference_due;
3601
+ if (amount == null || amount === void 0) {
3602
+ return "—";
3603
+ }
3604
+ const displayAmount = Number(amount) / 100;
3605
+ const currency = swap.currency_code || "$";
3606
+ const sign = displayAmount >= 0 ? "+" : "";
3607
+ return `${sign}${currency}${displayAmount.toFixed(2)}`;
3608
+ })() }),
3609
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(swap.created_at).toLocaleDateString("en-US", {
3610
+ year: "numeric",
3611
+ month: "short",
3612
+ day: "numeric",
3613
+ hour: "numeric",
3614
+ minute: "2-digit",
3615
+ hour12: true
3616
+ }) }),
3617
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
3618
+ Button,
3619
+ {
3620
+ variant: "transparent",
3621
+ size: "small",
3622
+ onClick: (e) => {
3623
+ e.stopPropagation();
3624
+ navigate(`/app/orders/${swap.order_id}`);
3625
+ },
3626
+ children: "Go to order"
3627
+ }
3628
+ ) })
3629
+ ]
3630
+ },
3631
+ swap.id
3632
+ )) })
3633
+ ] }) }),
3634
+ hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
3635
+ Button,
3636
+ {
3637
+ variant: "secondary",
3638
+ isLoading: isFetchingMore,
3639
+ onClick: () => loadSwaps(offset, false),
3640
+ children: "Load more"
3641
+ }
3642
+ ) }) : null
3643
+ ] }) });
3644
+ };
3645
+ const config$5 = defineRouteConfig({
3646
+ label: "Exchanges",
3647
+ icon: ArrowPath
3648
+ });
3649
+ const useDebounce = (value, delay) => {
3650
+ const [debouncedValue, setDebouncedValue] = useState(value);
3651
+ useEffect(() => {
3652
+ const handler = setTimeout(() => setDebouncedValue(value), delay);
3653
+ return () => clearTimeout(handler);
3654
+ }, [value, delay]);
3655
+ return debouncedValue;
3656
+ };
3657
+ const getStatusBadgeClass$4 = (status) => {
3658
+ const s2 = status.toLowerCase();
3659
+ if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
3660
+ if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3661
+ if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
3662
+ if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3663
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
3664
+ };
3665
+ const RefundsPage = () => {
3666
+ const navigate = useNavigate();
3667
+ const [items, setItems] = useState([]);
3668
+ const [orderIdSearch, setOrderIdSearch] = useState("");
3669
+ const debouncedOrderId = useDebounce(orderIdSearch, 300);
3670
+ const [paymentStatusFilter, setPaymentStatusFilter] = useState("all");
3671
+ const [providerSearch, setProviderSearch] = useState("");
3672
+ const debouncedProvider = useDebounce(providerSearch, 300);
3673
+ const [currencySearch, setCurrencySearch] = useState("");
3674
+ const debouncedCurrency = useDebounce(currencySearch, 300);
3675
+ const [dateFrom, setDateFrom] = useState("");
3676
+ const [dateTo, setDateTo] = useState("");
3677
+ const [amountMin, setAmountMin] = useState("");
3678
+ const [amountMax, setAmountMax] = useState("");
3679
+ const [isLoading, setIsLoading] = useState(true);
3680
+ const [isFetchingMore, setIsFetchingMore] = useState(false);
3681
+ const [error, setError] = useState(null);
3682
+ const [offset, setOffset] = useState(0);
3683
+ const [count, setCount] = useState(0);
3684
+ const limit = 50;
3685
+ const loadRefunds = useCallback(
3686
+ async (nextOffset, replace) => {
3687
+ try {
3688
+ if (replace) setIsLoading(true);
3689
+ else setIsFetchingMore(true);
3690
+ setError(null);
3691
+ const params = new URLSearchParams();
3692
+ params.set("limit", String(limit));
3693
+ params.set("offset", String(nextOffset));
3694
+ if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
3695
+ if (paymentStatusFilter !== "all") params.set("payment_status", paymentStatusFilter);
3696
+ if (debouncedProvider.trim()) params.set("provider_id", debouncedProvider.trim());
3697
+ if (debouncedCurrency.trim()) params.set("currency_code", debouncedCurrency.trim());
3698
+ if (dateFrom.trim()) params.set("date_from", dateFrom.trim());
3699
+ if (dateTo.trim()) params.set("date_to", dateTo.trim());
3700
+ const min = amountMin.trim() ? Number(amountMin) : void 0;
3701
+ const max = amountMax.trim() ? Number(amountMax) : void 0;
3702
+ if (min != null && !Number.isNaN(min)) params.set("amount_min", String(min));
3703
+ if (max != null && !Number.isNaN(max)) params.set("amount_max", String(max));
3704
+ const response = await fetch(`/admin/refunds?${params.toString()}`, {
3705
+ credentials: "include"
3706
+ });
3707
+ if (!response.ok) {
3708
+ const text = await response.text();
3709
+ throw new Error(text || "Failed to load refunds");
3710
+ }
3711
+ const payload = await response.json();
3712
+ const list = payload.refunds ?? [];
3713
+ setCount(payload.count ?? 0);
3714
+ setOffset(nextOffset + list.length);
3715
+ setItems((prev) => replace ? list : [...prev, ...list]);
3716
+ } catch (e) {
3717
+ setError(e instanceof Error ? e.message : "Failed to load");
3718
+ } finally {
3719
+ setIsLoading(false);
3720
+ setIsFetchingMore(false);
3721
+ }
3722
+ },
3723
+ [
3724
+ debouncedOrderId,
3725
+ paymentStatusFilter,
3726
+ debouncedProvider,
3727
+ debouncedCurrency,
3728
+ dateFrom,
3729
+ dateTo,
3730
+ amountMin,
3731
+ amountMax
3732
+ ]
3733
+ );
3734
+ useEffect(() => {
3735
+ void loadRefunds(0, true);
3736
+ }, [loadRefunds]);
3737
+ const hasMore = useMemo(() => offset < count, [offset, count]);
3738
+ const displayAmount = (r) => {
3739
+ const code = (r.currency_code ?? "USD").toUpperCase();
3740
+ return `${code} ${Number(r.amount)}`;
3741
+ };
3742
+ const displayStatus = (r) => {
3743
+ const s2 = r.payment_status ?? "";
3744
+ return s2 !== "" ? s2 : "—";
3745
+ };
3746
+ 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: [
3747
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
3748
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3749
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refunds" }),
3750
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Refund records — amount, order, payment status" })
3751
+ ] }),
3752
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadRefunds(0, true), children: "Refresh" })
3753
+ ] }),
3754
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
3755
+ /* @__PURE__ */ jsx(
3756
+ Input,
3757
+ {
3758
+ placeholder: "Order ID",
3759
+ value: orderIdSearch,
3760
+ onChange: (e) => setOrderIdSearch(e.target.value),
3761
+ className: "md:max-w-[180px]",
3762
+ "aria-label": "Filter by order ID"
3763
+ }
3764
+ ),
3765
+ /* @__PURE__ */ jsx(
3766
+ Input,
3767
+ {
3768
+ placeholder: "Provider",
3769
+ value: providerSearch,
3770
+ onChange: (e) => setProviderSearch(e.target.value),
3771
+ className: "md:max-w-[140px]",
3772
+ "aria-label": "Filter by provider"
3773
+ }
3774
+ ),
3775
+ /* @__PURE__ */ jsx(
3776
+ Input,
3777
+ {
3778
+ placeholder: "Currency",
3779
+ value: currencySearch,
3780
+ onChange: (e) => setCurrencySearch(e.target.value),
3781
+ className: "md:max-w-[100px]",
3782
+ "aria-label": "Filter by currency"
3783
+ }
3784
+ ),
3785
+ /* @__PURE__ */ jsxs(
3786
+ "select",
3787
+ {
3788
+ value: paymentStatusFilter,
3789
+ onChange: (e) => setPaymentStatusFilter(e.target.value),
3790
+ 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]",
3791
+ "aria-label": "Filter by payment status",
3792
+ children: [
3793
+ /* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
3794
+ /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
3795
+ /* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
3796
+ /* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
3797
+ /* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
3798
+ /* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
3799
+ /* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
3800
+ ]
3801
+ }
3802
+ ),
3803
+ /* @__PURE__ */ jsx(
3804
+ Input,
3805
+ {
3806
+ type: "date",
3807
+ placeholder: "From",
3808
+ value: dateFrom,
3809
+ onChange: (e) => setDateFrom(e.target.value),
3810
+ className: "md:max-w-[140px]",
3811
+ "aria-label": "Date from"
3812
+ }
3813
+ ),
3814
+ /* @__PURE__ */ jsx(
3815
+ Input,
3816
+ {
3817
+ type: "date",
3818
+ placeholder: "To",
3819
+ value: dateTo,
3820
+ onChange: (e) => setDateTo(e.target.value),
3821
+ className: "md:max-w-[140px]",
3822
+ "aria-label": "Date to"
3823
+ }
3824
+ ),
3825
+ /* @__PURE__ */ jsx(
3826
+ Input,
3827
+ {
3828
+ placeholder: "Amount min",
3829
+ value: amountMin,
3830
+ onChange: (e) => setAmountMin(e.target.value),
3831
+ type: "number",
3832
+ min: 0,
3833
+ className: "md:max-w-[100px]",
3834
+ "aria-label": "Refund amount minimum"
3835
+ }
3836
+ ),
3837
+ /* @__PURE__ */ jsx(
3838
+ Input,
3839
+ {
3840
+ placeholder: "Amount max",
3841
+ value: amountMax,
3842
+ onChange: (e) => setAmountMax(e.target.value),
3843
+ type: "number",
3844
+ min: 0,
3845
+ className: "md:max-w-[100px]",
3846
+ "aria-label": "Refund amount maximum"
3847
+ }
3848
+ )
3849
+ ] }) }),
3850
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3851
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3852
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadRefunds(0, true), children: "Try again" }) })
3853
+ ] }) : null,
3854
+ 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: [
3855
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No refunds yet" }),
3856
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Refund records will appear here." })
3857
+ ] }) : /* @__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: [
3858
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3859
+ /* @__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" }),
3860
+ /* @__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" }),
3861
+ /* @__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" }),
3862
+ /* @__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" }),
3863
+ /* @__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" }),
3864
+ /* @__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" }),
3865
+ /* @__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" }),
3866
+ /* @__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" }),
3867
+ /* @__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" }),
3868
+ /* @__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" })
3869
+ ] }) }),
3870
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
3871
+ "tr",
3872
+ {
3873
+ className: "cursor-pointer hover:bg-ui-bg-subtle/60",
3874
+ onClick: () => navigate(`/refunds/${r.refund_id}`),
3875
+ children: [
3876
+ /* @__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 }),
3877
+ /* @__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 ?? "—" }),
3878
+ /* @__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 }),
3879
+ /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
3880
+ /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
3881
+ /* @__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 || "—" }),
3882
+ /* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
3883
+ Badge,
3884
+ {
3885
+ size: "2xsmall",
3886
+ className: `uppercase ${getStatusBadgeClass$4(displayStatus(r))}`,
3887
+ children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
3888
+ }
3889
+ ) }),
3890
+ /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
3891
+ /* @__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", {
3892
+ month: "short",
3893
+ day: "numeric",
3894
+ hour: "numeric",
3895
+ minute: "2-digit",
3896
+ hour12: true
3897
+ }) }),
3898
+ /* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
3899
+ /* @__PURE__ */ jsx(
3900
+ Button,
3901
+ {
3902
+ variant: "transparent",
3903
+ size: "small",
3904
+ onClick: (e) => {
3905
+ e.stopPropagation();
3906
+ navigate(`/refunds/${r.refund_id}`);
3907
+ },
3908
+ children: "Details"
3909
+ }
3910
+ ),
3911
+ r.order_id ? /* @__PURE__ */ jsx(
3912
+ Button,
3913
+ {
3914
+ variant: "transparent",
3915
+ size: "small",
3916
+ onClick: (e) => {
3917
+ e.stopPropagation();
3918
+ navigate(`/orders/${r.order_id}`);
3919
+ },
3920
+ children: "Order"
3921
+ }
3922
+ ) : null
3923
+ ] }) })
3924
+ ]
3925
+ },
3926
+ r.refund_id
3927
+ )) })
3928
+ ] }) }),
3929
+ hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
3930
+ Button,
3931
+ {
3932
+ variant: "secondary",
3933
+ isLoading: isFetchingMore,
3934
+ onClick: () => loadRefunds(offset, false),
3935
+ children: "Load more"
3936
+ }
3937
+ ) }) : null
3938
+ ] }) });
3939
3939
  };
3940
- const GENERIC_FIELDS = [
3941
- { key: "display_id", label: "Number" },
3942
- { key: "title", label: "Title" },
3943
- { key: "name", label: "Name" },
3944
- NAME,
3945
- { key: "email", label: "Email" },
3946
- { key: "phone", label: "Phone" },
3947
- { key: "handle", label: "Handle" },
3948
- { key: "sku", label: "SKU" },
3949
- { key: "code", label: "Code" },
3950
- { key: "status", label: "Status", kind: "status" },
3951
- { key: "type", label: "Type" },
3952
- { key: "amount", label: "Amount", kind: "money" },
3953
- { key: "quantity", label: "Quantity", kind: "number" },
3954
- { key: "currency_code", label: "Currency" },
3955
- { key: "order_id", label: "Order ID", kind: "id" },
3956
- { key: "customer_id", label: "Customer ID", kind: "id" },
3957
- { key: "product_id", label: "Product ID", kind: "id" },
3958
- { key: "payment_id", label: "Payment ID", kind: "id" },
3959
- { key: "provider_id", label: "Provider" },
3960
- CREATED,
3961
- { key: "updated_at", label: "Last updated", kind: "date" }
3962
- ];
3963
- const MAX_GENERIC_FIELDS = 8;
3964
- function amountOf(value) {
3965
- if (typeof value === "number" && Number.isFinite(value)) return value;
3966
- if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
3967
- if (value !== null && typeof value === "object" && "value" in value) {
3968
- return amountOf(value.value);
3940
+ const config$4 = defineRouteConfig({
3941
+ label: "Refunds",
3942
+ icon: Receipt
3943
+ });
3944
+ const getStatusBadgeClass$3 = (status) => {
3945
+ const s2 = status.toLowerCase();
3946
+ if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
3947
+ if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3948
+ if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
3949
+ if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3950
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
3951
+ };
3952
+ const PaymentDetailPage = () => {
3953
+ var _a;
3954
+ const navigate = useNavigate();
3955
+ const params = useParams();
3956
+ const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
3957
+ const [detail, setDetail] = useState(null);
3958
+ const [loading, setLoading] = useState(!!id);
3959
+ const [error, setError] = useState(null);
3960
+ useEffect(() => {
3961
+ if (!id) {
3962
+ setLoading(false);
3963
+ return;
3964
+ }
3965
+ let cancelled = false;
3966
+ setLoading(true);
3967
+ setError(null);
3968
+ fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
3969
+ if (!res.ok) throw new Error(res.statusText || "Failed to load");
3970
+ return res.json();
3971
+ }).then((data) => {
3972
+ if (!cancelled) setDetail(data);
3973
+ }).catch((e) => {
3974
+ if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
3975
+ }).finally(() => {
3976
+ if (!cancelled) setLoading(false);
3977
+ });
3978
+ return () => {
3979
+ cancelled = true;
3980
+ };
3981
+ }, [id]);
3982
+ const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
3983
+ const sessionStatusRaw = (detail == null ? void 0 : detail.session_status) ?? "—";
3984
+ const paymentStatusRaw = (detail == null ? void 0 : detail.payment_id) != null ? (detail == null ? void 0 : detail.payment_status) ?? "—" : "—";
3985
+ const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
3986
+ 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: [
3987
+ /* @__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: [
3988
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
3989
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
3990
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
3991
+ ] }) }),
3992
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3993
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3994
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
3995
+ ] }) : 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: [
3996
+ /* @__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: [
3997
+ /* @__PURE__ */ jsxs("div", { children: [
3998
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
3999
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
4000
+ Button,
4001
+ {
4002
+ variant: "transparent",
4003
+ size: "small",
4004
+ onClick: () => navigate(`/orders/${detail.order_id}`),
4005
+ children: detail.order_id
4006
+ }
4007
+ ) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
4008
+ ] }),
4009
+ /* @__PURE__ */ jsxs("div", { children: [
4010
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
4011
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
4012
+ ] }),
4013
+ /* @__PURE__ */ jsxs("div", { children: [
4014
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
4015
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
4016
+ ] }),
4017
+ /* @__PURE__ */ jsxs("div", { children: [
4018
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
4019
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
4020
+ Badge,
4021
+ {
4022
+ size: "2xsmall",
4023
+ className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
4024
+ children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
4025
+ }
4026
+ ) })
4027
+ ] }),
4028
+ /* @__PURE__ */ jsxs("div", { children: [
4029
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
4030
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
4031
+ ] }),
4032
+ /* @__PURE__ */ jsxs("div", { children: [
4033
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
4034
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
4035
+ ] }),
4036
+ /* @__PURE__ */ jsxs("div", { children: [
4037
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
4038
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
4039
+ ] }),
4040
+ /* @__PURE__ */ jsxs("div", { children: [
4041
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
4042
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
4043
+ year: "numeric",
4044
+ month: "short",
4045
+ day: "numeric",
4046
+ hour: "numeric",
4047
+ minute: "2-digit",
4048
+ hour12: true
4049
+ }) })
4050
+ ] })
4051
+ ] }) }),
4052
+ Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
4053
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
4054
+ /* @__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) })
4055
+ ] }) : /* @__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." }) })
4056
+ ] }) : null
4057
+ ] }) });
4058
+ };
4059
+ const config$3 = defineRouteConfig({
4060
+ label: "Payment details",
4061
+ icon: CreditCard
4062
+ });
4063
+ const getStatusBadgeClass$2 = (status) => {
4064
+ const statusLower = status.toLowerCase();
4065
+ if (statusLower === "requested") {
4066
+ return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3969
4067
  }
3970
- return null;
3971
- }
3972
- function formatValue(raw, kind, row) {
3973
- if (raw === null || raw === void 0 || raw === "") return null;
3974
- if (raw === MASKED_VALUE) return { value: MASKED_VALUE, kind: "masked" };
3975
- switch (kind) {
3976
- case "money": {
3977
- const amount = amountOf(raw);
3978
- if (amount === null) return null;
3979
- const currency = typeof row.currency_code === "string" ? row.currency_code : null;
3980
- return { value: formatMoney(amount, currency), kind };
3981
- }
3982
- case "date":
3983
- return typeof raw === "string" || raw instanceof Date ? { value: formatDate(raw), kind } : null;
3984
- case "boolean":
3985
- return { value: raw === true || raw === "true" ? "Yes" : "No", kind };
3986
- case "number": {
3987
- const n = amountOf(raw);
3988
- return n === null ? null : { value: formatNumber(n), kind };
3989
- }
3990
- case "status":
3991
- return { value: String(raw).replace(/_/g, " "), kind };
3992
- default:
3993
- if (typeof raw === "object") return null;
3994
- if (typeof raw === "string" && raw.length > 160) return { value: `${raw.slice(0, 157)}…`, kind };
3995
- return { value: String(raw), kind };
4068
+ if (statusLower === "approved") {
4069
+ return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3996
4070
  }
3997
- }
3998
- function summarizeOldData(tableName, oldData) {
3999
- if (!oldData) return [];
4000
- const { value: row } = maskSensitiveData(oldData, tableName);
4001
- const specific = ENTITY_FIELDS[tableName];
4002
- const specs = specific ?? GENERIC_FIELDS;
4003
- const fields = [];
4004
- const seenLabels = /* @__PURE__ */ new Set();
4005
- for (const spec of specs) {
4006
- const raw = spec.derive ? spec.derive(row) : row[spec.key];
4007
- const formatted = formatValue(raw, spec.kind ?? "text", row);
4008
- if (!formatted || seenLabels.has(spec.label)) continue;
4009
- seenLabels.add(spec.label);
4010
- const value = spec.key === "currency_code" ? formatted.value.toUpperCase() : formatted.value;
4011
- fields.push({ key: spec.key, label: spec.label, value, kind: formatted.kind });
4012
- if (!specific && fields.length >= MAX_GENERIC_FIELDS) break;
4071
+ if (statusLower === "rejected") {
4072
+ return "bg-ui-tag-red-bg text-ui-tag-red-text";
4013
4073
  }
4014
- return fields;
4015
- }
4016
- function readLastListSearch() {
4017
- try {
4018
- return window.sessionStorage.getItem(LAST_LIST_URL_KEY) ?? "";
4019
- } catch {
4020
- return "";
4074
+ if (statusLower === "completed") {
4075
+ return "bg-ui-tag-green-bg text-ui-tag-green-text";
4021
4076
  }
4022
- }
4023
- const DeletedRecordDetailPage = () => {
4024
- var _a;
4077
+ if (statusLower === "cancelled" || statusLower === "canceled") {
4078
+ return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
4079
+ }
4080
+ if (statusLower === "pending") {
4081
+ return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
4082
+ }
4083
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
4084
+ };
4085
+ const SwapDetailPage = () => {
4086
+ var _a, _b, _c;
4025
4087
  const navigate = useNavigate();
4026
- const location = useLocation();
4027
- const { id = "" } = useParams();
4028
- const [state, setState] = useState({ status: "loading" });
4029
- const [reloadToken, setReloadToken] = useState(0);
4030
- const cameFromList = ((_a = location.state) == null ? void 0 : _a.fromList) === true;
4031
- const goBack = () => {
4032
- if (cameFromList) navigate(-1);
4033
- else navigate(`/deleted-records-audit${readLastListSearch()}`);
4034
- };
4088
+ const { id } = useParams();
4089
+ const [swap, setSwap] = useState(null);
4090
+ const [order, setOrder] = useState(null);
4091
+ const [isLoading, setIsLoading] = useState(true);
4092
+ useState(false);
4093
+ const [isCancelling, setIsCancelling] = useState(false);
4094
+ const [error, setError] = useState(null);
4095
+ const [updateError, setUpdateError] = useState(null);
4096
+ const [updateSuccess, setUpdateSuccess] = useState(false);
4035
4097
  useEffect(() => {
4036
- const controller = new AbortController();
4037
- setState({ status: "loading" });
4038
- fetchAuditDetail(id, controller.signal).then((audit) => setState({ status: "ready", audit })).catch((e) => {
4039
- if (controller.signal.aborted) return;
4040
- setState({
4041
- status: "error",
4042
- message: e instanceof Error ? e.message : "Unknown error",
4043
- notFound: e instanceof AuditApiError && e.status === 404
4044
- });
4045
- });
4046
- return () => controller.abort();
4047
- }, [id, reloadToken]);
4048
- 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: [
4049
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "transparent", size: "small", onClick: goBack, className: "-ml-2", children: [
4050
- /* @__PURE__ */ jsx(ArrowLeft, {}),
4051
- "Back to Deleted Records"
4052
- ] }) }),
4053
- state.status === "loading" ? /* @__PURE__ */ jsx(DetailSkeleton, {}) : state.status === "error" ? /* @__PURE__ */ jsx(
4054
- DetailError,
4055
- {
4056
- notFound: state.notFound,
4057
- message: state.message,
4058
- onRetry: () => setReloadToken((t) => t + 1),
4059
- onBack: goBack
4098
+ if (!id) {
4099
+ navigate("/swaps");
4100
+ return;
4101
+ }
4102
+ const loadSwap = async () => {
4103
+ try {
4104
+ setIsLoading(true);
4105
+ setError(null);
4106
+ const response = await fetch(`/admin/swaps/${id}`, {
4107
+ credentials: "include"
4108
+ });
4109
+ if (!response.ok) {
4110
+ const message = await response.text();
4111
+ throw new Error(message || "Unable to load swap");
4112
+ }
4113
+ const payload = await response.json();
4114
+ setSwap(payload.swap);
4115
+ setOrder(payload.order || null);
4116
+ } catch (loadError) {
4117
+ const message = loadError instanceof Error ? loadError.message : "Unable to load swap";
4118
+ setError(message);
4119
+ } finally {
4120
+ setIsLoading(false);
4060
4121
  }
4061
- ) : /* @__PURE__ */ jsx(DetailContent, { audit: state.audit })
4062
- ] }) });
4063
- };
4064
- const DetailContent = ({ audit }) => {
4065
- const navigate = useNavigate();
4066
- const entity = getEntityInfo(audit.table_name);
4067
- const source = describeSource(audit.source);
4068
- const summary = useMemo(() => summarizeOldData(audit.table_name, audit.old_data), [audit]);
4069
- const masked = useMemo(() => maskSensitiveData(audit.old_data, audit.table_name), [audit]);
4070
- const guidance = getNextSteps(entity.category.id);
4071
- const related = getRelatedLinks(audit.table_name, audit.old_data);
4072
- const [showRaw, setShowRaw] = useState(false);
4073
- const copyJson = async () => {
4122
+ };
4123
+ void loadSwap();
4124
+ }, [id, navigate]);
4125
+ const handleCancelExchange = async () => {
4126
+ if (!id) {
4127
+ return;
4128
+ }
4074
4129
  try {
4075
- await navigator.clipboard.writeText(JSON.stringify(masked.value, null, 2));
4076
- toast.success("Record data copied", {
4077
- description: masked.maskedCount ? "Sensitive values were left hidden." : void 0
4130
+ setIsCancelling(true);
4131
+ setUpdateError(null);
4132
+ setUpdateSuccess(false);
4133
+ const response = await fetch(`/admin/swaps/${id}/cancel`, {
4134
+ method: "POST",
4135
+ headers: {
4136
+ "Content-Type": "application/json"
4137
+ },
4138
+ credentials: "include"
4078
4139
  });
4079
- } catch {
4080
- toast.error("Couldn’t copy to clipboard");
4140
+ if (!response.ok) {
4141
+ const message = await response.text();
4142
+ throw new Error(message || "Unable to cancel exchange");
4143
+ }
4144
+ const payload = await response.json();
4145
+ setSwap(payload.swap);
4146
+ setUpdateSuccess(true);
4147
+ setTimeout(() => setUpdateSuccess(false), 3e3);
4148
+ const detailResponse = await fetch(`/admin/swaps/${id}`, {
4149
+ credentials: "include"
4150
+ });
4151
+ if (detailResponse.ok) {
4152
+ const detailPayload = await detailResponse.json();
4153
+ setSwap(detailPayload.swap);
4154
+ setOrder(detailPayload.order || null);
4155
+ }
4156
+ } catch (cancelErr) {
4157
+ const message = cancelErr instanceof Error ? cancelErr.message : "Unable to cancel exchange";
4158
+ setUpdateError(message);
4159
+ } finally {
4160
+ setIsCancelling(false);
4081
4161
  }
4082
4162
  };
4083
- return /* @__PURE__ */ jsxs(Fragment, { children: [
4163
+ const isOrderExchange = Boolean(swap == null ? void 0 : swap.exchange_id);
4164
+ const canCancelExchange = isOrderExchange && swap && !["cancelled", "canceled", "completed", "declined"].includes(
4165
+ ((_a = swap.status) == null ? void 0 : _a.toLowerCase()) ?? ""
4166
+ );
4167
+ if (isLoading) {
4168
+ 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 swap..." }) }) }) });
4169
+ }
4170
+ if (error || !swap) {
4171
+ 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: [
4172
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Swap not found" }),
4173
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/swaps"), children: "Back to list" }) })
4174
+ ] }) }) });
4175
+ }
4176
+ const statusHistory = ((_b = swap.metadata) == null ? void 0 : _b.status_history) || [];
4177
+ 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: [
4084
4178
  /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
4085
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
4086
- /* @__PURE__ */ jsxs(Badge, { size: "small", color: "red", children: [
4087
- /* @__PURE__ */ jsx(Trash, {}),
4088
- "Deleted"
4089
- ] }),
4090
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: entity.category.label })
4091
- ] }),
4092
- /* @__PURE__ */ jsxs(Heading, { level: "h1", children: [
4093
- "Deleted ",
4094
- entity.label
4095
- ] }),
4096
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4097
- /* @__PURE__ */ jsx(CopyableId, { value: audit.record_id, emptyLabel: "This record type has no ID column", className: "text-sm" }),
4098
- /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
4099
- "Database table: ",
4100
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: audit.table_name })
4101
- ] })
4179
+ /* @__PURE__ */ jsxs(
4180
+ Button,
4181
+ {
4182
+ variant: "transparent",
4183
+ size: "small",
4184
+ onClick: () => navigate("/swaps"),
4185
+ className: "w-fit",
4186
+ children: [
4187
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2" }),
4188
+ "Back to list"
4189
+ ]
4190
+ }
4191
+ ),
4192
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 md:flex-row md:items-center md:justify-between", children: [
4193
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4194
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Exchange Details" }),
4195
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: swap.id })
4196
+ ] }),
4197
+ /* @__PURE__ */ jsx(
4198
+ Badge,
4199
+ {
4200
+ size: "small",
4201
+ className: `uppercase ${getStatusBadgeClass$2(swap.status)}`,
4202
+ children: swap.status.replace(/_/g, " ")
4203
+ }
4204
+ )
4102
4205
  ] })
4103
4206
  ] }),
4104
- /* @__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: [
4105
- /* @__PURE__ */ jsx(InformationCircle, { className: "mt-0.5 shrink-0 text-ui-tag-orange-icon" }),
4106
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-tag-orange-text", children: [
4107
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "This is a historical snapshot" }),
4108
- " captured immediately before deletion. The record no longer exists in the database, so changes elsewhere in the admin are not reflected here."
4109
- ] })
4207
+ canCancelExchange && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4208
+ /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsx(
4209
+ Button,
4210
+ {
4211
+ variant: "danger",
4212
+ onClick: handleCancelExchange,
4213
+ disabled: isCancelling,
4214
+ isLoading: isCancelling,
4215
+ children: "Cancel Exchange"
4216
+ }
4217
+ ) }),
4218
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "This will cancel the exchange request. The order will remain unchanged." })
4110
4219
  ] }),
4111
- /* @__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: [
4112
- /* @__PURE__ */ jsx(Field, { label: "Deleted", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
4113
- /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: formatExactDateTime(audit.occurred_at) }),
4114
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-ui-fg-muted", children: [
4115
- /* @__PURE__ */ jsx(ClockSolid, { className: "size-3" }),
4116
- formatRelativeTime(audit.occurred_at)
4220
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
4221
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4222
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Exchange Information" }),
4223
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
4224
+ /* @__PURE__ */ jsxs("div", { children: [
4225
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
4226
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.id })
4227
+ ] }),
4228
+ /* @__PURE__ */ jsxs("div", { children: [
4229
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Status" }),
4230
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.status })
4231
+ ] }),
4232
+ /* @__PURE__ */ jsxs("div", { children: [
4233
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Difference Due" }),
4234
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.difference_due != null ? `${swap.currency_code || "$"}${(Number(swap.difference_due) / 100).toFixed(2)}` : "—" })
4235
+ ] }),
4236
+ swap.reason && /* @__PURE__ */ jsxs("div", { children: [
4237
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Reason" }),
4238
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.reason })
4239
+ ] }),
4240
+ swap.note && /* @__PURE__ */ jsxs("div", { children: [
4241
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Note" }),
4242
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.note })
4243
+ ] }),
4244
+ /* @__PURE__ */ jsxs("div", { children: [
4245
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Created" }),
4246
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(swap.created_at).toLocaleString() })
4247
+ ] }),
4248
+ /* @__PURE__ */ jsxs("div", { children: [
4249
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Last Updated" }),
4250
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(swap.updated_at).toLocaleString() })
4251
+ ] }),
4252
+ swap.exchange_id && /* @__PURE__ */ jsxs("div", { children: [
4253
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
4254
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.exchange_id })
4255
+ ] })
4117
4256
  ] })
4118
- ] }) }),
4119
- /* @__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" }) }),
4120
- /* @__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 }) }),
4121
- /* @__PURE__ */ jsx(Field, { label: "Action", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Permanently deleted" }) })
4122
- ] }) }),
4123
- /* @__PURE__ */ jsx(
4124
- Section,
4125
- {
4126
- title: "Record summary",
4127
- description: `Key details of this ${entity.label.toLowerCase()} at the moment it was deleted.`,
4128
- 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." })
4129
- }
4130
- ),
4131
- /* @__PURE__ */ jsx(
4132
- Section,
4133
- {
4134
- title: "Original record data",
4135
- description: "The complete data captured before deletion.",
4136
- actions: showRaw && audit.old_data ? /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: copyJson, children: [
4137
- /* @__PURE__ */ jsx(SquareTwoStack, {}),
4138
- "Copy JSON"
4139
- ] }) : null,
4140
- children: audit.old_data ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4141
- masked.maskedCount > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4142
- /* @__PURE__ */ jsx(ShieldCheck, { className: "shrink-0 text-ui-fg-muted" }),
4143
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
4144
- masked.maskedCount,
4145
- " sensitive ",
4146
- masked.maskedCount === 1 ? "value is" : "values are",
4147
- " hidden for security (passwords, tokens, card or account numbers)."
4148
- ] })
4149
- ] }) : null,
4150
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: () => setShowRaw((s2) => !s2), "aria-expanded": showRaw, children: [
4151
- showRaw ? /* @__PURE__ */ jsx(ChevronDownMini, {}) : /* @__PURE__ */ jsx(ChevronRightMini, {}),
4152
- showRaw ? "Hide full record" : "View full record"
4153
- ] }) }),
4154
- showRaw ? /* @__PURE__ */ jsx(JsonViewer, { data: masked.value }) : null
4155
- ] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No data was captured for this deletion." })
4156
- }
4157
- ),
4158
- /* @__PURE__ */ jsx(Section, { title: "What you can do now", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
4159
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-base", children: [
4160
- "This record was permanently deleted. ",
4161
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Automatic restoration is not available" }),
4162
- " ",
4163
- "from this screen."
4164
4257
  ] }),
4165
- /* @__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: [
4166
- /* @__PURE__ */ jsxs("li", { children: [
4167
- /* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Check whether this was expected." }),
4168
- " ",
4169
- 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)}.`,
4170
- " ",
4171
- guidance.headline
4258
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4259
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Status History" }),
4260
+ statusHistory.length > 0 ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: statusHistory.map((entry, index) => /* @__PURE__ */ jsx(
4261
+ "div",
4262
+ {
4263
+ className: "flex items-center justify-between border-b border-ui-border-subtle pb-2 last:border-0",
4264
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4265
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
4266
+ Badge,
4267
+ {
4268
+ size: "2xsmall",
4269
+ className: `uppercase ${getStatusBadgeClass$2(entry.status)}`,
4270
+ children: entry.status.replace(/_/g, " ")
4271
+ }
4272
+ ) }),
4273
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
4274
+ new Date(entry.timestamp).toLocaleString(),
4275
+ entry.admin_id && ` by ${entry.admin_id}`,
4276
+ entry.reason && ` - ${entry.reason}`
4277
+ ] })
4278
+ ] })
4279
+ },
4280
+ index
4281
+ )) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No status history available" })
4282
+ ] })
4283
+ ] }),
4284
+ order && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4285
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Related Order Information" }),
4286
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
4287
+ /* @__PURE__ */ jsxs("div", { children: [
4288
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order ID" }),
4289
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: order.id })
4172
4290
  ] }),
4173
- /* @__PURE__ */ jsxs("li", { children: [
4174
- /* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "If it needs to come back:" }),
4175
- " ",
4176
- guidance.recreate
4291
+ /* @__PURE__ */ jsxs("div", { children: [
4292
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Status" }),
4293
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: order.status || "—" })
4177
4294
  ] }),
4178
- /* @__PURE__ */ jsxs("li", { children: [
4179
- /* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Need the details?" }),
4180
- " Use “View full record” above to see or copy everything that was stored. Sensitive values stay hidden."
4295
+ /* @__PURE__ */ jsxs("div", { children: [
4296
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
4297
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: ((_c = order.customer) == null ? void 0 : _c.email) || order.email || "—" })
4298
+ ] }),
4299
+ order.total && /* @__PURE__ */ jsxs("div", { children: [
4300
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
4301
+ /* @__PURE__ */ jsxs(Text, { className: "font-medium", children: [
4302
+ order.currency_code || "$",
4303
+ (Number(order.total) / 100).toFixed(2)
4304
+ ] })
4181
4305
  ] })
4182
- ] }),
4183
- guidance.adminSection || related.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
4184
- guidance.adminSection ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => navigate(guidance.adminSection.path), children: guidance.adminSection.label }) : null,
4185
- related.map((link) => /* @__PURE__ */ jsxs(
4186
- Button,
4187
- {
4188
- variant: "transparent",
4189
- size: "small",
4190
- onClick: () => navigate(link.path),
4191
- title: `Opens ${link.label.toLowerCase()} ${link.id} if it still exists`,
4192
- children: [
4193
- "Open related ",
4194
- link.label.toLowerCase(),
4195
- /* @__PURE__ */ jsx(ChevronRightMini, {})
4196
- ]
4197
- },
4198
- link.path
4199
- ))
4200
- ] }) : null,
4201
- 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
4202
- ] }) })
4203
- ] });
4204
- };
4205
- const Section = ({
4206
- title,
4207
- description,
4208
- actions,
4209
- children
4210
- }) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4 rounded-lg border border-ui-border-base p-5", children: [
4211
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [
4212
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
4213
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
4214
- description ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: description }) : null
4306
+ ] })
4215
4307
  ] }),
4216
- actions
4217
- ] }),
4218
- children
4219
- ] });
4220
- const Field = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4221
- /* @__PURE__ */ jsx("dt", { className: "text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: label }),
4222
- /* @__PURE__ */ jsx("dd", { className: "min-w-0", children })
4223
- ] });
4224
- const DetailSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "aria-busy": "true", children: [
4225
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4226
- /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" }),
4227
- /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-64" }),
4228
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
4229
- ] }),
4230
- /* @__PURE__ */ jsx(Skeleton, { className: "h-14 w-full" }),
4231
- 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: [
4232
- /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" }),
4233
- /* @__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: [
4234
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" }),
4235
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-36" })
4236
- ] }, j)) })
4237
- ] }, i))
4238
- ] });
4239
- const DetailError = ({
4240
- notFound,
4241
- message,
4242
- onRetry,
4243
- onBack
4244
- }) => /* @__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: [
4245
- /* @__PURE__ */ jsx(ExclamationCircle, { className: clx(notFound ? "text-ui-fg-muted" : "text-ui-fg-error") }),
4246
- /* @__PURE__ */ jsx(Heading, { level: "h3", children: notFound ? "Audit entry not found" : "Unable to load this deleted record" }),
4247
- /* @__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." }),
4248
- !notFound ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: message }) : null,
4249
- /* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
4250
- /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: onBack, children: "Back to Deleted Records" }),
4251
- !notFound ? /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: onRetry, children: "Try again" }) : null
4252
- ] })
4253
- ] });
4254
- defineRouteConfig({});
4308
+ swap.return_items && swap.return_items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4309
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Items" }),
4310
+ /* @__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: [
4311
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
4312
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Item ID" }),
4313
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" }),
4314
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Reason" })
4315
+ ] }) }),
4316
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.return_items.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [
4317
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.id }),
4318
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity }),
4319
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.reason || "—" })
4320
+ ] }, item.id || index)) })
4321
+ ] }) })
4322
+ ] }),
4323
+ swap.new_items && swap.new_items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4324
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "New Items" }),
4325
+ /* @__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: [
4326
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
4327
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Variant ID" }),
4328
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" })
4329
+ ] }) }),
4330
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.new_items.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [
4331
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.variant_id }),
4332
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity })
4333
+ ] }, item.variant_id || index)) })
4334
+ ] }) })
4335
+ ] })
4336
+ ] }) });
4337
+ };
4338
+ const config$2 = defineRouteConfig({
4339
+ label: "Swap Details",
4340
+ icon: ArrowPath
4341
+ });
4255
4342
  const getStatusBadgeClass$1 = (status) => {
4256
4343
  const statusLower = status.toLowerCase();
4257
4344
  if (statusLower === "requested") {
@@ -4536,283 +4623,196 @@ const config$1 = defineRouteConfig({
4536
4623
  icon: CheckCircle
4537
4624
  });
4538
4625
  const getStatusBadgeClass = (status) => {
4539
- const statusLower = status.toLowerCase();
4540
- if (statusLower === "requested") {
4541
- return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
4542
- }
4543
- if (statusLower === "approved") {
4544
- return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
4545
- }
4546
- if (statusLower === "rejected") {
4547
- return "bg-ui-tag-red-bg text-ui-tag-red-text";
4548
- }
4549
- if (statusLower === "completed") {
4550
- return "bg-ui-tag-green-bg text-ui-tag-green-text";
4551
- }
4552
- if (statusLower === "cancelled" || statusLower === "canceled") {
4553
- return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
4554
- }
4555
- if (statusLower === "pending") {
4556
- return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
4557
- }
4626
+ const s2 = status.toLowerCase();
4627
+ if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
4628
+ if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
4629
+ if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
4630
+ if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
4558
4631
  return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
4559
4632
  };
4560
- const SwapDetailPage = () => {
4633
+ const formatAmount = (value) => {
4634
+ return String(value);
4635
+ };
4636
+ const RefundDetailPage = () => {
4561
4637
  var _a, _b, _c;
4562
4638
  const navigate = useNavigate();
4563
- const { id } = useParams();
4564
- const [swap, setSwap] = useState(null);
4565
- const [order, setOrder] = useState(null);
4566
- const [isLoading, setIsLoading] = useState(true);
4567
- useState(false);
4568
- const [isCancelling, setIsCancelling] = useState(false);
4639
+ const params = useParams();
4640
+ const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
4641
+ const [detail, setDetail] = useState(null);
4642
+ const [loading, setLoading] = useState(!!id);
4569
4643
  const [error, setError] = useState(null);
4570
- const [updateError, setUpdateError] = useState(null);
4571
- const [updateSuccess, setUpdateSuccess] = useState(false);
4644
+ const [gatewayExpanded, setGatewayExpanded] = useState(false);
4572
4645
  useEffect(() => {
4573
4646
  if (!id) {
4574
- navigate("/swaps");
4647
+ setLoading(false);
4575
4648
  return;
4576
4649
  }
4577
- const loadSwap = async () => {
4578
- try {
4579
- setIsLoading(true);
4580
- setError(null);
4581
- const response = await fetch(`/admin/swaps/${id}`, {
4582
- credentials: "include"
4583
- });
4584
- if (!response.ok) {
4585
- const message = await response.text();
4586
- throw new Error(message || "Unable to load swap");
4587
- }
4588
- const payload = await response.json();
4589
- setSwap(payload.swap);
4590
- setOrder(payload.order || null);
4591
- } catch (loadError) {
4592
- const message = loadError instanceof Error ? loadError.message : "Unable to load swap";
4593
- setError(message);
4594
- } finally {
4595
- setIsLoading(false);
4596
- }
4650
+ let cancelled = false;
4651
+ setLoading(true);
4652
+ setError(null);
4653
+ fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
4654
+ if (!res.ok) throw new Error(res.statusText || "Failed to load");
4655
+ return res.json();
4656
+ }).then((data) => {
4657
+ if (!cancelled) setDetail(data);
4658
+ }).catch((e) => {
4659
+ if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
4660
+ }).finally(() => {
4661
+ if (!cancelled) setLoading(false);
4662
+ });
4663
+ return () => {
4664
+ cancelled = true;
4597
4665
  };
4598
- void loadSwap();
4599
- }, [id, navigate]);
4600
- const handleCancelExchange = async () => {
4601
- if (!id) {
4602
- return;
4603
- }
4604
- try {
4605
- setIsCancelling(true);
4606
- setUpdateError(null);
4607
- setUpdateSuccess(false);
4608
- const response = await fetch(`/admin/swaps/${id}/cancel`, {
4609
- method: "POST",
4610
- headers: {
4611
- "Content-Type": "application/json"
4612
- },
4613
- credentials: "include"
4614
- });
4615
- if (!response.ok) {
4616
- const message = await response.text();
4617
- throw new Error(message || "Unable to cancel exchange");
4618
- }
4619
- const payload = await response.json();
4620
- setSwap(payload.swap);
4621
- setUpdateSuccess(true);
4622
- setTimeout(() => setUpdateSuccess(false), 3e3);
4623
- const detailResponse = await fetch(`/admin/swaps/${id}`, {
4624
- credentials: "include"
4625
- });
4626
- if (detailResponse.ok) {
4627
- const detailPayload = await detailResponse.json();
4628
- setSwap(detailPayload.swap);
4629
- setOrder(detailPayload.order || null);
4630
- }
4631
- } catch (cancelErr) {
4632
- const message = cancelErr instanceof Error ? cancelErr.message : "Unable to cancel exchange";
4633
- setUpdateError(message);
4634
- } finally {
4635
- setIsCancelling(false);
4636
- }
4637
- };
4638
- const isOrderExchange = Boolean(swap == null ? void 0 : swap.exchange_id);
4639
- const canCancelExchange = isOrderExchange && swap && !["cancelled", "canceled", "completed", "declined"].includes(
4640
- ((_a = swap.status) == null ? void 0 : _a.toLowerCase()) ?? ""
4641
- );
4642
- if (isLoading) {
4643
- 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 swap..." }) }) }) });
4644
- }
4645
- if (error || !swap) {
4646
- 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: [
4647
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error || "Swap not found" }),
4648
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/swaps"), children: "Back to list" }) })
4649
- ] }) }) });
4650
- }
4651
- const statusHistory = ((_b = swap.metadata) == null ? void 0 : _b.status_history) || [];
4652
- 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: [
4653
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
4654
- /* @__PURE__ */ jsxs(
4655
- Button,
4656
- {
4657
- variant: "transparent",
4658
- size: "small",
4659
- onClick: () => navigate("/swaps"),
4660
- className: "w-fit",
4661
- children: [
4662
- /* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2" }),
4663
- "Back to list"
4664
- ]
4665
- }
4666
- ),
4667
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 md:flex-row md:items-center md:justify-between", children: [
4668
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4669
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Exchange Details" }),
4670
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: swap.id })
4671
- ] }),
4672
- /* @__PURE__ */ jsx(
4673
- Badge,
4674
- {
4675
- size: "small",
4676
- className: `uppercase ${getStatusBadgeClass(swap.status)}`,
4677
- children: swap.status.replace(/_/g, " ")
4678
- }
4679
- )
4680
- ] })
4681
- ] }),
4682
- canCancelExchange && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4683
- /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsx(
4684
- Button,
4685
- {
4686
- variant: "danger",
4687
- onClick: handleCancelExchange,
4688
- disabled: isCancelling,
4689
- isLoading: isCancelling,
4690
- children: "Cancel Exchange"
4691
- }
4692
- ) }),
4693
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "This will cancel the exchange request. The order will remain unchanged." })
4694
- ] }),
4695
- /* @__PURE__ */ jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
4696
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4697
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Exchange Information" }),
4698
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
4666
+ }, [id]);
4667
+ const paymentStatus = ((_b = detail == null ? void 0 : detail.payment) == null ? void 0 : _b.status) ?? "—";
4668
+ const hasGatewayData = ((_c = detail == null ? void 0 : detail.payment) == null ? void 0 : _c.payment_data) && typeof detail.payment.payment_data === "object" && Object.keys(detail.payment.payment_data).length > 0;
4669
+ 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: [
4670
+ /* @__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: [
4671
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
4672
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
4673
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
4674
+ ] }) }),
4675
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
4676
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
4677
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
4678
+ ] }) : 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: [
4679
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
4680
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
4681
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
4699
4682
  /* @__PURE__ */ jsxs("div", { children: [
4700
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
4701
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.id })
4683
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund ID" }),
4684
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.id })
4685
+ ] }),
4686
+ /* @__PURE__ */ jsxs("div", { children: [
4687
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
4688
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.refund.amount) })
4689
+ ] }),
4690
+ /* @__PURE__ */ jsxs("div", { children: [
4691
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Note" }),
4692
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.refund.note ?? "—" })
4693
+ ] }),
4694
+ /* @__PURE__ */ jsxs("div", { children: [
4695
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created at" }),
4696
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.refund.created_at).toLocaleDateString("en-US", {
4697
+ year: "numeric",
4698
+ month: "short",
4699
+ day: "numeric",
4700
+ hour: "numeric",
4701
+ minute: "2-digit",
4702
+ hour12: true
4703
+ }) })
4704
+ ] }),
4705
+ detail.refund.created_by ? /* @__PURE__ */ jsxs("div", { children: [
4706
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created by" }),
4707
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.created_by })
4708
+ ] }) : null
4709
+ ] })
4710
+ ] }),
4711
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
4712
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
4713
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
4714
+ /* @__PURE__ */ jsxs("div", { children: [
4715
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
4716
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
4702
4717
  ] }),
4703
4718
  /* @__PURE__ */ jsxs("div", { children: [
4704
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Status" }),
4705
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.status })
4719
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
4720
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
4706
4721
  ] }),
4707
4722
  /* @__PURE__ */ jsxs("div", { children: [
4708
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Difference Due" }),
4709
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.difference_due != null ? `${swap.currency_code || "$"}${(Number(swap.difference_due) / 100).toFixed(2)}` : "—" })
4710
- ] }),
4711
- swap.reason && /* @__PURE__ */ jsxs("div", { children: [
4712
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Reason" }),
4713
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.reason })
4714
- ] }),
4715
- swap.note && /* @__PURE__ */ jsxs("div", { children: [
4716
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Note" }),
4717
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.note })
4723
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
4724
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
4718
4725
  ] }),
4719
4726
  /* @__PURE__ */ jsxs("div", { children: [
4720
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Created" }),
4721
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(swap.created_at).toLocaleString() })
4727
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
4728
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
4722
4729
  ] }),
4723
4730
  /* @__PURE__ */ jsxs("div", { children: [
4724
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Last Updated" }),
4725
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: new Date(swap.updated_at).toLocaleString() })
4731
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
4732
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
4733
+ Badge,
4734
+ {
4735
+ size: "2xsmall",
4736
+ className: `uppercase ${getStatusBadgeClass(paymentStatus)}`,
4737
+ children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
4738
+ }
4739
+ ) })
4726
4740
  ] }),
4727
- swap.exchange_id && /* @__PURE__ */ jsxs("div", { children: [
4728
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Exchange ID" }),
4729
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: swap.exchange_id })
4730
- ] })
4731
- ] })
4732
- ] }),
4733
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4734
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Status History" }),
4735
- statusHistory.length > 0 ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: statusHistory.map((entry, index) => /* @__PURE__ */ jsx(
4736
- "div",
4737
- {
4738
- className: "flex items-center justify-between border-b border-ui-border-subtle pb-2 last:border-0",
4739
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4740
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
4741
- Badge,
4742
- {
4743
- size: "2xsmall",
4744
- className: `uppercase ${getStatusBadgeClass(entry.status)}`,
4745
- children: entry.status.replace(/_/g, " ")
4746
- }
4747
- ) }),
4748
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
4749
- new Date(entry.timestamp).toLocaleString(),
4750
- entry.admin_id && ` by ${entry.admin_id}`,
4751
- entry.reason && ` - ${entry.reason}`
4741
+ detail.computed ? /* @__PURE__ */ jsxs(Fragment, { children: [
4742
+ /* @__PURE__ */ jsxs("div", { children: [
4743
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Full refund" }),
4744
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.computed.is_full_refund ? "Yes" : "No" })
4745
+ ] }),
4746
+ /* @__PURE__ */ jsxs("div", { children: [
4747
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Remaining refundable" }),
4748
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.computed.remaining_refundable_amount) })
4749
+ ] }),
4750
+ /* @__PURE__ */ jsxs("div", { children: [
4751
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund %" }),
4752
+ /* @__PURE__ */ jsxs(Text, { className: "mt-1 block", children: [
4753
+ detail.computed.refund_percentage.toFixed(1),
4754
+ "%"
4752
4755
  ] })
4753
4756
  ] })
4754
- },
4755
- index
4756
- )) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "No status history available" })
4757
- ] })
4758
- ] }),
4759
- order && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4760
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Related Order Information" }),
4761
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
4762
- /* @__PURE__ */ jsxs("div", { children: [
4763
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order ID" }),
4764
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: order.id })
4765
- ] }),
4766
- /* @__PURE__ */ jsxs("div", { children: [
4767
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Status" }),
4768
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: order.status || "—" })
4769
- ] }),
4770
- /* @__PURE__ */ jsxs("div", { children: [
4771
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
4772
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: ((_c = order.customer) == null ? void 0 : _c.email) || order.email || "—" })
4773
- ] }),
4774
- order.total && /* @__PURE__ */ jsxs("div", { children: [
4775
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
4776
- /* @__PURE__ */ jsxs(Text, { className: "font-medium", children: [
4777
- order.currency_code || "$",
4778
- (Number(order.total) / 100).toFixed(2)
4779
- ] })
4757
+ ] }) : null
4780
4758
  ] })
4759
+ ] }),
4760
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
4761
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Order summary" }),
4762
+ detail.order ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
4763
+ /* @__PURE__ */ jsxs("div", { children: [
4764
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order" }),
4765
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
4766
+ Button,
4767
+ {
4768
+ variant: "transparent",
4769
+ size: "small",
4770
+ onClick: () => navigate(`/orders/${detail.order.order_id}`),
4771
+ children: detail.order.order_number ?? detail.order.order_id
4772
+ }
4773
+ ) })
4774
+ ] }),
4775
+ detail.order.total != null ? /* @__PURE__ */ jsxs("div", { children: [
4776
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Total" }),
4777
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.order.total) })
4778
+ ] }) : null,
4779
+ detail.order.customer_id ? /* @__PURE__ */ jsxs("div", { children: [
4780
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Customer ID" }),
4781
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.order.customer_id })
4782
+ ] }) : null,
4783
+ detail.order.region ? /* @__PURE__ */ jsxs("div", { children: [
4784
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Region" }),
4785
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.region })
4786
+ ] }) : null,
4787
+ detail.order.fulfillment_status ? /* @__PURE__ */ jsxs("div", { children: [
4788
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
4789
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
4790
+ ] }) : null
4791
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
4792
+ ] }),
4793
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
4794
+ /* @__PURE__ */ jsxs(
4795
+ "button",
4796
+ {
4797
+ type: "button",
4798
+ className: "flex w-full items-center justify-between text-left",
4799
+ onClick: () => setGatewayExpanded((prev) => !prev),
4800
+ "aria-expanded": gatewayExpanded,
4801
+ "aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
4802
+ children: [
4803
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
4804
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
4805
+ ]
4806
+ }
4807
+ ),
4808
+ 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." }) })
4781
4809
  ] })
4782
- ] }),
4783
- swap.return_items && swap.return_items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4784
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Items" }),
4785
- /* @__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: [
4786
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
4787
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Item ID" }),
4788
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" }),
4789
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Reason" })
4790
- ] }) }),
4791
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.return_items.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [
4792
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.id }),
4793
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity }),
4794
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.reason || "—" })
4795
- ] }, item.id || index)) })
4796
- ] }) })
4797
- ] }),
4798
- swap.new_items && swap.new_items.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
4799
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "New Items" }),
4800
- /* @__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: [
4801
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
4802
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Variant ID" }),
4803
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Quantity" })
4804
- ] }) }),
4805
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: swap.new_items.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [
4806
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: item.variant_id }),
4807
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: item.quantity })
4808
- ] }, item.variant_id || index)) })
4809
- ] }) })
4810
- ] })
4810
+ ] }) : null
4811
4811
  ] }) });
4812
4812
  };
4813
4813
  const config = defineRouteConfig({
4814
- label: "Swap Details",
4815
- icon: ArrowPath
4814
+ label: "Refund details",
4815
+ icon: Receipt
4816
4816
  });
4817
4817
  const i18nTranslations0 = {};
4818
4818
  const widgetModule = { widgets: [
@@ -4827,72 +4827,84 @@ const widgetModule = { widgets: [
4827
4827
  ] };
4828
4828
  const routeModule = {
4829
4829
  routes: [
4830
- {
4831
- Component: PaymentsPage,
4832
- path: "/payments"
4833
- },
4834
- {
4835
- Component: RefundsPage,
4836
- path: "/refunds"
4837
- },
4838
4830
  {
4839
4831
  Component: DeletedRecordsPage,
4840
4832
  path: "/deleted-records-audit"
4841
4833
  },
4834
+ {
4835
+ Component: PaymentsPage,
4836
+ path: "/payments"
4837
+ },
4842
4838
  {
4843
4839
  Component: ReturnsPage,
4844
4840
  path: "/returns"
4845
4841
  },
4842
+ {
4843
+ Component: DeletedRecordDetailPage,
4844
+ path: "/deleted-records-audit/:id"
4845
+ },
4846
4846
  {
4847
4847
  Component: SwapsPage,
4848
4848
  path: "/swaps"
4849
4849
  },
4850
4850
  {
4851
- Component: PaymentDetailPage,
4852
- path: "/payments/:id"
4851
+ Component: RefundsPage,
4852
+ path: "/refunds"
4853
4853
  },
4854
4854
  {
4855
- Component: RefundDetailPage,
4856
- path: "/refunds/:id"
4855
+ Component: PaymentDetailPage,
4856
+ path: "/payments/:id"
4857
4857
  },
4858
4858
  {
4859
- Component: DeletedRecordDetailPage,
4860
- path: "/deleted-records-audit/:id"
4859
+ Component: SwapDetailPage,
4860
+ path: "/swaps/:id"
4861
4861
  },
4862
4862
  {
4863
4863
  Component: ReturnDetailPage,
4864
4864
  path: "/returns/:id"
4865
4865
  },
4866
4866
  {
4867
- Component: SwapDetailPage,
4868
- path: "/swaps/:id"
4867
+ Component: RefundDetailPage,
4868
+ path: "/refunds/:id"
4869
4869
  }
4870
4870
  ]
4871
4871
  };
4872
4872
  const menuItemModule = {
4873
4873
  menuItems: [
4874
4874
  {
4875
- label: config$5.label,
4876
- icon: config$5.icon,
4877
- path: "/returns",
4875
+ label: config$8.label,
4876
+ icon: config$8.icon,
4877
+ path: "/deleted-records-audit",
4878
4878
  nested: void 0
4879
4879
  },
4880
4880
  {
4881
4881
  label: config$7.label,
4882
4882
  icon: config$7.icon,
4883
- path: "/refunds",
4883
+ path: "/payments",
4884
+ nested: void 0
4885
+ },
4886
+ {
4887
+ label: config$6.label,
4888
+ icon: config$6.icon,
4889
+ path: "/returns",
4890
+ nested: void 0
4891
+ },
4892
+ {
4893
+ label: config$5.label,
4894
+ icon: config$5.icon,
4895
+ path: "/swaps",
4884
4896
  nested: void 0
4885
4897
  },
4886
4898
  {
4887
4899
  label: config$4.label,
4888
4900
  icon: config$4.icon,
4889
- path: "/swaps",
4901
+ path: "/refunds",
4890
4902
  nested: void 0
4891
4903
  },
4892
4904
  {
4893
- label: config$6.label,
4894
- icon: config$6.icon,
4895
- path: "/deleted-records-audit",
4905
+ label: config$3.label,
4906
+ icon: config$3.icon,
4907
+ path: "/payments/:id",
4896
4908
  nested: void 0
4897
4909
  },
4898
4910
  {
@@ -4901,28 +4913,16 @@ const menuItemModule = {
4901
4913
  path: "/returns/:id",
4902
4914
  nested: void 0
4903
4915
  },
4904
- {
4905
- label: config$8.label,
4906
- icon: config$8.icon,
4907
- path: "/payments",
4908
- nested: void 0
4909
- },
4910
4916
  {
4911
4917
  label: config$2.label,
4912
4918
  icon: config$2.icon,
4913
- path: "/refunds/:id",
4919
+ path: "/swaps/:id",
4914
4920
  nested: void 0
4915
4921
  },
4916
4922
  {
4917
4923
  label: config.label,
4918
4924
  icon: config.icon,
4919
- path: "/swaps/:id",
4920
- nested: void 0
4921
- },
4922
- {
4923
- label: config$3.label,
4924
- icon: config$3.icon,
4925
- path: "/payments/:id",
4925
+ path: "/refunds/:id",
4926
4926
  nested: void 0
4927
4927
  }
4928
4928
  ]