order-management 0.0.100 → 0.0.102
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +1340 -1330
- package/.medusa/server/src/admin/index.mjs +1343 -1333
- package/.medusa/server/src/api/store/carts/[id]/pickup/route.js +113 -0
- package/.medusa/server/src/api/store/guest-orders/[id]/returns/route.js +12 -1
- package/.medusa/server/src/api/store/guest-orders/[id]/swaps/route.js +14 -2
- package/.medusa/server/src/api/store/pickup-locations/route.js +20 -0
- package/.medusa/server/src/api/store/returns/route.js +15 -3
- package/.medusa/server/src/api/store/swaps/route.js +17 -2
- package/.medusa/server/src/config.js +4 -1
- package/.medusa/server/src/helpers/pickup-locations.js +155 -0
- package/.medusa/server/src/subscribers/order-status-change.js +37 -2
- package/.medusa/server/src/utils/order-fulfillment-metadata.js +68 -0
- package/README.md +10 -1
- package/package.json +1 -1
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
5
2
|
import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
|
|
6
|
-
import { useState, useEffect, useRef,
|
|
7
|
-
import { Text, Container, Heading, Badge, Button, Label, Select, Textarea,
|
|
8
|
-
import { CashSolid, PencilSquareSolid, Trash,
|
|
3
|
+
import { useState, useEffect, useRef, useMemo, useCallback } from "react";
|
|
4
|
+
import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Popover, clx, Input, Copy, Skeleton, Tooltip, toast } from "@medusajs/ui";
|
|
5
|
+
import { CashSolid, PencilSquareSolid, Trash, ChevronDownMini, Check, ArrowPath, InformationCircle, ExclamationCircle, MagnifierAlert, ChevronRightMini, CreditCard, Receipt, ArrowLeft, ClockSolid, ShieldCheck, SquareTwoStack, CheckCircle } from "@medusajs/icons";
|
|
9
6
|
import { useNavigate, useLocation, useSearchParams, useParams } from "react-router-dom";
|
|
10
7
|
function roundRectPath(ctx, x, y, w, h, r) {
|
|
11
8
|
ctx.beginPath();
|
|
@@ -377,15 +374,14 @@ const s = {
|
|
|
377
374
|
const OrderGiftItemsWidget = ({ data }) => {
|
|
378
375
|
const [fetchedItems, setFetchedItems] = useState(null);
|
|
379
376
|
useEffect(() => {
|
|
380
|
-
if (!
|
|
377
|
+
if (!data?.id) return;
|
|
381
378
|
fetch(
|
|
382
379
|
`/admin/orders/${data.id}?fields=*items,items.metadata`
|
|
383
|
-
).then((r) => r.json()).then(({ order }) => setFetchedItems(
|
|
384
|
-
}, [data
|
|
385
|
-
const items = fetchedItems ??
|
|
380
|
+
).then((r) => r.json()).then(({ order }) => setFetchedItems(order?.items ?? [])).catch(() => setFetchedItems(data?.items ?? []));
|
|
381
|
+
}, [data?.id]);
|
|
382
|
+
const items = fetchedItems ?? data?.items ?? [];
|
|
386
383
|
const giftedItems = items.filter((i) => {
|
|
387
|
-
|
|
388
|
-
const flag = (_a = i.metadata) == null ? void 0 : _a.is_gift;
|
|
384
|
+
const flag = i.metadata?.is_gift;
|
|
389
385
|
return flag === "true" || flag === true;
|
|
390
386
|
});
|
|
391
387
|
return /* @__PURE__ */ jsxs("div", { style: s.widget, children: [
|
|
@@ -414,9 +410,9 @@ const OrderGiftItemsWidget = ({ data }) => {
|
|
|
414
410
|
),
|
|
415
411
|
giftedItems.map((item) => {
|
|
416
412
|
const meta = item.metadata;
|
|
417
|
-
const from = meta
|
|
418
|
-
const to = meta
|
|
419
|
-
const message = meta
|
|
413
|
+
const from = meta?.gift_from;
|
|
414
|
+
const to = meta?.gift_to;
|
|
415
|
+
const message = meta?.gift_message;
|
|
420
416
|
return /* @__PURE__ */ jsxs("div", { style: s.card, children: [
|
|
421
417
|
/* @__PURE__ */ jsxs("div", { style: s.ribbon, children: [
|
|
422
418
|
/* @__PURE__ */ jsx("span", { style: s.bowCenter, children: "🎀" }),
|
|
@@ -480,7 +476,7 @@ function formatRefundCurrency(amount, currencyCode = "inr", options) {
|
|
|
480
476
|
minimumFractionDigits: 2,
|
|
481
477
|
maximumFractionDigits: 2
|
|
482
478
|
}).format(amount);
|
|
483
|
-
if (
|
|
479
|
+
if (options?.signed && amount > 0) {
|
|
484
480
|
return `−${formatted}`;
|
|
485
481
|
}
|
|
486
482
|
return formatted;
|
|
@@ -535,8 +531,7 @@ function getOrderIdFromPath() {
|
|
|
535
531
|
return m ? m[1] : void 0;
|
|
536
532
|
}
|
|
537
533
|
const OrderRefundContextWidget = (props) => {
|
|
538
|
-
|
|
539
|
-
const orderId = ((_a = props.order) == null ? void 0 : _a.id) ?? ((_c = (_b = props.data) == null ? void 0 : _b.order) == null ? void 0 : _c.id) ?? getOrderIdFromPath();
|
|
534
|
+
const orderId = props.order?.id ?? props.data?.order?.id ?? getOrderIdFromPath();
|
|
540
535
|
const [context, setContext] = useState(null);
|
|
541
536
|
const [loading, setLoading] = useState(!!orderId);
|
|
542
537
|
const [error, setError] = useState(null);
|
|
@@ -574,7 +569,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
574
569
|
};
|
|
575
570
|
}, [orderId]);
|
|
576
571
|
const handleMarkRefunded = async () => {
|
|
577
|
-
if (!
|
|
572
|
+
if (!context?.return_id || !context?.refund_mapping || context.refund_mapping.is_refunded || !context.can_process_refund) {
|
|
578
573
|
return;
|
|
579
574
|
}
|
|
580
575
|
setMarking(true);
|
|
@@ -591,17 +586,14 @@ const OrderRefundContextWidget = (props) => {
|
|
|
591
586
|
}
|
|
592
587
|
const data = await res.json();
|
|
593
588
|
setContext(
|
|
594
|
-
(prev) => {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
} : prev;
|
|
604
|
-
}
|
|
589
|
+
(prev) => prev && prev.refund_mapping ? {
|
|
590
|
+
...prev,
|
|
591
|
+
can_process_refund: false,
|
|
592
|
+
refund_mapping: {
|
|
593
|
+
...prev.refund_mapping,
|
|
594
|
+
is_refunded: data.refund_payment_mapping?.is_refunded ?? true
|
|
595
|
+
}
|
|
596
|
+
} : prev
|
|
605
597
|
);
|
|
606
598
|
} catch (e) {
|
|
607
599
|
setMarkError(e instanceof Error ? e.message : "Failed to mark refunded");
|
|
@@ -610,20 +602,19 @@ const OrderRefundContextWidget = (props) => {
|
|
|
610
602
|
}
|
|
611
603
|
};
|
|
612
604
|
const handleEditClick = () => {
|
|
613
|
-
const mapping = context
|
|
614
|
-
const mode = mapping
|
|
605
|
+
const mapping = context?.refund_mapping;
|
|
606
|
+
const mode = mapping?.refund_mode;
|
|
615
607
|
setEditRefundMode(
|
|
616
608
|
mode === "offline" || mode === "online" ? mode : ""
|
|
617
609
|
);
|
|
618
|
-
setEditDetails(
|
|
619
|
-
setEditImageUrls(
|
|
610
|
+
setEditDetails(mapping?.details ?? "");
|
|
611
|
+
setEditImageUrls(mapping?.images ?? []);
|
|
620
612
|
setSaveError(null);
|
|
621
613
|
setUploadError(null);
|
|
622
614
|
setEditing(true);
|
|
623
615
|
};
|
|
624
616
|
const handleUploadImage = async (e) => {
|
|
625
|
-
|
|
626
|
-
const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
|
|
617
|
+
const file = e.target.files?.[0];
|
|
627
618
|
if (!file) return;
|
|
628
619
|
setUploading(true);
|
|
629
620
|
setUploadError(null);
|
|
@@ -640,7 +631,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
640
631
|
throw new Error(data2.message || "Upload failed");
|
|
641
632
|
}
|
|
642
633
|
const data = await res.json();
|
|
643
|
-
const url =
|
|
634
|
+
const url = data.files?.[0]?.url;
|
|
644
635
|
if (url) setEditImageUrls((prev) => [...prev, url]);
|
|
645
636
|
} catch (err) {
|
|
646
637
|
setUploadError(err instanceof Error ? err.message : "Upload failed");
|
|
@@ -653,7 +644,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
653
644
|
setEditImageUrls((prev) => prev.filter((_, i) => i !== index));
|
|
654
645
|
};
|
|
655
646
|
const handleSaveAdminFields = async () => {
|
|
656
|
-
if (!
|
|
647
|
+
if (!context?.return_id) return;
|
|
657
648
|
setSaving(true);
|
|
658
649
|
setSaveError(null);
|
|
659
650
|
try {
|
|
@@ -690,14 +681,14 @@ const OrderRefundContextWidget = (props) => {
|
|
|
690
681
|
if (error) {
|
|
691
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-error", children: error }) }) });
|
|
692
683
|
}
|
|
693
|
-
const hasReturn = !!
|
|
694
|
-
const hasMapping = !!
|
|
695
|
-
const canMarkRefunded = Boolean(context
|
|
696
|
-
const returnStatus =
|
|
697
|
-
const showReceiveFirstHint = hasReturn && !
|
|
698
|
-
const paymentDetail = context
|
|
699
|
-
const paymentDetails =
|
|
700
|
-
const orderPayment = context
|
|
684
|
+
const hasReturn = !!context?.return_id;
|
|
685
|
+
const hasMapping = !!context?.refund_mapping;
|
|
686
|
+
const canMarkRefunded = Boolean(context?.can_process_refund);
|
|
687
|
+
const returnStatus = context?.return_status ?? null;
|
|
688
|
+
const showReceiveFirstHint = hasReturn && !context?.refund_mapping?.is_refunded && returnStatus !== "received" && returnStatus !== "canceled";
|
|
689
|
+
const paymentDetail = context?.payment_detail;
|
|
690
|
+
const paymentDetails = context?.payment_details && context.payment_details.length > 0 ? context.payment_details : paymentDetail ? [paymentDetail] : [];
|
|
691
|
+
const orderPayment = context?.order_payment;
|
|
701
692
|
return /* @__PURE__ */ jsx(Container, { className: "mt-6 divide-y p-0", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 py-4", children: [
|
|
702
693
|
/* @__PURE__ */ jsxs(Heading, { level: "h2", className: "flex items-center gap-2", children: [
|
|
703
694
|
/* @__PURE__ */ jsx(CashSolid, { className: "text-ui-fg-subtle" }),
|
|
@@ -709,7 +700,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
709
700
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
710
701
|
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Return" }),
|
|
711
702
|
/* @__PURE__ */ jsx(Text, { size: "small", children: context.return_id }),
|
|
712
|
-
|
|
703
|
+
context.refund_mapping?.is_refunded ? /* @__PURE__ */ jsx(Badge, { color: "green", children: "Refunded" }) : /* @__PURE__ */ jsx(Badge, { color: "orange", children: "Not refunded" })
|
|
713
704
|
] }),
|
|
714
705
|
context.refund ? /* @__PURE__ */ jsx("div", { className: "mt-3 border-t border-ui-border-base pt-3", children: /* @__PURE__ */ jsx(RefundCalculationBlock, { refund: context.refund }) }) : null,
|
|
715
706
|
orderPayment && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2 border-t border-ui-border-base pt-3", children: [
|
|
@@ -723,17 +714,17 @@ const OrderRefundContextWidget = (props) => {
|
|
|
723
714
|
/* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2 border-t border-ui-border-base pt-3", children: [
|
|
724
715
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
725
716
|
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Payment method (refund destination)" }),
|
|
726
|
-
|
|
717
|
+
context.refund_mapping?.payment_id ? /* @__PURE__ */ jsx(Badge, { color: "green", children: "Customer specified" }) : paymentDetail ? /* @__PURE__ */ jsx(Badge, { color: "orange", children: "Customer default" }) : orderPayment && !orderPayment.is_cod ? /* @__PURE__ */ jsx(Badge, { color: "blue", children: "Original payment method" }) : null
|
|
727
718
|
] }),
|
|
728
|
-
|
|
729
|
-
!
|
|
730
|
-
!
|
|
719
|
+
context.refund_mapping?.payment_id && !paymentDetail && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-orange-200 bg-orange-50 px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "The customer specified a payment method for this return, but that payment method has since been removed from their account. Ask the customer to update their refund payment method." }) }),
|
|
720
|
+
!context.refund_mapping?.payment_id && paymentDetail?.source === "default" && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "The customer did not specify a payment method for this return. Showing their default payment method." }) }),
|
|
721
|
+
!context.refund_mapping?.payment_id && !paymentDetail && orderPayment && !orderPayment.is_cod && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
731
722
|
"Refund will go to the original payment method (",
|
|
732
723
|
orderPayment.label,
|
|
733
724
|
")."
|
|
734
725
|
] }) }),
|
|
735
|
-
!
|
|
736
|
-
!
|
|
726
|
+
!context.refund_mapping?.payment_id && !paymentDetail && (context.is_cod || orderPayment?.is_cod) && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "This order was paid with Cash on Delivery. No stored bank/UPI refund destination." }) }),
|
|
727
|
+
!context.refund_mapping?.payment_id && !paymentDetail && !orderPayment && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted", children: "No payment method found for this customer." }) }),
|
|
737
728
|
paymentDetails.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: paymentDetails.map((detail) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
738
729
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
739
730
|
/* @__PURE__ */ jsx(Badge, { children: detail.type.toUpperCase() }),
|
|
@@ -745,7 +736,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
745
736
|
] }, `${detail.id}-${k}`)) })
|
|
746
737
|
] }, detail.id)) })
|
|
747
738
|
] }),
|
|
748
|
-
|
|
739
|
+
context?.refund_mapping && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-3 border-t border-ui-border-base pt-3", children: [
|
|
749
740
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
750
741
|
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Refund mode, details & images" }),
|
|
751
742
|
!editing ? /* @__PURE__ */ jsxs(
|
|
@@ -833,10 +824,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
833
824
|
variant: "secondary",
|
|
834
825
|
type: "button",
|
|
835
826
|
disabled: uploading,
|
|
836
|
-
onClick: () =>
|
|
837
|
-
var _a2;
|
|
838
|
-
return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
|
|
839
|
-
},
|
|
827
|
+
onClick: () => fileInputRef.current?.click(),
|
|
840
828
|
children: uploading ? "Uploading…" : "Upload image"
|
|
841
829
|
}
|
|
842
830
|
),
|
|
@@ -887,7 +875,7 @@ const OrderRefundContextWidget = (props) => {
|
|
|
887
875
|
] }),
|
|
888
876
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
889
877
|
/* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted", children: "Images" }),
|
|
890
|
-
|
|
878
|
+
context.refund_mapping.images?.length ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-2", children: context.refund_mapping.images.map((url, i) => /* @__PURE__ */ jsxs(
|
|
891
879
|
"a",
|
|
892
880
|
{
|
|
893
881
|
href: url,
|
|
@@ -917,10 +905,10 @@ const OrderRefundContextWidget = (props) => {
|
|
|
917
905
|
),
|
|
918
906
|
markError && /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-error", children: markError })
|
|
919
907
|
] }),
|
|
920
|
-
hasMapping && !canMarkRefunded && !
|
|
908
|
+
hasMapping && !canMarkRefunded && !context.refund_mapping?.is_refunded && showReceiveFirstHint && /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-4 text-ui-fg-muted", children: "Mark refunded is available after the return is received." })
|
|
921
909
|
] }),
|
|
922
910
|
hasReturn && !hasMapping && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-4", children: [
|
|
923
|
-
|
|
911
|
+
context?.refund ? /* @__PURE__ */ jsx(RefundCalculationBlock, { refund: context.refund }) : null,
|
|
924
912
|
orderPayment && /* @__PURE__ */ jsxs("div", { className: "mb-3 space-y-1", children: [
|
|
925
913
|
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: "Order payment method" }),
|
|
926
914
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
@@ -935,501 +923,6 @@ const OrderRefundContextWidget = (props) => {
|
|
|
935
923
|
defineWidgetConfig({
|
|
936
924
|
zone: "order.details.after"
|
|
937
925
|
});
|
|
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
926
|
const AUDITED_TABLE_NAMES = [
|
|
1434
927
|
"account_deletion_request",
|
|
1435
928
|
"account_holder",
|
|
@@ -1853,7 +1346,7 @@ function getEntityInfo(tableName) {
|
|
|
1853
1346
|
const def = ENTITY_DEFINITIONS[tableName];
|
|
1854
1347
|
return {
|
|
1855
1348
|
tableName,
|
|
1856
|
-
label:
|
|
1349
|
+
label: def?.label ?? humanizeTableName(tableName),
|
|
1857
1350
|
category: def && CATEGORY_BY_ID.get(def.category) || SYSTEM_CATEGORY
|
|
1858
1351
|
};
|
|
1859
1352
|
}
|
|
@@ -1878,13 +1371,11 @@ function getTablesForCategory(id) {
|
|
|
1878
1371
|
}
|
|
1879
1372
|
const GROUPS = getEntitiesByCategory();
|
|
1880
1373
|
function triggerLabel(entity, category) {
|
|
1881
|
-
var _a;
|
|
1882
1374
|
if (entity) return getEntityInfo(entity).label;
|
|
1883
|
-
if (category) return `All ${
|
|
1375
|
+
if (category) return `All ${getCategory(category)?.label ?? category}`;
|
|
1884
1376
|
return "All entities";
|
|
1885
1377
|
}
|
|
1886
1378
|
const EntityPicker = ({ entity, category, onChange }) => {
|
|
1887
|
-
var _a;
|
|
1888
1379
|
const [open, setOpen] = useState(false);
|
|
1889
1380
|
const [search, setSearch] = useState("");
|
|
1890
1381
|
const searchRef = useRef(null);
|
|
@@ -1904,7 +1395,7 @@ const EntityPicker = ({ entity, category, onChange }) => {
|
|
|
1904
1395
|
setOpen(false);
|
|
1905
1396
|
setSearch("");
|
|
1906
1397
|
};
|
|
1907
|
-
const firstMatch =
|
|
1398
|
+
const firstMatch = filteredGroups[0]?.entities[0];
|
|
1908
1399
|
const isAll = !entity && !category;
|
|
1909
1400
|
return /* @__PURE__ */ jsxs(
|
|
1910
1401
|
Popover,
|
|
@@ -1937,9 +1428,8 @@ const EntityPicker = ({ entity, category, onChange }) => {
|
|
|
1937
1428
|
align: "start",
|
|
1938
1429
|
className: "w-[min(360px,calc(100vw-2rem))] p-0",
|
|
1939
1430
|
onOpenAutoFocus: (event) => {
|
|
1940
|
-
var _a2;
|
|
1941
1431
|
event.preventDefault();
|
|
1942
|
-
|
|
1432
|
+
searchRef.current?.focus();
|
|
1943
1433
|
},
|
|
1944
1434
|
children: [
|
|
1945
1435
|
/* @__PURE__ */ jsx("div", { className: "border-b border-ui-border-base p-2", children: /* @__PURE__ */ jsx(
|
|
@@ -2079,7 +1569,7 @@ function formatNumber(value) {
|
|
|
2079
1569
|
return new Intl.NumberFormat().format(value);
|
|
2080
1570
|
}
|
|
2081
1571
|
function formatMoney(amount, currencyCode) {
|
|
2082
|
-
const code = currencyCode
|
|
1572
|
+
const code = currencyCode?.trim().toUpperCase();
|
|
2083
1573
|
if (code && /^[A-Z]{3}$/.test(code)) {
|
|
2084
1574
|
try {
|
|
2085
1575
|
return new Intl.NumberFormat(void 0, { style: "currency", currency: code }).format(amount);
|
|
@@ -2146,9 +1636,9 @@ const SummaryCards = ({ stats, loading, failed }) => {
|
|
|
2146
1636
|
};
|
|
2147
1637
|
const BASE = "/admin/deleted-records-audit";
|
|
2148
1638
|
class AuditApiError extends Error {
|
|
1639
|
+
status;
|
|
2149
1640
|
constructor(message, status) {
|
|
2150
1641
|
super(message);
|
|
2151
|
-
__publicField(this, "status");
|
|
2152
1642
|
this.status = status;
|
|
2153
1643
|
}
|
|
2154
1644
|
}
|
|
@@ -2213,10 +1703,7 @@ const URL_KEYS = {
|
|
|
2213
1703
|
const DATE_PRESET_VALUES = new Set(DATE_PRESETS.map((p) => p.value));
|
|
2214
1704
|
const DAY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
2215
1705
|
function filtersFromSearchParams(params) {
|
|
2216
|
-
const read = (key) =>
|
|
2217
|
-
var _a;
|
|
2218
|
-
return ((_a = params.get(URL_KEYS[key])) == null ? void 0 : _a.trim()) ?? "";
|
|
2219
|
-
};
|
|
1706
|
+
const read = (key) => params.get(URL_KEYS[key])?.trim() ?? "";
|
|
2220
1707
|
const date = read("date");
|
|
2221
1708
|
const from = read("from");
|
|
2222
1709
|
const to = read("to");
|
|
@@ -2370,9 +1857,9 @@ const DeletedRecordsPage = () => {
|
|
|
2370
1857
|
try {
|
|
2371
1858
|
setStats(await fetchAuditStats(signal));
|
|
2372
1859
|
} catch (e) {
|
|
2373
|
-
if (!
|
|
1860
|
+
if (!signal?.aborted) setStatsFailed(true);
|
|
2374
1861
|
} finally {
|
|
2375
|
-
if (!
|
|
1862
|
+
if (!signal?.aborted) setStatsLoading(false);
|
|
2376
1863
|
}
|
|
2377
1864
|
}, []);
|
|
2378
1865
|
useEffect(() => {
|
|
@@ -2429,7 +1916,7 @@ const DeletedRecordsPage = () => {
|
|
|
2429
1916
|
const visible = Array.from(document.querySelectorAll(`[data-audit-row="${lastViewed}"]`)).find(
|
|
2430
1917
|
(el) => el.offsetParent !== null
|
|
2431
1918
|
);
|
|
2432
|
-
visible
|
|
1919
|
+
visible?.scrollIntoView({ block: "center" });
|
|
2433
1920
|
});
|
|
2434
1921
|
const handle = setTimeout(() => setHighlightId(null), 2500);
|
|
2435
1922
|
return () => clearTimeout(handle);
|
|
@@ -2456,8 +1943,8 @@ const DeletedRecordsPage = () => {
|
|
|
2456
1943
|
};
|
|
2457
1944
|
const refresh = () => setReloadToken((t) => t + 1);
|
|
2458
1945
|
const hasMore = items.length < count;
|
|
2459
|
-
const knownSources =
|
|
2460
|
-
const knownDeletedBy =
|
|
1946
|
+
const knownSources = stats?.sources ?? [];
|
|
1947
|
+
const knownDeletedBy = stats?.deleted_by ?? [];
|
|
2461
1948
|
const attributionMissing = !!stats && stats.total > 0 && knownSources.length === 0 && knownDeletedBy.length === 0;
|
|
2462
1949
|
return /* @__PURE__ */ jsx("div", { className: "w-full p-3 md:p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-4 md:p-6", children: [
|
|
2463
1950
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [
|
|
@@ -2721,11 +2208,11 @@ const ErrorState = ({ onRetry, detail }) => /* @__PURE__ */ jsxs("div", { classN
|
|
|
2721
2208
|
/* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: detail }),
|
|
2722
2209
|
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", className: "mt-2", onClick: onRetry, children: "Try again" })
|
|
2723
2210
|
] });
|
|
2724
|
-
const config$
|
|
2211
|
+
const config$9 = defineRouteConfig({
|
|
2725
2212
|
label: "Deleted Records",
|
|
2726
2213
|
icon: Trash
|
|
2727
2214
|
});
|
|
2728
|
-
const useDebounce$
|
|
2215
|
+
const useDebounce$3 = (value, delay) => {
|
|
2729
2216
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2730
2217
|
useEffect(() => {
|
|
2731
2218
|
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
@@ -2733,201 +2220,145 @@ const useDebounce$1 = (value, delay) => {
|
|
|
2733
2220
|
}, [value, delay]);
|
|
2734
2221
|
return debouncedValue;
|
|
2735
2222
|
};
|
|
2736
|
-
const getStatusBadgeClass$
|
|
2737
|
-
const
|
|
2738
|
-
if (
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
if (
|
|
2742
|
-
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2743
|
-
}
|
|
2744
|
-
if (statusLower === "requires_action") {
|
|
2745
|
-
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2746
|
-
}
|
|
2747
|
-
if (statusLower === "completed") {
|
|
2748
|
-
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2749
|
-
}
|
|
2750
|
-
if (statusLower === "canceled") {
|
|
2751
|
-
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
2752
|
-
}
|
|
2223
|
+
const getStatusBadgeClass$7 = (status) => {
|
|
2224
|
+
const s2 = status.toLowerCase();
|
|
2225
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2226
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2227
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2228
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2753
2229
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
2754
2230
|
};
|
|
2755
|
-
const
|
|
2231
|
+
const PaymentsPage = () => {
|
|
2756
2232
|
const navigate = useNavigate();
|
|
2757
2233
|
const [items, setItems] = useState([]);
|
|
2758
2234
|
const [statusFilter, setStatusFilter] = useState("all");
|
|
2759
|
-
const [
|
|
2760
|
-
const
|
|
2761
|
-
const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
|
|
2235
|
+
const [orderIdSearch, setOrderIdSearch] = useState("");
|
|
2236
|
+
const debouncedOrderId = useDebounce$3(orderIdSearch, 300);
|
|
2762
2237
|
const [isLoading, setIsLoading] = useState(true);
|
|
2763
2238
|
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
2764
2239
|
const [error, setError] = useState(null);
|
|
2765
2240
|
const [offset, setOffset] = useState(0);
|
|
2766
2241
|
const [count, setCount] = useState(0);
|
|
2767
2242
|
const limit = 50;
|
|
2768
|
-
const
|
|
2769
|
-
async (nextOffset, replace
|
|
2770
|
-
var _a;
|
|
2243
|
+
const loadTransactions = useCallback(
|
|
2244
|
+
async (nextOffset, replace) => {
|
|
2771
2245
|
try {
|
|
2772
|
-
if (replace)
|
|
2773
|
-
|
|
2774
|
-
} else {
|
|
2775
|
-
setIsFetchingMore(true);
|
|
2776
|
-
}
|
|
2246
|
+
if (replace) setIsLoading(true);
|
|
2247
|
+
else setIsFetchingMore(true);
|
|
2777
2248
|
setError(null);
|
|
2778
2249
|
const params = new URLSearchParams();
|
|
2779
2250
|
params.set("limit", String(limit));
|
|
2780
2251
|
params.set("offset", String(nextOffset));
|
|
2781
|
-
if (statusFilter !== "all")
|
|
2782
|
-
|
|
2783
|
-
}
|
|
2784
|
-
if (debouncedSearchQuery.trim()) {
|
|
2785
|
-
params.set("q", debouncedSearchQuery.trim());
|
|
2786
|
-
}
|
|
2787
|
-
if (createdByFilter !== "all") {
|
|
2788
|
-
params.set("created_by", createdByFilter);
|
|
2789
|
-
}
|
|
2790
|
-
params.set("order", "created_at");
|
|
2252
|
+
if (statusFilter !== "all") params.set("status", statusFilter);
|
|
2253
|
+
if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
|
|
2791
2254
|
const response = await fetch(
|
|
2792
|
-
`/admin/
|
|
2255
|
+
`/admin/payment-transactions?${params.toString()}`,
|
|
2793
2256
|
{ credentials: "include" }
|
|
2794
2257
|
);
|
|
2795
2258
|
if (!response.ok) {
|
|
2796
|
-
const
|
|
2797
|
-
throw new Error(
|
|
2259
|
+
const text = await response.text();
|
|
2260
|
+
throw new Error(text || "Failed to load payment transactions");
|
|
2798
2261
|
}
|
|
2799
2262
|
const payload = await response.json();
|
|
2263
|
+
const list = payload.transactions ?? [];
|
|
2800
2264
|
setCount(payload.count ?? 0);
|
|
2801
|
-
setOffset(nextOffset +
|
|
2802
|
-
setItems(
|
|
2803
|
-
|
|
2804
|
-
);
|
|
2805
|
-
} catch (loadError) {
|
|
2806
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
2807
|
-
setError(message);
|
|
2265
|
+
setOffset(nextOffset + list.length);
|
|
2266
|
+
setItems((prev) => replace ? list : [...prev, ...list]);
|
|
2267
|
+
} catch (e) {
|
|
2268
|
+
setError(e instanceof Error ? e.message : "Failed to load");
|
|
2808
2269
|
} finally {
|
|
2809
2270
|
setIsLoading(false);
|
|
2810
2271
|
setIsFetchingMore(false);
|
|
2811
2272
|
}
|
|
2812
2273
|
},
|
|
2813
|
-
[statusFilter,
|
|
2274
|
+
[statusFilter, debouncedOrderId]
|
|
2814
2275
|
);
|
|
2815
2276
|
useEffect(() => {
|
|
2816
|
-
void
|
|
2817
|
-
}, [
|
|
2277
|
+
void loadTransactions(0, true);
|
|
2278
|
+
}, [loadTransactions]);
|
|
2818
2279
|
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
2819
|
-
const
|
|
2820
|
-
const
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2280
|
+
const displayStatus = (t) => {
|
|
2281
|
+
const s2 = t.payment_id != null && t.payment_status != null && t.payment_status !== "" ? t.payment_status : t.session_status ?? "";
|
|
2282
|
+
return s2 !== "" ? s2 : "—";
|
|
2283
|
+
};
|
|
2284
|
+
const displayAmount = (t) => {
|
|
2285
|
+
const code = (t.currency_code ?? "USD").toUpperCase();
|
|
2286
|
+
return `${code} ${Number(t.amount)}`;
|
|
2287
|
+
};
|
|
2824
2288
|
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: [
|
|
2825
2289
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2826
2290
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2827
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "
|
|
2828
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
2291
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payments" }),
|
|
2292
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "All payment attempts — completed, pending, failed, requires action" })
|
|
2829
2293
|
] }),
|
|
2830
|
-
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () =>
|
|
2294
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadTransactions(0, true), children: "Refresh" })
|
|
2831
2295
|
] }),
|
|
2832
2296
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2833
2297
|
/* @__PURE__ */ jsx(
|
|
2834
2298
|
Input,
|
|
2835
2299
|
{
|
|
2836
|
-
placeholder: "Search by
|
|
2837
|
-
value:
|
|
2838
|
-
onChange: (
|
|
2839
|
-
className: "md:max-w-sm"
|
|
2300
|
+
placeholder: "Search by Order ID",
|
|
2301
|
+
value: orderIdSearch,
|
|
2302
|
+
onChange: (e) => setOrderIdSearch(e.target.value),
|
|
2303
|
+
className: "md:max-w-sm",
|
|
2304
|
+
"aria-label": "Search by order ID"
|
|
2840
2305
|
}
|
|
2841
2306
|
),
|
|
2842
|
-
/* @__PURE__ */
|
|
2843
|
-
|
|
2844
|
-
"select",
|
|
2845
|
-
{
|
|
2846
|
-
value: createdByFilter,
|
|
2847
|
-
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
2848
|
-
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",
|
|
2849
|
-
children: [
|
|
2850
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
2851
|
-
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
2852
|
-
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
2853
|
-
]
|
|
2854
|
-
}
|
|
2855
|
-
),
|
|
2856
|
-
/* @__PURE__ */ jsxs(
|
|
2857
|
-
"select",
|
|
2858
|
-
{
|
|
2859
|
-
value: statusFilter,
|
|
2860
|
-
onChange: (event) => setStatusFilter(event.target.value),
|
|
2861
|
-
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",
|
|
2862
|
-
children: [
|
|
2863
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
2864
|
-
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
2865
|
-
]
|
|
2866
|
-
}
|
|
2867
|
-
)
|
|
2868
|
-
] })
|
|
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,
|
|
2307
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs(
|
|
2308
|
+
"select",
|
|
2874
2309
|
{
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2310
|
+
value: statusFilter,
|
|
2311
|
+
onChange: (e) => setStatusFilter(e.target.value),
|
|
2312
|
+
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",
|
|
2313
|
+
"aria-label": "Filter by status",
|
|
2314
|
+
children: [
|
|
2315
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
|
|
2316
|
+
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
2317
|
+
/* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
|
|
2318
|
+
/* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
|
|
2319
|
+
/* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
|
|
2320
|
+
/* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
|
|
2321
|
+
/* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
|
|
2322
|
+
]
|
|
2878
2323
|
}
|
|
2879
2324
|
) })
|
|
2325
|
+
] }),
|
|
2326
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
2327
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
2328
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadTransactions(0, true), children: "Try again" }) })
|
|
2880
2329
|
] }) : null,
|
|
2881
|
-
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading
|
|
2882
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No
|
|
2883
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "
|
|
2330
|
+
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: [
|
|
2331
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No payment transactions yet" }),
|
|
2332
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Payment attempts will appear here." })
|
|
2884
2333
|
] }) : /* @__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
2334
|
/* @__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
2335
|
/* @__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: "
|
|
2336
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Amount" }),
|
|
2337
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Provider" }),
|
|
2889
2338
|
/* @__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: "
|
|
2339
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Finalized" }),
|
|
2891
2340
|
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
2892
2341
|
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
2893
2342
|
] }) }),
|
|
2894
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((
|
|
2343
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((t) => /* @__PURE__ */ jsxs(
|
|
2895
2344
|
"tr",
|
|
2896
2345
|
{
|
|
2897
2346
|
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
2898
|
-
onClick: () => navigate(`/
|
|
2347
|
+
onClick: () => navigate(`/payments/${t.payment_session_id}`),
|
|
2899
2348
|
children: [
|
|
2900
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children:
|
|
2901
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children:
|
|
2902
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children:
|
|
2349
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: t.order_id ?? "—" }),
|
|
2350
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: displayAmount(t) }),
|
|
2351
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.provider_id }),
|
|
2903
2352
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
2904
2353
|
Badge,
|
|
2905
2354
|
{
|
|
2906
2355
|
size: "2xsmall",
|
|
2907
|
-
className: `uppercase ${getStatusBadgeClass$
|
|
2908
|
-
children:
|
|
2356
|
+
className: `uppercase ${getStatusBadgeClass$7(displayStatus(t))}`,
|
|
2357
|
+
children: displayStatus(t) !== "—" ? displayStatus(t).replace(/_/g, " ") : "—"
|
|
2909
2358
|
}
|
|
2910
2359
|
) }),
|
|
2911
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children:
|
|
2912
|
-
|
|
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", {
|
|
2360
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: t.payment_id != null ? "Yes" : "No" }),
|
|
2361
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(t.created_at).toLocaleDateString("en-US", {
|
|
2931
2362
|
year: "numeric",
|
|
2932
2363
|
month: "short",
|
|
2933
2364
|
day: "numeric",
|
|
@@ -2935,21 +2366,35 @@ const ReturnsPage = () => {
|
|
|
2935
2366
|
minute: "2-digit",
|
|
2936
2367
|
hour12: true
|
|
2937
2368
|
}) }),
|
|
2938
|
-
/* @__PURE__ */
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
e
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2369
|
+
/* @__PURE__ */ jsxs("td", { className: "px-4 py-4", children: [
|
|
2370
|
+
/* @__PURE__ */ jsx(
|
|
2371
|
+
Button,
|
|
2372
|
+
{
|
|
2373
|
+
variant: "transparent",
|
|
2374
|
+
size: "small",
|
|
2375
|
+
onClick: (e) => {
|
|
2376
|
+
e.stopPropagation();
|
|
2377
|
+
navigate(`/payments/${t.payment_session_id}`);
|
|
2378
|
+
},
|
|
2379
|
+
children: "View details"
|
|
2380
|
+
}
|
|
2381
|
+
),
|
|
2382
|
+
t.order_id ? /* @__PURE__ */ jsx(
|
|
2383
|
+
Button,
|
|
2384
|
+
{
|
|
2385
|
+
variant: "transparent",
|
|
2386
|
+
size: "small",
|
|
2387
|
+
onClick: (e) => {
|
|
2388
|
+
e.stopPropagation();
|
|
2389
|
+
navigate(`/orders/${t.order_id}`);
|
|
2390
|
+
},
|
|
2391
|
+
children: "Order"
|
|
2392
|
+
}
|
|
2393
|
+
) : null
|
|
2394
|
+
] })
|
|
2950
2395
|
]
|
|
2951
2396
|
},
|
|
2952
|
-
|
|
2397
|
+
t.payment_session_id
|
|
2953
2398
|
)) })
|
|
2954
2399
|
] }) }),
|
|
2955
2400
|
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
@@ -2957,17 +2402,17 @@ const ReturnsPage = () => {
|
|
|
2957
2402
|
{
|
|
2958
2403
|
variant: "secondary",
|
|
2959
2404
|
isLoading: isFetchingMore,
|
|
2960
|
-
onClick: () =>
|
|
2405
|
+
onClick: () => loadTransactions(offset, false),
|
|
2961
2406
|
children: "Load more"
|
|
2962
2407
|
}
|
|
2963
2408
|
) }) : null
|
|
2964
2409
|
] }) });
|
|
2965
2410
|
};
|
|
2966
|
-
const config$
|
|
2967
|
-
label: "
|
|
2968
|
-
icon:
|
|
2411
|
+
const config$8 = defineRouteConfig({
|
|
2412
|
+
label: "Payments",
|
|
2413
|
+
icon: CreditCard
|
|
2969
2414
|
});
|
|
2970
|
-
const useDebounce = (value, delay) => {
|
|
2415
|
+
const useDebounce$2 = (value, delay) => {
|
|
2971
2416
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2972
2417
|
useEffect(() => {
|
|
2973
2418
|
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
@@ -2975,547 +2420,771 @@ const useDebounce = (value, delay) => {
|
|
|
2975
2420
|
}, [value, delay]);
|
|
2976
2421
|
return debouncedValue;
|
|
2977
2422
|
};
|
|
2978
|
-
const getStatusBadgeClass$
|
|
2979
|
-
const
|
|
2980
|
-
if (
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
if (
|
|
2984
|
-
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2985
|
-
}
|
|
2986
|
-
if (statusLower === "rejected") {
|
|
2987
|
-
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2988
|
-
}
|
|
2989
|
-
if (statusLower === "completed") {
|
|
2990
|
-
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2991
|
-
}
|
|
2992
|
-
if (statusLower === "cancelled") {
|
|
2993
|
-
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
2994
|
-
}
|
|
2423
|
+
const getStatusBadgeClass$6 = (status) => {
|
|
2424
|
+
const s2 = status.toLowerCase();
|
|
2425
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2426
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2427
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2428
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2995
2429
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
2996
2430
|
};
|
|
2997
|
-
const
|
|
2431
|
+
const RefundsPage = () => {
|
|
2998
2432
|
const navigate = useNavigate();
|
|
2999
2433
|
const [items, setItems] = useState([]);
|
|
3000
|
-
const [
|
|
3001
|
-
const
|
|
3002
|
-
const [
|
|
3003
|
-
const
|
|
2434
|
+
const [orderIdSearch, setOrderIdSearch] = useState("");
|
|
2435
|
+
const debouncedOrderId = useDebounce$2(orderIdSearch, 300);
|
|
2436
|
+
const [paymentStatusFilter, setPaymentStatusFilter] = useState("all");
|
|
2437
|
+
const [providerSearch, setProviderSearch] = useState("");
|
|
2438
|
+
const debouncedProvider = useDebounce$2(providerSearch, 300);
|
|
2439
|
+
const [currencySearch, setCurrencySearch] = useState("");
|
|
2440
|
+
const debouncedCurrency = useDebounce$2(currencySearch, 300);
|
|
2441
|
+
const [dateFrom, setDateFrom] = useState("");
|
|
2442
|
+
const [dateTo, setDateTo] = useState("");
|
|
2443
|
+
const [amountMin, setAmountMin] = useState("");
|
|
2444
|
+
const [amountMax, setAmountMax] = useState("");
|
|
3004
2445
|
const [isLoading, setIsLoading] = useState(true);
|
|
3005
2446
|
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
3006
2447
|
const [error, setError] = useState(null);
|
|
3007
2448
|
const [offset, setOffset] = useState(0);
|
|
3008
2449
|
const [count, setCount] = useState(0);
|
|
3009
2450
|
const limit = 50;
|
|
3010
|
-
const
|
|
3011
|
-
async (nextOffset, replace
|
|
3012
|
-
var _a;
|
|
2451
|
+
const loadRefunds = useCallback(
|
|
2452
|
+
async (nextOffset, replace) => {
|
|
3013
2453
|
try {
|
|
3014
|
-
if (replace)
|
|
3015
|
-
|
|
3016
|
-
} else {
|
|
3017
|
-
setIsFetchingMore(true);
|
|
3018
|
-
}
|
|
2454
|
+
if (replace) setIsLoading(true);
|
|
2455
|
+
else setIsFetchingMore(true);
|
|
3019
2456
|
setError(null);
|
|
3020
2457
|
const params = new URLSearchParams();
|
|
3021
2458
|
params.set("limit", String(limit));
|
|
3022
2459
|
params.set("offset", String(nextOffset));
|
|
3023
|
-
if (
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
if (
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
);
|
|
2460
|
+
if (debouncedOrderId.trim()) params.set("order_id", debouncedOrderId.trim());
|
|
2461
|
+
if (paymentStatusFilter !== "all") params.set("payment_status", paymentStatusFilter);
|
|
2462
|
+
if (debouncedProvider.trim()) params.set("provider_id", debouncedProvider.trim());
|
|
2463
|
+
if (debouncedCurrency.trim()) params.set("currency_code", debouncedCurrency.trim());
|
|
2464
|
+
if (dateFrom.trim()) params.set("date_from", dateFrom.trim());
|
|
2465
|
+
if (dateTo.trim()) params.set("date_to", dateTo.trim());
|
|
2466
|
+
const min = amountMin.trim() ? Number(amountMin) : void 0;
|
|
2467
|
+
const max = amountMax.trim() ? Number(amountMax) : void 0;
|
|
2468
|
+
if (min != null && !Number.isNaN(min)) params.set("amount_min", String(min));
|
|
2469
|
+
if (max != null && !Number.isNaN(max)) params.set("amount_max", String(max));
|
|
2470
|
+
const response = await fetch(`/admin/refunds?${params.toString()}`, {
|
|
2471
|
+
credentials: "include"
|
|
2472
|
+
});
|
|
3036
2473
|
if (!response.ok) {
|
|
3037
|
-
const
|
|
3038
|
-
throw new Error(
|
|
2474
|
+
const text = await response.text();
|
|
2475
|
+
throw new Error(text || "Failed to load refunds");
|
|
3039
2476
|
}
|
|
3040
2477
|
const payload = await response.json();
|
|
2478
|
+
const list = payload.refunds ?? [];
|
|
3041
2479
|
setCount(payload.count ?? 0);
|
|
3042
|
-
setOffset(nextOffset +
|
|
3043
|
-
setItems(
|
|
3044
|
-
|
|
3045
|
-
);
|
|
3046
|
-
} catch (loadError) {
|
|
3047
|
-
const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
|
|
3048
|
-
setError(message);
|
|
2480
|
+
setOffset(nextOffset + list.length);
|
|
2481
|
+
setItems((prev) => replace ? list : [...prev, ...list]);
|
|
2482
|
+
} catch (e) {
|
|
2483
|
+
setError(e instanceof Error ? e.message : "Failed to load");
|
|
3049
2484
|
} finally {
|
|
3050
2485
|
setIsLoading(false);
|
|
3051
2486
|
setIsFetchingMore(false);
|
|
3052
2487
|
}
|
|
3053
2488
|
},
|
|
3054
|
-
[
|
|
2489
|
+
[
|
|
2490
|
+
debouncedOrderId,
|
|
2491
|
+
paymentStatusFilter,
|
|
2492
|
+
debouncedProvider,
|
|
2493
|
+
debouncedCurrency,
|
|
2494
|
+
dateFrom,
|
|
2495
|
+
dateTo,
|
|
2496
|
+
amountMin,
|
|
2497
|
+
amountMax
|
|
2498
|
+
]
|
|
3055
2499
|
);
|
|
3056
2500
|
useEffect(() => {
|
|
3057
|
-
void
|
|
3058
|
-
}, [
|
|
2501
|
+
void loadRefunds(0, true);
|
|
2502
|
+
}, [loadRefunds]);
|
|
3059
2503
|
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
3060
|
-
const
|
|
3061
|
-
const
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
2504
|
+
const displayAmount = (r) => {
|
|
2505
|
+
const code = (r.currency_code ?? "USD").toUpperCase();
|
|
2506
|
+
return `${code} ${Number(r.amount)}`;
|
|
2507
|
+
};
|
|
2508
|
+
const displayStatus = (r) => {
|
|
2509
|
+
const s2 = r.payment_status ?? "";
|
|
2510
|
+
return s2 !== "" ? s2 : "—";
|
|
2511
|
+
};
|
|
3065
2512
|
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
2513
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
3067
2514
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3068
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "
|
|
3069
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
2515
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refunds" }),
|
|
2516
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Refund records — amount, order, payment status" })
|
|
3070
2517
|
] }),
|
|
3071
|
-
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () =>
|
|
2518
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadRefunds(0, true), children: "Refresh" })
|
|
3072
2519
|
] }),
|
|
3073
|
-
/* @__PURE__ */
|
|
2520
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
3074
2521
|
/* @__PURE__ */ jsx(
|
|
3075
2522
|
Input,
|
|
3076
2523
|
{
|
|
3077
|
-
placeholder: "
|
|
3078
|
-
value:
|
|
3079
|
-
onChange: (
|
|
3080
|
-
className: "md:max-w-
|
|
2524
|
+
placeholder: "Order ID",
|
|
2525
|
+
value: orderIdSearch,
|
|
2526
|
+
onChange: (e) => setOrderIdSearch(e.target.value),
|
|
2527
|
+
className: "md:max-w-[180px]",
|
|
2528
|
+
"aria-label": "Filter by order ID"
|
|
3081
2529
|
}
|
|
3082
2530
|
),
|
|
3083
|
-
/* @__PURE__ */
|
|
3084
|
-
|
|
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,
|
|
2531
|
+
/* @__PURE__ */ jsx(
|
|
2532
|
+
Input,
|
|
3115
2533
|
{
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
2534
|
+
placeholder: "Provider",
|
|
2535
|
+
value: providerSearch,
|
|
2536
|
+
onChange: (e) => setProviderSearch(e.target.value),
|
|
2537
|
+
className: "md:max-w-[140px]",
|
|
2538
|
+
"aria-label": "Filter by provider"
|
|
3119
2539
|
}
|
|
3120
|
-
)
|
|
3121
|
-
|
|
3122
|
-
|
|
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",
|
|
2540
|
+
),
|
|
2541
|
+
/* @__PURE__ */ jsx(
|
|
2542
|
+
Input,
|
|
3136
2543
|
{
|
|
3137
|
-
|
|
3138
|
-
|
|
2544
|
+
placeholder: "Currency",
|
|
2545
|
+
value: currencySearch,
|
|
2546
|
+
onChange: (e) => setCurrencySearch(e.target.value),
|
|
2547
|
+
className: "md:max-w-[100px]",
|
|
2548
|
+
"aria-label": "Filter by currency"
|
|
2549
|
+
}
|
|
2550
|
+
),
|
|
2551
|
+
/* @__PURE__ */ jsxs(
|
|
2552
|
+
"select",
|
|
2553
|
+
{
|
|
2554
|
+
value: paymentStatusFilter,
|
|
2555
|
+
onChange: (e) => setPaymentStatusFilter(e.target.value),
|
|
2556
|
+
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]",
|
|
2557
|
+
"aria-label": "Filter by payment status",
|
|
3139
2558
|
children: [
|
|
3140
|
-
/* @__PURE__ */ jsx("
|
|
3141
|
-
/* @__PURE__ */ jsx("
|
|
3142
|
-
/* @__PURE__ */ jsx("
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
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
|
-
) })
|
|
2559
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All statuses" }),
|
|
2560
|
+
/* @__PURE__ */ jsx("option", { value: "pending", children: "Pending" }),
|
|
2561
|
+
/* @__PURE__ */ jsx("option", { value: "requires_more", children: "Requires more" }),
|
|
2562
|
+
/* @__PURE__ */ jsx("option", { value: "error", children: "Error" }),
|
|
2563
|
+
/* @__PURE__ */ jsx("option", { value: "canceled", children: "Canceled" }),
|
|
2564
|
+
/* @__PURE__ */ jsx("option", { value: "authorized", children: "Authorized" }),
|
|
2565
|
+
/* @__PURE__ */ jsx("option", { value: "captured", children: "Captured" })
|
|
3180
2566
|
]
|
|
3181
|
-
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
2567
|
+
}
|
|
2568
|
+
),
|
|
2569
|
+
/* @__PURE__ */ jsx(
|
|
2570
|
+
Input,
|
|
2571
|
+
{
|
|
2572
|
+
type: "date",
|
|
2573
|
+
placeholder: "From",
|
|
2574
|
+
value: dateFrom,
|
|
2575
|
+
onChange: (e) => setDateFrom(e.target.value),
|
|
2576
|
+
className: "md:max-w-[140px]",
|
|
2577
|
+
"aria-label": "Date from"
|
|
2578
|
+
}
|
|
2579
|
+
),
|
|
2580
|
+
/* @__PURE__ */ jsx(
|
|
2581
|
+
Input,
|
|
2582
|
+
{
|
|
2583
|
+
type: "date",
|
|
2584
|
+
placeholder: "To",
|
|
2585
|
+
value: dateTo,
|
|
2586
|
+
onChange: (e) => setDateTo(e.target.value),
|
|
2587
|
+
className: "md:max-w-[140px]",
|
|
2588
|
+
"aria-label": "Date to"
|
|
2589
|
+
}
|
|
2590
|
+
),
|
|
2591
|
+
/* @__PURE__ */ jsx(
|
|
2592
|
+
Input,
|
|
2593
|
+
{
|
|
2594
|
+
placeholder: "Amount min",
|
|
2595
|
+
value: amountMin,
|
|
2596
|
+
onChange: (e) => setAmountMin(e.target.value),
|
|
2597
|
+
type: "number",
|
|
2598
|
+
min: 0,
|
|
2599
|
+
className: "md:max-w-[100px]",
|
|
2600
|
+
"aria-label": "Refund amount minimum"
|
|
2601
|
+
}
|
|
2602
|
+
),
|
|
2603
|
+
/* @__PURE__ */ jsx(
|
|
2604
|
+
Input,
|
|
2605
|
+
{
|
|
2606
|
+
placeholder: "Amount max",
|
|
2607
|
+
value: amountMax,
|
|
2608
|
+
onChange: (e) => setAmountMax(e.target.value),
|
|
2609
|
+
type: "number",
|
|
2610
|
+
min: 0,
|
|
2611
|
+
className: "md:max-w-[100px]",
|
|
2612
|
+
"aria-label": "Refund amount maximum"
|
|
2613
|
+
}
|
|
2614
|
+
)
|
|
2615
|
+
] }) }),
|
|
2616
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
2617
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
2618
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => loadRefunds(0, true), children: "Try again" }) })
|
|
2619
|
+
] }) : null,
|
|
2620
|
+
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: [
|
|
2621
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No refunds yet" }),
|
|
2622
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Refund records will appear here." })
|
|
2623
|
+
] }) : /* @__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: [
|
|
2624
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2625
|
+
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund ID" }),
|
|
2626
|
+
/* @__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" }),
|
|
2627
|
+
/* @__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" }),
|
|
2628
|
+
/* @__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" }),
|
|
2629
|
+
/* @__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" }),
|
|
2630
|
+
/* @__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" }),
|
|
2631
|
+
/* @__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" }),
|
|
2632
|
+
/* @__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" }),
|
|
2633
|
+
/* @__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" }),
|
|
2634
|
+
/* @__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" })
|
|
2635
|
+
] }) }),
|
|
2636
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
|
|
2637
|
+
"tr",
|
|
2638
|
+
{
|
|
2639
|
+
className: "cursor-pointer hover:bg-ui-bg-subtle/60",
|
|
2640
|
+
onClick: () => navigate(`/refunds/${r.refund_id}`),
|
|
2641
|
+
children: [
|
|
2642
|
+
/* @__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 }),
|
|
2643
|
+
/* @__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 ?? "—" }),
|
|
2644
|
+
/* @__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 }),
|
|
2645
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
|
|
2646
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
|
|
2647
|
+
/* @__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 || "—" }),
|
|
2648
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
|
|
2649
|
+
Badge,
|
|
2650
|
+
{
|
|
2651
|
+
size: "2xsmall",
|
|
2652
|
+
className: `uppercase ${getStatusBadgeClass$6(displayStatus(r))}`,
|
|
2653
|
+
children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
|
|
2654
|
+
}
|
|
2655
|
+
) }),
|
|
2656
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
|
|
2657
|
+
/* @__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", {
|
|
2658
|
+
month: "short",
|
|
2659
|
+
day: "numeric",
|
|
2660
|
+
hour: "numeric",
|
|
2661
|
+
minute: "2-digit",
|
|
2662
|
+
hour12: true
|
|
2663
|
+
}) }),
|
|
2664
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
2665
|
+
/* @__PURE__ */ jsx(
|
|
2666
|
+
Button,
|
|
2667
|
+
{
|
|
2668
|
+
variant: "transparent",
|
|
2669
|
+
size: "small",
|
|
2670
|
+
onClick: (e) => {
|
|
2671
|
+
e.stopPropagation();
|
|
2672
|
+
navigate(`/refunds/${r.refund_id}`);
|
|
2673
|
+
},
|
|
2674
|
+
children: "Details"
|
|
2675
|
+
}
|
|
2676
|
+
),
|
|
2677
|
+
r.order_id ? /* @__PURE__ */ jsx(
|
|
2678
|
+
Button,
|
|
2679
|
+
{
|
|
2680
|
+
variant: "transparent",
|
|
2681
|
+
size: "small",
|
|
2682
|
+
onClick: (e) => {
|
|
2683
|
+
e.stopPropagation();
|
|
2684
|
+
navigate(`/orders/${r.order_id}`);
|
|
2685
|
+
},
|
|
2686
|
+
children: "Order"
|
|
2687
|
+
}
|
|
2688
|
+
) : null
|
|
2689
|
+
] }) })
|
|
2690
|
+
]
|
|
2691
|
+
},
|
|
2692
|
+
r.refund_id
|
|
2693
|
+
)) })
|
|
2694
|
+
] }) }),
|
|
2695
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
3186
2696
|
Button,
|
|
3187
2697
|
{
|
|
3188
2698
|
variant: "secondary",
|
|
3189
2699
|
isLoading: isFetchingMore,
|
|
3190
|
-
onClick: () =>
|
|
2700
|
+
onClick: () => loadRefunds(offset, false),
|
|
3191
2701
|
children: "Load more"
|
|
3192
2702
|
}
|
|
3193
2703
|
) }) : null
|
|
3194
2704
|
] }) });
|
|
3195
2705
|
};
|
|
3196
|
-
const config$
|
|
3197
|
-
label: "
|
|
3198
|
-
icon:
|
|
2706
|
+
const config$7 = defineRouteConfig({
|
|
2707
|
+
label: "Refunds",
|
|
2708
|
+
icon: Receipt
|
|
3199
2709
|
});
|
|
3200
|
-
const
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
2710
|
+
const useDebounce$1 = (value, delay) => {
|
|
2711
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2712
|
+
useEffect(() => {
|
|
2713
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
2714
|
+
return () => clearTimeout(handler);
|
|
2715
|
+
}, [value, delay]);
|
|
2716
|
+
return debouncedValue;
|
|
2717
|
+
};
|
|
2718
|
+
const getStatusBadgeClass$5 = (status) => {
|
|
2719
|
+
const statusLower = status.toLowerCase();
|
|
2720
|
+
if (statusLower === "requested") {
|
|
2721
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2722
|
+
}
|
|
2723
|
+
if (statusLower === "received") {
|
|
2724
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2725
|
+
}
|
|
2726
|
+
if (statusLower === "requires_action") {
|
|
2727
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2728
|
+
}
|
|
2729
|
+
if (statusLower === "completed") {
|
|
2730
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2731
|
+
}
|
|
2732
|
+
if (statusLower === "canceled") {
|
|
2733
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
2734
|
+
}
|
|
3206
2735
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3207
2736
|
};
|
|
3208
|
-
const
|
|
3209
|
-
var _a;
|
|
2737
|
+
const ReturnsPage = () => {
|
|
3210
2738
|
const navigate = useNavigate();
|
|
3211
|
-
const
|
|
3212
|
-
const
|
|
3213
|
-
const [
|
|
3214
|
-
const [
|
|
2739
|
+
const [items, setItems] = useState([]);
|
|
2740
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
2741
|
+
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
2742
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
2743
|
+
const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
|
|
2744
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
2745
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
3215
2746
|
const [error, setError] = useState(null);
|
|
2747
|
+
const [offset, setOffset] = useState(0);
|
|
2748
|
+
const [count, setCount] = useState(0);
|
|
2749
|
+
const limit = 50;
|
|
2750
|
+
const loadReturns = useCallback(
|
|
2751
|
+
async (nextOffset, replace = false) => {
|
|
2752
|
+
try {
|
|
2753
|
+
if (replace) {
|
|
2754
|
+
setIsLoading(true);
|
|
2755
|
+
} else {
|
|
2756
|
+
setIsFetchingMore(true);
|
|
2757
|
+
}
|
|
2758
|
+
setError(null);
|
|
2759
|
+
const params = new URLSearchParams();
|
|
2760
|
+
params.set("limit", String(limit));
|
|
2761
|
+
params.set("offset", String(nextOffset));
|
|
2762
|
+
if (statusFilter !== "all") {
|
|
2763
|
+
params.set("status", statusFilter);
|
|
2764
|
+
}
|
|
2765
|
+
if (debouncedSearchQuery.trim()) {
|
|
2766
|
+
params.set("q", debouncedSearchQuery.trim());
|
|
2767
|
+
}
|
|
2768
|
+
if (createdByFilter !== "all") {
|
|
2769
|
+
params.set("created_by", createdByFilter);
|
|
2770
|
+
}
|
|
2771
|
+
params.set("order", "created_at");
|
|
2772
|
+
const response = await fetch(
|
|
2773
|
+
`/admin/return?${params.toString()}`,
|
|
2774
|
+
{ credentials: "include" }
|
|
2775
|
+
);
|
|
2776
|
+
if (!response.ok) {
|
|
2777
|
+
const message = await response.text();
|
|
2778
|
+
throw new Error(message || "Unable to load return orders");
|
|
2779
|
+
}
|
|
2780
|
+
const payload = await response.json();
|
|
2781
|
+
setCount(payload.count ?? 0);
|
|
2782
|
+
setOffset(nextOffset + (payload.returns?.length ?? 0));
|
|
2783
|
+
setItems(
|
|
2784
|
+
(prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
|
|
2785
|
+
);
|
|
2786
|
+
} catch (loadError) {
|
|
2787
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
2788
|
+
setError(message);
|
|
2789
|
+
} finally {
|
|
2790
|
+
setIsLoading(false);
|
|
2791
|
+
setIsFetchingMore(false);
|
|
2792
|
+
}
|
|
2793
|
+
},
|
|
2794
|
+
[statusFilter, createdByFilter, debouncedSearchQuery]
|
|
2795
|
+
);
|
|
3216
2796
|
useEffect(() => {
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
2797
|
+
void loadReturns(0, true);
|
|
2798
|
+
}, [statusFilter, createdByFilter, debouncedSearchQuery, loadReturns]);
|
|
2799
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
2800
|
+
const availableStatuses = useMemo(() => {
|
|
2801
|
+
const statuses = /* @__PURE__ */ new Set();
|
|
2802
|
+
items.forEach((item) => statuses.add(item.status));
|
|
2803
|
+
return Array.from(statuses).sort();
|
|
2804
|
+
}, [items]);
|
|
2805
|
+
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: [
|
|
2806
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2807
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2808
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Orders" }),
|
|
2809
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
|
|
2810
|
+
] }),
|
|
2811
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
|
|
2812
|
+
] }),
|
|
2813
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
2814
|
+
/* @__PURE__ */ jsx(
|
|
2815
|
+
Input,
|
|
2816
|
+
{
|
|
2817
|
+
placeholder: "Search by return ID, order ID, or customer email",
|
|
2818
|
+
value: searchQuery,
|
|
2819
|
+
onChange: (event) => setSearchQuery(event.target.value),
|
|
2820
|
+
className: "md:max-w-sm"
|
|
2821
|
+
}
|
|
2822
|
+
),
|
|
2823
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
2824
|
+
/* @__PURE__ */ jsxs(
|
|
2825
|
+
"select",
|
|
2826
|
+
{
|
|
2827
|
+
value: createdByFilter,
|
|
2828
|
+
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
2829
|
+
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",
|
|
2830
|
+
children: [
|
|
2831
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
2832
|
+
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
2833
|
+
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
2834
|
+
]
|
|
2835
|
+
}
|
|
2836
|
+
),
|
|
2837
|
+
/* @__PURE__ */ jsxs(
|
|
2838
|
+
"select",
|
|
2839
|
+
{
|
|
2840
|
+
value: statusFilter,
|
|
2841
|
+
onChange: (event) => setStatusFilter(event.target.value),
|
|
2842
|
+
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",
|
|
2843
|
+
children: [
|
|
2844
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
2845
|
+
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
2846
|
+
]
|
|
2847
|
+
}
|
|
2848
|
+
)
|
|
2849
|
+
] })
|
|
2850
|
+
] }),
|
|
3248
2851
|
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3249
2852
|
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3250
|
-
/* @__PURE__ */ jsx(
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
/* @__PURE__ */
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
/* @__PURE__ */
|
|
3270
|
-
|
|
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
|
-
] })
|
|
2853
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
2854
|
+
Button,
|
|
2855
|
+
{
|
|
2856
|
+
variant: "secondary",
|
|
2857
|
+
onClick: () => loadReturns(0, true),
|
|
2858
|
+
children: "Try again"
|
|
2859
|
+
}
|
|
2860
|
+
) })
|
|
2861
|
+
] }) : null,
|
|
2862
|
+
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: [
|
|
2863
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
|
|
2864
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
|
|
2865
|
+
] }) : /* @__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: [
|
|
2866
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2867
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
|
|
2868
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
2869
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
2870
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
2871
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
|
|
2872
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
2873
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
3307
2874
|
] }) }),
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
}
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
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", {
|
|
2875
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
|
|
2876
|
+
"tr",
|
|
2877
|
+
{
|
|
2878
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
2879
|
+
onClick: () => navigate(`/returns/${returnOrder.id}`),
|
|
2880
|
+
children: [
|
|
2881
|
+
/* @__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 }) }) }),
|
|
2882
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
|
|
2883
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
2884
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
2885
|
+
Badge,
|
|
2886
|
+
{
|
|
2887
|
+
size: "2xsmall",
|
|
2888
|
+
className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
|
|
2889
|
+
children: returnOrder.status.replace(/_/g, " ")
|
|
2890
|
+
}
|
|
2891
|
+
) }),
|
|
2892
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
2893
|
+
const calc = returnOrder.refund;
|
|
2894
|
+
if (calc?.is_processed && calc.final_refund_amount != null) {
|
|
2895
|
+
return formatRefundCurrency(
|
|
2896
|
+
calc.final_refund_amount,
|
|
2897
|
+
calc.currency_code || returnOrder.currency_code
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
if (calc) {
|
|
2901
|
+
return "Pending";
|
|
2902
|
+
}
|
|
2903
|
+
if (returnOrder.refund_amount == null) {
|
|
2904
|
+
return "—";
|
|
2905
|
+
}
|
|
2906
|
+
return formatRefundCurrency(
|
|
2907
|
+
Number(returnOrder.refund_amount),
|
|
2908
|
+
returnOrder.currency_code
|
|
2909
|
+
);
|
|
2910
|
+
})() }),
|
|
2911
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
|
|
3391
2912
|
year: "numeric",
|
|
3392
2913
|
month: "short",
|
|
3393
2914
|
day: "numeric",
|
|
3394
2915
|
hour: "numeric",
|
|
3395
2916
|
minute: "2-digit",
|
|
3396
2917
|
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
|
-
] })
|
|
3453
|
-
] }),
|
|
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(
|
|
2918
|
+
}) }),
|
|
2919
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3460
2920
|
Button,
|
|
3461
2921
|
{
|
|
3462
2922
|
variant: "transparent",
|
|
3463
2923
|
size: "small",
|
|
3464
|
-
onClick: () =>
|
|
3465
|
-
|
|
2924
|
+
onClick: (e) => {
|
|
2925
|
+
e.stopPropagation();
|
|
2926
|
+
navigate(`/app/orders/${returnOrder.order_id}`);
|
|
2927
|
+
},
|
|
2928
|
+
children: "Go to order"
|
|
3466
2929
|
}
|
|
3467
2930
|
) })
|
|
3468
|
-
]
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
2931
|
+
]
|
|
2932
|
+
},
|
|
2933
|
+
returnOrder.id
|
|
2934
|
+
)) })
|
|
2935
|
+
] }) }),
|
|
2936
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
2937
|
+
Button,
|
|
2938
|
+
{
|
|
2939
|
+
variant: "secondary",
|
|
2940
|
+
isLoading: isFetchingMore,
|
|
2941
|
+
onClick: () => loadReturns(offset, false),
|
|
2942
|
+
children: "Load more"
|
|
2943
|
+
}
|
|
2944
|
+
) }) : null
|
|
2945
|
+
] }) });
|
|
2946
|
+
};
|
|
2947
|
+
const config$6 = defineRouteConfig({
|
|
2948
|
+
label: "Return Orders",
|
|
2949
|
+
icon: ArrowPath
|
|
2950
|
+
});
|
|
2951
|
+
const useDebounce = (value, delay) => {
|
|
2952
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2953
|
+
useEffect(() => {
|
|
2954
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
2955
|
+
return () => clearTimeout(handler);
|
|
2956
|
+
}, [value, delay]);
|
|
2957
|
+
return debouncedValue;
|
|
2958
|
+
};
|
|
2959
|
+
const getStatusBadgeClass$4 = (status) => {
|
|
2960
|
+
const statusLower = status.toLowerCase();
|
|
2961
|
+
if (statusLower === "requested") {
|
|
2962
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
2963
|
+
}
|
|
2964
|
+
if (statusLower === "approved") {
|
|
2965
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
2966
|
+
}
|
|
2967
|
+
if (statusLower === "rejected") {
|
|
2968
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
2969
|
+
}
|
|
2970
|
+
if (statusLower === "completed") {
|
|
2971
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
2972
|
+
}
|
|
2973
|
+
if (statusLower === "cancelled") {
|
|
2974
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
2975
|
+
}
|
|
2976
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
2977
|
+
};
|
|
2978
|
+
const SwapsPage = () => {
|
|
2979
|
+
const navigate = useNavigate();
|
|
2980
|
+
const [items, setItems] = useState([]);
|
|
2981
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
2982
|
+
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
2983
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
2984
|
+
const debouncedSearchQuery = useDebounce(searchQuery, 300);
|
|
2985
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
2986
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
2987
|
+
const [error, setError] = useState(null);
|
|
2988
|
+
const [offset, setOffset] = useState(0);
|
|
2989
|
+
const [count, setCount] = useState(0);
|
|
2990
|
+
const limit = 50;
|
|
2991
|
+
const loadSwaps = useCallback(
|
|
2992
|
+
async (nextOffset, replace = false) => {
|
|
2993
|
+
try {
|
|
2994
|
+
if (replace) {
|
|
2995
|
+
setIsLoading(true);
|
|
2996
|
+
} else {
|
|
2997
|
+
setIsFetchingMore(true);
|
|
2998
|
+
}
|
|
2999
|
+
setError(null);
|
|
3000
|
+
const params = new URLSearchParams();
|
|
3001
|
+
params.set("limit", String(limit));
|
|
3002
|
+
params.set("offset", String(nextOffset));
|
|
3003
|
+
if (statusFilter !== "all") {
|
|
3004
|
+
params.set("status", statusFilter);
|
|
3005
|
+
}
|
|
3006
|
+
if (debouncedSearchQuery.trim()) {
|
|
3007
|
+
params.set("order_id", debouncedSearchQuery.trim());
|
|
3008
|
+
}
|
|
3009
|
+
if (createdByFilter !== "all") {
|
|
3010
|
+
params.set("created_by", createdByFilter);
|
|
3011
|
+
}
|
|
3012
|
+
const response = await fetch(
|
|
3013
|
+
`/admin/swaps?${params.toString()}`,
|
|
3014
|
+
{ credentials: "include" }
|
|
3015
|
+
);
|
|
3016
|
+
if (!response.ok) {
|
|
3017
|
+
const message = await response.text();
|
|
3018
|
+
throw new Error(message || "Unable to load swaps");
|
|
3019
|
+
}
|
|
3020
|
+
const payload = await response.json();
|
|
3021
|
+
setCount(payload.count ?? 0);
|
|
3022
|
+
setOffset(nextOffset + (payload.swaps?.length ?? 0));
|
|
3023
|
+
setItems(
|
|
3024
|
+
(prev) => replace ? payload.swaps ?? [] : [...prev, ...payload.swaps ?? []]
|
|
3025
|
+
);
|
|
3026
|
+
} catch (loadError) {
|
|
3027
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load swaps";
|
|
3028
|
+
setError(message);
|
|
3029
|
+
} finally {
|
|
3030
|
+
setIsLoading(false);
|
|
3031
|
+
setIsFetchingMore(false);
|
|
3032
|
+
}
|
|
3033
|
+
},
|
|
3034
|
+
[statusFilter, createdByFilter, debouncedSearchQuery]
|
|
3035
|
+
);
|
|
3036
|
+
useEffect(() => {
|
|
3037
|
+
void loadSwaps(0, true);
|
|
3038
|
+
}, [statusFilter, createdByFilter, debouncedSearchQuery, loadSwaps]);
|
|
3039
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
3040
|
+
const availableStatuses = useMemo(() => {
|
|
3041
|
+
const statuses = /* @__PURE__ */ new Set();
|
|
3042
|
+
items.forEach((item) => statuses.add(item.status));
|
|
3043
|
+
return Array.from(statuses).sort();
|
|
3044
|
+
}, [items]);
|
|
3045
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-6", children: [
|
|
3046
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
3047
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3048
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Exchanges" }),
|
|
3049
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer exchange requests" })
|
|
3486
3050
|
] }),
|
|
3487
|
-
/* @__PURE__ */
|
|
3051
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadSwaps(0, true), children: "Refresh" })
|
|
3052
|
+
] }),
|
|
3053
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
3054
|
+
/* @__PURE__ */ jsx(
|
|
3055
|
+
Input,
|
|
3056
|
+
{
|
|
3057
|
+
placeholder: "Search by swap ID or order ID",
|
|
3058
|
+
value: searchQuery,
|
|
3059
|
+
onChange: (event) => setSearchQuery(event.target.value),
|
|
3060
|
+
className: "md:max-w-sm"
|
|
3061
|
+
}
|
|
3062
|
+
),
|
|
3063
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
3488
3064
|
/* @__PURE__ */ jsxs(
|
|
3489
|
-
"
|
|
3065
|
+
"select",
|
|
3490
3066
|
{
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
"aria-expanded": gatewayExpanded,
|
|
3495
|
-
"aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
|
|
3067
|
+
value: createdByFilter,
|
|
3068
|
+
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
3069
|
+
className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive md:max-w-xs",
|
|
3496
3070
|
children: [
|
|
3497
|
-
/* @__PURE__ */ jsx(
|
|
3498
|
-
/* @__PURE__ */ jsx(
|
|
3071
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
3072
|
+
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
3073
|
+
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
3499
3074
|
]
|
|
3500
3075
|
}
|
|
3501
3076
|
),
|
|
3502
|
-
|
|
3077
|
+
/* @__PURE__ */ jsxs(
|
|
3078
|
+
"select",
|
|
3079
|
+
{
|
|
3080
|
+
value: statusFilter,
|
|
3081
|
+
onChange: (event) => setStatusFilter(event.target.value),
|
|
3082
|
+
className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive md:max-w-xs",
|
|
3083
|
+
children: [
|
|
3084
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
3085
|
+
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
3086
|
+
]
|
|
3087
|
+
}
|
|
3088
|
+
)
|
|
3503
3089
|
] })
|
|
3504
|
-
] })
|
|
3505
|
-
|
|
3506
|
-
}
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3090
|
+
] }),
|
|
3091
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3092
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3093
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
3094
|
+
Button,
|
|
3095
|
+
{
|
|
3096
|
+
variant: "secondary",
|
|
3097
|
+
onClick: () => loadSwaps(0, true),
|
|
3098
|
+
children: "Try again"
|
|
3099
|
+
}
|
|
3100
|
+
) })
|
|
3101
|
+
] }) : null,
|
|
3102
|
+
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: [
|
|
3103
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No exchanges yet" }),
|
|
3104
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Exchange requests created by customers will appear here." })
|
|
3105
|
+
] }) : /* @__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: [
|
|
3106
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
3107
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Exchange ID" }),
|
|
3108
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
3109
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
3110
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Difference Due" }),
|
|
3111
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
3112
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
3113
|
+
] }) }),
|
|
3114
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((swap) => /* @__PURE__ */ jsxs(
|
|
3115
|
+
"tr",
|
|
3116
|
+
{
|
|
3117
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
3118
|
+
onClick: () => navigate(`/swaps/${swap.id}`),
|
|
3119
|
+
children: [
|
|
3120
|
+
/* @__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 }) }) }),
|
|
3121
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: swap.order_id }),
|
|
3122
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3123
|
+
Badge,
|
|
3124
|
+
{
|
|
3125
|
+
size: "2xsmall",
|
|
3126
|
+
className: `uppercase ${getStatusBadgeClass$4(swap.status)}`,
|
|
3127
|
+
children: swap.status.replace(/_/g, " ")
|
|
3128
|
+
}
|
|
3129
|
+
) }),
|
|
3130
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
3131
|
+
const amount = swap.difference_due;
|
|
3132
|
+
if (amount == null || amount === void 0) {
|
|
3133
|
+
return "—";
|
|
3134
|
+
}
|
|
3135
|
+
const displayAmount = Number(amount) / 100;
|
|
3136
|
+
const currency = swap.currency_code || "$";
|
|
3137
|
+
const sign = displayAmount >= 0 ? "+" : "";
|
|
3138
|
+
return `${sign}${currency}${displayAmount.toFixed(2)}`;
|
|
3139
|
+
})() }),
|
|
3140
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(swap.created_at).toLocaleDateString("en-US", {
|
|
3141
|
+
year: "numeric",
|
|
3142
|
+
month: "short",
|
|
3143
|
+
day: "numeric",
|
|
3144
|
+
hour: "numeric",
|
|
3145
|
+
minute: "2-digit",
|
|
3146
|
+
hour12: true
|
|
3147
|
+
}) }),
|
|
3148
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
3149
|
+
Button,
|
|
3150
|
+
{
|
|
3151
|
+
variant: "transparent",
|
|
3152
|
+
size: "small",
|
|
3153
|
+
onClick: (e) => {
|
|
3154
|
+
e.stopPropagation();
|
|
3155
|
+
navigate(`/app/orders/${swap.order_id}`);
|
|
3156
|
+
},
|
|
3157
|
+
children: "Go to order"
|
|
3158
|
+
}
|
|
3159
|
+
) })
|
|
3160
|
+
]
|
|
3161
|
+
},
|
|
3162
|
+
swap.id
|
|
3163
|
+
)) })
|
|
3164
|
+
] }) }),
|
|
3165
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
3166
|
+
Button,
|
|
3167
|
+
{
|
|
3168
|
+
variant: "secondary",
|
|
3169
|
+
isLoading: isFetchingMore,
|
|
3170
|
+
onClick: () => loadSwaps(offset, false),
|
|
3171
|
+
children: "Load more"
|
|
3172
|
+
}
|
|
3173
|
+
) }) : null
|
|
3174
|
+
] }) });
|
|
3175
|
+
};
|
|
3176
|
+
const config$5 = defineRouteConfig({
|
|
3177
|
+
label: "Exchanges",
|
|
3178
|
+
icon: ArrowPath
|
|
3179
|
+
});
|
|
3180
|
+
const MASKED_VALUE = "••••••••••••";
|
|
3181
|
+
const SENSITIVE_KEY_PATTERNS = [
|
|
3182
|
+
/password|passwd|passphrase/i,
|
|
3183
|
+
/secret/i,
|
|
3184
|
+
/token/i,
|
|
3185
|
+
/api_?key$/i,
|
|
3186
|
+
/private_?key/i,
|
|
3187
|
+
/access_?key/i,
|
|
3519
3188
|
/(^|_)hash(ed)?($|_)/i,
|
|
3520
3189
|
/(^|_)salt$/i,
|
|
3521
3190
|
/^cvv$|^cvc$|security_code/i,
|
|
@@ -3549,13 +3218,12 @@ function isSensitiveKey(key) {
|
|
|
3549
3218
|
const FULLY_SECRET_TABLES = /* @__PURE__ */ new Set(["auth_mfa_recovery_code", "auth_password_reset_token"]);
|
|
3550
3219
|
const ALWAYS_VISIBLE_KEYS = /* @__PURE__ */ new Set(["id", "created_at", "updated_at", "deleted_at", "expires_at", "used_at"]);
|
|
3551
3220
|
function maskValue(value, ctx, depth) {
|
|
3552
|
-
var _a;
|
|
3553
3221
|
if (Array.isArray(value)) return value.map((item) => maskValue(item, ctx, depth + 1));
|
|
3554
3222
|
if (value !== null && typeof value === "object") {
|
|
3555
3223
|
const out = {};
|
|
3556
3224
|
for (const [key, inner] of Object.entries(value)) {
|
|
3557
3225
|
const topLevel = depth === 0;
|
|
3558
|
-
const secret = inner !== null && inner !== void 0 && inner !== "" && (isSensitiveKey(key) || topLevel &&
|
|
3226
|
+
const secret = inner !== null && inner !== void 0 && inner !== "" && (isSensitiveKey(key) || topLevel && ctx.tableKeys?.has(key.toLowerCase()) === true || topLevel && ctx.maskAll && !ALWAYS_VISIBLE_KEYS.has(key) && !key.endsWith("_id"));
|
|
3559
3227
|
if (secret) {
|
|
3560
3228
|
ctx.count += 1;
|
|
3561
3229
|
out[key] = MASKED_VALUE;
|
|
@@ -4021,13 +3689,12 @@ function readLastListSearch() {
|
|
|
4021
3689
|
}
|
|
4022
3690
|
}
|
|
4023
3691
|
const DeletedRecordDetailPage = () => {
|
|
4024
|
-
var _a;
|
|
4025
3692
|
const navigate = useNavigate();
|
|
4026
3693
|
const location = useLocation();
|
|
4027
3694
|
const { id = "" } = useParams();
|
|
4028
3695
|
const [state, setState] = useState({ status: "loading" });
|
|
4029
3696
|
const [reloadToken, setReloadToken] = useState(0);
|
|
4030
|
-
const cameFromList =
|
|
3697
|
+
const cameFromList = location.state?.fromList === true;
|
|
4031
3698
|
const goBack = () => {
|
|
4032
3699
|
if (cameFromList) navigate(-1);
|
|
4033
3700
|
else navigate(`/deleted-records-audit${readLastListSearch()}`);
|
|
@@ -4162,96 +3829,405 @@ const DetailContent = ({ audit }) => {
|
|
|
4162
3829
|
" ",
|
|
4163
3830
|
"from this screen."
|
|
4164
3831
|
] }),
|
|
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
|
|
4172
|
-
] }),
|
|
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
|
|
4177
|
-
] }),
|
|
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."
|
|
3832
|
+
/* @__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: [
|
|
3833
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
3834
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Check whether this was expected." }),
|
|
3835
|
+
" ",
|
|
3836
|
+
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)}.`,
|
|
3837
|
+
" ",
|
|
3838
|
+
guidance.headline
|
|
3839
|
+
] }),
|
|
3840
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
3841
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "If it needs to come back:" }),
|
|
3842
|
+
" ",
|
|
3843
|
+
guidance.recreate
|
|
3844
|
+
] }),
|
|
3845
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
3846
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Need the details?" }),
|
|
3847
|
+
" Use “View full record” above to see or copy everything that was stored. Sensitive values stay hidden."
|
|
3848
|
+
] })
|
|
3849
|
+
] }),
|
|
3850
|
+
guidance.adminSection || related.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
3851
|
+
guidance.adminSection ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => navigate(guidance.adminSection.path), children: guidance.adminSection.label }) : null,
|
|
3852
|
+
related.map((link) => /* @__PURE__ */ jsxs(
|
|
3853
|
+
Button,
|
|
3854
|
+
{
|
|
3855
|
+
variant: "transparent",
|
|
3856
|
+
size: "small",
|
|
3857
|
+
onClick: () => navigate(link.path),
|
|
3858
|
+
title: `Opens ${link.label.toLowerCase()} ${link.id} if it still exists`,
|
|
3859
|
+
children: [
|
|
3860
|
+
"Open related ",
|
|
3861
|
+
link.label.toLowerCase(),
|
|
3862
|
+
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
3863
|
+
]
|
|
3864
|
+
},
|
|
3865
|
+
link.path
|
|
3866
|
+
))
|
|
3867
|
+
] }) : null,
|
|
3868
|
+
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
|
|
3869
|
+
] }) })
|
|
3870
|
+
] });
|
|
3871
|
+
};
|
|
3872
|
+
const Section = ({
|
|
3873
|
+
title,
|
|
3874
|
+
description,
|
|
3875
|
+
actions,
|
|
3876
|
+
children
|
|
3877
|
+
}) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4 rounded-lg border border-ui-border-base p-5", children: [
|
|
3878
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [
|
|
3879
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
3880
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: title }),
|
|
3881
|
+
description ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: description }) : null
|
|
3882
|
+
] }),
|
|
3883
|
+
actions
|
|
3884
|
+
] }),
|
|
3885
|
+
children
|
|
3886
|
+
] });
|
|
3887
|
+
const Field = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
|
|
3888
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: label }),
|
|
3889
|
+
/* @__PURE__ */ jsx("dd", { className: "min-w-0", children })
|
|
3890
|
+
] });
|
|
3891
|
+
const DetailSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "aria-busy": "true", children: [
|
|
3892
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
3893
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" }),
|
|
3894
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-64" }),
|
|
3895
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
|
|
3896
|
+
] }),
|
|
3897
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-14 w-full" }),
|
|
3898
|
+
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: [
|
|
3899
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" }),
|
|
3900
|
+
/* @__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: [
|
|
3901
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" }),
|
|
3902
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-36" })
|
|
3903
|
+
] }, j)) })
|
|
3904
|
+
] }, i))
|
|
3905
|
+
] });
|
|
3906
|
+
const DetailError = ({
|
|
3907
|
+
notFound,
|
|
3908
|
+
message,
|
|
3909
|
+
onRetry,
|
|
3910
|
+
onBack
|
|
3911
|
+
}) => /* @__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: [
|
|
3912
|
+
/* @__PURE__ */ jsx(ExclamationCircle, { className: clx(notFound ? "text-ui-fg-muted" : "text-ui-fg-error") }),
|
|
3913
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", children: notFound ? "Audit entry not found" : "Unable to load this deleted record" }),
|
|
3914
|
+
/* @__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." }),
|
|
3915
|
+
!notFound ? /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: message }) : null,
|
|
3916
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
|
|
3917
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: onBack, children: "Back to Deleted Records" }),
|
|
3918
|
+
!notFound ? /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: onRetry, children: "Try again" }) : null
|
|
3919
|
+
] })
|
|
3920
|
+
] });
|
|
3921
|
+
const config$4 = defineRouteConfig({});
|
|
3922
|
+
const getStatusBadgeClass$3 = (status) => {
|
|
3923
|
+
const s2 = status.toLowerCase();
|
|
3924
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3925
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
3926
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
3927
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
3928
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3929
|
+
};
|
|
3930
|
+
const PaymentDetailPage = () => {
|
|
3931
|
+
const navigate = useNavigate();
|
|
3932
|
+
const params = useParams();
|
|
3933
|
+
const id = params?.id?.trim();
|
|
3934
|
+
const [detail, setDetail] = useState(null);
|
|
3935
|
+
const [loading, setLoading] = useState(!!id);
|
|
3936
|
+
const [error, setError] = useState(null);
|
|
3937
|
+
useEffect(() => {
|
|
3938
|
+
if (!id) {
|
|
3939
|
+
setLoading(false);
|
|
3940
|
+
return;
|
|
3941
|
+
}
|
|
3942
|
+
let cancelled = false;
|
|
3943
|
+
setLoading(true);
|
|
3944
|
+
setError(null);
|
|
3945
|
+
fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
|
|
3946
|
+
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
3947
|
+
return res.json();
|
|
3948
|
+
}).then((data) => {
|
|
3949
|
+
if (!cancelled) setDetail(data);
|
|
3950
|
+
}).catch((e) => {
|
|
3951
|
+
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
3952
|
+
}).finally(() => {
|
|
3953
|
+
if (!cancelled) setLoading(false);
|
|
3954
|
+
});
|
|
3955
|
+
return () => {
|
|
3956
|
+
cancelled = true;
|
|
3957
|
+
};
|
|
3958
|
+
}, [id]);
|
|
3959
|
+
const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
|
|
3960
|
+
const sessionStatusRaw = detail?.session_status ?? "—";
|
|
3961
|
+
const paymentStatusRaw = detail?.payment_id != null ? detail?.payment_status ?? "—" : "—";
|
|
3962
|
+
const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
|
|
3963
|
+
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: [
|
|
3964
|
+
/* @__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: [
|
|
3965
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
|
|
3966
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
|
|
3967
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
|
|
3968
|
+
] }) }),
|
|
3969
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3970
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3971
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
|
|
3972
|
+
] }) : 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: [
|
|
3973
|
+
/* @__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: [
|
|
3974
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3975
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
|
|
3976
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
|
|
3977
|
+
Button,
|
|
3978
|
+
{
|
|
3979
|
+
variant: "transparent",
|
|
3980
|
+
size: "small",
|
|
3981
|
+
onClick: () => navigate(`/orders/${detail.order_id}`),
|
|
3982
|
+
children: detail.order_id
|
|
3983
|
+
}
|
|
3984
|
+
) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
|
|
3985
|
+
] }),
|
|
3986
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3987
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
3988
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
|
|
3989
|
+
] }),
|
|
3990
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3991
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
3992
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
|
|
3993
|
+
] }),
|
|
3994
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3995
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
3996
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
3997
|
+
Badge,
|
|
3998
|
+
{
|
|
3999
|
+
size: "2xsmall",
|
|
4000
|
+
className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
|
|
4001
|
+
children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
|
|
4002
|
+
}
|
|
4003
|
+
) })
|
|
4004
|
+
] }),
|
|
4005
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4006
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
|
|
4007
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
|
|
4008
|
+
] }),
|
|
4009
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4010
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
|
|
4011
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
|
|
4012
|
+
] }),
|
|
4013
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4014
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
|
|
4015
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
|
|
4016
|
+
] }),
|
|
4017
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4018
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
|
|
4019
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
|
|
4020
|
+
year: "numeric",
|
|
4021
|
+
month: "short",
|
|
4022
|
+
day: "numeric",
|
|
4023
|
+
hour: "numeric",
|
|
4024
|
+
minute: "2-digit",
|
|
4025
|
+
hour12: true
|
|
4026
|
+
}) })
|
|
4027
|
+
] })
|
|
4028
|
+
] }) }),
|
|
4029
|
+
Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4030
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
|
|
4031
|
+
/* @__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) })
|
|
4032
|
+
] }) : /* @__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." }) })
|
|
4033
|
+
] }) : null
|
|
4034
|
+
] }) });
|
|
4035
|
+
};
|
|
4036
|
+
const config$3 = defineRouteConfig({
|
|
4037
|
+
label: "Payment details",
|
|
4038
|
+
icon: CreditCard
|
|
4039
|
+
});
|
|
4040
|
+
const getStatusBadgeClass$2 = (status) => {
|
|
4041
|
+
const s2 = status.toLowerCase();
|
|
4042
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
4043
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
4044
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
4045
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
4046
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
4047
|
+
};
|
|
4048
|
+
const formatAmount = (value) => {
|
|
4049
|
+
return String(value);
|
|
4050
|
+
};
|
|
4051
|
+
const RefundDetailPage = () => {
|
|
4052
|
+
const navigate = useNavigate();
|
|
4053
|
+
const params = useParams();
|
|
4054
|
+
const id = params?.id?.trim();
|
|
4055
|
+
const [detail, setDetail] = useState(null);
|
|
4056
|
+
const [loading, setLoading] = useState(!!id);
|
|
4057
|
+
const [error, setError] = useState(null);
|
|
4058
|
+
const [gatewayExpanded, setGatewayExpanded] = useState(false);
|
|
4059
|
+
useEffect(() => {
|
|
4060
|
+
if (!id) {
|
|
4061
|
+
setLoading(false);
|
|
4062
|
+
return;
|
|
4063
|
+
}
|
|
4064
|
+
let cancelled = false;
|
|
4065
|
+
setLoading(true);
|
|
4066
|
+
setError(null);
|
|
4067
|
+
fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
|
|
4068
|
+
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
4069
|
+
return res.json();
|
|
4070
|
+
}).then((data) => {
|
|
4071
|
+
if (!cancelled) setDetail(data);
|
|
4072
|
+
}).catch((e) => {
|
|
4073
|
+
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
4074
|
+
}).finally(() => {
|
|
4075
|
+
if (!cancelled) setLoading(false);
|
|
4076
|
+
});
|
|
4077
|
+
return () => {
|
|
4078
|
+
cancelled = true;
|
|
4079
|
+
};
|
|
4080
|
+
}, [id]);
|
|
4081
|
+
const paymentStatus = detail?.payment?.status ?? "—";
|
|
4082
|
+
const hasGatewayData = detail?.payment?.payment_data && typeof detail.payment.payment_data === "object" && Object.keys(detail.payment.payment_data).length > 0;
|
|
4083
|
+
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: [
|
|
4084
|
+
/* @__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: [
|
|
4085
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
|
|
4086
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
|
|
4087
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
|
|
4088
|
+
] }) }),
|
|
4089
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
4090
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
4091
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
|
|
4092
|
+
] }) : 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: [
|
|
4093
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4094
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
|
|
4095
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4096
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4097
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund ID" }),
|
|
4098
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.id })
|
|
4099
|
+
] }),
|
|
4100
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4101
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
4102
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.refund.amount) })
|
|
4103
|
+
] }),
|
|
4104
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4105
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Note" }),
|
|
4106
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.refund.note ?? "—" })
|
|
4107
|
+
] }),
|
|
4108
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4109
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created at" }),
|
|
4110
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.refund.created_at).toLocaleDateString("en-US", {
|
|
4111
|
+
year: "numeric",
|
|
4112
|
+
month: "short",
|
|
4113
|
+
day: "numeric",
|
|
4114
|
+
hour: "numeric",
|
|
4115
|
+
minute: "2-digit",
|
|
4116
|
+
hour12: true
|
|
4117
|
+
}) })
|
|
4118
|
+
] }),
|
|
4119
|
+
detail.refund.created_by ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4120
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created by" }),
|
|
4121
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.created_by })
|
|
4122
|
+
] }) : null
|
|
4123
|
+
] })
|
|
4124
|
+
] }),
|
|
4125
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4126
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
|
|
4127
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4128
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4129
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
|
|
4130
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
|
|
4131
|
+
] }),
|
|
4132
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4133
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
|
|
4134
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
|
|
4135
|
+
] }),
|
|
4136
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4137
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
|
|
4138
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
|
|
4139
|
+
] }),
|
|
4140
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4141
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
4142
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
|
|
4143
|
+
] }),
|
|
4144
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4145
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
4146
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
4147
|
+
Badge,
|
|
4148
|
+
{
|
|
4149
|
+
size: "2xsmall",
|
|
4150
|
+
className: `uppercase ${getStatusBadgeClass$2(paymentStatus)}`,
|
|
4151
|
+
children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
|
|
4152
|
+
}
|
|
4153
|
+
) })
|
|
4154
|
+
] }),
|
|
4155
|
+
detail.computed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4156
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4157
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Full refund" }),
|
|
4158
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.computed.is_full_refund ? "Yes" : "No" })
|
|
4159
|
+
] }),
|
|
4160
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4161
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Remaining refundable" }),
|
|
4162
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.computed.remaining_refundable_amount) })
|
|
4163
|
+
] }),
|
|
4164
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4165
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund %" }),
|
|
4166
|
+
/* @__PURE__ */ jsxs(Text, { className: "mt-1 block", children: [
|
|
4167
|
+
detail.computed.refund_percentage.toFixed(1),
|
|
4168
|
+
"%"
|
|
4169
|
+
] })
|
|
4170
|
+
] })
|
|
4171
|
+
] }) : null
|
|
4181
4172
|
] })
|
|
4182
4173
|
] }),
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4174
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4175
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Order summary" }),
|
|
4176
|
+
detail.order ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4177
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4178
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order" }),
|
|
4179
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
4180
|
+
Button,
|
|
4181
|
+
{
|
|
4182
|
+
variant: "transparent",
|
|
4183
|
+
size: "small",
|
|
4184
|
+
onClick: () => navigate(`/orders/${detail.order.order_id}`),
|
|
4185
|
+
children: detail.order.order_number ?? detail.order.order_id
|
|
4186
|
+
}
|
|
4187
|
+
) })
|
|
4188
|
+
] }),
|
|
4189
|
+
detail.order.total != null ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4190
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Total" }),
|
|
4191
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.order.total) })
|
|
4192
|
+
] }) : null,
|
|
4193
|
+
detail.order.customer_id ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4194
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Customer ID" }),
|
|
4195
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.order.customer_id })
|
|
4196
|
+
] }) : null,
|
|
4197
|
+
detail.order.region ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4198
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Region" }),
|
|
4199
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.region })
|
|
4200
|
+
] }) : null,
|
|
4201
|
+
detail.order.fulfillment_status ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4202
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
|
|
4203
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
|
|
4204
|
+
] }) : null
|
|
4205
|
+
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
|
|
4206
|
+
] }),
|
|
4207
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4208
|
+
/* @__PURE__ */ jsxs(
|
|
4209
|
+
"button",
|
|
4187
4210
|
{
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
onClick: () =>
|
|
4191
|
-
|
|
4211
|
+
type: "button",
|
|
4212
|
+
className: "flex w-full items-center justify-between text-left",
|
|
4213
|
+
onClick: () => setGatewayExpanded((prev) => !prev),
|
|
4214
|
+
"aria-expanded": gatewayExpanded,
|
|
4215
|
+
"aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
|
|
4192
4216
|
children: [
|
|
4193
|
-
"
|
|
4194
|
-
|
|
4195
|
-
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
4217
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
|
|
4218
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
|
|
4196
4219
|
]
|
|
4197
|
-
}
|
|
4198
|
-
|
|
4199
|
-
))
|
|
4200
|
-
] })
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
] });
|
|
4220
|
+
}
|
|
4221
|
+
),
|
|
4222
|
+
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." }) })
|
|
4223
|
+
] })
|
|
4224
|
+
] }) : null
|
|
4225
|
+
] }) });
|
|
4204
4226
|
};
|
|
4205
|
-
const
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
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
|
|
4215
|
-
] }),
|
|
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({});
|
|
4227
|
+
const config$2 = defineRouteConfig({
|
|
4228
|
+
label: "Refund details",
|
|
4229
|
+
icon: Receipt
|
|
4230
|
+
});
|
|
4255
4231
|
const getStatusBadgeClass$1 = (status) => {
|
|
4256
4232
|
const statusLower = status.toLowerCase();
|
|
4257
4233
|
if (statusLower === "requested") {
|
|
@@ -4278,7 +4254,6 @@ const getStatusBadgeClass$1 = (status) => {
|
|
|
4278
4254
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
4279
4255
|
};
|
|
4280
4256
|
const ReturnDetailPage = () => {
|
|
4281
|
-
var _a, _b, _c;
|
|
4282
4257
|
const navigate = useNavigate();
|
|
4283
4258
|
const { id } = useParams();
|
|
4284
4259
|
const [returnOrder, setReturnOrder] = useState(null);
|
|
@@ -4361,7 +4336,7 @@ const ReturnDetailPage = () => {
|
|
|
4361
4336
|
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/returns"), children: "Back to list" }) })
|
|
4362
4337
|
] }) }) });
|
|
4363
4338
|
}
|
|
4364
|
-
const statusHistory =
|
|
4339
|
+
const statusHistory = returnOrder.metadata?.status_history || [];
|
|
4365
4340
|
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: [
|
|
4366
4341
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
4367
4342
|
/* @__PURE__ */ jsxs(
|
|
@@ -4497,11 +4472,11 @@ const ReturnDetailPage = () => {
|
|
|
4497
4472
|
] }),
|
|
4498
4473
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
4499
4474
|
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
|
|
4500
|
-
/* @__PURE__ */ jsx(Text, { className: "font-medium", children:
|
|
4475
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.customer?.email || returnOrder.order.email || "—" })
|
|
4501
4476
|
] }),
|
|
4502
4477
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
4503
4478
|
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Payment method" }),
|
|
4504
|
-
/* @__PURE__ */ jsx(Text, { className: "font-medium", children:
|
|
4479
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: returnOrder.order.order_payment?.label || "—" })
|
|
4505
4480
|
] }),
|
|
4506
4481
|
returnOrder.order.total && /* @__PURE__ */ jsxs("div", { children: [
|
|
4507
4482
|
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
@@ -4558,13 +4533,12 @@ const getStatusBadgeClass = (status) => {
|
|
|
4558
4533
|
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
4559
4534
|
};
|
|
4560
4535
|
const SwapDetailPage = () => {
|
|
4561
|
-
var _a, _b, _c;
|
|
4562
4536
|
const navigate = useNavigate();
|
|
4563
4537
|
const { id } = useParams();
|
|
4564
4538
|
const [swap, setSwap] = useState(null);
|
|
4565
4539
|
const [order, setOrder] = useState(null);
|
|
4566
4540
|
const [isLoading, setIsLoading] = useState(true);
|
|
4567
|
-
useState(false);
|
|
4541
|
+
const [isRejecting, setIsRejecting] = useState(false);
|
|
4568
4542
|
const [isCancelling, setIsCancelling] = useState(false);
|
|
4569
4543
|
const [error, setError] = useState(null);
|
|
4570
4544
|
const [updateError, setUpdateError] = useState(null);
|
|
@@ -4635,9 +4609,9 @@ const SwapDetailPage = () => {
|
|
|
4635
4609
|
setIsCancelling(false);
|
|
4636
4610
|
}
|
|
4637
4611
|
};
|
|
4638
|
-
const isOrderExchange = Boolean(swap
|
|
4612
|
+
const isOrderExchange = Boolean(swap?.exchange_id);
|
|
4639
4613
|
const canCancelExchange = isOrderExchange && swap && !["cancelled", "canceled", "completed", "declined"].includes(
|
|
4640
|
-
|
|
4614
|
+
swap.status?.toLowerCase() ?? ""
|
|
4641
4615
|
);
|
|
4642
4616
|
if (isLoading) {
|
|
4643
4617
|
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..." }) }) }) });
|
|
@@ -4648,7 +4622,7 @@ const SwapDetailPage = () => {
|
|
|
4648
4622
|
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/swaps"), children: "Back to list" }) })
|
|
4649
4623
|
] }) }) });
|
|
4650
4624
|
}
|
|
4651
|
-
const statusHistory =
|
|
4625
|
+
const statusHistory = swap.metadata?.status_history || [];
|
|
4652
4626
|
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
4627
|
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3", children: [
|
|
4654
4628
|
/* @__PURE__ */ jsxs(
|
|
@@ -4769,7 +4743,7 @@ const SwapDetailPage = () => {
|
|
|
4769
4743
|
] }),
|
|
4770
4744
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
4771
4745
|
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Customer" }),
|
|
4772
|
-
/* @__PURE__ */ jsx(Text, { className: "font-medium", children:
|
|
4746
|
+
/* @__PURE__ */ jsx(Text, { className: "font-medium", children: order.customer?.email || order.email || "—" })
|
|
4773
4747
|
] }),
|
|
4774
4748
|
order.total && /* @__PURE__ */ jsxs("div", { children: [
|
|
4775
4749
|
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Order Total" }),
|
|
@@ -4818,112 +4792,142 @@ const i18nTranslations0 = {};
|
|
|
4818
4792
|
const widgetModule = { widgets: [
|
|
4819
4793
|
{
|
|
4820
4794
|
Component: OrderGiftItemsWidget,
|
|
4821
|
-
zone: ["order.details.side.after"]
|
|
4795
|
+
zone: ["order.details.side.after"],
|
|
4796
|
+
widgetId: "Widget-b753"
|
|
4822
4797
|
},
|
|
4823
4798
|
{
|
|
4824
4799
|
Component: OrderRefundContextWidget,
|
|
4825
|
-
zone: ["order.details.after"]
|
|
4800
|
+
zone: ["order.details.after"],
|
|
4801
|
+
widgetId: "Widget-0606"
|
|
4826
4802
|
}
|
|
4827
4803
|
] };
|
|
4828
4804
|
const routeModule = {
|
|
4829
4805
|
routes: [
|
|
4830
4806
|
{
|
|
4831
|
-
Component:
|
|
4832
|
-
path: "/
|
|
4807
|
+
Component: DeletedRecordsPage,
|
|
4808
|
+
path: "/deleted-records-audit",
|
|
4809
|
+
handle: { label: config$9.label, translationNs: config$9.translationNs }
|
|
4833
4810
|
},
|
|
4834
4811
|
{
|
|
4835
|
-
Component:
|
|
4836
|
-
path: "/
|
|
4812
|
+
Component: PaymentsPage,
|
|
4813
|
+
path: "/payments",
|
|
4814
|
+
handle: { label: config$8.label, translationNs: config$8.translationNs }
|
|
4837
4815
|
},
|
|
4838
4816
|
{
|
|
4839
|
-
Component:
|
|
4840
|
-
path: "/
|
|
4817
|
+
Component: RefundsPage,
|
|
4818
|
+
path: "/refunds",
|
|
4819
|
+
handle: { label: config$7.label, translationNs: config$7.translationNs }
|
|
4841
4820
|
},
|
|
4842
4821
|
{
|
|
4843
4822
|
Component: ReturnsPage,
|
|
4844
|
-
path: "/returns"
|
|
4823
|
+
path: "/returns",
|
|
4824
|
+
handle: { label: config$6.label, translationNs: config$6.translationNs }
|
|
4845
4825
|
},
|
|
4846
4826
|
{
|
|
4847
4827
|
Component: SwapsPage,
|
|
4848
|
-
path: "/swaps"
|
|
4828
|
+
path: "/swaps",
|
|
4829
|
+
handle: { label: config$5.label, translationNs: config$5.translationNs }
|
|
4849
4830
|
},
|
|
4850
4831
|
{
|
|
4851
|
-
Component:
|
|
4852
|
-
path: "/
|
|
4832
|
+
Component: DeletedRecordDetailPage,
|
|
4833
|
+
path: "/deleted-records-audit/:id",
|
|
4834
|
+
handle: { label: config$4.label, translationNs: config$4.translationNs }
|
|
4853
4835
|
},
|
|
4854
4836
|
{
|
|
4855
|
-
Component:
|
|
4856
|
-
path: "/
|
|
4837
|
+
Component: PaymentDetailPage,
|
|
4838
|
+
path: "/payments/:id",
|
|
4839
|
+
handle: { label: config$3.label, translationNs: config$3.translationNs }
|
|
4857
4840
|
},
|
|
4858
4841
|
{
|
|
4859
|
-
Component:
|
|
4860
|
-
path: "/
|
|
4842
|
+
Component: RefundDetailPage,
|
|
4843
|
+
path: "/refunds/:id",
|
|
4844
|
+
handle: { label: config$2.label, translationNs: config$2.translationNs }
|
|
4861
4845
|
},
|
|
4862
4846
|
{
|
|
4863
4847
|
Component: ReturnDetailPage,
|
|
4864
|
-
path: "/returns/:id"
|
|
4848
|
+
path: "/returns/:id",
|
|
4849
|
+
handle: { label: config$1.label, translationNs: config$1.translationNs }
|
|
4865
4850
|
},
|
|
4866
4851
|
{
|
|
4867
4852
|
Component: SwapDetailPage,
|
|
4868
|
-
path: "/swaps/:id"
|
|
4853
|
+
path: "/swaps/:id",
|
|
4854
|
+
handle: { label: config.label, translationNs: config.translationNs }
|
|
4869
4855
|
}
|
|
4870
4856
|
]
|
|
4871
4857
|
};
|
|
4872
4858
|
const menuItemModule = {
|
|
4873
4859
|
menuItems: [
|
|
4874
4860
|
{
|
|
4875
|
-
label: config$
|
|
4876
|
-
icon: config$
|
|
4877
|
-
path: "/
|
|
4878
|
-
nested: void 0
|
|
4861
|
+
label: config$9.label,
|
|
4862
|
+
icon: config$9.icon,
|
|
4863
|
+
path: "/deleted-records-audit",
|
|
4864
|
+
nested: void 0,
|
|
4865
|
+
rank: void 0,
|
|
4866
|
+
translationNs: void 0
|
|
4867
|
+
},
|
|
4868
|
+
{
|
|
4869
|
+
label: config$8.label,
|
|
4870
|
+
icon: config$8.icon,
|
|
4871
|
+
path: "/payments",
|
|
4872
|
+
nested: void 0,
|
|
4873
|
+
rank: void 0,
|
|
4874
|
+
translationNs: void 0
|
|
4879
4875
|
},
|
|
4880
4876
|
{
|
|
4881
4877
|
label: config$7.label,
|
|
4882
4878
|
icon: config$7.icon,
|
|
4883
4879
|
path: "/refunds",
|
|
4884
|
-
nested: void 0
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
label: config$4.label,
|
|
4888
|
-
icon: config$4.icon,
|
|
4889
|
-
path: "/swaps",
|
|
4890
|
-
nested: void 0
|
|
4880
|
+
nested: void 0,
|
|
4881
|
+
rank: void 0,
|
|
4882
|
+
translationNs: void 0
|
|
4891
4883
|
},
|
|
4892
4884
|
{
|
|
4893
4885
|
label: config$6.label,
|
|
4894
4886
|
icon: config$6.icon,
|
|
4895
|
-
path: "/
|
|
4896
|
-
nested: void 0
|
|
4887
|
+
path: "/returns",
|
|
4888
|
+
nested: void 0,
|
|
4889
|
+
rank: void 0,
|
|
4890
|
+
translationNs: void 0
|
|
4897
4891
|
},
|
|
4898
4892
|
{
|
|
4899
|
-
label: config$
|
|
4900
|
-
icon: config$
|
|
4901
|
-
path: "/
|
|
4902
|
-
nested: void 0
|
|
4893
|
+
label: config$5.label,
|
|
4894
|
+
icon: config$5.icon,
|
|
4895
|
+
path: "/swaps",
|
|
4896
|
+
nested: void 0,
|
|
4897
|
+
rank: void 0,
|
|
4898
|
+
translationNs: void 0
|
|
4903
4899
|
},
|
|
4904
4900
|
{
|
|
4905
|
-
label: config$
|
|
4906
|
-
icon: config$
|
|
4907
|
-
path: "/payments",
|
|
4908
|
-
nested: void 0
|
|
4901
|
+
label: config$3.label,
|
|
4902
|
+
icon: config$3.icon,
|
|
4903
|
+
path: "/payments/:id",
|
|
4904
|
+
nested: void 0,
|
|
4905
|
+
rank: void 0,
|
|
4906
|
+
translationNs: void 0
|
|
4909
4907
|
},
|
|
4910
4908
|
{
|
|
4911
4909
|
label: config$2.label,
|
|
4912
4910
|
icon: config$2.icon,
|
|
4913
4911
|
path: "/refunds/:id",
|
|
4914
|
-
nested: void 0
|
|
4912
|
+
nested: void 0,
|
|
4913
|
+
rank: void 0,
|
|
4914
|
+
translationNs: void 0
|
|
4915
|
+
},
|
|
4916
|
+
{
|
|
4917
|
+
label: config$1.label,
|
|
4918
|
+
icon: config$1.icon,
|
|
4919
|
+
path: "/returns/:id",
|
|
4920
|
+
nested: void 0,
|
|
4921
|
+
rank: void 0,
|
|
4922
|
+
translationNs: void 0
|
|
4915
4923
|
},
|
|
4916
4924
|
{
|
|
4917
4925
|
label: config.label,
|
|
4918
4926
|
icon: config.icon,
|
|
4919
4927
|
path: "/swaps/:id",
|
|
4920
|
-
nested: void 0
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
label: config$3.label,
|
|
4924
|
-
icon: config$3.icon,
|
|
4925
|
-
path: "/payments/:id",
|
|
4926
|
-
nested: void 0
|
|
4928
|
+
nested: void 0,
|
|
4929
|
+
rank: void 0,
|
|
4930
|
+
translationNs: void 0
|
|
4927
4931
|
}
|
|
4928
4932
|
]
|
|
4929
4933
|
};
|
|
@@ -4932,13 +4936,19 @@ const displayModule = {
|
|
|
4932
4936
|
displays: {}
|
|
4933
4937
|
};
|
|
4934
4938
|
const i18nModule = { resources: i18nTranslations0 };
|
|
4939
|
+
const cellRendererModule = {};
|
|
4940
|
+
const layoutModule = { layouts: [] };
|
|
4941
|
+
const searchEntityModule = {};
|
|
4935
4942
|
const plugin = {
|
|
4936
4943
|
widgetModule,
|
|
4937
4944
|
routeModule,
|
|
4938
4945
|
menuItemModule,
|
|
4939
4946
|
formModule,
|
|
4940
4947
|
displayModule,
|
|
4941
|
-
i18nModule
|
|
4948
|
+
i18nModule,
|
|
4949
|
+
cellRendererModule,
|
|
4950
|
+
layoutModule,
|
|
4951
|
+
searchEntityModule
|
|
4942
4952
|
};
|
|
4943
4953
|
export {
|
|
4944
4954
|
plugin as default
|