order-management 0.0.90 → 0.0.91

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.
@@ -1,8 +1,8 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
3
3
  import { useState, useEffect, useRef, useCallback, useMemo } from "react";
4
- import { Container, Text, Heading, Badge, Button, Label, Select, Textarea, Input } from "@medusajs/ui";
5
- import { CashSolid, PencilSquareSolid, Trash, Receipt, ArrowPath, CheckCircle, ArrowLeft, CreditCard } from "@medusajs/icons";
4
+ import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Input } from "@medusajs/ui";
5
+ import { CashSolid, PencilSquareSolid, Trash, CreditCard, Receipt, ArrowPath, CheckCircle, ArrowLeft } from "@medusajs/icons";
6
6
  import { useNavigate, useParams } from "react-router-dom";
7
7
  function roundRectPath(ctx, x, y, w, h, r) {
8
8
  ctx.beginPath();
@@ -469,6 +469,48 @@ const OrderGiftItemsWidget = ({ data }) => {
469
469
  defineWidgetConfig({
470
470
  zone: "order.details.side.after"
471
471
  });
472
+ function formatRefundCurrency(amount, currencyCode = "inr", options) {
473
+ const formatted = new Intl.NumberFormat("en-IN", {
474
+ style: "currency",
475
+ currency: (currencyCode || "inr").toUpperCase(),
476
+ currencyDisplay: "symbol",
477
+ minimumFractionDigits: 2,
478
+ maximumFractionDigits: 2
479
+ }).format(amount);
480
+ if ((options == null ? void 0 : options.signed) && amount > 0) {
481
+ return `−${formatted}`;
482
+ }
483
+ return formatted;
484
+ }
485
+ const RefundCalculationBlock = ({ refund }) => {
486
+ const currency = refund.currency_code || "inr";
487
+ const finalLabel = refund.is_processed ? formatRefundCurrency(refund.final_refund_amount ?? 0, currency) : "Refund pending";
488
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
489
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Refund calculation" }),
490
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
491
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
492
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Product amount" }),
493
+ /* @__PURE__ */ jsx(Text, { size: "small", children: formatRefundCurrency(refund.product_amount, currency) })
494
+ ] }),
495
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
496
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Return charge" }),
497
+ /* @__PURE__ */ jsx(Text, { size: "small", children: formatRefundCurrency(refund.return_charge, currency, { signed: true }) })
498
+ ] }),
499
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4 border-t border-ui-border-base pt-1.5", children: [
500
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Final refund amount" }),
501
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: finalLabel })
502
+ ] })
503
+ ] }),
504
+ refund.is_processed && refund.destination_label ? /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
505
+ formatRefundCurrency(refund.final_refund_amount ?? 0, currency),
506
+ " will be refunded to",
507
+ " ",
508
+ refund.destination_label,
509
+ "."
510
+ ] }) : null,
511
+ !refund.is_processed ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "Refund pending." }) : null
512
+ ] });
513
+ };
472
514
  const FIELD_LABELS = {
473
515
  // UPI
474
516
  upi_id: "UPI ID",
@@ -635,7 +677,7 @@ const OrderRefundContextWidget = (props) => {
635
677
  }
636
678
  };
637
679
  if (!orderId) return null;
638
- if (!loading && !error && context && !context.refund_mapping) return null;
680
+ if (!loading && !error && context && !context.refund_mapping && !context.refund) return null;
639
681
  if (loading) {
640
682
  return /* @__PURE__ */ jsx(Container, { className: "mt-6 divide-y p-0", children: /* @__PURE__ */ jsx("div", { className: "py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Loading refund context..." }) }) });
641
683
  }
@@ -658,6 +700,7 @@ const OrderRefundContextWidget = (props) => {
658
700
  /* @__PURE__ */ jsx(Text, { size: "small", children: context.return_id }),
659
701
  ((_d = context.refund_mapping) == null ? void 0 : _d.is_refunded) ? /* @__PURE__ */ jsx(Badge, { color: "green", children: "Refunded" }) : /* @__PURE__ */ jsx(Badge, { color: "orange", children: "Not refunded" })
660
702
  ] }),
703
+ context.refund ? /* @__PURE__ */ jsx("div", { className: "mt-3 border-t border-ui-border-base pt-3", children: /* @__PURE__ */ jsx(RefundCalculationBlock, { refund: context.refund }) }) : null,
661
704
  /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2 border-t border-ui-border-base pt-3", children: [
662
705
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
663
706
  /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Payment method (refund destination)" }),
@@ -850,7 +893,10 @@ const OrderRefundContextWidget = (props) => {
850
893
  markError && /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-error", children: markError })
851
894
  ] })
852
895
  ] }),
853
- hasReturn && !hasMapping && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No refund payment mapping for this return. Ensure the refund_payment_mapping module is registered and a mapping was created when the return was created." })
896
+ hasReturn && !hasMapping && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-4", children: [
897
+ (context == null ? void 0 : context.refund) ? /* @__PURE__ */ jsx(RefundCalculationBlock, { refund: context.refund }) : null,
898
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No refund payment mapping for this return. Ensure the refund_payment_mapping module is registered and a mapping was created when the return was created." })
899
+ ] })
854
900
  ] }) });
855
901
  };
856
902
  defineWidgetConfig({
@@ -872,16 +918,216 @@ const getStatusBadgeClass$7 = (status) => {
872
918
  if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
873
919
  return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
874
920
  };
875
- const RefundsPage = () => {
921
+ const PaymentsPage = () => {
876
922
  const navigate = useNavigate();
877
923
  const [items, setItems] = useState([]);
924
+ const [statusFilter, setStatusFilter] = useState("all");
878
925
  const [orderIdSearch, setOrderIdSearch] = useState("");
879
926
  const debouncedOrderId = useDebounce$3(orderIdSearch, 300);
927
+ const [isLoading, setIsLoading] = useState(true);
928
+ const [isFetchingMore, setIsFetchingMore] = useState(false);
929
+ const [error, setError] = useState(null);
930
+ const [offset, setOffset] = useState(0);
931
+ const [count, setCount] = useState(0);
932
+ const limit = 50;
933
+ const loadTransactions = useCallback(
934
+ async (nextOffset, replace) => {
935
+ try {
936
+ if (replace) setIsLoading(true);
937
+ else setIsFetchingMore(true);
938
+ setError(null);
939
+ const params = new URLSearchParams();
940
+ params.set("limit", String(limit));
941
+ params.set("offset", String(nextOffset));
942
+ if (statusFilter !== "all") params.set("status", statusFilter);
943
+ if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
944
+ const response = await fetch(
945
+ `/admin/payment-transactions?${params.toString()}`,
946
+ { credentials: "include" }
947
+ );
948
+ if (!response.ok) {
949
+ const text = await response.text();
950
+ throw new Error(text || "Failed to load payment transactions");
951
+ }
952
+ const payload = await response.json();
953
+ const list = payload.transactions ?? [];
954
+ setCount(payload.count ?? 0);
955
+ setOffset(nextOffset + list.length);
956
+ setItems((prev) => replace ? list : [...prev, ...list]);
957
+ } catch (e) {
958
+ setError(e instanceof Error ? e.message : "Failed to load");
959
+ } finally {
960
+ setIsLoading(false);
961
+ setIsFetchingMore(false);
962
+ }
963
+ },
964
+ [statusFilter, debouncedOrderId]
965
+ );
966
+ useEffect(() => {
967
+ void loadTransactions(0, true);
968
+ }, [loadTransactions]);
969
+ const hasMore = useMemo(() => offset < count, [offset, count]);
970
+ const displayStatus = (t) => {
971
+ const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
972
+ return s2 !== "" ? s2 : "—";
973
+ };
974
+ const displayAmount = (t) => {
975
+ const code = (t.currency_code ?? "USD").toUpperCase();
976
+ return `${code} ${Number(t.amount)}`;
977
+ };
978
+ 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: [
979
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
980
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
981
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
982
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
983
+ ] }),
984
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
985
+ ] }),
986
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
987
+ /* @__PURE__ */ jsx(
988
+ Input,
989
+ {
990
+ placeholder: "Search by Order ID",
991
+ value: orderIdSearch,
992
+ onChange: (e) => setOrderIdSearch(e.target.value),
993
+ className: "md:max-w-sm",
994
+ "aria-label": "Search by order ID"
995
+ }
996
+ ),
997
+ /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
998
+ "select",
999
+ {
1000
+ value: statusFilter,
1001
+ onChange: (e) => setStatusFilter(e.target.value),
1002
+ 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",
1003
+ "aria-label": "Filter by status",
1004
+ children: [
1005
+ /* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
1006
+ /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
1007
+ /* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
1008
+ /* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
1009
+ /* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
1010
+ /* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
1011
+ /* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
1012
+ ]
1013
+ }
1014
+ ) })
1015
+ ] }),
1016
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
1017
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
1018
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
1019
+ ] }) : null,
1020
+ 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: [
1021
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
1022
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
1023
+ ] }) : /* @__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: [
1024
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
1025
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
1026
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
1027
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
1028
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
1029
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
1030
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
1031
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
1032
+ ] }) }),
1033
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
1034
+ "tr",
1035
+ {
1036
+ className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
1037
+ onClick: () => navigate(`/payments/${t.payment_session_id}`),
1038
+ children: [
1039
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
1040
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
1041
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
1042
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
1043
+ Badge,
1044
+ {
1045
+ size: "2xsmall",
1046
+ className: `uppercase ${getStatusBadgeClass$7(displayStatus(t))}`,
1047
+ children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
1048
+ }
1049
+ ) }),
1050
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
1051
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
1052
+ year: "numeric",
1053
+ month: "short",
1054
+ day: "numeric",
1055
+ hour: "numeric",
1056
+ minute: "2-digit",
1057
+ hour12: true
1058
+ }) }),
1059
+ /* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
1060
+ /* @__PURE__ */ jsx(
1061
+ Button,
1062
+ {
1063
+ variant: "transparent",
1064
+ size: "small",
1065
+ onClick: (e) => {
1066
+ e.stopPropagation();
1067
+ navigate(`/payments/${t.payment_session_id}`);
1068
+ },
1069
+ children: "View details"
1070
+ }
1071
+ ),
1072
+ t.order_id ? /* @__PURE__ */ jsx(
1073
+ Button,
1074
+ {
1075
+ variant: "transparent",
1076
+ size: "small",
1077
+ onClick: (e) => {
1078
+ e.stopPropagation();
1079
+ navigate(`/orders/${t.order_id}`);
1080
+ },
1081
+ children: "Order"
1082
+ }
1083
+ ) : null
1084
+ ] })
1085
+ ]
1086
+ },
1087
+ t.payment_session_id
1088
+ )) })
1089
+ ] }) }),
1090
+ hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
1091
+ Button,
1092
+ {
1093
+ variant: "secondary",
1094
+ isLoading: isFetchingMore,
1095
+ onClick: () => loadTransactions(offset, false),
1096
+ children: "Load more"
1097
+ }
1098
+ ) }) : null
1099
+ ] }) });
1100
+ };
1101
+ const config$7 = defineRouteConfig({
1102
+ label: "Payments",
1103
+ icon: CreditCard
1104
+ });
1105
+ const useDebounce$2 = (value, delay) => {
1106
+ const [debouncedValue, setDebouncedValue] = useState(value);
1107
+ useEffect(() => {
1108
+ const handler = setTimeout(() => setDebouncedValue(value), delay);
1109
+ return () => clearTimeout(handler);
1110
+ }, [value, delay]);
1111
+ return debouncedValue;
1112
+ };
1113
+ const getStatusBadgeClass$6 = (status) => {
1114
+ const s2 = status.toLowerCase();
1115
+ if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
1116
+ if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
1117
+ if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
1118
+ if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
1119
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
1120
+ };
1121
+ const RefundsPage = () => {
1122
+ const navigate = useNavigate();
1123
+ const [items, setItems] = useState([]);
1124
+ const [orderIdSearch, setOrderIdSearch] = useState("");
1125
+ const debouncedOrderId = useDebounce$2(orderIdSearch, 300);
880
1126
  const [paymentStatusFilter, setPaymentStatusFilter] = useState("all");
881
1127
  const [providerSearch, setProviderSearch] = useState("");
882
- const debouncedProvider = useDebounce$3(providerSearch, 300);
1128
+ const debouncedProvider = useDebounce$2(providerSearch, 300);
883
1129
  const [currencySearch, setCurrencySearch] = useState("");
884
- const debouncedCurrency = useDebounce$3(currencySearch, 300);
1130
+ const debouncedCurrency = useDebounce$2(currencySearch, 300);
885
1131
  const [dateFrom, setDateFrom] = useState("");
886
1132
  const [dateTo, setDateTo] = useState("");
887
1133
  const [amountMin, setAmountMin] = useState("");
@@ -1093,7 +1339,7 @@ const RefundsPage = () => {
1093
1339
  Badge,
1094
1340
  {
1095
1341
  size: "2xsmall",
1096
- className: `uppercase ${getStatusBadgeClass$7(displayStatus(r))}`,
1342
+ className: `uppercase ${getStatusBadgeClass$6(displayStatus(r))}`,
1097
1343
  children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
1098
1344
  }
1099
1345
  ) }),
@@ -1147,11 +1393,11 @@ const RefundsPage = () => {
1147
1393
  ) }) : null
1148
1394
  ] }) });
1149
1395
  };
1150
- const config$7 = defineRouteConfig({
1396
+ const config$6 = defineRouteConfig({
1151
1397
  label: "Refunds",
1152
1398
  icon: Receipt
1153
1399
  });
1154
- const useDebounce$2 = (value, delay) => {
1400
+ const useDebounce$1 = (value, delay) => {
1155
1401
  const [debouncedValue, setDebouncedValue] = useState(value);
1156
1402
  useEffect(() => {
1157
1403
  const handler = setTimeout(() => setDebouncedValue(value), delay);
@@ -1159,7 +1405,7 @@ const useDebounce$2 = (value, delay) => {
1159
1405
  }, [value, delay]);
1160
1406
  return debouncedValue;
1161
1407
  };
1162
- const getStatusBadgeClass$6 = (status) => {
1408
+ const getStatusBadgeClass$5 = (status) => {
1163
1409
  const statusLower = status.toLowerCase();
1164
1410
  if (statusLower === "requested") {
1165
1411
  return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
@@ -1184,7 +1430,7 @@ const ReturnsPage = () => {
1184
1430
  const [statusFilter, setStatusFilter] = useState("all");
1185
1431
  const [createdByFilter, setCreatedByFilter] = useState("all");
1186
1432
  const [searchQuery, setSearchQuery] = useState("");
1187
- const debouncedSearchQuery = useDebounce$2(searchQuery, 300);
1433
+ const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
1188
1434
  const [isLoading, setIsLoading] = useState(true);
1189
1435
  const [isFetchingMore, setIsFetchingMore] = useState(false);
1190
1436
  const [error, setError] = useState(null);
@@ -1330,18 +1576,28 @@ const ReturnsPage = () => {
1330
1576
  Badge,
1331
1577
  {
1332
1578
  size: "2xsmall",
1333
- className: `uppercase ${getStatusBadgeClass$6(returnOrder.status)}`,
1579
+ className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
1334
1580
  children: returnOrder.status.replace(/_/g, " ")
1335
1581
  }
1336
1582
  ) }),
1337
1583
  /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
1338
- const amount = returnOrder.refund_amount;
1339
- if (amount == null || amount === void 0) {
1584
+ const calc = returnOrder.refund;
1585
+ if ((calc == null ? void 0 : calc.is_processed) && calc.final_refund_amount != null) {
1586
+ return formatRefundCurrency(
1587
+ calc.final_refund_amount,
1588
+ calc.currency_code || returnOrder.currency_code
1589
+ );
1590
+ }
1591
+ if (calc) {
1592
+ return "Pending";
1593
+ }
1594
+ if (returnOrder.refund_amount == null) {
1340
1595
  return "—";
1341
1596
  }
1342
- const displayAmount = Number(amount) / 100;
1343
- const currency = returnOrder.currency_code || "$";
1344
- return `${currency}${displayAmount.toFixed(2)}`;
1597
+ return formatRefundCurrency(
1598
+ Number(returnOrder.refund_amount),
1599
+ returnOrder.currency_code
1600
+ );
1345
1601
  })() }),
1346
1602
  /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
1347
1603
  year: "numeric",
@@ -1379,11 +1635,11 @@ const ReturnsPage = () => {
1379
1635
  ) }) : null
1380
1636
  ] }) });
1381
1637
  };
1382
- const config$6 = defineRouteConfig({
1638
+ const config$5 = defineRouteConfig({
1383
1639
  label: "Return Orders",
1384
1640
  icon: ArrowPath
1385
1641
  });
1386
- const useDebounce$1 = (value, delay) => {
1642
+ const useDebounce = (value, delay) => {
1387
1643
  const [debouncedValue, setDebouncedValue] = useState(value);
1388
1644
  useEffect(() => {
1389
1645
  const handler = setTimeout(() => setDebouncedValue(value), delay);
@@ -1391,7 +1647,7 @@ const useDebounce$1 = (value, delay) => {
1391
1647
  }, [value, delay]);
1392
1648
  return debouncedValue;
1393
1649
  };
1394
- const getStatusBadgeClass$5 = (status) => {
1650
+ const getStatusBadgeClass$4 = (status) => {
1395
1651
  const statusLower = status.toLowerCase();
1396
1652
  if (statusLower === "requested") {
1397
1653
  return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
@@ -1416,7 +1672,7 @@ const SwapsPage = () => {
1416
1672
  const [statusFilter, setStatusFilter] = useState("all");
1417
1673
  const [createdByFilter, setCreatedByFilter] = useState("all");
1418
1674
  const [searchQuery, setSearchQuery] = useState("");
1419
- const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
1675
+ const debouncedSearchQuery = useDebounce(searchQuery, 300);
1420
1676
  const [isLoading, setIsLoading] = useState(true);
1421
1677
  const [isFetchingMore, setIsFetchingMore] = useState(false);
1422
1678
  const [error, setError] = useState(null);
@@ -1559,7 +1815,7 @@ const SwapsPage = () => {
1559
1815
  Badge,
1560
1816
  {
1561
1817
  size: "2xsmall",
1562
- className: `uppercase ${getStatusBadgeClass$5(swap.status)}`,
1818
+ className: `uppercase ${getStatusBadgeClass$4(swap.status)}`,
1563
1819
  children: swap.status.replace(/_/g, " ")
1564
1820
  }
1565
1821
  ) }),
@@ -1609,11 +1865,11 @@ const SwapsPage = () => {
1609
1865
  ) }) : null
1610
1866
  ] }) });
1611
1867
  };
1612
- const config$5 = defineRouteConfig({
1868
+ const config$4 = defineRouteConfig({
1613
1869
  label: "Exchanges",
1614
1870
  icon: ArrowPath
1615
1871
  });
1616
- const getStatusBadgeClass$4 = (status) => {
1872
+ const getStatusBadgeClass$3 = (status) => {
1617
1873
  const s2 = status.toLowerCase();
1618
1874
  if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
1619
1875
  if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
@@ -1621,18 +1877,14 @@ const getStatusBadgeClass$4 = (status) => {
1621
1877
  if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
1622
1878
  return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
1623
1879
  };
1624
- const formatAmount = (value) => {
1625
- return String(value);
1626
- };
1627
- const RefundDetailPage = () => {
1628
- var _a, _b, _c;
1880
+ const PaymentDetailPage = () => {
1881
+ var _a;
1629
1882
  const navigate = useNavigate();
1630
1883
  const params = useParams();
1631
1884
  const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
1632
1885
  const [detail, setDetail] = useState(null);
1633
1886
  const [loading, setLoading] = useState(!!id);
1634
1887
  const [error, setError] = useState(null);
1635
- const [gatewayExpanded, setGatewayExpanded] = useState(false);
1636
1888
  useEffect(() => {
1637
1889
  if (!id) {
1638
1890
  setLoading(false);
@@ -1641,7 +1893,7 @@ const RefundDetailPage = () => {
1641
1893
  let cancelled = false;
1642
1894
  setLoading(true);
1643
1895
  setError(null);
1644
- fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
1896
+ fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
1645
1897
  if (!res.ok) throw new Error(res.statusText || "Failed to load");
1646
1898
  return res.json();
1647
1899
  }).then((data) => {
@@ -1655,17 +1907,140 @@ const RefundDetailPage = () => {
1655
1907
  cancelled = true;
1656
1908
  };
1657
1909
  }, [id]);
1658
- const paymentStatus = ((_b = detail == null ? void 0 : detail.payment) == null ? void 0 : _b.status) ?? "—";
1659
- 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;
1910
+ const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
1911
+ const sessionStatusRaw = (detail == null ? void 0 : detail.session_status) ?? "—";
1912
+ const paymentStatusRaw = (detail == null ? void 0 : detail.payment_id) != null ? (detail == null ? void 0 : detail.payment_status) ?? "—" : "—";
1913
+ const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
1660
1914
  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: [
1661
1915
  /* @__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: [
1662
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
1663
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
1664
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
1916
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
1917
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
1918
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
1665
1919
  ] }) }),
1666
1920
  error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
1667
1921
  /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
1668
- /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
1922
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
1923
+ ] }) : 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: [
1924
+ /* @__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: [
1925
+ /* @__PURE__ */ jsxs("div", { children: [
1926
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
1927
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
1928
+ Button,
1929
+ {
1930
+ variant: "transparent",
1931
+ size: "small",
1932
+ onClick: () => navigate(`/orders/${detail.order_id}`),
1933
+ children: detail.order_id
1934
+ }
1935
+ ) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
1936
+ ] }),
1937
+ /* @__PURE__ */ jsxs("div", { children: [
1938
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
1939
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
1940
+ ] }),
1941
+ /* @__PURE__ */ jsxs("div", { children: [
1942
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
1943
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
1944
+ ] }),
1945
+ /* @__PURE__ */ jsxs("div", { children: [
1946
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
1947
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
1948
+ Badge,
1949
+ {
1950
+ size: "2xsmall",
1951
+ className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
1952
+ children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
1953
+ }
1954
+ ) })
1955
+ ] }),
1956
+ /* @__PURE__ */ jsxs("div", { children: [
1957
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
1958
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
1959
+ ] }),
1960
+ /* @__PURE__ */ jsxs("div", { children: [
1961
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
1962
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
1963
+ ] }),
1964
+ /* @__PURE__ */ jsxs("div", { children: [
1965
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
1966
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
1967
+ ] }),
1968
+ /* @__PURE__ */ jsxs("div", { children: [
1969
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
1970
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
1971
+ year: "numeric",
1972
+ month: "short",
1973
+ day: "numeric",
1974
+ hour: "numeric",
1975
+ minute: "2-digit",
1976
+ hour12: true
1977
+ }) })
1978
+ ] })
1979
+ ] }) }),
1980
+ Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
1981
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
1982
+ /* @__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) })
1983
+ ] }) : /* @__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." }) })
1984
+ ] }) : null
1985
+ ] }) });
1986
+ };
1987
+ const config$3 = defineRouteConfig({
1988
+ label: "Payment details",
1989
+ icon: CreditCard
1990
+ });
1991
+ const getStatusBadgeClass$2 = (status) => {
1992
+ const s2 = status.toLowerCase();
1993
+ if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
1994
+ if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
1995
+ if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
1996
+ if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
1997
+ return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
1998
+ };
1999
+ const formatAmount = (value) => {
2000
+ return String(value);
2001
+ };
2002
+ const RefundDetailPage = () => {
2003
+ var _a, _b, _c;
2004
+ const navigate = useNavigate();
2005
+ const params = useParams();
2006
+ const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
2007
+ const [detail, setDetail] = useState(null);
2008
+ const [loading, setLoading] = useState(!!id);
2009
+ const [error, setError] = useState(null);
2010
+ const [gatewayExpanded, setGatewayExpanded] = useState(false);
2011
+ useEffect(() => {
2012
+ if (!id) {
2013
+ setLoading(false);
2014
+ return;
2015
+ }
2016
+ let cancelled = false;
2017
+ setLoading(true);
2018
+ setError(null);
2019
+ fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
2020
+ if (!res.ok) throw new Error(res.statusText || "Failed to load");
2021
+ return res.json();
2022
+ }).then((data) => {
2023
+ if (!cancelled) setDetail(data);
2024
+ }).catch((e) => {
2025
+ if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
2026
+ }).finally(() => {
2027
+ if (!cancelled) setLoading(false);
2028
+ });
2029
+ return () => {
2030
+ cancelled = true;
2031
+ };
2032
+ }, [id]);
2033
+ const paymentStatus = ((_b = detail == null ? void 0 : detail.payment) == null ? void 0 : _b.status) ?? "—";
2034
+ 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;
2035
+ 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: [
2036
+ /* @__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: [
2037
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
2038
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
2039
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
2040
+ ] }) }),
2041
+ error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2042
+ /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2043
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
1669
2044
  ] }) : 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: [
1670
2045
  /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
1671
2046
  /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
@@ -1724,7 +2099,7 @@ const RefundDetailPage = () => {
1724
2099
  Badge,
1725
2100
  {
1726
2101
  size: "2xsmall",
1727
- className: `uppercase ${getStatusBadgeClass$4(paymentStatus)}`,
2102
+ className: `uppercase ${getStatusBadgeClass$2(paymentStatus)}`,
1728
2103
  children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
1729
2104
  }
1730
2105
  ) })
@@ -1801,11 +2176,11 @@ const RefundDetailPage = () => {
1801
2176
  ] }) : null
1802
2177
  ] }) });
1803
2178
  };
1804
- const config$4 = defineRouteConfig({
2179
+ const config$2 = defineRouteConfig({
1805
2180
  label: "Refund details",
1806
2181
  icon: Receipt
1807
2182
  });
1808
- const getStatusBadgeClass$3 = (status) => {
2183
+ const getStatusBadgeClass$1 = (status) => {
1809
2184
  const statusLower = status.toLowerCase();
1810
2185
  if (statusLower === "requested") {
1811
2186
  return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
@@ -1849,7 +2224,7 @@ const ReturnDetailPage = () => {
1849
2224
  try {
1850
2225
  setIsLoading(true);
1851
2226
  setError(null);
1852
- const response = await fetch(`/admin/returns/${id}`, {
2227
+ const response = await fetch(`/admin/return/${id}`, {
1853
2228
  credentials: "include"
1854
2229
  });
1855
2230
  if (!response.ok) {
@@ -1875,7 +2250,7 @@ const ReturnDetailPage = () => {
1875
2250
  setIsRejecting(true);
1876
2251
  setUpdateError(null);
1877
2252
  setUpdateSuccess(false);
1878
- const response = await fetch(`/admin/returns/${id}/reject`, {
2253
+ const response = await fetch(`/admin/return/${id}/reject`, {
1879
2254
  method: "POST",
1880
2255
  headers: {
1881
2256
  "Content-Type": "application/json"
@@ -1891,7 +2266,7 @@ const ReturnDetailPage = () => {
1891
2266
  setReturnOrder(payload.return);
1892
2267
  setUpdateSuccess(true);
1893
2268
  setTimeout(() => setUpdateSuccess(false), 3e3);
1894
- const detailResponse = await fetch(`/admin/returns/${id}`, {
2269
+ const detailResponse = await fetch(`/admin/return/${id}`, {
1895
2270
  credentials: "include"
1896
2271
  });
1897
2272
  if (detailResponse.ok) {
@@ -1939,7 +2314,7 @@ const ReturnDetailPage = () => {
1939
2314
  Badge,
1940
2315
  {
1941
2316
  size: "small",
1942
- className: `uppercase ${getStatusBadgeClass$3(returnOrder.status)}`,
2317
+ className: `uppercase ${getStatusBadgeClass$1(returnOrder.status)}`,
1943
2318
  children: returnOrder.status.replace(/_/g, " ")
1944
2319
  }
1945
2320
  )
@@ -1958,6 +2333,7 @@ const ReturnDetailPage = () => {
1958
2333
  ) }),
1959
2334
  /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: 'Cancel this return request. Use "Mark as received" when items are received.' })
1960
2335
  ] }),
2336
+ returnOrder.refund ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: /* @__PURE__ */ jsx(RefundCalculationBlock, { refund: returnOrder.refund }) }) : null,
1961
2337
  /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
1962
2338
  /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-4 text-lg", children: "Return Information" }),
1963
2339
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
@@ -2021,7 +2397,7 @@ const ReturnDetailPage = () => {
2021
2397
  Badge,
2022
2398
  {
2023
2399
  size: "2xsmall",
2024
- className: `uppercase ${getStatusBadgeClass$3(entry.status)}`,
2400
+ className: `uppercase ${getStatusBadgeClass$1(entry.status)}`,
2025
2401
  children: entry.status.replace(/_/g, " ")
2026
2402
  }
2027
2403
  ) }),
@@ -2079,11 +2455,11 @@ const ReturnDetailPage = () => {
2079
2455
  updateSuccess && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-ui-border-success bg-ui-bg-success-subtle p-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-success", children: "Action completed successfully" }) })
2080
2456
  ] }) });
2081
2457
  };
2082
- const config$3 = defineRouteConfig({
2458
+ const config$1 = defineRouteConfig({
2083
2459
  label: "Return Order Details",
2084
2460
  icon: CheckCircle
2085
2461
  });
2086
- const getStatusBadgeClass$2 = (status) => {
2462
+ const getStatusBadgeClass = (status) => {
2087
2463
  const statusLower = status.toLowerCase();
2088
2464
  if (statusLower === "requested") {
2089
2465
  return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
@@ -2221,7 +2597,7 @@ const SwapDetailPage = () => {
2221
2597
  Badge,
2222
2598
  {
2223
2599
  size: "small",
2224
- className: `uppercase ${getStatusBadgeClass$2(swap.status)}`,
2600
+ className: `uppercase ${getStatusBadgeClass(swap.status)}`,
2225
2601
  children: swap.status.replace(/_/g, " ")
2226
2602
  }
2227
2603
  )
@@ -2289,7 +2665,7 @@ const SwapDetailPage = () => {
2289
2665
  Badge,
2290
2666
  {
2291
2667
  size: "2xsmall",
2292
- className: `uppercase ${getStatusBadgeClass$2(entry.status)}`,
2668
+ className: `uppercase ${getStatusBadgeClass(entry.status)}`,
2293
2669
  children: entry.status.replace(/_/g, " ")
2294
2670
  }
2295
2671
  ) }),
@@ -2358,329 +2734,10 @@ const SwapDetailPage = () => {
2358
2734
  ] })
2359
2735
  ] }) });
2360
2736
  };
2361
- const config$2 = defineRouteConfig({
2737
+ const config = defineRouteConfig({
2362
2738
  label: "Swap Details",
2363
2739
  icon: ArrowPath
2364
2740
  });
2365
- const useDebounce = (value, delay) => {
2366
- const [debouncedValue, setDebouncedValue] = useState(value);
2367
- useEffect(() => {
2368
- const handler = setTimeout(() => setDebouncedValue(value), delay);
2369
- return () => clearTimeout(handler);
2370
- }, [value, delay]);
2371
- return debouncedValue;
2372
- };
2373
- const getStatusBadgeClass$1 = (status) => {
2374
- const s2 = status.toLowerCase();
2375
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
2376
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
2377
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
2378
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
2379
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
2380
- };
2381
- const PaymentsPage = () => {
2382
- const navigate = useNavigate();
2383
- const [items, setItems] = useState([]);
2384
- const [statusFilter, setStatusFilter] = useState("all");
2385
- const [orderIdSearch, setOrderIdSearch] = useState("");
2386
- const debouncedOrderId = useDebounce(orderIdSearch, 300);
2387
- const [isLoading, setIsLoading] = useState(true);
2388
- const [isFetchingMore, setIsFetchingMore] = useState(false);
2389
- const [error, setError] = useState(null);
2390
- const [offset, setOffset] = useState(0);
2391
- const [count, setCount] = useState(0);
2392
- const limit = 50;
2393
- const loadTransactions = useCallback(
2394
- async (nextOffset, replace) => {
2395
- try {
2396
- if (replace) setIsLoading(true);
2397
- else setIsFetchingMore(true);
2398
- setError(null);
2399
- const params = new URLSearchParams();
2400
- params.set("limit", String(limit));
2401
- params.set("offset", String(nextOffset));
2402
- if (statusFilter !== "all") params.set("status", statusFilter);
2403
- if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
2404
- const response = await fetch(
2405
- `/admin/payment-transactions?${params.toString()}`,
2406
- { credentials: "include" }
2407
- );
2408
- if (!response.ok) {
2409
- const text = await response.text();
2410
- throw new Error(text || "Failed to load payment transactions");
2411
- }
2412
- const payload = await response.json();
2413
- const list = payload.transactions ?? [];
2414
- setCount(payload.count ?? 0);
2415
- setOffset(nextOffset + list.length);
2416
- setItems((prev) => replace ? list : [...prev, ...list]);
2417
- } catch (e) {
2418
- setError(e instanceof Error ? e.message : "Failed to load");
2419
- } finally {
2420
- setIsLoading(false);
2421
- setIsFetchingMore(false);
2422
- }
2423
- },
2424
- [statusFilter, debouncedOrderId]
2425
- );
2426
- useEffect(() => {
2427
- void loadTransactions(0, true);
2428
- }, [loadTransactions]);
2429
- const hasMore = useMemo(() => offset < count, [offset, count]);
2430
- const displayStatus = (t) => {
2431
- const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
2432
- return s2 !== "" ? s2 : "—";
2433
- };
2434
- const displayAmount = (t) => {
2435
- const code = (t.currency_code ?? "USD").toUpperCase();
2436
- return `${code} ${Number(t.amount)}`;
2437
- };
2438
- 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: [
2439
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
2440
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2441
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
2442
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
2443
- ] }),
2444
- /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
2445
- ] }),
2446
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
2447
- /* @__PURE__ */ jsx(
2448
- Input,
2449
- {
2450
- placeholder: "Search by Order ID",
2451
- value: orderIdSearch,
2452
- onChange: (e) => setOrderIdSearch(e.target.value),
2453
- className: "md:max-w-sm",
2454
- "aria-label": "Search by order ID"
2455
- }
2456
- ),
2457
- /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
2458
- "select",
2459
- {
2460
- value: statusFilter,
2461
- onChange: (e) => setStatusFilter(e.target.value),
2462
- 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",
2463
- "aria-label": "Filter by status",
2464
- children: [
2465
- /* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
2466
- /* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
2467
- /* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
2468
- /* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
2469
- /* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
2470
- /* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
2471
- /* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
2472
- ]
2473
- }
2474
- ) })
2475
- ] }),
2476
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2477
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2478
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
2479
- ] }) : null,
2480
- 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: [
2481
- /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
2482
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
2483
- ] }) : /* @__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: [
2484
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2485
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
2486
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
2487
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
2488
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
2489
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
2490
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
2491
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
2492
- ] }) }),
2493
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
2494
- "tr",
2495
- {
2496
- className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
2497
- onClick: () => navigate(`/payments/${t.payment_session_id}`),
2498
- children: [
2499
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
2500
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
2501
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
2502
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
2503
- Badge,
2504
- {
2505
- size: "2xsmall",
2506
- className: `uppercase ${getStatusBadgeClass$1(displayStatus(t))}`,
2507
- children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
2508
- }
2509
- ) }),
2510
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
2511
- /* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
2512
- year: "numeric",
2513
- month: "short",
2514
- day: "numeric",
2515
- hour: "numeric",
2516
- minute: "2-digit",
2517
- hour12: true
2518
- }) }),
2519
- /* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
2520
- /* @__PURE__ */ jsx(
2521
- Button,
2522
- {
2523
- variant: "transparent",
2524
- size: "small",
2525
- onClick: (e) => {
2526
- e.stopPropagation();
2527
- navigate(`/payments/${t.payment_session_id}`);
2528
- },
2529
- children: "View details"
2530
- }
2531
- ),
2532
- t.order_id ? /* @__PURE__ */ jsx(
2533
- Button,
2534
- {
2535
- variant: "transparent",
2536
- size: "small",
2537
- onClick: (e) => {
2538
- e.stopPropagation();
2539
- navigate(`/orders/${t.order_id}`);
2540
- },
2541
- children: "Order"
2542
- }
2543
- ) : null
2544
- ] })
2545
- ]
2546
- },
2547
- t.payment_session_id
2548
- )) })
2549
- ] }) }),
2550
- hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
2551
- Button,
2552
- {
2553
- variant: "secondary",
2554
- isLoading: isFetchingMore,
2555
- onClick: () => loadTransactions(offset, false),
2556
- children: "Load more"
2557
- }
2558
- ) }) : null
2559
- ] }) });
2560
- };
2561
- const config$1 = defineRouteConfig({
2562
- label: "Payments",
2563
- icon: CreditCard
2564
- });
2565
- const getStatusBadgeClass = (status) => {
2566
- const s2 = status.toLowerCase();
2567
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
2568
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
2569
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
2570
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
2571
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
2572
- };
2573
- const PaymentDetailPage = () => {
2574
- var _a;
2575
- const navigate = useNavigate();
2576
- const params = useParams();
2577
- const id = (_a = params == null ? void 0 : params.id) == null ? void 0 : _a.trim();
2578
- const [detail, setDetail] = useState(null);
2579
- const [loading, setLoading] = useState(!!id);
2580
- const [error, setError] = useState(null);
2581
- useEffect(() => {
2582
- if (!id) {
2583
- setLoading(false);
2584
- return;
2585
- }
2586
- let cancelled = false;
2587
- setLoading(true);
2588
- setError(null);
2589
- fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
2590
- if (!res.ok) throw new Error(res.statusText || "Failed to load");
2591
- return res.json();
2592
- }).then((data) => {
2593
- if (!cancelled) setDetail(data);
2594
- }).catch((e) => {
2595
- if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
2596
- }).finally(() => {
2597
- if (!cancelled) setLoading(false);
2598
- });
2599
- return () => {
2600
- cancelled = true;
2601
- };
2602
- }, [id]);
2603
- const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
2604
- const sessionStatusRaw = (detail == null ? void 0 : detail.session_status) ?? "—";
2605
- const paymentStatusRaw = (detail == null ? void 0 : detail.payment_id) != null ? (detail == null ? void 0 : detail.payment_status) ?? "—" : "—";
2606
- const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
2607
- 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: [
2608
- /* @__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: [
2609
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
2610
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
2611
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
2612
- ] }) }),
2613
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2614
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2615
- /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
2616
- ] }) : 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: [
2617
- /* @__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: [
2618
- /* @__PURE__ */ jsxs("div", { children: [
2619
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
2620
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
2621
- Button,
2622
- {
2623
- variant: "transparent",
2624
- size: "small",
2625
- onClick: () => navigate(`/orders/${detail.order_id}`),
2626
- children: detail.order_id
2627
- }
2628
- ) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
2629
- ] }),
2630
- /* @__PURE__ */ jsxs("div", { children: [
2631
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
2632
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
2633
- ] }),
2634
- /* @__PURE__ */ jsxs("div", { children: [
2635
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
2636
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
2637
- ] }),
2638
- /* @__PURE__ */ jsxs("div", { children: [
2639
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
2640
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
2641
- Badge,
2642
- {
2643
- size: "2xsmall",
2644
- className: `uppercase ${getStatusBadgeClass(displayStatus)}`,
2645
- children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
2646
- }
2647
- ) })
2648
- ] }),
2649
- /* @__PURE__ */ jsxs("div", { children: [
2650
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
2651
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
2652
- ] }),
2653
- /* @__PURE__ */ jsxs("div", { children: [
2654
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
2655
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
2656
- ] }),
2657
- /* @__PURE__ */ jsxs("div", { children: [
2658
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
2659
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
2660
- ] }),
2661
- /* @__PURE__ */ jsxs("div", { children: [
2662
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
2663
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
2664
- year: "numeric",
2665
- month: "short",
2666
- day: "numeric",
2667
- hour: "numeric",
2668
- minute: "2-digit",
2669
- hour12: true
2670
- }) })
2671
- ] })
2672
- ] }) }),
2673
- Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
2674
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
2675
- /* @__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) })
2676
- ] }) : /* @__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." }) })
2677
- ] }) : null
2678
- ] }) });
2679
- };
2680
- const config = defineRouteConfig({
2681
- label: "Payment details",
2682
- icon: CreditCard
2683
- });
2684
2741
  const i18nTranslations0 = {};
2685
2742
  const widgetModule = { widgets: [
2686
2743
  {
@@ -2694,6 +2751,10 @@ const widgetModule = { widgets: [
2694
2751
  ] };
2695
2752
  const routeModule = {
2696
2753
  routes: [
2754
+ {
2755
+ Component: PaymentsPage,
2756
+ path: "/payments"
2757
+ },
2697
2758
  {
2698
2759
  Component: RefundsPage,
2699
2760
  path: "/refunds"
@@ -2706,6 +2767,10 @@ const routeModule = {
2706
2767
  Component: SwapsPage,
2707
2768
  path: "/swaps"
2708
2769
  },
2770
+ {
2771
+ Component: PaymentDetailPage,
2772
+ path: "/payments/:id"
2773
+ },
2709
2774
  {
2710
2775
  Component: RefundDetailPage,
2711
2776
  path: "/refunds/:id"
@@ -2717,14 +2782,6 @@ const routeModule = {
2717
2782
  {
2718
2783
  Component: SwapDetailPage,
2719
2784
  path: "/swaps/:id"
2720
- },
2721
- {
2722
- Component: PaymentsPage,
2723
- path: "/payments"
2724
- },
2725
- {
2726
- Component: PaymentDetailPage,
2727
- path: "/payments/:id"
2728
2785
  }
2729
2786
  ]
2730
2787
  };
@@ -2733,49 +2790,49 @@ const menuItemModule = {
2733
2790
  {
2734
2791
  label: config$6.label,
2735
2792
  icon: config$6.icon,
2793
+ path: "/refunds",
2794
+ nested: void 0
2795
+ },
2796
+ {
2797
+ label: config$5.label,
2798
+ icon: config$5.icon,
2736
2799
  path: "/returns",
2737
2800
  nested: void 0
2738
2801
  },
2739
2802
  {
2740
- label: config$1.label,
2741
- icon: config$1.icon,
2742
- path: "/payments",
2803
+ label: config$4.label,
2804
+ icon: config$4.icon,
2805
+ path: "/swaps",
2743
2806
  nested: void 0
2744
2807
  },
2745
2808
  {
2746
2809
  label: config$7.label,
2747
2810
  icon: config$7.icon,
2748
- path: "/refunds",
2811
+ path: "/payments",
2749
2812
  nested: void 0
2750
2813
  },
2751
2814
  {
2752
- label: config$5.label,
2753
- icon: config$5.icon,
2754
- path: "/swaps",
2815
+ label: config$2.label,
2816
+ icon: config$2.icon,
2817
+ path: "/refunds/:id",
2755
2818
  nested: void 0
2756
2819
  },
2757
2820
  {
2758
- label: config$3.label,
2759
- icon: config$3.icon,
2821
+ label: config$1.label,
2822
+ icon: config$1.icon,
2760
2823
  path: "/returns/:id",
2761
2824
  nested: void 0
2762
2825
  },
2763
- {
2764
- label: config$4.label,
2765
- icon: config$4.icon,
2766
- path: "/refunds/:id",
2767
- nested: void 0
2768
- },
2769
2826
  {
2770
2827
  label: config.label,
2771
2828
  icon: config.icon,
2772
- path: "/payments/:id",
2829
+ path: "/swaps/:id",
2773
2830
  nested: void 0
2774
2831
  },
2775
2832
  {
2776
- label: config$2.label,
2777
- icon: config$2.icon,
2778
- path: "/swaps/:id",
2833
+ label: config$3.label,
2834
+ icon: config$3.icon,
2835
+ path: "/payments/:id",
2779
2836
  nested: void 0
2780
2837
  }
2781
2838
  ]