order-management 0.0.104 → 0.0.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
|
-
import { useState, useEffect, useRef,
|
|
4
|
-
import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Popover, clx,
|
|
5
|
-
import { CashSolid, PencilSquareSolid, Trash,
|
|
3
|
+
import { useState, useEffect, useRef, useCallback, useMemo } from "react";
|
|
4
|
+
import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Input, Popover, clx, Copy, Skeleton, Tooltip, toast } from "@medusajs/ui";
|
|
5
|
+
import { CashSolid, PencilSquareSolid, Trash, CreditCard, Receipt, ArrowPath, ChevronDownMini, Check, InformationCircle, ExclamationCircle, MagnifierAlert, ChevronRightMini, ArrowLeft, ClockSolid, ShieldCheck, SquareTwoStack, CheckCircle } from "@medusajs/icons";
|
|
6
6
|
import { useNavigate, useLocation, useSearchParams, useParams } from "react-router-dom";
|
|
7
7
|
function roundRectPath(ctx, x, y, w, h, r) {
|
|
8
8
|
ctx.beginPath();
|
|
@@ -923,1295 +923,6 @@ const OrderRefundContextWidget = (props) => {
|
|
|
923
923
|
defineWidgetConfig({
|
|
924
924
|
zone: "order.details.after"
|
|
925
925
|
});
|
|
926
|
-
const AUDITED_TABLE_NAMES = [
|
|
927
|
-
"account_deletion_request",
|
|
928
|
-
"account_holder",
|
|
929
|
-
"api_key",
|
|
930
|
-
"application_method_buy_rules",
|
|
931
|
-
"application_method_target_rules",
|
|
932
|
-
"auth_identity",
|
|
933
|
-
"auth_mfa_factor",
|
|
934
|
-
"auth_mfa_recovery_code",
|
|
935
|
-
"auth_password_reset_token",
|
|
936
|
-
"auth_verification",
|
|
937
|
-
"cancel_order_reason_mapping",
|
|
938
|
-
"capture",
|
|
939
|
-
"cart",
|
|
940
|
-
"cart_address",
|
|
941
|
-
"cart_line_item",
|
|
942
|
-
"cart_line_item_adjustment",
|
|
943
|
-
"cart_line_item_tax_line",
|
|
944
|
-
"cart_payment_collection",
|
|
945
|
-
"cart_promotion",
|
|
946
|
-
"cart_shipping_method",
|
|
947
|
-
"cart_shipping_method_adjustment",
|
|
948
|
-
"cart_shipping_method_tax_line",
|
|
949
|
-
"contact_email_subscription",
|
|
950
|
-
"contact_request",
|
|
951
|
-
"contact_request_comment",
|
|
952
|
-
"credit_line",
|
|
953
|
-
"currency",
|
|
954
|
-
"customer",
|
|
955
|
-
"customer_account_holder",
|
|
956
|
-
"customer_address",
|
|
957
|
-
"customer_group",
|
|
958
|
-
"customer_group_customer",
|
|
959
|
-
"dynamic_config_value",
|
|
960
|
-
"fulfillment",
|
|
961
|
-
"fulfillment_address",
|
|
962
|
-
"fulfillment_item",
|
|
963
|
-
"fulfillment_label",
|
|
964
|
-
"fulfillment_provider",
|
|
965
|
-
"fulfillment_set",
|
|
966
|
-
"geo_zone",
|
|
967
|
-
"image",
|
|
968
|
-
"inventory_count_item",
|
|
969
|
-
"inventory_count_session",
|
|
970
|
-
"inventory_item",
|
|
971
|
-
"inventory_level",
|
|
972
|
-
"inventory_movement",
|
|
973
|
-
"inventory_purchase",
|
|
974
|
-
"inventory_purchase_attachment",
|
|
975
|
-
"inventory_purchase_audit_event",
|
|
976
|
-
"inventory_purchase_batch",
|
|
977
|
-
"inventory_purchase_line_item",
|
|
978
|
-
"invite",
|
|
979
|
-
"invite_rbac_role",
|
|
980
|
-
"invoice",
|
|
981
|
-
"invoice_sequence",
|
|
982
|
-
"layout_configuration",
|
|
983
|
-
"link_module_migrations",
|
|
984
|
-
"location_fulfillment_provider",
|
|
985
|
-
"location_fulfillment_set",
|
|
986
|
-
"loyalty_gift_card",
|
|
987
|
-
"mikro_orm_migrations",
|
|
988
|
-
"notification",
|
|
989
|
-
"notification_provider",
|
|
990
|
-
"notification_tokens",
|
|
991
|
-
"order",
|
|
992
|
-
"order_address",
|
|
993
|
-
"order_cart",
|
|
994
|
-
"order_change",
|
|
995
|
-
"order_change_action",
|
|
996
|
-
"order_claim",
|
|
997
|
-
"order_claim_item",
|
|
998
|
-
"order_claim_item_image",
|
|
999
|
-
"order_credit_line",
|
|
1000
|
-
"order_exchange",
|
|
1001
|
-
"order_exchange_item",
|
|
1002
|
-
"order_fulfillment",
|
|
1003
|
-
"order_item",
|
|
1004
|
-
"order_line_item",
|
|
1005
|
-
"order_line_item_adjustment",
|
|
1006
|
-
"order_line_item_tax_line",
|
|
1007
|
-
"order_payment_collection",
|
|
1008
|
-
"order_promotion",
|
|
1009
|
-
"order_shipping",
|
|
1010
|
-
"order_shipping_method",
|
|
1011
|
-
"order_shipping_method_adjustment",
|
|
1012
|
-
"order_shipping_method_tax_line",
|
|
1013
|
-
"order_summary",
|
|
1014
|
-
"order_transaction",
|
|
1015
|
-
"otp_verification",
|
|
1016
|
-
"payment",
|
|
1017
|
-
"payment_collection",
|
|
1018
|
-
"payment_collection_payment_providers",
|
|
1019
|
-
"payment_detail",
|
|
1020
|
-
"payment_provider",
|
|
1021
|
-
"payment_session",
|
|
1022
|
-
"payout_request",
|
|
1023
|
-
"price",
|
|
1024
|
-
"price_list",
|
|
1025
|
-
"price_list_rule",
|
|
1026
|
-
"price_preference",
|
|
1027
|
-
"price_rule",
|
|
1028
|
-
"price_set",
|
|
1029
|
-
"product",
|
|
1030
|
-
"product_category",
|
|
1031
|
-
"product_category_product",
|
|
1032
|
-
"product_collection",
|
|
1033
|
-
"product_display_priority",
|
|
1034
|
-
"product_option",
|
|
1035
|
-
"product_option_value",
|
|
1036
|
-
"product_product_option",
|
|
1037
|
-
"product_product_option_value",
|
|
1038
|
-
"product_sales_channel",
|
|
1039
|
-
"product_shipping_profile",
|
|
1040
|
-
"product_tag",
|
|
1041
|
-
"product_tags",
|
|
1042
|
-
"product_type",
|
|
1043
|
-
"product_variant",
|
|
1044
|
-
"product_variant_inventory_item",
|
|
1045
|
-
"product_variant_option",
|
|
1046
|
-
"product_variant_price_set",
|
|
1047
|
-
"product_variant_product_image",
|
|
1048
|
-
"product_view",
|
|
1049
|
-
"promotion",
|
|
1050
|
-
"promotion_application_method",
|
|
1051
|
-
"promotion_campaign",
|
|
1052
|
-
"promotion_campaign_budget",
|
|
1053
|
-
"promotion_campaign_budget_usage",
|
|
1054
|
-
"promotion_promotion_rule",
|
|
1055
|
-
"promotion_rule",
|
|
1056
|
-
"promotion_rule_value",
|
|
1057
|
-
"property_label",
|
|
1058
|
-
"provider_identity",
|
|
1059
|
-
"publishable_api_key_sales_channel",
|
|
1060
|
-
"purchase_supplier",
|
|
1061
|
-
"referral_link",
|
|
1062
|
-
"referral_reward",
|
|
1063
|
-
"refund",
|
|
1064
|
-
"refund_payment_mapping",
|
|
1065
|
-
"refund_reason",
|
|
1066
|
-
"region",
|
|
1067
|
-
"region_country",
|
|
1068
|
-
"region_payment_provider",
|
|
1069
|
-
"reservation_item",
|
|
1070
|
-
"return",
|
|
1071
|
-
"return_fulfillment",
|
|
1072
|
-
"return_item",
|
|
1073
|
-
"return_reason",
|
|
1074
|
-
"review",
|
|
1075
|
-
"sales_channel",
|
|
1076
|
-
"sales_channel_stock_location",
|
|
1077
|
-
"script_migrations",
|
|
1078
|
-
"search_index",
|
|
1079
|
-
"search_index_sync",
|
|
1080
|
-
"search_index_version",
|
|
1081
|
-
"search_postgres_index",
|
|
1082
|
-
"service_zone",
|
|
1083
|
-
"shipment_tracking_event",
|
|
1084
|
-
"shipping_option",
|
|
1085
|
-
"shipping_option_price_set",
|
|
1086
|
-
"shipping_option_rule",
|
|
1087
|
-
"shipping_option_type",
|
|
1088
|
-
"shipping_profile",
|
|
1089
|
-
"skip_merge_cart",
|
|
1090
|
-
"stock_location",
|
|
1091
|
-
"stock_location_address",
|
|
1092
|
-
"store",
|
|
1093
|
-
"store_credit_account",
|
|
1094
|
-
"store_credit_account_transaction",
|
|
1095
|
-
"store_currency",
|
|
1096
|
-
"store_locale",
|
|
1097
|
-
"tax_provider",
|
|
1098
|
-
"tax_rate",
|
|
1099
|
-
"tax_rate_rule",
|
|
1100
|
-
"tax_region",
|
|
1101
|
-
"telegram_config",
|
|
1102
|
-
"telegram_notification_log",
|
|
1103
|
-
"user",
|
|
1104
|
-
"user_preference",
|
|
1105
|
-
"user_rbac_role",
|
|
1106
|
-
"view_configuration",
|
|
1107
|
-
"wallet_account",
|
|
1108
|
-
"wallet_credit_lot",
|
|
1109
|
-
"wallet_gift_card",
|
|
1110
|
-
"wallet_hold",
|
|
1111
|
-
"wallet_ledger_entry",
|
|
1112
|
-
"wallet_rate_limit",
|
|
1113
|
-
"wallet_refund_intent",
|
|
1114
|
-
"wallet_top_up_request",
|
|
1115
|
-
"wishlist",
|
|
1116
|
-
"workflow_execution"
|
|
1117
|
-
];
|
|
1118
|
-
const ENTITY_CATEGORIES = [
|
|
1119
|
-
{ id: "orders", label: "Orders", description: "Orders, items, returns, exchanges and claims" },
|
|
1120
|
-
{ id: "carts", label: "Carts", description: "Shopping carts and checkout data" },
|
|
1121
|
-
{ id: "customers", label: "Customers", description: "Customers, addresses and groups" },
|
|
1122
|
-
{ id: "catalog", label: "Catalog", description: "Products, variants, categories and collections" },
|
|
1123
|
-
{ id: "pricing", label: "Pricing & Promotions", description: "Prices, price lists and promotions" },
|
|
1124
|
-
{ id: "payments", label: "Payments & Refunds", description: "Payments, sessions, captures and refunds" },
|
|
1125
|
-
{ id: "fulfillment", label: "Fulfillment & Shipping", description: "Fulfillments, shipping options and tracking" },
|
|
1126
|
-
{ id: "inventory", label: "Inventory & Purchasing", description: "Stock, locations, reservations and purchases" },
|
|
1127
|
-
{ id: "wallet", label: "Wallet & Credits", description: "Wallets, store credit and gift cards" },
|
|
1128
|
-
{ id: "access", label: "Users & Access", description: "Admin users, logins, roles and API keys" },
|
|
1129
|
-
{ id: "store", label: "Store & Regions", description: "Store, regions, currencies, taxes and sales channels" },
|
|
1130
|
-
{ id: "engagement", label: "Engagement", description: "Reviews, wishlists, referrals and contact requests" },
|
|
1131
|
-
{ id: "notifications", label: "Notifications", description: "Notifications and messaging" },
|
|
1132
|
-
{ id: "system", label: "System & Configuration", description: "Settings, search, workflows and migrations" }
|
|
1133
|
-
];
|
|
1134
|
-
const ENTITY_DEFINITIONS = {
|
|
1135
|
-
// Orders
|
|
1136
|
-
order: { label: "Order", category: "orders" },
|
|
1137
|
-
order_address: { label: "Order Address", category: "orders" },
|
|
1138
|
-
order_cart: { label: "Order–Cart Link", category: "orders" },
|
|
1139
|
-
order_change: { label: "Order Change", category: "orders" },
|
|
1140
|
-
order_change_action: { label: "Order Change Action", category: "orders" },
|
|
1141
|
-
order_claim: { label: "Claim", category: "orders" },
|
|
1142
|
-
order_claim_item: { label: "Claim Item", category: "orders" },
|
|
1143
|
-
order_claim_item_image: { label: "Claim Item Image", category: "orders" },
|
|
1144
|
-
order_credit_line: { label: "Order Credit Line", category: "orders" },
|
|
1145
|
-
order_exchange: { label: "Exchange", category: "orders" },
|
|
1146
|
-
order_exchange_item: { label: "Exchange Item", category: "orders" },
|
|
1147
|
-
order_fulfillment: { label: "Order–Fulfillment Link", category: "orders" },
|
|
1148
|
-
order_item: { label: "Order Item Quantity", category: "orders" },
|
|
1149
|
-
order_line_item: { label: "Order Item", category: "orders" },
|
|
1150
|
-
order_line_item_adjustment: { label: "Order Item Discount", category: "orders" },
|
|
1151
|
-
order_line_item_tax_line: { label: "Order Item Tax", category: "orders" },
|
|
1152
|
-
order_payment_collection: { label: "Order–Payment Link", category: "orders" },
|
|
1153
|
-
order_promotion: { label: "Order Promotion", category: "orders" },
|
|
1154
|
-
order_shipping: { label: "Order Shipping", category: "orders" },
|
|
1155
|
-
order_shipping_method: { label: "Order Shipping Method", category: "orders" },
|
|
1156
|
-
order_shipping_method_adjustment: { label: "Order Shipping Discount", category: "orders" },
|
|
1157
|
-
order_shipping_method_tax_line: { label: "Order Shipping Tax", category: "orders" },
|
|
1158
|
-
order_summary: { label: "Order Summary", category: "orders" },
|
|
1159
|
-
order_transaction: { label: "Order Transaction", category: "orders" },
|
|
1160
|
-
return: { label: "Return", category: "orders" },
|
|
1161
|
-
return_fulfillment: { label: "Return–Fulfillment Link", category: "orders" },
|
|
1162
|
-
return_item: { label: "Return Item", category: "orders" },
|
|
1163
|
-
return_reason: { label: "Return Reason", category: "orders" },
|
|
1164
|
-
cancel_order_reason_mapping: { label: "Order Cancellation Reason", category: "orders" },
|
|
1165
|
-
credit_line: { label: "Credit Line", category: "orders" },
|
|
1166
|
-
invoice: { label: "Invoice", category: "orders" },
|
|
1167
|
-
invoice_sequence: { label: "Invoice Number Sequence", category: "orders" },
|
|
1168
|
-
// Carts
|
|
1169
|
-
cart: { label: "Cart", category: "carts" },
|
|
1170
|
-
cart_address: { label: "Cart Address", category: "carts" },
|
|
1171
|
-
cart_line_item: { label: "Cart Item", category: "carts" },
|
|
1172
|
-
cart_line_item_adjustment: { label: "Cart Item Discount", category: "carts" },
|
|
1173
|
-
cart_line_item_tax_line: { label: "Cart Item Tax", category: "carts" },
|
|
1174
|
-
cart_payment_collection: { label: "Cart–Payment Link", category: "carts" },
|
|
1175
|
-
cart_promotion: { label: "Cart Promotion", category: "carts" },
|
|
1176
|
-
cart_shipping_method: { label: "Cart Shipping Method", category: "carts" },
|
|
1177
|
-
cart_shipping_method_adjustment: { label: "Cart Shipping Discount", category: "carts" },
|
|
1178
|
-
cart_shipping_method_tax_line: { label: "Cart Shipping Tax", category: "carts" },
|
|
1179
|
-
skip_merge_cart: { label: "Cart Merge Exclusion", category: "carts" },
|
|
1180
|
-
// Customers
|
|
1181
|
-
customer: { label: "Customer", category: "customers" },
|
|
1182
|
-
customer_address: { label: "Customer Address", category: "customers" },
|
|
1183
|
-
customer_group: { label: "Customer Group", category: "customers" },
|
|
1184
|
-
customer_group_customer: { label: "Customer Group Member", category: "customers" },
|
|
1185
|
-
customer_account_holder: { label: "Customer–Account Holder Link", category: "customers" },
|
|
1186
|
-
account_holder: { label: "Payment Account Holder", category: "customers" },
|
|
1187
|
-
account_deletion_request: { label: "Account Deletion Request", category: "customers" },
|
|
1188
|
-
payment_detail: { label: "Customer Refund Method", category: "customers" },
|
|
1189
|
-
otp_verification: { label: "OTP Verification", category: "customers" },
|
|
1190
|
-
// Catalog
|
|
1191
|
-
product: { label: "Product", category: "catalog" },
|
|
1192
|
-
product_variant: { label: "Product Variant", category: "catalog" },
|
|
1193
|
-
product_category: { label: "Product Category", category: "catalog" },
|
|
1194
|
-
product_category_product: { label: "Product–Category Link", category: "catalog" },
|
|
1195
|
-
product_collection: { label: "Collection", category: "catalog" },
|
|
1196
|
-
product_option: { label: "Product Option", category: "catalog" },
|
|
1197
|
-
product_option_value: { label: "Product Option Value", category: "catalog" },
|
|
1198
|
-
product_product_option: { label: "Product–Option Link", category: "catalog" },
|
|
1199
|
-
product_product_option_value: { label: "Product–Option Value Link", category: "catalog" },
|
|
1200
|
-
product_tag: { label: "Product Tag", category: "catalog" },
|
|
1201
|
-
product_tags: { label: "Product–Tag Link", category: "catalog" },
|
|
1202
|
-
product_type: { label: "Product Type", category: "catalog" },
|
|
1203
|
-
product_sales_channel: { label: "Product–Sales Channel Link", category: "catalog" },
|
|
1204
|
-
product_shipping_profile: { label: "Product–Shipping Profile Link", category: "catalog" },
|
|
1205
|
-
product_variant_inventory_item: { label: "Variant–Inventory Link", category: "catalog" },
|
|
1206
|
-
product_variant_option: { label: "Variant Option", category: "catalog" },
|
|
1207
|
-
product_variant_price_set: { label: "Variant–Price Link", category: "catalog" },
|
|
1208
|
-
product_variant_product_image: { label: "Variant Image", category: "catalog" },
|
|
1209
|
-
product_display_priority: { label: "Product Display Priority", category: "catalog" },
|
|
1210
|
-
product_view: { label: "Product View", category: "catalog" },
|
|
1211
|
-
image: { label: "Product Image", category: "catalog" },
|
|
1212
|
-
property_label: { label: "Property Label", category: "catalog" },
|
|
1213
|
-
// Pricing & promotions
|
|
1214
|
-
price: { label: "Price", category: "pricing" },
|
|
1215
|
-
price_list: { label: "Price List", category: "pricing" },
|
|
1216
|
-
price_list_rule: { label: "Price List Rule", category: "pricing" },
|
|
1217
|
-
price_preference: { label: "Price Preference", category: "pricing" },
|
|
1218
|
-
price_rule: { label: "Price Rule", category: "pricing" },
|
|
1219
|
-
price_set: { label: "Price Set", category: "pricing" },
|
|
1220
|
-
promotion: { label: "Promotion", category: "pricing" },
|
|
1221
|
-
promotion_application_method: { label: "Promotion Application Method", category: "pricing" },
|
|
1222
|
-
promotion_campaign: { label: "Campaign", category: "pricing" },
|
|
1223
|
-
promotion_campaign_budget: { label: "Campaign Budget", category: "pricing" },
|
|
1224
|
-
promotion_campaign_budget_usage: { label: "Campaign Budget Usage", category: "pricing" },
|
|
1225
|
-
promotion_promotion_rule: { label: "Promotion–Rule Link", category: "pricing" },
|
|
1226
|
-
promotion_rule: { label: "Promotion Rule", category: "pricing" },
|
|
1227
|
-
promotion_rule_value: { label: "Promotion Rule Value", category: "pricing" },
|
|
1228
|
-
application_method_buy_rules: { label: "Promotion Buy Rule", category: "pricing" },
|
|
1229
|
-
application_method_target_rules: { label: "Promotion Target Rule", category: "pricing" },
|
|
1230
|
-
// Payments
|
|
1231
|
-
payment: { label: "Payment", category: "payments" },
|
|
1232
|
-
payment_collection: { label: "Payment Collection", category: "payments" },
|
|
1233
|
-
payment_collection_payment_providers: { label: "Payment Collection–Provider Link", category: "payments" },
|
|
1234
|
-
payment_provider: { label: "Payment Provider", category: "payments" },
|
|
1235
|
-
payment_session: { label: "Payment Session", category: "payments" },
|
|
1236
|
-
capture: { label: "Payment Capture", category: "payments" },
|
|
1237
|
-
refund: { label: "Refund", category: "payments" },
|
|
1238
|
-
refund_reason: { label: "Refund Reason", category: "payments" },
|
|
1239
|
-
refund_payment_mapping: { label: "Return Refund Mapping", category: "payments" },
|
|
1240
|
-
payout_request: { label: "Payout Request", category: "payments" },
|
|
1241
|
-
// Fulfillment
|
|
1242
|
-
fulfillment: { label: "Fulfillment", category: "fulfillment" },
|
|
1243
|
-
fulfillment_address: { label: "Fulfillment Address", category: "fulfillment" },
|
|
1244
|
-
fulfillment_item: { label: "Fulfillment Item", category: "fulfillment" },
|
|
1245
|
-
fulfillment_label: { label: "Shipping Label", category: "fulfillment" },
|
|
1246
|
-
fulfillment_provider: { label: "Fulfillment Provider", category: "fulfillment" },
|
|
1247
|
-
fulfillment_set: { label: "Fulfillment Set", category: "fulfillment" },
|
|
1248
|
-
geo_zone: { label: "Geo Zone", category: "fulfillment" },
|
|
1249
|
-
service_zone: { label: "Service Zone", category: "fulfillment" },
|
|
1250
|
-
shipping_option: { label: "Shipping Option", category: "fulfillment" },
|
|
1251
|
-
shipping_option_price_set: { label: "Shipping Option–Price Link", category: "fulfillment" },
|
|
1252
|
-
shipping_option_rule: { label: "Shipping Option Rule", category: "fulfillment" },
|
|
1253
|
-
shipping_option_type: { label: "Shipping Option Type", category: "fulfillment" },
|
|
1254
|
-
shipping_profile: { label: "Shipping Profile", category: "fulfillment" },
|
|
1255
|
-
shipment_tracking_event: { label: "Shipment Tracking Event", category: "fulfillment" },
|
|
1256
|
-
location_fulfillment_provider: { label: "Location–Fulfillment Provider Link", category: "fulfillment" },
|
|
1257
|
-
location_fulfillment_set: { label: "Location–Fulfillment Set Link", category: "fulfillment" },
|
|
1258
|
-
// Inventory
|
|
1259
|
-
inventory_item: { label: "Inventory Item", category: "inventory" },
|
|
1260
|
-
inventory_level: { label: "Inventory Level", category: "inventory" },
|
|
1261
|
-
inventory_movement: { label: "Inventory Movement", category: "inventory" },
|
|
1262
|
-
inventory_count_item: { label: "Stock Count Item", category: "inventory" },
|
|
1263
|
-
inventory_count_session: { label: "Stock Count Session", category: "inventory" },
|
|
1264
|
-
inventory_purchase: { label: "Purchase", category: "inventory" },
|
|
1265
|
-
inventory_purchase_attachment: { label: "Purchase Attachment", category: "inventory" },
|
|
1266
|
-
inventory_purchase_audit_event: { label: "Purchase Audit Event", category: "inventory" },
|
|
1267
|
-
inventory_purchase_batch: { label: "Purchase Batch", category: "inventory" },
|
|
1268
|
-
inventory_purchase_line_item: { label: "Purchase Item", category: "inventory" },
|
|
1269
|
-
purchase_supplier: { label: "Supplier", category: "inventory" },
|
|
1270
|
-
reservation_item: { label: "Stock Reservation", category: "inventory" },
|
|
1271
|
-
stock_location: { label: "Stock Location", category: "inventory" },
|
|
1272
|
-
stock_location_address: { label: "Stock Location Address", category: "inventory" },
|
|
1273
|
-
sales_channel_stock_location: { label: "Sales Channel–Location Link", category: "inventory" },
|
|
1274
|
-
// Wallet
|
|
1275
|
-
wallet_account: { label: "Wallet Account", category: "wallet" },
|
|
1276
|
-
wallet_credit_lot: { label: "Wallet Credit Lot", category: "wallet" },
|
|
1277
|
-
wallet_gift_card: { label: "Wallet Gift Card", category: "wallet" },
|
|
1278
|
-
wallet_hold: { label: "Wallet Hold", category: "wallet" },
|
|
1279
|
-
wallet_ledger_entry: { label: "Wallet Ledger Entry", category: "wallet" },
|
|
1280
|
-
wallet_rate_limit: { label: "Wallet Rate Limit", category: "wallet" },
|
|
1281
|
-
wallet_refund_intent: { label: "Wallet Refund", category: "wallet" },
|
|
1282
|
-
wallet_top_up_request: { label: "Wallet Top-up Request", category: "wallet" },
|
|
1283
|
-
store_credit_account: { label: "Store Credit Account", category: "wallet" },
|
|
1284
|
-
store_credit_account_transaction: { label: "Store Credit Transaction", category: "wallet" },
|
|
1285
|
-
loyalty_gift_card: { label: "Loyalty Gift Card", category: "wallet" },
|
|
1286
|
-
// Users & access
|
|
1287
|
-
user: { label: "Admin User", category: "access" },
|
|
1288
|
-
user_preference: { label: "User Preference", category: "access" },
|
|
1289
|
-
user_rbac_role: { label: "User Role", category: "access" },
|
|
1290
|
-
invite: { label: "Admin Invite", category: "access" },
|
|
1291
|
-
invite_rbac_role: { label: "Invite Role", category: "access" },
|
|
1292
|
-
api_key: { label: "API Key", category: "access" },
|
|
1293
|
-
publishable_api_key_sales_channel: { label: "API Key–Sales Channel Link", category: "access" },
|
|
1294
|
-
auth_identity: { label: "Login Identity", category: "access" },
|
|
1295
|
-
auth_mfa_factor: { label: "MFA Factor", category: "access" },
|
|
1296
|
-
auth_mfa_recovery_code: { label: "MFA Recovery Code", category: "access" },
|
|
1297
|
-
auth_password_reset_token: { label: "Password Reset Token", category: "access" },
|
|
1298
|
-
auth_verification: { label: "Auth Verification", category: "access" },
|
|
1299
|
-
provider_identity: { label: "Login Provider Identity", category: "access" },
|
|
1300
|
-
// Store & regions
|
|
1301
|
-
store: { label: "Store", category: "store" },
|
|
1302
|
-
store_currency: { label: "Store Currency", category: "store" },
|
|
1303
|
-
store_locale: { label: "Store Locale", category: "store" },
|
|
1304
|
-
currency: { label: "Currency", category: "store" },
|
|
1305
|
-
region: { label: "Region", category: "store" },
|
|
1306
|
-
region_country: { label: "Region Country", category: "store" },
|
|
1307
|
-
region_payment_provider: { label: "Region–Payment Provider Link", category: "store" },
|
|
1308
|
-
sales_channel: { label: "Sales Channel", category: "store" },
|
|
1309
|
-
tax_provider: { label: "Tax Provider", category: "store" },
|
|
1310
|
-
tax_rate: { label: "Tax Rate", category: "store" },
|
|
1311
|
-
tax_rate_rule: { label: "Tax Rate Rule", category: "store" },
|
|
1312
|
-
tax_region: { label: "Tax Region", category: "store" },
|
|
1313
|
-
// Engagement
|
|
1314
|
-
review: { label: "Review", category: "engagement" },
|
|
1315
|
-
wishlist: { label: "Wishlist", category: "engagement" },
|
|
1316
|
-
referral_link: { label: "Referral Link", category: "engagement" },
|
|
1317
|
-
referral_reward: { label: "Referral Reward", category: "engagement" },
|
|
1318
|
-
contact_request: { label: "Contact Request", category: "engagement" },
|
|
1319
|
-
contact_request_comment: { label: "Contact Request Comment", category: "engagement" },
|
|
1320
|
-
contact_email_subscription: { label: "Email Subscription", category: "engagement" },
|
|
1321
|
-
// Notifications
|
|
1322
|
-
notification: { label: "Notification", category: "notifications" },
|
|
1323
|
-
notification_provider: { label: "Notification Provider", category: "notifications" },
|
|
1324
|
-
notification_tokens: { label: "Push Notification Token", category: "notifications" },
|
|
1325
|
-
telegram_config: { label: "Telegram Settings", category: "notifications" },
|
|
1326
|
-
telegram_notification_log: { label: "Telegram Notification Log", category: "notifications" },
|
|
1327
|
-
// System
|
|
1328
|
-
dynamic_config_value: { label: "Plugin Setting", category: "system" },
|
|
1329
|
-
layout_configuration: { label: "Layout Configuration", category: "system" },
|
|
1330
|
-
view_configuration: { label: "View Configuration", category: "system" },
|
|
1331
|
-
workflow_execution: { label: "Workflow Execution", category: "system" },
|
|
1332
|
-
search_index: { label: "Search Index", category: "system" },
|
|
1333
|
-
search_index_sync: { label: "Search Index Sync", category: "system" },
|
|
1334
|
-
search_index_version: { label: "Search Index Version", category: "system" },
|
|
1335
|
-
search_postgres_index: { label: "Search Index Entry", category: "system" },
|
|
1336
|
-
link_module_migrations: { label: "Link Migration Record", category: "system" },
|
|
1337
|
-
mikro_orm_migrations: { label: "Database Migration Record", category: "system" },
|
|
1338
|
-
script_migrations: { label: "Script Migration Record", category: "system" }
|
|
1339
|
-
};
|
|
1340
|
-
const CATEGORY_BY_ID = new Map(ENTITY_CATEGORIES.map((c) => [c.id, c]));
|
|
1341
|
-
const SYSTEM_CATEGORY = CATEGORY_BY_ID.get("system");
|
|
1342
|
-
function humanizeTableName(tableName) {
|
|
1343
|
-
return tableName.split("_").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
1344
|
-
}
|
|
1345
|
-
function getEntityInfo(tableName) {
|
|
1346
|
-
const def = ENTITY_DEFINITIONS[tableName];
|
|
1347
|
-
return {
|
|
1348
|
-
tableName,
|
|
1349
|
-
label: def?.label ?? humanizeTableName(tableName),
|
|
1350
|
-
category: def && CATEGORY_BY_ID.get(def.category) || SYSTEM_CATEGORY
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
function getEntitiesByCategory() {
|
|
1354
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1355
|
-
for (const table of AUDITED_TABLE_NAMES) {
|
|
1356
|
-
const info = getEntityInfo(table);
|
|
1357
|
-
const list = groups.get(info.category.id) ?? [];
|
|
1358
|
-
list.push(info);
|
|
1359
|
-
groups.set(info.category.id, list);
|
|
1360
|
-
}
|
|
1361
|
-
return ENTITY_CATEGORIES.filter((category) => groups.has(category.id)).map((category) => ({
|
|
1362
|
-
category,
|
|
1363
|
-
entities: (groups.get(category.id) ?? []).sort((a, b) => a.label.localeCompare(b.label))
|
|
1364
|
-
}));
|
|
1365
|
-
}
|
|
1366
|
-
function getCategory(id) {
|
|
1367
|
-
return CATEGORY_BY_ID.get(id);
|
|
1368
|
-
}
|
|
1369
|
-
function getTablesForCategory(id) {
|
|
1370
|
-
return AUDITED_TABLE_NAMES.filter((table) => getEntityInfo(table).category.id === id);
|
|
1371
|
-
}
|
|
1372
|
-
const GROUPS = getEntitiesByCategory();
|
|
1373
|
-
function triggerLabel(entity, category) {
|
|
1374
|
-
if (entity) return getEntityInfo(entity).label;
|
|
1375
|
-
if (category) return `All ${getCategory(category)?.label ?? category}`;
|
|
1376
|
-
return "All entities";
|
|
1377
|
-
}
|
|
1378
|
-
const EntityPicker = ({ entity, category, onChange }) => {
|
|
1379
|
-
const [open, setOpen] = useState(false);
|
|
1380
|
-
const [search, setSearch] = useState("");
|
|
1381
|
-
const searchRef = useRef(null);
|
|
1382
|
-
const filteredGroups = useMemo(() => {
|
|
1383
|
-
const term = search.trim().toLowerCase();
|
|
1384
|
-
if (!term) return GROUPS;
|
|
1385
|
-
return GROUPS.map((group) => {
|
|
1386
|
-
const categoryMatches = group.category.label.toLowerCase().includes(term);
|
|
1387
|
-
const entities = categoryMatches ? group.entities : group.entities.filter(
|
|
1388
|
-
(e) => e.label.toLowerCase().includes(term) || e.tableName.includes(term.replace(/\s+/g, "_"))
|
|
1389
|
-
);
|
|
1390
|
-
return { ...group, entities };
|
|
1391
|
-
}).filter((group) => group.entities.length > 0);
|
|
1392
|
-
}, [search]);
|
|
1393
|
-
const select = (next) => {
|
|
1394
|
-
onChange(next);
|
|
1395
|
-
setOpen(false);
|
|
1396
|
-
setSearch("");
|
|
1397
|
-
};
|
|
1398
|
-
const firstMatch = filteredGroups[0]?.entities[0];
|
|
1399
|
-
const isAll = !entity && !category;
|
|
1400
|
-
return /* @__PURE__ */ jsxs(
|
|
1401
|
-
Popover,
|
|
1402
|
-
{
|
|
1403
|
-
open,
|
|
1404
|
-
onOpenChange: (next) => {
|
|
1405
|
-
setOpen(next);
|
|
1406
|
-
if (!next) setSearch("");
|
|
1407
|
-
},
|
|
1408
|
-
children: [
|
|
1409
|
-
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1410
|
-
"button",
|
|
1411
|
-
{
|
|
1412
|
-
type: "button",
|
|
1413
|
-
"aria-label": "Filter by entity",
|
|
1414
|
-
className: clx(
|
|
1415
|
-
"txt-compact-small flex h-7 w-full min-w-[200px] items-center justify-between gap-2 rounded-md bg-ui-bg-field px-2 text-left shadow-borders-base outline-none transition-fg",
|
|
1416
|
-
"hover:bg-ui-bg-field-hover focus-visible:shadow-borders-interactive-with-active md:w-auto",
|
|
1417
|
-
isAll ? "text-ui-fg-muted" : "text-ui-fg-base"
|
|
1418
|
-
),
|
|
1419
|
-
children: [
|
|
1420
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: triggerLabel(entity, category) }),
|
|
1421
|
-
/* @__PURE__ */ jsx(ChevronDownMini, { className: "shrink-0 text-ui-fg-muted" })
|
|
1422
|
-
]
|
|
1423
|
-
}
|
|
1424
|
-
) }),
|
|
1425
|
-
/* @__PURE__ */ jsxs(
|
|
1426
|
-
Popover.Content,
|
|
1427
|
-
{
|
|
1428
|
-
align: "start",
|
|
1429
|
-
className: "w-[min(360px,calc(100vw-2rem))] p-0",
|
|
1430
|
-
onOpenAutoFocus: (event) => {
|
|
1431
|
-
event.preventDefault();
|
|
1432
|
-
searchRef.current?.focus();
|
|
1433
|
-
},
|
|
1434
|
-
children: [
|
|
1435
|
-
/* @__PURE__ */ jsx("div", { className: "border-b border-ui-border-base p-2", children: /* @__PURE__ */ jsx(
|
|
1436
|
-
Input,
|
|
1437
|
-
{
|
|
1438
|
-
ref: searchRef,
|
|
1439
|
-
size: "small",
|
|
1440
|
-
type: "search",
|
|
1441
|
-
placeholder: "Search entities, e.g. order, wallet…",
|
|
1442
|
-
value: search,
|
|
1443
|
-
onChange: (e) => setSearch(e.target.value),
|
|
1444
|
-
onKeyDown: (e) => {
|
|
1445
|
-
if (e.key === "Enter" && firstMatch) {
|
|
1446
|
-
e.preventDefault();
|
|
1447
|
-
select({ entity: firstMatch.tableName, category: "" });
|
|
1448
|
-
}
|
|
1449
|
-
},
|
|
1450
|
-
"aria-label": "Search entities"
|
|
1451
|
-
}
|
|
1452
|
-
) }),
|
|
1453
|
-
/* @__PURE__ */ jsxs("div", { className: "max-h-[360px] overflow-y-auto p-1", role: "listbox", "aria-label": "Entities", children: [
|
|
1454
|
-
!search.trim() ? /* @__PURE__ */ jsx(PickerOption, { selected: isAll, onSelect: () => select({ entity: "", category: "" }), children: "All entities" }) : null,
|
|
1455
|
-
filteredGroups.length === 0 ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "px-3 py-6 text-center text-ui-fg-muted", children: [
|
|
1456
|
-
"No entities match “",
|
|
1457
|
-
search.trim(),
|
|
1458
|
-
"”"
|
|
1459
|
-
] }) : null,
|
|
1460
|
-
filteredGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
1461
|
-
/* @__PURE__ */ jsx("div", { className: "px-2 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: group.category.label }),
|
|
1462
|
-
!search.trim() ? /* @__PURE__ */ jsxs(
|
|
1463
|
-
PickerOption,
|
|
1464
|
-
{
|
|
1465
|
-
selected: !entity && category === group.category.id,
|
|
1466
|
-
onSelect: () => select({ entity: "", category: group.category.id }),
|
|
1467
|
-
secondary: group.category.description,
|
|
1468
|
-
children: [
|
|
1469
|
-
"All ",
|
|
1470
|
-
group.category.label
|
|
1471
|
-
]
|
|
1472
|
-
}
|
|
1473
|
-
) : null,
|
|
1474
|
-
group.entities.map((info) => /* @__PURE__ */ jsx(
|
|
1475
|
-
PickerOption,
|
|
1476
|
-
{
|
|
1477
|
-
selected: entity === info.tableName,
|
|
1478
|
-
onSelect: () => select({ entity: info.tableName, category: "" }),
|
|
1479
|
-
secondary: info.tableName,
|
|
1480
|
-
secondaryMono: true,
|
|
1481
|
-
indent: !search.trim(),
|
|
1482
|
-
children: info.label
|
|
1483
|
-
},
|
|
1484
|
-
info.tableName
|
|
1485
|
-
))
|
|
1486
|
-
] }, group.category.id))
|
|
1487
|
-
] })
|
|
1488
|
-
]
|
|
1489
|
-
}
|
|
1490
|
-
)
|
|
1491
|
-
]
|
|
1492
|
-
}
|
|
1493
|
-
);
|
|
1494
|
-
};
|
|
1495
|
-
const PickerOption = ({ selected, onSelect, children, secondary, secondaryMono, indent }) => /* @__PURE__ */ jsxs(
|
|
1496
|
-
"button",
|
|
1497
|
-
{
|
|
1498
|
-
type: "button",
|
|
1499
|
-
role: "option",
|
|
1500
|
-
"aria-selected": selected,
|
|
1501
|
-
onClick: onSelect,
|
|
1502
|
-
className: clx(
|
|
1503
|
-
"flex w-full items-start gap-2 rounded-md px-2 py-1.5 text-left outline-none transition-fg",
|
|
1504
|
-
"hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-hover",
|
|
1505
|
-
indent && "pl-4"
|
|
1506
|
-
),
|
|
1507
|
-
children: [
|
|
1508
|
-
/* @__PURE__ */ jsx("span", { className: "mt-0.5 flex size-4 shrink-0 items-center justify-center text-ui-fg-interactive", children: selected ? /* @__PURE__ */ jsx(Check, {}) : null }),
|
|
1509
|
-
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
1510
|
-
/* @__PURE__ */ jsx("span", { className: "truncate text-sm text-ui-fg-base", children }),
|
|
1511
|
-
secondary ? /* @__PURE__ */ jsx("span", { className: clx("truncate text-xs text-ui-fg-muted", secondaryMono && "font-mono"), children: secondary }) : null
|
|
1512
|
-
] })
|
|
1513
|
-
]
|
|
1514
|
-
}
|
|
1515
|
-
);
|
|
1516
|
-
const CopyableId = ({ value, emptyLabel = "No ID", className }) => {
|
|
1517
|
-
if (!value) {
|
|
1518
|
-
return /* @__PURE__ */ jsx(Text, { size: "small", className: "italic text-ui-fg-muted", children: emptyLabel });
|
|
1519
|
-
}
|
|
1520
|
-
return /* @__PURE__ */ jsxs("span", { className: clx("inline-flex min-w-0 max-w-full items-center gap-1", className), children: [
|
|
1521
|
-
/* @__PURE__ */ jsx("span", { className: "truncate font-mono text-xs text-ui-fg-base", title: value, children: value }),
|
|
1522
|
-
/* @__PURE__ */ jsx("span", { onClick: (e) => e.stopPropagation(), className: "inline-flex shrink-0", children: /* @__PURE__ */ jsx(Copy, { content: value, variant: "mini", className: "text-ui-fg-muted", "aria-label": `Copy ${value}` }) })
|
|
1523
|
-
] });
|
|
1524
|
-
};
|
|
1525
|
-
const RELATIVE_UNITS = [
|
|
1526
|
-
{ unit: "year", seconds: 60 * 60 * 24 * 365 },
|
|
1527
|
-
{ unit: "month", seconds: 60 * 60 * 24 * 30 },
|
|
1528
|
-
{ unit: "week", seconds: 60 * 60 * 24 * 7 },
|
|
1529
|
-
{ unit: "day", seconds: 60 * 60 * 24 },
|
|
1530
|
-
{ unit: "hour", seconds: 60 * 60 },
|
|
1531
|
-
{ unit: "minute", seconds: 60 }
|
|
1532
|
-
];
|
|
1533
|
-
function toDate(value) {
|
|
1534
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
1535
|
-
return Number.isNaN(date.getTime()) ? null : date;
|
|
1536
|
-
}
|
|
1537
|
-
function formatRelativeTime(value, now = /* @__PURE__ */ new Date()) {
|
|
1538
|
-
const date = toDate(value);
|
|
1539
|
-
if (!date) return "—";
|
|
1540
|
-
const diffSeconds = Math.round((date.getTime() - now.getTime()) / 1e3);
|
|
1541
|
-
if (Math.abs(diffSeconds) < 45) return "just now";
|
|
1542
|
-
const rtf = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
|
|
1543
|
-
for (const { unit, seconds } of RELATIVE_UNITS) {
|
|
1544
|
-
if (Math.abs(diffSeconds) >= seconds) {
|
|
1545
|
-
return rtf.format(Math.round(diffSeconds / seconds), unit);
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
|
-
return rtf.format(Math.round(diffSeconds / 60), "minute");
|
|
1549
|
-
}
|
|
1550
|
-
function formatExactDateTime(value) {
|
|
1551
|
-
const date = toDate(value);
|
|
1552
|
-
if (!date) return "—";
|
|
1553
|
-
return new Intl.DateTimeFormat(void 0, {
|
|
1554
|
-
day: "2-digit",
|
|
1555
|
-
month: "short",
|
|
1556
|
-
year: "numeric",
|
|
1557
|
-
hour: "2-digit",
|
|
1558
|
-
minute: "2-digit",
|
|
1559
|
-
second: "2-digit",
|
|
1560
|
-
timeZoneName: "short"
|
|
1561
|
-
}).format(date);
|
|
1562
|
-
}
|
|
1563
|
-
function formatDate(value) {
|
|
1564
|
-
const date = toDate(value);
|
|
1565
|
-
if (!date) return "—";
|
|
1566
|
-
return new Intl.DateTimeFormat(void 0, { day: "2-digit", month: "short", year: "numeric" }).format(date);
|
|
1567
|
-
}
|
|
1568
|
-
function formatNumber(value) {
|
|
1569
|
-
return new Intl.NumberFormat().format(value);
|
|
1570
|
-
}
|
|
1571
|
-
function formatMoney(amount, currencyCode) {
|
|
1572
|
-
const code = currencyCode?.trim().toUpperCase();
|
|
1573
|
-
if (code && /^[A-Z]{3}$/.test(code)) {
|
|
1574
|
-
try {
|
|
1575
|
-
return new Intl.NumberFormat(void 0, { style: "currency", currency: code }).format(amount);
|
|
1576
|
-
} catch {
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
return code ? `${code} ${formatNumber(amount)}` : formatNumber(amount);
|
|
1580
|
-
}
|
|
1581
|
-
const SOURCE_ALIASES = {
|
|
1582
|
-
admin: { kind: "admin", label: "Admin Panel" },
|
|
1583
|
-
admin_panel: { kind: "admin", label: "Admin Panel" },
|
|
1584
|
-
dashboard: { kind: "admin", label: "Admin Panel" },
|
|
1585
|
-
api: { kind: "api", label: "API" },
|
|
1586
|
-
store_api: { kind: "api", label: "Storefront API" },
|
|
1587
|
-
admin_api: { kind: "api", label: "Admin API" },
|
|
1588
|
-
system: { kind: "system", label: "System" },
|
|
1589
|
-
job: { kind: "job", label: "Background Job" },
|
|
1590
|
-
background_job: { kind: "job", label: "Background Job" },
|
|
1591
|
-
scheduled_job: { kind: "job", label: "Background Job" },
|
|
1592
|
-
cron: { kind: "job", label: "Background Job" },
|
|
1593
|
-
workflow: { kind: "workflow", label: "Workflow" },
|
|
1594
|
-
migration: { kind: "system", label: "Migration" }
|
|
1595
|
-
};
|
|
1596
|
-
function describeSource(source) {
|
|
1597
|
-
if (!source || !source.trim()) return { kind: "unknown", label: "Unknown" };
|
|
1598
|
-
const key = source.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
1599
|
-
return SOURCE_ALIASES[key] ?? { kind: "other", label: source.trim() };
|
|
1600
|
-
}
|
|
1601
|
-
function sourceBadgeColor(kind) {
|
|
1602
|
-
switch (kind) {
|
|
1603
|
-
case "admin":
|
|
1604
|
-
return "blue";
|
|
1605
|
-
case "api":
|
|
1606
|
-
return "purple";
|
|
1607
|
-
case "job":
|
|
1608
|
-
case "workflow":
|
|
1609
|
-
return "orange";
|
|
1610
|
-
case "system":
|
|
1611
|
-
return "green";
|
|
1612
|
-
default:
|
|
1613
|
-
return "grey";
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
const CARDS = [
|
|
1617
|
-
{ key: "total", label: "Total deleted", hint: "All records captured since auditing began" },
|
|
1618
|
-
{ key: "today", label: "Today", hint: "Deleted since midnight (your time)" },
|
|
1619
|
-
{ key: "last_7_days", label: "Last 7 days", hint: "Including today" },
|
|
1620
|
-
{ key: "tables_affected", label: "Entity types affected", hint: "Distinct kinds of records deleted" }
|
|
1621
|
-
];
|
|
1622
|
-
const SummaryCards = ({ stats, loading, failed }) => {
|
|
1623
|
-
if (failed && !stats) return null;
|
|
1624
|
-
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", children: CARDS.map((card) => /* @__PURE__ */ jsxs(
|
|
1625
|
-
"div",
|
|
1626
|
-
{
|
|
1627
|
-
className: "flex flex-col gap-1 rounded-lg border border-ui-border-base bg-ui-bg-subtle px-4 py-3",
|
|
1628
|
-
title: card.hint,
|
|
1629
|
-
children: [
|
|
1630
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: card.label }),
|
|
1631
|
-
loading || !stats ? /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-16" }) : /* @__PURE__ */ jsx(Text, { className: "text-2xl font-semibold leading-8 text-ui-fg-base", children: formatNumber(stats[card.key]) })
|
|
1632
|
-
]
|
|
1633
|
-
},
|
|
1634
|
-
card.key
|
|
1635
|
-
)) });
|
|
1636
|
-
};
|
|
1637
|
-
const BASE = "/admin/deleted-records-audit";
|
|
1638
|
-
class AuditApiError extends Error {
|
|
1639
|
-
status;
|
|
1640
|
-
constructor(message, status) {
|
|
1641
|
-
super(message);
|
|
1642
|
-
this.status = status;
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
async function getJson(url, signal) {
|
|
1646
|
-
const response = await fetch(url, { credentials: "include", signal });
|
|
1647
|
-
if (!response.ok) {
|
|
1648
|
-
let message = response.statusText || "Request failed";
|
|
1649
|
-
try {
|
|
1650
|
-
const body = await response.json();
|
|
1651
|
-
if (body && typeof body === "object" && "message" in body && typeof body.message === "string") {
|
|
1652
|
-
message = body.message;
|
|
1653
|
-
}
|
|
1654
|
-
} catch {
|
|
1655
|
-
}
|
|
1656
|
-
throw new AuditApiError(message, response.status);
|
|
1657
|
-
}
|
|
1658
|
-
return await response.json();
|
|
1659
|
-
}
|
|
1660
|
-
function fetchAuditList(params, signal) {
|
|
1661
|
-
return getJson(`${BASE}?${params.toString()}`, signal);
|
|
1662
|
-
}
|
|
1663
|
-
async function fetchAuditStats(signal) {
|
|
1664
|
-
const todayStart = /* @__PURE__ */ new Date();
|
|
1665
|
-
todayStart.setHours(0, 0, 0, 0);
|
|
1666
|
-
const params = new URLSearchParams({ today_start: todayStart.toISOString() });
|
|
1667
|
-
const body = await getJson(`${BASE}/stats?${params.toString()}`, signal);
|
|
1668
|
-
return body.stats;
|
|
1669
|
-
}
|
|
1670
|
-
async function fetchAuditDetail(id, signal) {
|
|
1671
|
-
const body = await getJson(`${BASE}/${encodeURIComponent(id)}`, signal);
|
|
1672
|
-
return body.audit;
|
|
1673
|
-
}
|
|
1674
|
-
const LAST_LIST_URL_KEY = "om.deleted-records-audit.last-list-search";
|
|
1675
|
-
const DATE_PRESETS = [
|
|
1676
|
-
{ value: "any", label: "Any time" },
|
|
1677
|
-
{ value: "today", label: "Today" },
|
|
1678
|
-
{ value: "yesterday", label: "Yesterday" },
|
|
1679
|
-
{ value: "7d", label: "Last 7 days" },
|
|
1680
|
-
{ value: "30d", label: "Last 30 days" },
|
|
1681
|
-
{ value: "custom", label: "Custom range" }
|
|
1682
|
-
];
|
|
1683
|
-
const EMPTY_FILTERS = {
|
|
1684
|
-
q: "",
|
|
1685
|
-
entity: "",
|
|
1686
|
-
category: "",
|
|
1687
|
-
date: "any",
|
|
1688
|
-
from: "",
|
|
1689
|
-
to: "",
|
|
1690
|
-
source: "",
|
|
1691
|
-
deletedBy: ""
|
|
1692
|
-
};
|
|
1693
|
-
const URL_KEYS = {
|
|
1694
|
-
q: "q",
|
|
1695
|
-
entity: "entity",
|
|
1696
|
-
category: "category",
|
|
1697
|
-
date: "date",
|
|
1698
|
-
from: "from",
|
|
1699
|
-
to: "to",
|
|
1700
|
-
source: "source",
|
|
1701
|
-
deletedBy: "deleted_by"
|
|
1702
|
-
};
|
|
1703
|
-
const DATE_PRESET_VALUES = new Set(DATE_PRESETS.map((p) => p.value));
|
|
1704
|
-
const DAY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
1705
|
-
function filtersFromSearchParams(params) {
|
|
1706
|
-
const read = (key) => params.get(URL_KEYS[key])?.trim() ?? "";
|
|
1707
|
-
const date = read("date");
|
|
1708
|
-
const from = read("from");
|
|
1709
|
-
const to = read("to");
|
|
1710
|
-
return {
|
|
1711
|
-
q: read("q"),
|
|
1712
|
-
entity: read("entity"),
|
|
1713
|
-
category: read("category"),
|
|
1714
|
-
date: DATE_PRESET_VALUES.has(date) ? date : "any",
|
|
1715
|
-
from: DAY_PATTERN.test(from) ? from : "",
|
|
1716
|
-
to: DAY_PATTERN.test(to) ? to : "",
|
|
1717
|
-
source: read("source"),
|
|
1718
|
-
deletedBy: read("deletedBy")
|
|
1719
|
-
};
|
|
1720
|
-
}
|
|
1721
|
-
function filtersToSearchParams(filters) {
|
|
1722
|
-
const params = new URLSearchParams();
|
|
1723
|
-
for (const key of Object.keys(URL_KEYS)) {
|
|
1724
|
-
const value = filters[key];
|
|
1725
|
-
if (!value || value === EMPTY_FILTERS[key]) continue;
|
|
1726
|
-
if ((key === "from" || key === "to") && filters.date !== "custom") continue;
|
|
1727
|
-
params.set(URL_KEYS[key], value);
|
|
1728
|
-
}
|
|
1729
|
-
return params;
|
|
1730
|
-
}
|
|
1731
|
-
function hasActiveFilters(filters) {
|
|
1732
|
-
return filtersToSearchParams(filters).toString() !== "";
|
|
1733
|
-
}
|
|
1734
|
-
function startOfDay(date) {
|
|
1735
|
-
const d = new Date(date);
|
|
1736
|
-
d.setHours(0, 0, 0, 0);
|
|
1737
|
-
return d;
|
|
1738
|
-
}
|
|
1739
|
-
function endOfDay(date) {
|
|
1740
|
-
const d = new Date(date);
|
|
1741
|
-
d.setHours(23, 59, 59, 999);
|
|
1742
|
-
return d;
|
|
1743
|
-
}
|
|
1744
|
-
function parseDay(day) {
|
|
1745
|
-
if (!DAY_PATTERN.test(day)) return null;
|
|
1746
|
-
const [y, m, d] = day.split("-").map(Number);
|
|
1747
|
-
const date = new Date(y, m - 1, d);
|
|
1748
|
-
return Number.isNaN(date.getTime()) ? null : date;
|
|
1749
|
-
}
|
|
1750
|
-
function resolveDateRange(filters, now = /* @__PURE__ */ new Date()) {
|
|
1751
|
-
const today = startOfDay(now);
|
|
1752
|
-
switch (filters.date) {
|
|
1753
|
-
case "today":
|
|
1754
|
-
return { from: today };
|
|
1755
|
-
case "yesterday": {
|
|
1756
|
-
const y = new Date(today);
|
|
1757
|
-
y.setDate(y.getDate() - 1);
|
|
1758
|
-
return { from: y, to: endOfDay(y) };
|
|
1759
|
-
}
|
|
1760
|
-
case "7d": {
|
|
1761
|
-
const from = new Date(today);
|
|
1762
|
-
from.setDate(from.getDate() - 6);
|
|
1763
|
-
return { from };
|
|
1764
|
-
}
|
|
1765
|
-
case "30d": {
|
|
1766
|
-
const from = new Date(today);
|
|
1767
|
-
from.setDate(from.getDate() - 29);
|
|
1768
|
-
return { from };
|
|
1769
|
-
}
|
|
1770
|
-
case "custom": {
|
|
1771
|
-
const from = parseDay(filters.from);
|
|
1772
|
-
const to = parseDay(filters.to);
|
|
1773
|
-
return { from: from ?? void 0, to: to ? endOfDay(to) : void 0 };
|
|
1774
|
-
}
|
|
1775
|
-
default:
|
|
1776
|
-
return {};
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
function filtersToApiParams(filters, page, now = /* @__PURE__ */ new Date()) {
|
|
1780
|
-
const params = new URLSearchParams();
|
|
1781
|
-
params.set("limit", String(page.limit));
|
|
1782
|
-
params.set("offset", String(page.offset));
|
|
1783
|
-
if (filters.q) params.set("q", filters.q);
|
|
1784
|
-
if (filters.entity) {
|
|
1785
|
-
params.set("table_name", filters.entity);
|
|
1786
|
-
} else if (filters.category) {
|
|
1787
|
-
const tables = getTablesForCategory(filters.category);
|
|
1788
|
-
if (tables.length) params.set("table_names", tables.join(","));
|
|
1789
|
-
}
|
|
1790
|
-
const range = resolveDateRange(filters, now);
|
|
1791
|
-
if (range.from) params.set("date_from", range.from.toISOString());
|
|
1792
|
-
if (range.to) params.set("date_to", range.to.toISOString());
|
|
1793
|
-
if (filters.source) params.set("source", filters.source);
|
|
1794
|
-
if (filters.deletedBy) params.set("deleted_by", filters.deletedBy);
|
|
1795
|
-
return params;
|
|
1796
|
-
}
|
|
1797
|
-
const PAGE_SIZE = 50;
|
|
1798
|
-
const RESTORE_PAGE_SIZE = 100;
|
|
1799
|
-
const MAX_RESTORE_ROWS = 500;
|
|
1800
|
-
const ALL = "__all__";
|
|
1801
|
-
const UNKNOWN_SOURCE = "unknown";
|
|
1802
|
-
const LOADED_COUNT_KEY_PREFIX = "om.deleted-records-audit.loaded:";
|
|
1803
|
-
const LAST_VIEWED_KEY = "om.deleted-records-audit.last-viewed";
|
|
1804
|
-
function readSession(key) {
|
|
1805
|
-
try {
|
|
1806
|
-
return window.sessionStorage.getItem(key);
|
|
1807
|
-
} catch {
|
|
1808
|
-
return null;
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
function writeSession(key, value) {
|
|
1812
|
-
try {
|
|
1813
|
-
window.sessionStorage.setItem(key, value);
|
|
1814
|
-
} catch {
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
const DeletedRecordsPage = () => {
|
|
1818
|
-
const navigate = useNavigate();
|
|
1819
|
-
const location = useLocation();
|
|
1820
|
-
const [searchParams, setSearchParams] = useSearchParams();
|
|
1821
|
-
const filters = useMemo(() => filtersFromSearchParams(searchParams), [searchParams]);
|
|
1822
|
-
const filterKey = filtersToSearchParams(filters).toString();
|
|
1823
|
-
const filtersActive = hasActiveFilters(filters);
|
|
1824
|
-
const [searchText, setSearchText] = useState(filters.q);
|
|
1825
|
-
const [items, setItems] = useState([]);
|
|
1826
|
-
const [count, setCount] = useState(0);
|
|
1827
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
1828
|
-
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
1829
|
-
const [error, setError] = useState(null);
|
|
1830
|
-
const [stats, setStats] = useState(null);
|
|
1831
|
-
const [statsLoading, setStatsLoading] = useState(true);
|
|
1832
|
-
const [statsFailed, setStatsFailed] = useState(false);
|
|
1833
|
-
const [reloadToken, setReloadToken] = useState(0);
|
|
1834
|
-
const [highlightId, setHighlightId] = useState(null);
|
|
1835
|
-
const restoredScrollRef = useRef(false);
|
|
1836
|
-
const updateFilters = useCallback(
|
|
1837
|
-
(patch) => {
|
|
1838
|
-
const next = { ...filters, ...patch };
|
|
1839
|
-
setSearchParams(filtersToSearchParams(next), { replace: true });
|
|
1840
|
-
},
|
|
1841
|
-
[filters, setSearchParams]
|
|
1842
|
-
);
|
|
1843
|
-
useEffect(() => {
|
|
1844
|
-
if (searchText.trim() === filters.q) return;
|
|
1845
|
-
const handle = setTimeout(() => updateFilters({ q: searchText.trim() }), 300);
|
|
1846
|
-
return () => clearTimeout(handle);
|
|
1847
|
-
}, [searchText, filters.q, updateFilters]);
|
|
1848
|
-
useEffect(() => {
|
|
1849
|
-
setSearchText((current) => current.trim() === filters.q ? current : filters.q);
|
|
1850
|
-
}, [filters.q]);
|
|
1851
|
-
useEffect(() => {
|
|
1852
|
-
writeSession(LAST_LIST_URL_KEY, location.search);
|
|
1853
|
-
}, [location.search]);
|
|
1854
|
-
const loadStats = useCallback(async (signal) => {
|
|
1855
|
-
setStatsLoading(true);
|
|
1856
|
-
setStatsFailed(false);
|
|
1857
|
-
try {
|
|
1858
|
-
setStats(await fetchAuditStats(signal));
|
|
1859
|
-
} catch (e) {
|
|
1860
|
-
if (!signal?.aborted) setStatsFailed(true);
|
|
1861
|
-
} finally {
|
|
1862
|
-
if (!signal?.aborted) setStatsLoading(false);
|
|
1863
|
-
}
|
|
1864
|
-
}, []);
|
|
1865
|
-
useEffect(() => {
|
|
1866
|
-
const controller = new AbortController();
|
|
1867
|
-
void loadStats(controller.signal);
|
|
1868
|
-
return () => controller.abort();
|
|
1869
|
-
}, [loadStats, reloadToken]);
|
|
1870
|
-
useEffect(() => {
|
|
1871
|
-
const controller = new AbortController();
|
|
1872
|
-
const restoreTarget = Math.min(
|
|
1873
|
-
MAX_RESTORE_ROWS,
|
|
1874
|
-
Math.max(PAGE_SIZE, Number(readSession(LOADED_COUNT_KEY_PREFIX + filterKey)) || 0)
|
|
1875
|
-
);
|
|
1876
|
-
setIsLoading(true);
|
|
1877
|
-
setError(null);
|
|
1878
|
-
(async () => {
|
|
1879
|
-
try {
|
|
1880
|
-
const collected = [];
|
|
1881
|
-
let total = 0;
|
|
1882
|
-
while (collected.length < restoreTarget) {
|
|
1883
|
-
const limit = restoreTarget > PAGE_SIZE ? RESTORE_PAGE_SIZE : PAGE_SIZE;
|
|
1884
|
-
const page = await fetchAuditList(
|
|
1885
|
-
filtersToApiParams(filters, { limit, offset: collected.length }),
|
|
1886
|
-
controller.signal
|
|
1887
|
-
);
|
|
1888
|
-
total = page.count;
|
|
1889
|
-
collected.push(...page.audits);
|
|
1890
|
-
if (page.audits.length < limit || collected.length >= total) break;
|
|
1891
|
-
}
|
|
1892
|
-
if (controller.signal.aborted) return;
|
|
1893
|
-
setItems(collected.slice(0, restoreTarget));
|
|
1894
|
-
setCount(total);
|
|
1895
|
-
} catch (e) {
|
|
1896
|
-
if (controller.signal.aborted) return;
|
|
1897
|
-
setItems([]);
|
|
1898
|
-
setCount(0);
|
|
1899
|
-
setError(e instanceof Error ? e.message : "Unknown error");
|
|
1900
|
-
} finally {
|
|
1901
|
-
if (!controller.signal.aborted) setIsLoading(false);
|
|
1902
|
-
}
|
|
1903
|
-
})();
|
|
1904
|
-
return () => controller.abort();
|
|
1905
|
-
}, [filterKey, reloadToken]);
|
|
1906
|
-
useEffect(() => {
|
|
1907
|
-
if (!isLoading) writeSession(LOADED_COUNT_KEY_PREFIX + filterKey, String(items.length));
|
|
1908
|
-
}, [items.length, isLoading, filterKey]);
|
|
1909
|
-
useEffect(() => {
|
|
1910
|
-
if (isLoading || restoredScrollRef.current) return;
|
|
1911
|
-
restoredScrollRef.current = true;
|
|
1912
|
-
const lastViewed = readSession(LAST_VIEWED_KEY);
|
|
1913
|
-
if (!lastViewed || !items.some((item) => item.id === lastViewed)) return;
|
|
1914
|
-
setHighlightId(lastViewed);
|
|
1915
|
-
requestAnimationFrame(() => {
|
|
1916
|
-
const visible = Array.from(document.querySelectorAll(`[data-audit-row="${lastViewed}"]`)).find(
|
|
1917
|
-
(el) => el.offsetParent !== null
|
|
1918
|
-
);
|
|
1919
|
-
visible?.scrollIntoView({ block: "center" });
|
|
1920
|
-
});
|
|
1921
|
-
const handle = setTimeout(() => setHighlightId(null), 2500);
|
|
1922
|
-
return () => clearTimeout(handle);
|
|
1923
|
-
}, [isLoading, items]);
|
|
1924
|
-
const loadMore = async () => {
|
|
1925
|
-
setIsFetchingMore(true);
|
|
1926
|
-
try {
|
|
1927
|
-
const page = await fetchAuditList(filtersToApiParams(filters, { limit: PAGE_SIZE, offset: items.length }));
|
|
1928
|
-
setItems((prev) => [...prev, ...page.audits]);
|
|
1929
|
-
setCount(page.count);
|
|
1930
|
-
} catch (e) {
|
|
1931
|
-
setError(e instanceof Error ? e.message : "Unknown error");
|
|
1932
|
-
} finally {
|
|
1933
|
-
setIsFetchingMore(false);
|
|
1934
|
-
}
|
|
1935
|
-
};
|
|
1936
|
-
const openDetail = (id) => {
|
|
1937
|
-
writeSession(LAST_VIEWED_KEY, id);
|
|
1938
|
-
navigate(`/deleted-records-audit/${id}`, { state: { fromList: true } });
|
|
1939
|
-
};
|
|
1940
|
-
const clearFilters = () => {
|
|
1941
|
-
setSearchText("");
|
|
1942
|
-
setSearchParams(filtersToSearchParams(EMPTY_FILTERS), { replace: true });
|
|
1943
|
-
};
|
|
1944
|
-
const refresh = () => setReloadToken((t) => t + 1);
|
|
1945
|
-
const hasMore = items.length < count;
|
|
1946
|
-
const knownSources = stats?.sources ?? [];
|
|
1947
|
-
const knownDeletedBy = stats?.deleted_by ?? [];
|
|
1948
|
-
const attributionMissing = !!stats && stats.total > 0 && knownSources.length === 0 && knownDeletedBy.length === 0;
|
|
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: [
|
|
1950
|
-
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [
|
|
1951
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1952
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Deleted Records" }),
|
|
1953
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Review records that were permanently deleted from the system." })
|
|
1954
|
-
] }),
|
|
1955
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: refresh, isLoading: isLoading && items.length > 0, children: [
|
|
1956
|
-
/* @__PURE__ */ jsx(ArrowPath, {}),
|
|
1957
|
-
"Refresh"
|
|
1958
|
-
] })
|
|
1959
|
-
] }),
|
|
1960
|
-
/* @__PURE__ */ jsx(SummaryCards, { stats, loading: statsLoading, failed: statsFailed }),
|
|
1961
|
-
/* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-3", "aria-label": "Search and filters", children: [
|
|
1962
|
-
/* @__PURE__ */ jsx(
|
|
1963
|
-
Input,
|
|
1964
|
-
{
|
|
1965
|
-
type: "search",
|
|
1966
|
-
size: "base",
|
|
1967
|
-
placeholder: "Search by record ID, e.g. order_01J…, prod_…, cus_…",
|
|
1968
|
-
value: searchText,
|
|
1969
|
-
onChange: (e) => setSearchText(e.target.value),
|
|
1970
|
-
"aria-label": "Search by record ID",
|
|
1971
|
-
className: "w-full"
|
|
1972
|
-
}
|
|
1973
|
-
),
|
|
1974
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 md:flex-row md:flex-wrap md:items-center", children: [
|
|
1975
|
-
/* @__PURE__ */ jsx(
|
|
1976
|
-
EntityPicker,
|
|
1977
|
-
{
|
|
1978
|
-
entity: filters.entity,
|
|
1979
|
-
category: filters.category,
|
|
1980
|
-
onChange: (next) => updateFilters(next)
|
|
1981
|
-
}
|
|
1982
|
-
),
|
|
1983
|
-
/* @__PURE__ */ jsx("div", { className: "md:w-[160px]", children: /* @__PURE__ */ jsxs(
|
|
1984
|
-
Select,
|
|
1985
|
-
{
|
|
1986
|
-
size: "small",
|
|
1987
|
-
value: filters.date,
|
|
1988
|
-
onValueChange: (value) => updateFilters({ date: value }),
|
|
1989
|
-
children: [
|
|
1990
|
-
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": "Filter by date", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
1991
|
-
/* @__PURE__ */ jsx(Select.Content, { children: DATE_PRESETS.map((preset) => /* @__PURE__ */ jsx(Select.Item, { value: preset.value, children: preset.label }, preset.value)) })
|
|
1992
|
-
]
|
|
1993
|
-
}
|
|
1994
|
-
) }),
|
|
1995
|
-
filters.date === "custom" ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1996
|
-
/* @__PURE__ */ jsx(
|
|
1997
|
-
Input,
|
|
1998
|
-
{
|
|
1999
|
-
type: "date",
|
|
2000
|
-
size: "small",
|
|
2001
|
-
value: filters.from,
|
|
2002
|
-
max: filters.to || void 0,
|
|
2003
|
-
onChange: (e) => updateFilters({ from: e.target.value }),
|
|
2004
|
-
"aria-label": "From date"
|
|
2005
|
-
}
|
|
2006
|
-
),
|
|
2007
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "to" }),
|
|
2008
|
-
/* @__PURE__ */ jsx(
|
|
2009
|
-
Input,
|
|
2010
|
-
{
|
|
2011
|
-
type: "date",
|
|
2012
|
-
size: "small",
|
|
2013
|
-
value: filters.to,
|
|
2014
|
-
min: filters.from || void 0,
|
|
2015
|
-
onChange: (e) => updateFilters({ to: e.target.value }),
|
|
2016
|
-
"aria-label": "To date"
|
|
2017
|
-
}
|
|
2018
|
-
)
|
|
2019
|
-
] }) : null,
|
|
2020
|
-
knownSources.length > 0 || filters.source ? /* @__PURE__ */ jsx("div", { className: "md:w-[170px]", children: /* @__PURE__ */ jsxs(
|
|
2021
|
-
Select,
|
|
2022
|
-
{
|
|
2023
|
-
size: "small",
|
|
2024
|
-
value: filters.source || ALL,
|
|
2025
|
-
onValueChange: (value) => updateFilters({ source: value === ALL ? "" : value }),
|
|
2026
|
-
children: [
|
|
2027
|
-
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": "Filter by source", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
2028
|
-
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
2029
|
-
/* @__PURE__ */ jsx(Select.Item, { value: ALL, children: "All sources" }),
|
|
2030
|
-
knownSources.map((source) => /* @__PURE__ */ jsx(Select.Item, { value: source, children: describeSource(source).label }, source)),
|
|
2031
|
-
/* @__PURE__ */ jsx(Select.Item, { value: UNKNOWN_SOURCE, children: "Unknown" })
|
|
2032
|
-
] })
|
|
2033
|
-
]
|
|
2034
|
-
}
|
|
2035
|
-
) }) : null,
|
|
2036
|
-
knownDeletedBy.length > 0 || filters.deletedBy ? /* @__PURE__ */ jsxs("div", { className: "md:w-[200px]", children: [
|
|
2037
|
-
/* @__PURE__ */ jsx(
|
|
2038
|
-
Input,
|
|
2039
|
-
{
|
|
2040
|
-
size: "small",
|
|
2041
|
-
list: "deleted-records-audit-deleted-by",
|
|
2042
|
-
placeholder: "Deleted by (all users)",
|
|
2043
|
-
defaultValue: filters.deletedBy,
|
|
2044
|
-
onBlur: (e) => updateFilters({ deletedBy: e.target.value.trim() }),
|
|
2045
|
-
onKeyDown: (e) => {
|
|
2046
|
-
if (e.key === "Enter") updateFilters({ deletedBy: e.currentTarget.value.trim() });
|
|
2047
|
-
},
|
|
2048
|
-
"aria-label": "Filter by who deleted the record"
|
|
2049
|
-
},
|
|
2050
|
-
filters.deletedBy
|
|
2051
|
-
),
|
|
2052
|
-
/* @__PURE__ */ jsx("datalist", { id: "deleted-records-audit-deleted-by", children: knownDeletedBy.map((value) => /* @__PURE__ */ jsx("option", { value }, value)) })
|
|
2053
|
-
] }) : null,
|
|
2054
|
-
filtersActive ? /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: clearFilters, children: "Clear filters" }) : null
|
|
2055
|
-
] })
|
|
2056
|
-
] }),
|
|
2057
|
-
attributionMissing ? /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: [
|
|
2058
|
-
/* @__PURE__ */ jsx(InformationCircle, { className: "mt-0.5 shrink-0 text-ui-fg-muted" }),
|
|
2059
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Who deleted a record and where the deletion came from are not being recorded yet, so those columns show “Unknown”. Every deleted record is still captured in full." })
|
|
2060
|
-
] }) : null,
|
|
2061
|
-
!isLoading && !error && items.length > 0 ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", "aria-live": "polite", children: [
|
|
2062
|
-
"Showing ",
|
|
2063
|
-
formatNumber(items.length),
|
|
2064
|
-
" of ",
|
|
2065
|
-
formatNumber(count),
|
|
2066
|
-
" ",
|
|
2067
|
-
count === 1 ? "record" : "records",
|
|
2068
|
-
filtersActive ? " matching your filters" : ""
|
|
2069
|
-
] }) : null,
|
|
2070
|
-
error ? /* @__PURE__ */ jsx(ErrorState, { onRetry: refresh, detail: error }) : isLoading ? /* @__PURE__ */ jsx(ListSkeleton, {}) : items.length === 0 ? filtersActive ? /* @__PURE__ */ jsx(
|
|
2071
|
-
EmptyState,
|
|
2072
|
-
{
|
|
2073
|
-
title: "No deleted records found",
|
|
2074
|
-
body: "There are no audit records matching your current filters.",
|
|
2075
|
-
action: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: clearFilters, children: "Clear filters" })
|
|
2076
|
-
}
|
|
2077
|
-
) : /* @__PURE__ */ jsx(
|
|
2078
|
-
EmptyState,
|
|
2079
|
-
{
|
|
2080
|
-
title: "No deleted records yet",
|
|
2081
|
-
body: "Hard-deleted records will appear here automatically when a monitored database record is permanently deleted."
|
|
2082
|
-
}
|
|
2083
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2084
|
-
/* @__PURE__ */ jsx(AuditTable, { items, highlightId, onOpen: openDetail }),
|
|
2085
|
-
/* @__PURE__ */ jsx(AuditCards, { items, highlightId, onOpen: openDetail })
|
|
2086
|
-
] }),
|
|
2087
|
-
!error && !isLoading && hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: isFetchingMore, onClick: loadMore, children: "Load more" }) }) : null
|
|
2088
|
-
] }) });
|
|
2089
|
-
};
|
|
2090
|
-
const HEADER_CELL = "px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted";
|
|
2091
|
-
const DeletedWhen = ({ occurredAt }) => /* @__PURE__ */ jsx(Tooltip, { content: formatExactDateTime(occurredAt), children: /* @__PURE__ */ jsx("span", { className: "cursor-default text-sm text-ui-fg-base", children: formatRelativeTime(occurredAt) }) });
|
|
2092
|
-
const SourceBadge = ({ source }) => {
|
|
2093
|
-
const info = describeSource(source);
|
|
2094
|
-
if (info.kind === "unknown") {
|
|
2095
|
-
return /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Unknown" });
|
|
2096
|
-
}
|
|
2097
|
-
return /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: sourceBadgeColor(info.kind), className: "shrink-0 whitespace-nowrap", children: info.label });
|
|
2098
|
-
};
|
|
2099
|
-
const AuditTable = ({ items, highlightId, onOpen }) => /* @__PURE__ */ jsx("div", { className: "hidden w-full overflow-hidden rounded-xl border border-ui-border-base md:block", children: /* @__PURE__ */ jsxs("table", { className: "w-full table-fixed divide-y divide-ui-border-base", children: [
|
|
2100
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2101
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[22%]"), children: "Entity" }),
|
|
2102
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[24%]"), children: "Record" }),
|
|
2103
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[13%]"), children: "Deleted" }),
|
|
2104
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[13%]"), children: "Deleted by" }),
|
|
2105
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[11%]"), children: "Source" }),
|
|
2106
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[8%]"), children: "Status" }),
|
|
2107
|
-
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[9%]"), children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Action" }) })
|
|
2108
|
-
] }) }),
|
|
2109
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((item) => {
|
|
2110
|
-
const entity = getEntityInfo(item.table_name);
|
|
2111
|
-
return /* @__PURE__ */ jsxs(
|
|
2112
|
-
"tr",
|
|
2113
|
-
{
|
|
2114
|
-
"data-audit-row": item.id,
|
|
2115
|
-
tabIndex: 0,
|
|
2116
|
-
onClick: () => onOpen(item.id),
|
|
2117
|
-
onKeyDown: (e) => {
|
|
2118
|
-
if (e.key === "Enter") onOpen(item.id);
|
|
2119
|
-
},
|
|
2120
|
-
className: clx(
|
|
2121
|
-
"cursor-pointer outline-none transition-colors hover:bg-ui-bg-subtle/60 focus-visible:bg-ui-bg-subtle",
|
|
2122
|
-
highlightId === item.id && "bg-ui-bg-highlight"
|
|
2123
|
-
),
|
|
2124
|
-
children: [
|
|
2125
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col", children: [
|
|
2126
|
-
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-ui-fg-base", title: entity.label, children: entity.label }),
|
|
2127
|
-
/* @__PURE__ */ jsx("span", { className: "truncate text-xs text-ui-fg-muted", children: entity.category.label })
|
|
2128
|
-
] }) }),
|
|
2129
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(CopyableId, { value: item.record_id }) }),
|
|
2130
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(DeletedWhen, { occurredAt: item.occurred_at }) }),
|
|
2131
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-sm", title: item.deleted_by ?? void 0, children: item.deleted_by ? /* @__PURE__ */ jsx("span", { className: "text-ui-fg-base", children: item.deleted_by }) : /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "Unknown" }) }),
|
|
2132
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(SourceBadge, { source: item.source }) }),
|
|
2133
|
-
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "red", children: "Deleted" }) }),
|
|
2134
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-3 text-right", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-0.5 whitespace-nowrap text-sm font-medium text-ui-fg-interactive", children: [
|
|
2135
|
-
"View",
|
|
2136
|
-
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
2137
|
-
] }) })
|
|
2138
|
-
]
|
|
2139
|
-
},
|
|
2140
|
-
item.id
|
|
2141
|
-
);
|
|
2142
|
-
}) })
|
|
2143
|
-
] }) });
|
|
2144
|
-
const AuditCards = ({ items, highlightId, onOpen }) => /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2 md:hidden", children: items.map((item) => {
|
|
2145
|
-
const entity = getEntityInfo(item.table_name);
|
|
2146
|
-
return /* @__PURE__ */ jsx("li", { "data-audit-row": item.id, children: /* @__PURE__ */ jsxs(
|
|
2147
|
-
"div",
|
|
2148
|
-
{
|
|
2149
|
-
role: "button",
|
|
2150
|
-
tabIndex: 0,
|
|
2151
|
-
onClick: () => onOpen(item.id),
|
|
2152
|
-
onKeyDown: (e) => {
|
|
2153
|
-
if (e.key === "Enter") onOpen(item.id);
|
|
2154
|
-
},
|
|
2155
|
-
className: clx(
|
|
2156
|
-
"flex w-full flex-col gap-2 rounded-lg border border-ui-border-base p-3 text-left outline-none hover:bg-ui-bg-subtle/60 focus-visible:bg-ui-bg-subtle",
|
|
2157
|
-
highlightId === item.id && "bg-ui-bg-highlight"
|
|
2158
|
-
),
|
|
2159
|
-
children: [
|
|
2160
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2161
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col", children: [
|
|
2162
|
-
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-ui-fg-base", children: entity.label }),
|
|
2163
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-muted", children: entity.category.label })
|
|
2164
|
-
] }),
|
|
2165
|
-
/* @__PURE__ */ jsx(DeletedWhen, { occurredAt: item.occurred_at })
|
|
2166
|
-
] }),
|
|
2167
|
-
/* @__PURE__ */ jsx(CopyableId, { value: item.record_id }),
|
|
2168
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2169
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2170
|
-
/* @__PURE__ */ jsx(SourceBadge, { source: item.source }),
|
|
2171
|
-
item.deleted_by ? /* @__PURE__ */ jsxs("span", { className: "truncate text-xs text-ui-fg-subtle", children: [
|
|
2172
|
-
"by ",
|
|
2173
|
-
item.deleted_by
|
|
2174
|
-
] }) : null
|
|
2175
|
-
] }),
|
|
2176
|
-
/* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center whitespace-nowrap text-sm font-medium text-ui-fg-interactive", children: [
|
|
2177
|
-
"View details",
|
|
2178
|
-
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
2179
|
-
] })
|
|
2180
|
-
] })
|
|
2181
|
-
]
|
|
2182
|
-
}
|
|
2183
|
-
) }, item.id);
|
|
2184
|
-
}) });
|
|
2185
|
-
const ListSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0 overflow-hidden rounded-xl border border-ui-border-base", "aria-busy": "true", children: [
|
|
2186
|
-
/* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle px-3 py-3", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-40" }) }),
|
|
2187
|
-
Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 border-t border-ui-border-subtle px-3 py-4", children: [
|
|
2188
|
-
/* @__PURE__ */ jsxs("div", { className: "flex w-[22%] flex-col gap-1.5", children: [
|
|
2189
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-28" }),
|
|
2190
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-16" })
|
|
2191
|
-
] }),
|
|
2192
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-[20%]" }),
|
|
2193
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-[10%]" }),
|
|
2194
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "hidden h-3.5 w-[10%] md:block" }),
|
|
2195
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "hidden h-5 w-14 rounded-full md:block" })
|
|
2196
|
-
] }, i))
|
|
2197
|
-
] });
|
|
2198
|
-
const EmptyState = ({ title, body, action }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 rounded-lg border border-dashed border-ui-border-strong px-6 py-12 text-center", children: [
|
|
2199
|
-
/* @__PURE__ */ jsx(MagnifierAlert, { className: "text-ui-fg-muted" }),
|
|
2200
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", children: title }),
|
|
2201
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "max-w-md text-ui-fg-subtle", children: body }),
|
|
2202
|
-
action ? /* @__PURE__ */ jsx("div", { className: "mt-2", children: action }) : null
|
|
2203
|
-
] });
|
|
2204
|
-
const ErrorState = ({ onRetry, detail }) => /* @__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: [
|
|
2205
|
-
/* @__PURE__ */ jsx(ExclamationCircle, { className: "text-ui-fg-error" }),
|
|
2206
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", children: "Unable to load deleted records" }),
|
|
2207
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "max-w-md text-ui-fg-subtle", children: "We couldn’t retrieve the audit records right now. Check your connection and try again." }),
|
|
2208
|
-
/* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: detail }),
|
|
2209
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", className: "mt-2", onClick: onRetry, children: "Try again" })
|
|
2210
|
-
] });
|
|
2211
|
-
const config$9 = defineRouteConfig({
|
|
2212
|
-
label: "Deleted Records",
|
|
2213
|
-
icon: Trash
|
|
2214
|
-
});
|
|
2215
926
|
const useDebounce$3 = (value, delay) => {
|
|
2216
927
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2217
928
|
useEffect(() => {
|
|
@@ -2408,7 +1119,7 @@ const PaymentsPage = () => {
|
|
|
2408
1119
|
) }) : null
|
|
2409
1120
|
] }) });
|
|
2410
1121
|
};
|
|
2411
|
-
const config$
|
|
1122
|
+
const config$9 = defineRouteConfig({
|
|
2412
1123
|
label: "Payments",
|
|
2413
1124
|
icon: CreditCard
|
|
2414
1125
|
});
|
|
@@ -2633,320 +1344,1609 @@ const RefundsPage = () => {
|
|
|
2633
1344
|
/* @__PURE__ */ jsx("th", { className: "w-[11%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
2634
1345
|
/* @__PURE__ */ jsx("th", { className: "w-[8%] min-w-0 px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
2635
1346
|
] }) }),
|
|
2636
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
|
|
1347
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((r) => /* @__PURE__ */ jsxs(
|
|
1348
|
+
"tr",
|
|
1349
|
+
{
|
|
1350
|
+
className: "cursor-pointer hover:bg-ui-bg-subtle/60",
|
|
1351
|
+
onClick: () => navigate(`/refunds/${r.refund_id}`),
|
|
1352
|
+
children: [
|
|
1353
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-base", title: r.refund_id, children: r.refund_id }),
|
|
1354
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-medium text-ui-fg-base", title: r.order_id ?? void 0, children: r.order_id ?? "—" }),
|
|
1355
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-subtle", title: r.payment_id, children: r.payment_id }),
|
|
1356
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
|
|
1357
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
|
|
1358
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.provider_id || void 0, children: r.provider_id || "—" }),
|
|
1359
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
|
|
1360
|
+
Badge,
|
|
1361
|
+
{
|
|
1362
|
+
size: "2xsmall",
|
|
1363
|
+
className: `uppercase ${getStatusBadgeClass$6(displayStatus(r))}`,
|
|
1364
|
+
children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
|
|
1365
|
+
}
|
|
1366
|
+
) }),
|
|
1367
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
|
|
1368
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle text-xs", children: new Date(r.created_at).toLocaleDateString("en-US", {
|
|
1369
|
+
month: "short",
|
|
1370
|
+
day: "numeric",
|
|
1371
|
+
hour: "numeric",
|
|
1372
|
+
minute: "2-digit",
|
|
1373
|
+
hour12: true
|
|
1374
|
+
}) }),
|
|
1375
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
1376
|
+
/* @__PURE__ */ jsx(
|
|
1377
|
+
Button,
|
|
1378
|
+
{
|
|
1379
|
+
variant: "transparent",
|
|
1380
|
+
size: "small",
|
|
1381
|
+
onClick: (e) => {
|
|
1382
|
+
e.stopPropagation();
|
|
1383
|
+
navigate(`/refunds/${r.refund_id}`);
|
|
1384
|
+
},
|
|
1385
|
+
children: "Details"
|
|
1386
|
+
}
|
|
1387
|
+
),
|
|
1388
|
+
r.order_id ? /* @__PURE__ */ jsx(
|
|
1389
|
+
Button,
|
|
1390
|
+
{
|
|
1391
|
+
variant: "transparent",
|
|
1392
|
+
size: "small",
|
|
1393
|
+
onClick: (e) => {
|
|
1394
|
+
e.stopPropagation();
|
|
1395
|
+
navigate(`/orders/${r.order_id}`);
|
|
1396
|
+
},
|
|
1397
|
+
children: "Order"
|
|
1398
|
+
}
|
|
1399
|
+
) : null
|
|
1400
|
+
] }) })
|
|
1401
|
+
]
|
|
1402
|
+
},
|
|
1403
|
+
r.refund_id
|
|
1404
|
+
)) })
|
|
1405
|
+
] }) }),
|
|
1406
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1407
|
+
Button,
|
|
1408
|
+
{
|
|
1409
|
+
variant: "secondary",
|
|
1410
|
+
isLoading: isFetchingMore,
|
|
1411
|
+
onClick: () => loadRefunds(offset, false),
|
|
1412
|
+
children: "Load more"
|
|
1413
|
+
}
|
|
1414
|
+
) }) : null
|
|
1415
|
+
] }) });
|
|
1416
|
+
};
|
|
1417
|
+
const config$8 = defineRouteConfig({
|
|
1418
|
+
label: "Refunds",
|
|
1419
|
+
icon: Receipt
|
|
1420
|
+
});
|
|
1421
|
+
const useDebounce$1 = (value, delay) => {
|
|
1422
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
1423
|
+
useEffect(() => {
|
|
1424
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay);
|
|
1425
|
+
return () => clearTimeout(handler);
|
|
1426
|
+
}, [value, delay]);
|
|
1427
|
+
return debouncedValue;
|
|
1428
|
+
};
|
|
1429
|
+
const getStatusBadgeClass$5 = (status) => {
|
|
1430
|
+
const statusLower = status.toLowerCase();
|
|
1431
|
+
if (statusLower === "requested") {
|
|
1432
|
+
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
1433
|
+
}
|
|
1434
|
+
if (statusLower === "received") {
|
|
1435
|
+
return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
1436
|
+
}
|
|
1437
|
+
if (statusLower === "requires_action") {
|
|
1438
|
+
return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
1439
|
+
}
|
|
1440
|
+
if (statusLower === "completed") {
|
|
1441
|
+
return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
1442
|
+
}
|
|
1443
|
+
if (statusLower === "canceled") {
|
|
1444
|
+
return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
|
|
1445
|
+
}
|
|
1446
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
1447
|
+
};
|
|
1448
|
+
const ReturnsPage = () => {
|
|
1449
|
+
const navigate = useNavigate();
|
|
1450
|
+
const [items, setItems] = useState([]);
|
|
1451
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
1452
|
+
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
1453
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
1454
|
+
const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
|
|
1455
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
1456
|
+
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
1457
|
+
const [error, setError] = useState(null);
|
|
1458
|
+
const [offset, setOffset] = useState(0);
|
|
1459
|
+
const [count, setCount] = useState(0);
|
|
1460
|
+
const limit = 50;
|
|
1461
|
+
const loadReturns = useCallback(
|
|
1462
|
+
async (nextOffset, replace = false) => {
|
|
1463
|
+
try {
|
|
1464
|
+
if (replace) {
|
|
1465
|
+
setIsLoading(true);
|
|
1466
|
+
} else {
|
|
1467
|
+
setIsFetchingMore(true);
|
|
1468
|
+
}
|
|
1469
|
+
setError(null);
|
|
1470
|
+
const params = new URLSearchParams();
|
|
1471
|
+
params.set("limit", String(limit));
|
|
1472
|
+
params.set("offset", String(nextOffset));
|
|
1473
|
+
if (statusFilter !== "all") {
|
|
1474
|
+
params.set("status", statusFilter);
|
|
1475
|
+
}
|
|
1476
|
+
if (debouncedSearchQuery.trim()) {
|
|
1477
|
+
params.set("q", debouncedSearchQuery.trim());
|
|
1478
|
+
}
|
|
1479
|
+
if (createdByFilter !== "all") {
|
|
1480
|
+
params.set("created_by", createdByFilter);
|
|
1481
|
+
}
|
|
1482
|
+
params.set("order", "created_at");
|
|
1483
|
+
const response = await fetch(
|
|
1484
|
+
`/admin/return?${params.toString()}`,
|
|
1485
|
+
{ credentials: "include" }
|
|
1486
|
+
);
|
|
1487
|
+
if (!response.ok) {
|
|
1488
|
+
const message = await response.text();
|
|
1489
|
+
throw new Error(message || "Unable to load return orders");
|
|
1490
|
+
}
|
|
1491
|
+
const payload = await response.json();
|
|
1492
|
+
setCount(payload.count ?? 0);
|
|
1493
|
+
setOffset(nextOffset + (payload.returns?.length ?? 0));
|
|
1494
|
+
setItems(
|
|
1495
|
+
(prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
|
|
1496
|
+
);
|
|
1497
|
+
} catch (loadError) {
|
|
1498
|
+
const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
|
|
1499
|
+
setError(message);
|
|
1500
|
+
} finally {
|
|
1501
|
+
setIsLoading(false);
|
|
1502
|
+
setIsFetchingMore(false);
|
|
1503
|
+
}
|
|
1504
|
+
},
|
|
1505
|
+
[statusFilter, createdByFilter, debouncedSearchQuery]
|
|
1506
|
+
);
|
|
1507
|
+
useEffect(() => {
|
|
1508
|
+
void loadReturns(0, true);
|
|
1509
|
+
}, [statusFilter, createdByFilter, debouncedSearchQuery, loadReturns]);
|
|
1510
|
+
const hasMore = useMemo(() => offset < count, [offset, count]);
|
|
1511
|
+
const availableStatuses = useMemo(() => {
|
|
1512
|
+
const statuses = /* @__PURE__ */ new Set();
|
|
1513
|
+
items.forEach((item) => statuses.add(item.status));
|
|
1514
|
+
return Array.from(statuses).sort();
|
|
1515
|
+
}, [items]);
|
|
1516
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-6", children: [
|
|
1517
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1518
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1519
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Return Orders" }),
|
|
1520
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
|
|
1521
|
+
] }),
|
|
1522
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
|
|
1523
|
+
] }),
|
|
1524
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
1525
|
+
/* @__PURE__ */ jsx(
|
|
1526
|
+
Input,
|
|
1527
|
+
{
|
|
1528
|
+
placeholder: "Search by return ID, order ID, or customer email",
|
|
1529
|
+
value: searchQuery,
|
|
1530
|
+
onChange: (event) => setSearchQuery(event.target.value),
|
|
1531
|
+
className: "md:max-w-sm"
|
|
1532
|
+
}
|
|
1533
|
+
),
|
|
1534
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
1535
|
+
/* @__PURE__ */ jsxs(
|
|
1536
|
+
"select",
|
|
1537
|
+
{
|
|
1538
|
+
value: createdByFilter,
|
|
1539
|
+
onChange: (event) => setCreatedByFilter(event.target.value),
|
|
1540
|
+
className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive md:max-w-xs",
|
|
1541
|
+
children: [
|
|
1542
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All (Created by)" }),
|
|
1543
|
+
/* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
|
|
1544
|
+
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
1545
|
+
]
|
|
1546
|
+
}
|
|
1547
|
+
),
|
|
1548
|
+
/* @__PURE__ */ jsxs(
|
|
1549
|
+
"select",
|
|
1550
|
+
{
|
|
1551
|
+
value: statusFilter,
|
|
1552
|
+
onChange: (event) => setStatusFilter(event.target.value),
|
|
1553
|
+
className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive md:max-w-xs",
|
|
1554
|
+
children: [
|
|
1555
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
|
|
1556
|
+
availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
|
|
1557
|
+
]
|
|
1558
|
+
}
|
|
1559
|
+
)
|
|
1560
|
+
] })
|
|
1561
|
+
] }),
|
|
1562
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
1563
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
1564
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1565
|
+
Button,
|
|
1566
|
+
{
|
|
1567
|
+
variant: "secondary",
|
|
1568
|
+
onClick: () => loadReturns(0, true),
|
|
1569
|
+
children: "Try again"
|
|
1570
|
+
}
|
|
1571
|
+
) })
|
|
1572
|
+
] }) : null,
|
|
1573
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading return orders..." }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
|
|
1574
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
|
|
1575
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
|
|
1576
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
|
|
1577
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1578
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
|
|
1579
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
|
|
1580
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
|
|
1581
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
1582
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
|
|
1583
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
1584
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
1585
|
+
] }) }),
|
|
1586
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((returnOrder) => /* @__PURE__ */ jsxs(
|
|
2637
1587
|
"tr",
|
|
2638
1588
|
{
|
|
2639
|
-
className: "
|
|
2640
|
-
onClick: () => navigate(`/
|
|
1589
|
+
className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
|
|
1590
|
+
onClick: () => navigate(`/returns/${returnOrder.id}`),
|
|
2641
1591
|
children: [
|
|
2642
|
-
/* @__PURE__ */ jsx("td", { className: "
|
|
2643
|
-
/* @__PURE__ */ jsx("td", { className: "
|
|
2644
|
-
/* @__PURE__ */ jsx("td", { className: "
|
|
2645
|
-
/* @__PURE__ */ jsx("td", { className: "
|
|
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(
|
|
1592
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 font-medium text-ui-fg-base", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: /* @__PURE__ */ jsx("span", { children: returnOrder.id }) }) }),
|
|
1593
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.order_id }),
|
|
1594
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: returnOrder.customer_email || returnOrder.order_email || "—" }),
|
|
1595
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
2649
1596
|
Badge,
|
|
2650
1597
|
{
|
|
2651
1598
|
size: "2xsmall",
|
|
2652
|
-
className: `uppercase ${getStatusBadgeClass$
|
|
2653
|
-
children:
|
|
1599
|
+
className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
|
|
1600
|
+
children: returnOrder.status.replace(/_/g, " ")
|
|
2654
1601
|
}
|
|
2655
1602
|
) }),
|
|
2656
|
-
/* @__PURE__ */ jsx("td", { className: "
|
|
2657
|
-
|
|
1603
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: (() => {
|
|
1604
|
+
const calc = returnOrder.refund;
|
|
1605
|
+
if (calc?.is_processed && calc.final_refund_amount != null) {
|
|
1606
|
+
return formatRefundCurrency(
|
|
1607
|
+
calc.final_refund_amount,
|
|
1608
|
+
calc.currency_code || returnOrder.currency_code
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
if (calc) {
|
|
1612
|
+
return "Pending";
|
|
1613
|
+
}
|
|
1614
|
+
if (returnOrder.refund_amount == null) {
|
|
1615
|
+
return "—";
|
|
1616
|
+
}
|
|
1617
|
+
return formatRefundCurrency(
|
|
1618
|
+
Number(returnOrder.refund_amount),
|
|
1619
|
+
returnOrder.currency_code
|
|
1620
|
+
);
|
|
1621
|
+
})() }),
|
|
1622
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(returnOrder.created_at).toLocaleDateString("en-US", {
|
|
1623
|
+
year: "numeric",
|
|
2658
1624
|
month: "short",
|
|
2659
1625
|
day: "numeric",
|
|
2660
1626
|
hour: "numeric",
|
|
2661
1627
|
minute: "2-digit",
|
|
2662
1628
|
hour12: true
|
|
2663
1629
|
}) }),
|
|
2664
|
-
/* @__PURE__ */ jsx("td", { className: "
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
1630
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
1631
|
+
Button,
|
|
1632
|
+
{
|
|
1633
|
+
variant: "transparent",
|
|
1634
|
+
size: "small",
|
|
1635
|
+
onClick: (e) => {
|
|
1636
|
+
e.stopPropagation();
|
|
1637
|
+
navigate(`/app/orders/${returnOrder.order_id}`);
|
|
1638
|
+
},
|
|
1639
|
+
children: "Go to order"
|
|
1640
|
+
}
|
|
1641
|
+
) })
|
|
1642
|
+
]
|
|
1643
|
+
},
|
|
1644
|
+
returnOrder.id
|
|
1645
|
+
)) })
|
|
1646
|
+
] }) }),
|
|
1647
|
+
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
1648
|
+
Button,
|
|
1649
|
+
{
|
|
1650
|
+
variant: "secondary",
|
|
1651
|
+
isLoading: isFetchingMore,
|
|
1652
|
+
onClick: () => loadReturns(offset, false),
|
|
1653
|
+
children: "Load more"
|
|
1654
|
+
}
|
|
1655
|
+
) }) : null
|
|
1656
|
+
] }) });
|
|
1657
|
+
};
|
|
1658
|
+
const config$7 = defineRouteConfig({
|
|
1659
|
+
label: "Return Orders",
|
|
1660
|
+
icon: ArrowPath
|
|
1661
|
+
});
|
|
1662
|
+
const AUDITED_TABLE_NAMES = [
|
|
1663
|
+
"account_deletion_request",
|
|
1664
|
+
"account_holder",
|
|
1665
|
+
"api_key",
|
|
1666
|
+
"application_method_buy_rules",
|
|
1667
|
+
"application_method_target_rules",
|
|
1668
|
+
"auth_identity",
|
|
1669
|
+
"auth_mfa_factor",
|
|
1670
|
+
"auth_mfa_recovery_code",
|
|
1671
|
+
"auth_password_reset_token",
|
|
1672
|
+
"auth_verification",
|
|
1673
|
+
"cancel_order_reason_mapping",
|
|
1674
|
+
"capture",
|
|
1675
|
+
"cart",
|
|
1676
|
+
"cart_address",
|
|
1677
|
+
"cart_line_item",
|
|
1678
|
+
"cart_line_item_adjustment",
|
|
1679
|
+
"cart_line_item_tax_line",
|
|
1680
|
+
"cart_payment_collection",
|
|
1681
|
+
"cart_promotion",
|
|
1682
|
+
"cart_shipping_method",
|
|
1683
|
+
"cart_shipping_method_adjustment",
|
|
1684
|
+
"cart_shipping_method_tax_line",
|
|
1685
|
+
"contact_email_subscription",
|
|
1686
|
+
"contact_request",
|
|
1687
|
+
"contact_request_comment",
|
|
1688
|
+
"credit_line",
|
|
1689
|
+
"currency",
|
|
1690
|
+
"customer",
|
|
1691
|
+
"customer_account_holder",
|
|
1692
|
+
"customer_address",
|
|
1693
|
+
"customer_group",
|
|
1694
|
+
"customer_group_customer",
|
|
1695
|
+
"dynamic_config_value",
|
|
1696
|
+
"fulfillment",
|
|
1697
|
+
"fulfillment_address",
|
|
1698
|
+
"fulfillment_item",
|
|
1699
|
+
"fulfillment_label",
|
|
1700
|
+
"fulfillment_provider",
|
|
1701
|
+
"fulfillment_set",
|
|
1702
|
+
"geo_zone",
|
|
1703
|
+
"image",
|
|
1704
|
+
"inventory_count_item",
|
|
1705
|
+
"inventory_count_session",
|
|
1706
|
+
"inventory_item",
|
|
1707
|
+
"inventory_level",
|
|
1708
|
+
"inventory_movement",
|
|
1709
|
+
"inventory_purchase",
|
|
1710
|
+
"inventory_purchase_attachment",
|
|
1711
|
+
"inventory_purchase_audit_event",
|
|
1712
|
+
"inventory_purchase_batch",
|
|
1713
|
+
"inventory_purchase_line_item",
|
|
1714
|
+
"invite",
|
|
1715
|
+
"invite_rbac_role",
|
|
1716
|
+
"invoice",
|
|
1717
|
+
"invoice_sequence",
|
|
1718
|
+
"layout_configuration",
|
|
1719
|
+
"link_module_migrations",
|
|
1720
|
+
"location_fulfillment_provider",
|
|
1721
|
+
"location_fulfillment_set",
|
|
1722
|
+
"loyalty_gift_card",
|
|
1723
|
+
"mikro_orm_migrations",
|
|
1724
|
+
"notification",
|
|
1725
|
+
"notification_provider",
|
|
1726
|
+
"notification_tokens",
|
|
1727
|
+
"order",
|
|
1728
|
+
"order_address",
|
|
1729
|
+
"order_cart",
|
|
1730
|
+
"order_change",
|
|
1731
|
+
"order_change_action",
|
|
1732
|
+
"order_claim",
|
|
1733
|
+
"order_claim_item",
|
|
1734
|
+
"order_claim_item_image",
|
|
1735
|
+
"order_credit_line",
|
|
1736
|
+
"order_exchange",
|
|
1737
|
+
"order_exchange_item",
|
|
1738
|
+
"order_fulfillment",
|
|
1739
|
+
"order_item",
|
|
1740
|
+
"order_line_item",
|
|
1741
|
+
"order_line_item_adjustment",
|
|
1742
|
+
"order_line_item_tax_line",
|
|
1743
|
+
"order_payment_collection",
|
|
1744
|
+
"order_promotion",
|
|
1745
|
+
"order_shipping",
|
|
1746
|
+
"order_shipping_method",
|
|
1747
|
+
"order_shipping_method_adjustment",
|
|
1748
|
+
"order_shipping_method_tax_line",
|
|
1749
|
+
"order_summary",
|
|
1750
|
+
"order_transaction",
|
|
1751
|
+
"otp_verification",
|
|
1752
|
+
"payment",
|
|
1753
|
+
"payment_collection",
|
|
1754
|
+
"payment_collection_payment_providers",
|
|
1755
|
+
"payment_detail",
|
|
1756
|
+
"payment_provider",
|
|
1757
|
+
"payment_session",
|
|
1758
|
+
"payout_request",
|
|
1759
|
+
"price",
|
|
1760
|
+
"price_list",
|
|
1761
|
+
"price_list_rule",
|
|
1762
|
+
"price_preference",
|
|
1763
|
+
"price_rule",
|
|
1764
|
+
"price_set",
|
|
1765
|
+
"product",
|
|
1766
|
+
"product_category",
|
|
1767
|
+
"product_category_product",
|
|
1768
|
+
"product_collection",
|
|
1769
|
+
"product_display_priority",
|
|
1770
|
+
"product_option",
|
|
1771
|
+
"product_option_value",
|
|
1772
|
+
"product_product_option",
|
|
1773
|
+
"product_product_option_value",
|
|
1774
|
+
"product_sales_channel",
|
|
1775
|
+
"product_shipping_profile",
|
|
1776
|
+
"product_tag",
|
|
1777
|
+
"product_tags",
|
|
1778
|
+
"product_type",
|
|
1779
|
+
"product_variant",
|
|
1780
|
+
"product_variant_inventory_item",
|
|
1781
|
+
"product_variant_option",
|
|
1782
|
+
"product_variant_price_set",
|
|
1783
|
+
"product_variant_product_image",
|
|
1784
|
+
"product_view",
|
|
1785
|
+
"promotion",
|
|
1786
|
+
"promotion_application_method",
|
|
1787
|
+
"promotion_campaign",
|
|
1788
|
+
"promotion_campaign_budget",
|
|
1789
|
+
"promotion_campaign_budget_usage",
|
|
1790
|
+
"promotion_promotion_rule",
|
|
1791
|
+
"promotion_rule",
|
|
1792
|
+
"promotion_rule_value",
|
|
1793
|
+
"property_label",
|
|
1794
|
+
"provider_identity",
|
|
1795
|
+
"publishable_api_key_sales_channel",
|
|
1796
|
+
"purchase_supplier",
|
|
1797
|
+
"referral_link",
|
|
1798
|
+
"referral_reward",
|
|
1799
|
+
"refund",
|
|
1800
|
+
"refund_payment_mapping",
|
|
1801
|
+
"refund_reason",
|
|
1802
|
+
"region",
|
|
1803
|
+
"region_country",
|
|
1804
|
+
"region_payment_provider",
|
|
1805
|
+
"reservation_item",
|
|
1806
|
+
"return",
|
|
1807
|
+
"return_fulfillment",
|
|
1808
|
+
"return_item",
|
|
1809
|
+
"return_reason",
|
|
1810
|
+
"review",
|
|
1811
|
+
"sales_channel",
|
|
1812
|
+
"sales_channel_stock_location",
|
|
1813
|
+
"script_migrations",
|
|
1814
|
+
"search_index",
|
|
1815
|
+
"search_index_sync",
|
|
1816
|
+
"search_index_version",
|
|
1817
|
+
"search_postgres_index",
|
|
1818
|
+
"service_zone",
|
|
1819
|
+
"shipment_tracking_event",
|
|
1820
|
+
"shipping_option",
|
|
1821
|
+
"shipping_option_price_set",
|
|
1822
|
+
"shipping_option_rule",
|
|
1823
|
+
"shipping_option_type",
|
|
1824
|
+
"shipping_profile",
|
|
1825
|
+
"skip_merge_cart",
|
|
1826
|
+
"stock_location",
|
|
1827
|
+
"stock_location_address",
|
|
1828
|
+
"store",
|
|
1829
|
+
"store_credit_account",
|
|
1830
|
+
"store_credit_account_transaction",
|
|
1831
|
+
"store_currency",
|
|
1832
|
+
"store_locale",
|
|
1833
|
+
"tax_provider",
|
|
1834
|
+
"tax_rate",
|
|
1835
|
+
"tax_rate_rule",
|
|
1836
|
+
"tax_region",
|
|
1837
|
+
"telegram_config",
|
|
1838
|
+
"telegram_notification_log",
|
|
1839
|
+
"user",
|
|
1840
|
+
"user_preference",
|
|
1841
|
+
"user_rbac_role",
|
|
1842
|
+
"view_configuration",
|
|
1843
|
+
"wallet_account",
|
|
1844
|
+
"wallet_credit_lot",
|
|
1845
|
+
"wallet_gift_card",
|
|
1846
|
+
"wallet_hold",
|
|
1847
|
+
"wallet_ledger_entry",
|
|
1848
|
+
"wallet_rate_limit",
|
|
1849
|
+
"wallet_refund_intent",
|
|
1850
|
+
"wallet_top_up_request",
|
|
1851
|
+
"wishlist",
|
|
1852
|
+
"workflow_execution"
|
|
1853
|
+
];
|
|
1854
|
+
const ENTITY_CATEGORIES = [
|
|
1855
|
+
{ id: "orders", label: "Orders", description: "Orders, items, returns, exchanges and claims" },
|
|
1856
|
+
{ id: "carts", label: "Carts", description: "Shopping carts and checkout data" },
|
|
1857
|
+
{ id: "customers", label: "Customers", description: "Customers, addresses and groups" },
|
|
1858
|
+
{ id: "catalog", label: "Catalog", description: "Products, variants, categories and collections" },
|
|
1859
|
+
{ id: "pricing", label: "Pricing & Promotions", description: "Prices, price lists and promotions" },
|
|
1860
|
+
{ id: "payments", label: "Payments & Refunds", description: "Payments, sessions, captures and refunds" },
|
|
1861
|
+
{ id: "fulfillment", label: "Fulfillment & Shipping", description: "Fulfillments, shipping options and tracking" },
|
|
1862
|
+
{ id: "inventory", label: "Inventory & Purchasing", description: "Stock, locations, reservations and purchases" },
|
|
1863
|
+
{ id: "wallet", label: "Wallet & Credits", description: "Wallets, store credit and gift cards" },
|
|
1864
|
+
{ id: "access", label: "Users & Access", description: "Admin users, logins, roles and API keys" },
|
|
1865
|
+
{ id: "store", label: "Store & Regions", description: "Store, regions, currencies, taxes and sales channels" },
|
|
1866
|
+
{ id: "engagement", label: "Engagement", description: "Reviews, wishlists, referrals and contact requests" },
|
|
1867
|
+
{ id: "notifications", label: "Notifications", description: "Notifications and messaging" },
|
|
1868
|
+
{ id: "system", label: "System & Configuration", description: "Settings, search, workflows and migrations" }
|
|
1869
|
+
];
|
|
1870
|
+
const ENTITY_DEFINITIONS = {
|
|
1871
|
+
// Orders
|
|
1872
|
+
order: { label: "Order", category: "orders" },
|
|
1873
|
+
order_address: { label: "Order Address", category: "orders" },
|
|
1874
|
+
order_cart: { label: "Order–Cart Link", category: "orders" },
|
|
1875
|
+
order_change: { label: "Order Change", category: "orders" },
|
|
1876
|
+
order_change_action: { label: "Order Change Action", category: "orders" },
|
|
1877
|
+
order_claim: { label: "Claim", category: "orders" },
|
|
1878
|
+
order_claim_item: { label: "Claim Item", category: "orders" },
|
|
1879
|
+
order_claim_item_image: { label: "Claim Item Image", category: "orders" },
|
|
1880
|
+
order_credit_line: { label: "Order Credit Line", category: "orders" },
|
|
1881
|
+
order_exchange: { label: "Exchange", category: "orders" },
|
|
1882
|
+
order_exchange_item: { label: "Exchange Item", category: "orders" },
|
|
1883
|
+
order_fulfillment: { label: "Order–Fulfillment Link", category: "orders" },
|
|
1884
|
+
order_item: { label: "Order Item Quantity", category: "orders" },
|
|
1885
|
+
order_line_item: { label: "Order Item", category: "orders" },
|
|
1886
|
+
order_line_item_adjustment: { label: "Order Item Discount", category: "orders" },
|
|
1887
|
+
order_line_item_tax_line: { label: "Order Item Tax", category: "orders" },
|
|
1888
|
+
order_payment_collection: { label: "Order–Payment Link", category: "orders" },
|
|
1889
|
+
order_promotion: { label: "Order Promotion", category: "orders" },
|
|
1890
|
+
order_shipping: { label: "Order Shipping", category: "orders" },
|
|
1891
|
+
order_shipping_method: { label: "Order Shipping Method", category: "orders" },
|
|
1892
|
+
order_shipping_method_adjustment: { label: "Order Shipping Discount", category: "orders" },
|
|
1893
|
+
order_shipping_method_tax_line: { label: "Order Shipping Tax", category: "orders" },
|
|
1894
|
+
order_summary: { label: "Order Summary", category: "orders" },
|
|
1895
|
+
order_transaction: { label: "Order Transaction", category: "orders" },
|
|
1896
|
+
return: { label: "Return", category: "orders" },
|
|
1897
|
+
return_fulfillment: { label: "Return–Fulfillment Link", category: "orders" },
|
|
1898
|
+
return_item: { label: "Return Item", category: "orders" },
|
|
1899
|
+
return_reason: { label: "Return Reason", category: "orders" },
|
|
1900
|
+
cancel_order_reason_mapping: { label: "Order Cancellation Reason", category: "orders" },
|
|
1901
|
+
credit_line: { label: "Credit Line", category: "orders" },
|
|
1902
|
+
invoice: { label: "Invoice", category: "orders" },
|
|
1903
|
+
invoice_sequence: { label: "Invoice Number Sequence", category: "orders" },
|
|
1904
|
+
// Carts
|
|
1905
|
+
cart: { label: "Cart", category: "carts" },
|
|
1906
|
+
cart_address: { label: "Cart Address", category: "carts" },
|
|
1907
|
+
cart_line_item: { label: "Cart Item", category: "carts" },
|
|
1908
|
+
cart_line_item_adjustment: { label: "Cart Item Discount", category: "carts" },
|
|
1909
|
+
cart_line_item_tax_line: { label: "Cart Item Tax", category: "carts" },
|
|
1910
|
+
cart_payment_collection: { label: "Cart–Payment Link", category: "carts" },
|
|
1911
|
+
cart_promotion: { label: "Cart Promotion", category: "carts" },
|
|
1912
|
+
cart_shipping_method: { label: "Cart Shipping Method", category: "carts" },
|
|
1913
|
+
cart_shipping_method_adjustment: { label: "Cart Shipping Discount", category: "carts" },
|
|
1914
|
+
cart_shipping_method_tax_line: { label: "Cart Shipping Tax", category: "carts" },
|
|
1915
|
+
skip_merge_cart: { label: "Cart Merge Exclusion", category: "carts" },
|
|
1916
|
+
// Customers
|
|
1917
|
+
customer: { label: "Customer", category: "customers" },
|
|
1918
|
+
customer_address: { label: "Customer Address", category: "customers" },
|
|
1919
|
+
customer_group: { label: "Customer Group", category: "customers" },
|
|
1920
|
+
customer_group_customer: { label: "Customer Group Member", category: "customers" },
|
|
1921
|
+
customer_account_holder: { label: "Customer–Account Holder Link", category: "customers" },
|
|
1922
|
+
account_holder: { label: "Payment Account Holder", category: "customers" },
|
|
1923
|
+
account_deletion_request: { label: "Account Deletion Request", category: "customers" },
|
|
1924
|
+
payment_detail: { label: "Customer Refund Method", category: "customers" },
|
|
1925
|
+
otp_verification: { label: "OTP Verification", category: "customers" },
|
|
1926
|
+
// Catalog
|
|
1927
|
+
product: { label: "Product", category: "catalog" },
|
|
1928
|
+
product_variant: { label: "Product Variant", category: "catalog" },
|
|
1929
|
+
product_category: { label: "Product Category", category: "catalog" },
|
|
1930
|
+
product_category_product: { label: "Product–Category Link", category: "catalog" },
|
|
1931
|
+
product_collection: { label: "Collection", category: "catalog" },
|
|
1932
|
+
product_option: { label: "Product Option", category: "catalog" },
|
|
1933
|
+
product_option_value: { label: "Product Option Value", category: "catalog" },
|
|
1934
|
+
product_product_option: { label: "Product–Option Link", category: "catalog" },
|
|
1935
|
+
product_product_option_value: { label: "Product–Option Value Link", category: "catalog" },
|
|
1936
|
+
product_tag: { label: "Product Tag", category: "catalog" },
|
|
1937
|
+
product_tags: { label: "Product–Tag Link", category: "catalog" },
|
|
1938
|
+
product_type: { label: "Product Type", category: "catalog" },
|
|
1939
|
+
product_sales_channel: { label: "Product–Sales Channel Link", category: "catalog" },
|
|
1940
|
+
product_shipping_profile: { label: "Product–Shipping Profile Link", category: "catalog" },
|
|
1941
|
+
product_variant_inventory_item: { label: "Variant–Inventory Link", category: "catalog" },
|
|
1942
|
+
product_variant_option: { label: "Variant Option", category: "catalog" },
|
|
1943
|
+
product_variant_price_set: { label: "Variant–Price Link", category: "catalog" },
|
|
1944
|
+
product_variant_product_image: { label: "Variant Image", category: "catalog" },
|
|
1945
|
+
product_display_priority: { label: "Product Display Priority", category: "catalog" },
|
|
1946
|
+
product_view: { label: "Product View", category: "catalog" },
|
|
1947
|
+
image: { label: "Product Image", category: "catalog" },
|
|
1948
|
+
property_label: { label: "Property Label", category: "catalog" },
|
|
1949
|
+
// Pricing & promotions
|
|
1950
|
+
price: { label: "Price", category: "pricing" },
|
|
1951
|
+
price_list: { label: "Price List", category: "pricing" },
|
|
1952
|
+
price_list_rule: { label: "Price List Rule", category: "pricing" },
|
|
1953
|
+
price_preference: { label: "Price Preference", category: "pricing" },
|
|
1954
|
+
price_rule: { label: "Price Rule", category: "pricing" },
|
|
1955
|
+
price_set: { label: "Price Set", category: "pricing" },
|
|
1956
|
+
promotion: { label: "Promotion", category: "pricing" },
|
|
1957
|
+
promotion_application_method: { label: "Promotion Application Method", category: "pricing" },
|
|
1958
|
+
promotion_campaign: { label: "Campaign", category: "pricing" },
|
|
1959
|
+
promotion_campaign_budget: { label: "Campaign Budget", category: "pricing" },
|
|
1960
|
+
promotion_campaign_budget_usage: { label: "Campaign Budget Usage", category: "pricing" },
|
|
1961
|
+
promotion_promotion_rule: { label: "Promotion–Rule Link", category: "pricing" },
|
|
1962
|
+
promotion_rule: { label: "Promotion Rule", category: "pricing" },
|
|
1963
|
+
promotion_rule_value: { label: "Promotion Rule Value", category: "pricing" },
|
|
1964
|
+
application_method_buy_rules: { label: "Promotion Buy Rule", category: "pricing" },
|
|
1965
|
+
application_method_target_rules: { label: "Promotion Target Rule", category: "pricing" },
|
|
1966
|
+
// Payments
|
|
1967
|
+
payment: { label: "Payment", category: "payments" },
|
|
1968
|
+
payment_collection: { label: "Payment Collection", category: "payments" },
|
|
1969
|
+
payment_collection_payment_providers: { label: "Payment Collection–Provider Link", category: "payments" },
|
|
1970
|
+
payment_provider: { label: "Payment Provider", category: "payments" },
|
|
1971
|
+
payment_session: { label: "Payment Session", category: "payments" },
|
|
1972
|
+
capture: { label: "Payment Capture", category: "payments" },
|
|
1973
|
+
refund: { label: "Refund", category: "payments" },
|
|
1974
|
+
refund_reason: { label: "Refund Reason", category: "payments" },
|
|
1975
|
+
refund_payment_mapping: { label: "Return Refund Mapping", category: "payments" },
|
|
1976
|
+
payout_request: { label: "Payout Request", category: "payments" },
|
|
1977
|
+
// Fulfillment
|
|
1978
|
+
fulfillment: { label: "Fulfillment", category: "fulfillment" },
|
|
1979
|
+
fulfillment_address: { label: "Fulfillment Address", category: "fulfillment" },
|
|
1980
|
+
fulfillment_item: { label: "Fulfillment Item", category: "fulfillment" },
|
|
1981
|
+
fulfillment_label: { label: "Shipping Label", category: "fulfillment" },
|
|
1982
|
+
fulfillment_provider: { label: "Fulfillment Provider", category: "fulfillment" },
|
|
1983
|
+
fulfillment_set: { label: "Fulfillment Set", category: "fulfillment" },
|
|
1984
|
+
geo_zone: { label: "Geo Zone", category: "fulfillment" },
|
|
1985
|
+
service_zone: { label: "Service Zone", category: "fulfillment" },
|
|
1986
|
+
shipping_option: { label: "Shipping Option", category: "fulfillment" },
|
|
1987
|
+
shipping_option_price_set: { label: "Shipping Option–Price Link", category: "fulfillment" },
|
|
1988
|
+
shipping_option_rule: { label: "Shipping Option Rule", category: "fulfillment" },
|
|
1989
|
+
shipping_option_type: { label: "Shipping Option Type", category: "fulfillment" },
|
|
1990
|
+
shipping_profile: { label: "Shipping Profile", category: "fulfillment" },
|
|
1991
|
+
shipment_tracking_event: { label: "Shipment Tracking Event", category: "fulfillment" },
|
|
1992
|
+
location_fulfillment_provider: { label: "Location–Fulfillment Provider Link", category: "fulfillment" },
|
|
1993
|
+
location_fulfillment_set: { label: "Location–Fulfillment Set Link", category: "fulfillment" },
|
|
1994
|
+
// Inventory
|
|
1995
|
+
inventory_item: { label: "Inventory Item", category: "inventory" },
|
|
1996
|
+
inventory_level: { label: "Inventory Level", category: "inventory" },
|
|
1997
|
+
inventory_movement: { label: "Inventory Movement", category: "inventory" },
|
|
1998
|
+
inventory_count_item: { label: "Stock Count Item", category: "inventory" },
|
|
1999
|
+
inventory_count_session: { label: "Stock Count Session", category: "inventory" },
|
|
2000
|
+
inventory_purchase: { label: "Purchase", category: "inventory" },
|
|
2001
|
+
inventory_purchase_attachment: { label: "Purchase Attachment", category: "inventory" },
|
|
2002
|
+
inventory_purchase_audit_event: { label: "Purchase Audit Event", category: "inventory" },
|
|
2003
|
+
inventory_purchase_batch: { label: "Purchase Batch", category: "inventory" },
|
|
2004
|
+
inventory_purchase_line_item: { label: "Purchase Item", category: "inventory" },
|
|
2005
|
+
purchase_supplier: { label: "Supplier", category: "inventory" },
|
|
2006
|
+
reservation_item: { label: "Stock Reservation", category: "inventory" },
|
|
2007
|
+
stock_location: { label: "Stock Location", category: "inventory" },
|
|
2008
|
+
stock_location_address: { label: "Stock Location Address", category: "inventory" },
|
|
2009
|
+
sales_channel_stock_location: { label: "Sales Channel–Location Link", category: "inventory" },
|
|
2010
|
+
// Wallet
|
|
2011
|
+
wallet_account: { label: "Wallet Account", category: "wallet" },
|
|
2012
|
+
wallet_credit_lot: { label: "Wallet Credit Lot", category: "wallet" },
|
|
2013
|
+
wallet_gift_card: { label: "Wallet Gift Card", category: "wallet" },
|
|
2014
|
+
wallet_hold: { label: "Wallet Hold", category: "wallet" },
|
|
2015
|
+
wallet_ledger_entry: { label: "Wallet Ledger Entry", category: "wallet" },
|
|
2016
|
+
wallet_rate_limit: { label: "Wallet Rate Limit", category: "wallet" },
|
|
2017
|
+
wallet_refund_intent: { label: "Wallet Refund", category: "wallet" },
|
|
2018
|
+
wallet_top_up_request: { label: "Wallet Top-up Request", category: "wallet" },
|
|
2019
|
+
store_credit_account: { label: "Store Credit Account", category: "wallet" },
|
|
2020
|
+
store_credit_account_transaction: { label: "Store Credit Transaction", category: "wallet" },
|
|
2021
|
+
loyalty_gift_card: { label: "Loyalty Gift Card", category: "wallet" },
|
|
2022
|
+
// Users & access
|
|
2023
|
+
user: { label: "Admin User", category: "access" },
|
|
2024
|
+
user_preference: { label: "User Preference", category: "access" },
|
|
2025
|
+
user_rbac_role: { label: "User Role", category: "access" },
|
|
2026
|
+
invite: { label: "Admin Invite", category: "access" },
|
|
2027
|
+
invite_rbac_role: { label: "Invite Role", category: "access" },
|
|
2028
|
+
api_key: { label: "API Key", category: "access" },
|
|
2029
|
+
publishable_api_key_sales_channel: { label: "API Key–Sales Channel Link", category: "access" },
|
|
2030
|
+
auth_identity: { label: "Login Identity", category: "access" },
|
|
2031
|
+
auth_mfa_factor: { label: "MFA Factor", category: "access" },
|
|
2032
|
+
auth_mfa_recovery_code: { label: "MFA Recovery Code", category: "access" },
|
|
2033
|
+
auth_password_reset_token: { label: "Password Reset Token", category: "access" },
|
|
2034
|
+
auth_verification: { label: "Auth Verification", category: "access" },
|
|
2035
|
+
provider_identity: { label: "Login Provider Identity", category: "access" },
|
|
2036
|
+
// Store & regions
|
|
2037
|
+
store: { label: "Store", category: "store" },
|
|
2038
|
+
store_currency: { label: "Store Currency", category: "store" },
|
|
2039
|
+
store_locale: { label: "Store Locale", category: "store" },
|
|
2040
|
+
currency: { label: "Currency", category: "store" },
|
|
2041
|
+
region: { label: "Region", category: "store" },
|
|
2042
|
+
region_country: { label: "Region Country", category: "store" },
|
|
2043
|
+
region_payment_provider: { label: "Region–Payment Provider Link", category: "store" },
|
|
2044
|
+
sales_channel: { label: "Sales Channel", category: "store" },
|
|
2045
|
+
tax_provider: { label: "Tax Provider", category: "store" },
|
|
2046
|
+
tax_rate: { label: "Tax Rate", category: "store" },
|
|
2047
|
+
tax_rate_rule: { label: "Tax Rate Rule", category: "store" },
|
|
2048
|
+
tax_region: { label: "Tax Region", category: "store" },
|
|
2049
|
+
// Engagement
|
|
2050
|
+
review: { label: "Review", category: "engagement" },
|
|
2051
|
+
wishlist: { label: "Wishlist", category: "engagement" },
|
|
2052
|
+
referral_link: { label: "Referral Link", category: "engagement" },
|
|
2053
|
+
referral_reward: { label: "Referral Reward", category: "engagement" },
|
|
2054
|
+
contact_request: { label: "Contact Request", category: "engagement" },
|
|
2055
|
+
contact_request_comment: { label: "Contact Request Comment", category: "engagement" },
|
|
2056
|
+
contact_email_subscription: { label: "Email Subscription", category: "engagement" },
|
|
2057
|
+
// Notifications
|
|
2058
|
+
notification: { label: "Notification", category: "notifications" },
|
|
2059
|
+
notification_provider: { label: "Notification Provider", category: "notifications" },
|
|
2060
|
+
notification_tokens: { label: "Push Notification Token", category: "notifications" },
|
|
2061
|
+
telegram_config: { label: "Telegram Settings", category: "notifications" },
|
|
2062
|
+
telegram_notification_log: { label: "Telegram Notification Log", category: "notifications" },
|
|
2063
|
+
// System
|
|
2064
|
+
dynamic_config_value: { label: "Plugin Setting", category: "system" },
|
|
2065
|
+
layout_configuration: { label: "Layout Configuration", category: "system" },
|
|
2066
|
+
view_configuration: { label: "View Configuration", category: "system" },
|
|
2067
|
+
workflow_execution: { label: "Workflow Execution", category: "system" },
|
|
2068
|
+
search_index: { label: "Search Index", category: "system" },
|
|
2069
|
+
search_index_sync: { label: "Search Index Sync", category: "system" },
|
|
2070
|
+
search_index_version: { label: "Search Index Version", category: "system" },
|
|
2071
|
+
search_postgres_index: { label: "Search Index Entry", category: "system" },
|
|
2072
|
+
link_module_migrations: { label: "Link Migration Record", category: "system" },
|
|
2073
|
+
mikro_orm_migrations: { label: "Database Migration Record", category: "system" },
|
|
2074
|
+
script_migrations: { label: "Script Migration Record", category: "system" }
|
|
2075
|
+
};
|
|
2076
|
+
const CATEGORY_BY_ID = new Map(ENTITY_CATEGORIES.map((c) => [c.id, c]));
|
|
2077
|
+
const SYSTEM_CATEGORY = CATEGORY_BY_ID.get("system");
|
|
2078
|
+
function humanizeTableName(tableName) {
|
|
2079
|
+
return tableName.split("_").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
2080
|
+
}
|
|
2081
|
+
function getEntityInfo(tableName) {
|
|
2082
|
+
const def = ENTITY_DEFINITIONS[tableName];
|
|
2083
|
+
return {
|
|
2084
|
+
tableName,
|
|
2085
|
+
label: def?.label ?? humanizeTableName(tableName),
|
|
2086
|
+
category: def && CATEGORY_BY_ID.get(def.category) || SYSTEM_CATEGORY
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
function getEntitiesByCategory() {
|
|
2090
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2091
|
+
for (const table of AUDITED_TABLE_NAMES) {
|
|
2092
|
+
const info = getEntityInfo(table);
|
|
2093
|
+
const list = groups.get(info.category.id) ?? [];
|
|
2094
|
+
list.push(info);
|
|
2095
|
+
groups.set(info.category.id, list);
|
|
2096
|
+
}
|
|
2097
|
+
return ENTITY_CATEGORIES.filter((category) => groups.has(category.id)).map((category) => ({
|
|
2098
|
+
category,
|
|
2099
|
+
entities: (groups.get(category.id) ?? []).sort((a, b) => a.label.localeCompare(b.label))
|
|
2100
|
+
}));
|
|
2101
|
+
}
|
|
2102
|
+
function getCategory(id) {
|
|
2103
|
+
return CATEGORY_BY_ID.get(id);
|
|
2104
|
+
}
|
|
2105
|
+
function getTablesForCategory(id) {
|
|
2106
|
+
return AUDITED_TABLE_NAMES.filter((table) => getEntityInfo(table).category.id === id);
|
|
2107
|
+
}
|
|
2108
|
+
const GROUPS = getEntitiesByCategory();
|
|
2109
|
+
function triggerLabel(entity, category) {
|
|
2110
|
+
if (entity) return getEntityInfo(entity).label;
|
|
2111
|
+
if (category) return `All ${getCategory(category)?.label ?? category}`;
|
|
2112
|
+
return "All entities";
|
|
2113
|
+
}
|
|
2114
|
+
const EntityPicker = ({ entity, category, onChange }) => {
|
|
2115
|
+
const [open, setOpen] = useState(false);
|
|
2116
|
+
const [search, setSearch] = useState("");
|
|
2117
|
+
const searchRef = useRef(null);
|
|
2118
|
+
const filteredGroups = useMemo(() => {
|
|
2119
|
+
const term = search.trim().toLowerCase();
|
|
2120
|
+
if (!term) return GROUPS;
|
|
2121
|
+
return GROUPS.map((group) => {
|
|
2122
|
+
const categoryMatches = group.category.label.toLowerCase().includes(term);
|
|
2123
|
+
const entities = categoryMatches ? group.entities : group.entities.filter(
|
|
2124
|
+
(e) => e.label.toLowerCase().includes(term) || e.tableName.includes(term.replace(/\s+/g, "_"))
|
|
2125
|
+
);
|
|
2126
|
+
return { ...group, entities };
|
|
2127
|
+
}).filter((group) => group.entities.length > 0);
|
|
2128
|
+
}, [search]);
|
|
2129
|
+
const select = (next) => {
|
|
2130
|
+
onChange(next);
|
|
2131
|
+
setOpen(false);
|
|
2132
|
+
setSearch("");
|
|
2133
|
+
};
|
|
2134
|
+
const firstMatch = filteredGroups[0]?.entities[0];
|
|
2135
|
+
const isAll = !entity && !category;
|
|
2136
|
+
return /* @__PURE__ */ jsxs(
|
|
2137
|
+
Popover,
|
|
2138
|
+
{
|
|
2139
|
+
open,
|
|
2140
|
+
onOpenChange: (next) => {
|
|
2141
|
+
setOpen(next);
|
|
2142
|
+
if (!next) setSearch("");
|
|
2143
|
+
},
|
|
2144
|
+
children: [
|
|
2145
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
2146
|
+
"button",
|
|
2147
|
+
{
|
|
2148
|
+
type: "button",
|
|
2149
|
+
"aria-label": "Filter by entity",
|
|
2150
|
+
className: clx(
|
|
2151
|
+
"txt-compact-small flex h-7 w-full min-w-[200px] items-center justify-between gap-2 rounded-md bg-ui-bg-field px-2 text-left shadow-borders-base outline-none transition-fg",
|
|
2152
|
+
"hover:bg-ui-bg-field-hover focus-visible:shadow-borders-interactive-with-active md:w-auto",
|
|
2153
|
+
isAll ? "text-ui-fg-muted" : "text-ui-fg-base"
|
|
2154
|
+
),
|
|
2155
|
+
children: [
|
|
2156
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: triggerLabel(entity, category) }),
|
|
2157
|
+
/* @__PURE__ */ jsx(ChevronDownMini, { className: "shrink-0 text-ui-fg-muted" })
|
|
2158
|
+
]
|
|
2159
|
+
}
|
|
2160
|
+
) }),
|
|
2161
|
+
/* @__PURE__ */ jsxs(
|
|
2162
|
+
Popover.Content,
|
|
2163
|
+
{
|
|
2164
|
+
align: "start",
|
|
2165
|
+
className: "w-[min(360px,calc(100vw-2rem))] p-0",
|
|
2166
|
+
onOpenAutoFocus: (event) => {
|
|
2167
|
+
event.preventDefault();
|
|
2168
|
+
searchRef.current?.focus();
|
|
2169
|
+
},
|
|
2170
|
+
children: [
|
|
2171
|
+
/* @__PURE__ */ jsx("div", { className: "border-b border-ui-border-base p-2", children: /* @__PURE__ */ jsx(
|
|
2172
|
+
Input,
|
|
2679
2173
|
{
|
|
2680
|
-
|
|
2174
|
+
ref: searchRef,
|
|
2681
2175
|
size: "small",
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2176
|
+
type: "search",
|
|
2177
|
+
placeholder: "Search entities, e.g. order, wallet…",
|
|
2178
|
+
value: search,
|
|
2179
|
+
onChange: (e) => setSearch(e.target.value),
|
|
2180
|
+
onKeyDown: (e) => {
|
|
2181
|
+
if (e.key === "Enter" && firstMatch) {
|
|
2182
|
+
e.preventDefault();
|
|
2183
|
+
select({ entity: firstMatch.tableName, category: "" });
|
|
2184
|
+
}
|
|
2685
2185
|
},
|
|
2686
|
-
|
|
2186
|
+
"aria-label": "Search entities"
|
|
2687
2187
|
}
|
|
2688
|
-
)
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2188
|
+
) }),
|
|
2189
|
+
/* @__PURE__ */ jsxs("div", { className: "max-h-[360px] overflow-y-auto p-1", role: "listbox", "aria-label": "Entities", children: [
|
|
2190
|
+
!search.trim() ? /* @__PURE__ */ jsx(PickerOption, { selected: isAll, onSelect: () => select({ entity: "", category: "" }), children: "All entities" }) : null,
|
|
2191
|
+
filteredGroups.length === 0 ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "px-3 py-6 text-center text-ui-fg-muted", children: [
|
|
2192
|
+
"No entities match “",
|
|
2193
|
+
search.trim(),
|
|
2194
|
+
"”"
|
|
2195
|
+
] }) : null,
|
|
2196
|
+
filteredGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
2197
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: group.category.label }),
|
|
2198
|
+
!search.trim() ? /* @__PURE__ */ jsxs(
|
|
2199
|
+
PickerOption,
|
|
2200
|
+
{
|
|
2201
|
+
selected: !entity && category === group.category.id,
|
|
2202
|
+
onSelect: () => select({ entity: "", category: group.category.id }),
|
|
2203
|
+
secondary: group.category.description,
|
|
2204
|
+
children: [
|
|
2205
|
+
"All ",
|
|
2206
|
+
group.category.label
|
|
2207
|
+
]
|
|
2208
|
+
}
|
|
2209
|
+
) : null,
|
|
2210
|
+
group.entities.map((info) => /* @__PURE__ */ jsx(
|
|
2211
|
+
PickerOption,
|
|
2212
|
+
{
|
|
2213
|
+
selected: entity === info.tableName,
|
|
2214
|
+
onSelect: () => select({ entity: info.tableName, category: "" }),
|
|
2215
|
+
secondary: info.tableName,
|
|
2216
|
+
secondaryMono: true,
|
|
2217
|
+
indent: !search.trim(),
|
|
2218
|
+
children: info.label
|
|
2219
|
+
},
|
|
2220
|
+
info.tableName
|
|
2221
|
+
))
|
|
2222
|
+
] }, group.category.id))
|
|
2223
|
+
] })
|
|
2224
|
+
]
|
|
2225
|
+
}
|
|
2226
|
+
)
|
|
2227
|
+
]
|
|
2228
|
+
}
|
|
2229
|
+
);
|
|
2230
|
+
};
|
|
2231
|
+
const PickerOption = ({ selected, onSelect, children, secondary, secondaryMono, indent }) => /* @__PURE__ */ jsxs(
|
|
2232
|
+
"button",
|
|
2233
|
+
{
|
|
2234
|
+
type: "button",
|
|
2235
|
+
role: "option",
|
|
2236
|
+
"aria-selected": selected,
|
|
2237
|
+
onClick: onSelect,
|
|
2238
|
+
className: clx(
|
|
2239
|
+
"flex w-full items-start gap-2 rounded-md px-2 py-1.5 text-left outline-none transition-fg",
|
|
2240
|
+
"hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-hover",
|
|
2241
|
+
indent && "pl-4"
|
|
2242
|
+
),
|
|
2243
|
+
children: [
|
|
2244
|
+
/* @__PURE__ */ jsx("span", { className: "mt-0.5 flex size-4 shrink-0 items-center justify-center text-ui-fg-interactive", children: selected ? /* @__PURE__ */ jsx(Check, {}) : null }),
|
|
2245
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
2246
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm text-ui-fg-base", children }),
|
|
2247
|
+
secondary ? /* @__PURE__ */ jsx("span", { className: clx("truncate text-xs text-ui-fg-muted", secondaryMono && "font-mono"), children: secondary }) : null
|
|
2248
|
+
] })
|
|
2249
|
+
]
|
|
2250
|
+
}
|
|
2251
|
+
);
|
|
2252
|
+
const CopyableId = ({ value, emptyLabel = "No ID", className }) => {
|
|
2253
|
+
if (!value) {
|
|
2254
|
+
return /* @__PURE__ */ jsx(Text, { size: "small", className: "italic text-ui-fg-muted", children: emptyLabel });
|
|
2255
|
+
}
|
|
2256
|
+
return /* @__PURE__ */ jsxs("span", { className: clx("inline-flex min-w-0 max-w-full items-center gap-1", className), children: [
|
|
2257
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-mono text-xs text-ui-fg-base", title: value, children: value }),
|
|
2258
|
+
/* @__PURE__ */ jsx("span", { onClick: (e) => e.stopPropagation(), className: "inline-flex shrink-0", children: /* @__PURE__ */ jsx(Copy, { content: value, variant: "mini", className: "text-ui-fg-muted", "aria-label": `Copy ${value}` }) })
|
|
2259
|
+
] });
|
|
2260
|
+
};
|
|
2261
|
+
const RELATIVE_UNITS = [
|
|
2262
|
+
{ unit: "year", seconds: 60 * 60 * 24 * 365 },
|
|
2263
|
+
{ unit: "month", seconds: 60 * 60 * 24 * 30 },
|
|
2264
|
+
{ unit: "week", seconds: 60 * 60 * 24 * 7 },
|
|
2265
|
+
{ unit: "day", seconds: 60 * 60 * 24 },
|
|
2266
|
+
{ unit: "hour", seconds: 60 * 60 },
|
|
2267
|
+
{ unit: "minute", seconds: 60 }
|
|
2268
|
+
];
|
|
2269
|
+
function toDate(value) {
|
|
2270
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
2271
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
2272
|
+
}
|
|
2273
|
+
function formatRelativeTime(value, now = /* @__PURE__ */ new Date()) {
|
|
2274
|
+
const date = toDate(value);
|
|
2275
|
+
if (!date) return "—";
|
|
2276
|
+
const diffSeconds = Math.round((date.getTime() - now.getTime()) / 1e3);
|
|
2277
|
+
if (Math.abs(diffSeconds) < 45) return "just now";
|
|
2278
|
+
const rtf = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
|
|
2279
|
+
for (const { unit, seconds } of RELATIVE_UNITS) {
|
|
2280
|
+
if (Math.abs(diffSeconds) >= seconds) {
|
|
2281
|
+
return rtf.format(Math.round(diffSeconds / seconds), unit);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
return rtf.format(Math.round(diffSeconds / 60), "minute");
|
|
2285
|
+
}
|
|
2286
|
+
function formatExactDateTime(value) {
|
|
2287
|
+
const date = toDate(value);
|
|
2288
|
+
if (!date) return "—";
|
|
2289
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
2290
|
+
day: "2-digit",
|
|
2291
|
+
month: "short",
|
|
2292
|
+
year: "numeric",
|
|
2293
|
+
hour: "2-digit",
|
|
2294
|
+
minute: "2-digit",
|
|
2295
|
+
second: "2-digit",
|
|
2296
|
+
timeZoneName: "short"
|
|
2297
|
+
}).format(date);
|
|
2298
|
+
}
|
|
2299
|
+
function formatDate(value) {
|
|
2300
|
+
const date = toDate(value);
|
|
2301
|
+
if (!date) return "—";
|
|
2302
|
+
return new Intl.DateTimeFormat(void 0, { day: "2-digit", month: "short", year: "numeric" }).format(date);
|
|
2303
|
+
}
|
|
2304
|
+
function formatNumber(value) {
|
|
2305
|
+
return new Intl.NumberFormat().format(value);
|
|
2306
|
+
}
|
|
2307
|
+
function formatMoney(amount, currencyCode) {
|
|
2308
|
+
const code = currencyCode?.trim().toUpperCase();
|
|
2309
|
+
if (code && /^[A-Z]{3}$/.test(code)) {
|
|
2310
|
+
try {
|
|
2311
|
+
return new Intl.NumberFormat(void 0, { style: "currency", currency: code }).format(amount);
|
|
2312
|
+
} catch {
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return code ? `${code} ${formatNumber(amount)}` : formatNumber(amount);
|
|
2316
|
+
}
|
|
2317
|
+
const SOURCE_ALIASES = {
|
|
2318
|
+
admin: { kind: "admin", label: "Admin Panel" },
|
|
2319
|
+
admin_panel: { kind: "admin", label: "Admin Panel" },
|
|
2320
|
+
dashboard: { kind: "admin", label: "Admin Panel" },
|
|
2321
|
+
api: { kind: "api", label: "API" },
|
|
2322
|
+
store_api: { kind: "api", label: "Storefront API" },
|
|
2323
|
+
admin_api: { kind: "api", label: "Admin API" },
|
|
2324
|
+
system: { kind: "system", label: "System" },
|
|
2325
|
+
job: { kind: "job", label: "Background Job" },
|
|
2326
|
+
background_job: { kind: "job", label: "Background Job" },
|
|
2327
|
+
scheduled_job: { kind: "job", label: "Background Job" },
|
|
2328
|
+
cron: { kind: "job", label: "Background Job" },
|
|
2329
|
+
workflow: { kind: "workflow", label: "Workflow" },
|
|
2330
|
+
migration: { kind: "system", label: "Migration" }
|
|
2331
|
+
};
|
|
2332
|
+
function describeSource(source) {
|
|
2333
|
+
if (!source || !source.trim()) return { kind: "unknown", label: "Unknown" };
|
|
2334
|
+
const key = source.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
2335
|
+
return SOURCE_ALIASES[key] ?? { kind: "other", label: source.trim() };
|
|
2336
|
+
}
|
|
2337
|
+
function sourceBadgeColor(kind) {
|
|
2338
|
+
switch (kind) {
|
|
2339
|
+
case "admin":
|
|
2340
|
+
return "blue";
|
|
2341
|
+
case "api":
|
|
2342
|
+
return "purple";
|
|
2343
|
+
case "job":
|
|
2344
|
+
case "workflow":
|
|
2345
|
+
return "orange";
|
|
2346
|
+
case "system":
|
|
2347
|
+
return "green";
|
|
2348
|
+
default:
|
|
2349
|
+
return "grey";
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
const CARDS = [
|
|
2353
|
+
{ key: "total", label: "Total deleted", hint: "All records captured since auditing began" },
|
|
2354
|
+
{ key: "today", label: "Today", hint: "Deleted since midnight (your time)" },
|
|
2355
|
+
{ key: "last_7_days", label: "Last 7 days", hint: "Including today" },
|
|
2356
|
+
{ key: "tables_affected", label: "Entity types affected", hint: "Distinct kinds of records deleted" }
|
|
2357
|
+
];
|
|
2358
|
+
const SummaryCards = ({ stats, loading, failed }) => {
|
|
2359
|
+
if (failed && !stats) return null;
|
|
2360
|
+
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", children: CARDS.map((card) => /* @__PURE__ */ jsxs(
|
|
2361
|
+
"div",
|
|
2362
|
+
{
|
|
2363
|
+
className: "flex flex-col gap-1 rounded-lg border border-ui-border-base bg-ui-bg-subtle px-4 py-3",
|
|
2364
|
+
title: card.hint,
|
|
2365
|
+
children: [
|
|
2366
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: card.label }),
|
|
2367
|
+
loading || !stats ? /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-16" }) : /* @__PURE__ */ jsx(Text, { className: "text-2xl font-semibold leading-8 text-ui-fg-base", children: formatNumber(stats[card.key]) })
|
|
2368
|
+
]
|
|
2369
|
+
},
|
|
2370
|
+
card.key
|
|
2371
|
+
)) });
|
|
2372
|
+
};
|
|
2373
|
+
const BASE = "/admin/deleted-records-audit";
|
|
2374
|
+
class AuditApiError extends Error {
|
|
2375
|
+
status;
|
|
2376
|
+
constructor(message, status) {
|
|
2377
|
+
super(message);
|
|
2378
|
+
this.status = status;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
async function getJson(url, signal) {
|
|
2382
|
+
const response = await fetch(url, { credentials: "include", signal });
|
|
2383
|
+
if (!response.ok) {
|
|
2384
|
+
let message = response.statusText || "Request failed";
|
|
2385
|
+
try {
|
|
2386
|
+
const body = await response.json();
|
|
2387
|
+
if (body && typeof body === "object" && "message" in body && typeof body.message === "string") {
|
|
2388
|
+
message = body.message;
|
|
2702
2389
|
}
|
|
2703
|
-
|
|
2704
|
-
|
|
2390
|
+
} catch {
|
|
2391
|
+
}
|
|
2392
|
+
throw new AuditApiError(message, response.status);
|
|
2393
|
+
}
|
|
2394
|
+
return await response.json();
|
|
2395
|
+
}
|
|
2396
|
+
function fetchAuditList(params, signal) {
|
|
2397
|
+
return getJson(`${BASE}?${params.toString()}`, signal);
|
|
2398
|
+
}
|
|
2399
|
+
async function fetchAuditStats(signal) {
|
|
2400
|
+
const todayStart = /* @__PURE__ */ new Date();
|
|
2401
|
+
todayStart.setHours(0, 0, 0, 0);
|
|
2402
|
+
const params = new URLSearchParams({ today_start: todayStart.toISOString() });
|
|
2403
|
+
const body = await getJson(`${BASE}/stats?${params.toString()}`, signal);
|
|
2404
|
+
return body.stats;
|
|
2405
|
+
}
|
|
2406
|
+
async function fetchAuditDetail(id, signal) {
|
|
2407
|
+
const body = await getJson(`${BASE}/${encodeURIComponent(id)}`, signal);
|
|
2408
|
+
return body.audit;
|
|
2409
|
+
}
|
|
2410
|
+
const LAST_LIST_URL_KEY = "om.deleted-records-audit.last-list-search";
|
|
2411
|
+
const DATE_PRESETS = [
|
|
2412
|
+
{ value: "any", label: "Any time" },
|
|
2413
|
+
{ value: "today", label: "Today" },
|
|
2414
|
+
{ value: "yesterday", label: "Yesterday" },
|
|
2415
|
+
{ value: "7d", label: "Last 7 days" },
|
|
2416
|
+
{ value: "30d", label: "Last 30 days" },
|
|
2417
|
+
{ value: "custom", label: "Custom range" }
|
|
2418
|
+
];
|
|
2419
|
+
const EMPTY_FILTERS = {
|
|
2420
|
+
q: "",
|
|
2421
|
+
entity: "",
|
|
2422
|
+
category: "",
|
|
2423
|
+
date: "any",
|
|
2424
|
+
from: "",
|
|
2425
|
+
to: "",
|
|
2426
|
+
source: "",
|
|
2427
|
+
deletedBy: ""
|
|
2705
2428
|
};
|
|
2706
|
-
const
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
}, [value, delay]);
|
|
2716
|
-
return debouncedValue;
|
|
2429
|
+
const URL_KEYS = {
|
|
2430
|
+
q: "q",
|
|
2431
|
+
entity: "entity",
|
|
2432
|
+
category: "category",
|
|
2433
|
+
date: "date",
|
|
2434
|
+
from: "from",
|
|
2435
|
+
to: "to",
|
|
2436
|
+
source: "source",
|
|
2437
|
+
deletedBy: "deleted_by"
|
|
2717
2438
|
};
|
|
2718
|
-
const
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2439
|
+
const DATE_PRESET_VALUES = new Set(DATE_PRESETS.map((p) => p.value));
|
|
2440
|
+
const DAY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
2441
|
+
function filtersFromSearchParams(params) {
|
|
2442
|
+
const read = (key) => params.get(URL_KEYS[key])?.trim() ?? "";
|
|
2443
|
+
const date = read("date");
|
|
2444
|
+
const from = read("from");
|
|
2445
|
+
const to = read("to");
|
|
2446
|
+
return {
|
|
2447
|
+
q: read("q"),
|
|
2448
|
+
entity: read("entity"),
|
|
2449
|
+
category: read("category"),
|
|
2450
|
+
date: DATE_PRESET_VALUES.has(date) ? date : "any",
|
|
2451
|
+
from: DAY_PATTERN.test(from) ? from : "",
|
|
2452
|
+
to: DAY_PATTERN.test(to) ? to : "",
|
|
2453
|
+
source: read("source"),
|
|
2454
|
+
deletedBy: read("deletedBy")
|
|
2455
|
+
};
|
|
2456
|
+
}
|
|
2457
|
+
function filtersToSearchParams(filters) {
|
|
2458
|
+
const params = new URLSearchParams();
|
|
2459
|
+
for (const key of Object.keys(URL_KEYS)) {
|
|
2460
|
+
const value = filters[key];
|
|
2461
|
+
if (!value || value === EMPTY_FILTERS[key]) continue;
|
|
2462
|
+
if ((key === "from" || key === "to") && filters.date !== "custom") continue;
|
|
2463
|
+
params.set(URL_KEYS[key], value);
|
|
2722
2464
|
}
|
|
2723
|
-
|
|
2724
|
-
|
|
2465
|
+
return params;
|
|
2466
|
+
}
|
|
2467
|
+
function hasActiveFilters(filters) {
|
|
2468
|
+
return filtersToSearchParams(filters).toString() !== "";
|
|
2469
|
+
}
|
|
2470
|
+
function startOfDay(date) {
|
|
2471
|
+
const d = new Date(date);
|
|
2472
|
+
d.setHours(0, 0, 0, 0);
|
|
2473
|
+
return d;
|
|
2474
|
+
}
|
|
2475
|
+
function endOfDay(date) {
|
|
2476
|
+
const d = new Date(date);
|
|
2477
|
+
d.setHours(23, 59, 59, 999);
|
|
2478
|
+
return d;
|
|
2479
|
+
}
|
|
2480
|
+
function parseDay(day) {
|
|
2481
|
+
if (!DAY_PATTERN.test(day)) return null;
|
|
2482
|
+
const [y, m, d] = day.split("-").map(Number);
|
|
2483
|
+
const date = new Date(y, m - 1, d);
|
|
2484
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
2485
|
+
}
|
|
2486
|
+
function resolveDateRange(filters, now = /* @__PURE__ */ new Date()) {
|
|
2487
|
+
const today = startOfDay(now);
|
|
2488
|
+
switch (filters.date) {
|
|
2489
|
+
case "today":
|
|
2490
|
+
return { from: today };
|
|
2491
|
+
case "yesterday": {
|
|
2492
|
+
const y = new Date(today);
|
|
2493
|
+
y.setDate(y.getDate() - 1);
|
|
2494
|
+
return { from: y, to: endOfDay(y) };
|
|
2495
|
+
}
|
|
2496
|
+
case "7d": {
|
|
2497
|
+
const from = new Date(today);
|
|
2498
|
+
from.setDate(from.getDate() - 6);
|
|
2499
|
+
return { from };
|
|
2500
|
+
}
|
|
2501
|
+
case "30d": {
|
|
2502
|
+
const from = new Date(today);
|
|
2503
|
+
from.setDate(from.getDate() - 29);
|
|
2504
|
+
return { from };
|
|
2505
|
+
}
|
|
2506
|
+
case "custom": {
|
|
2507
|
+
const from = parseDay(filters.from);
|
|
2508
|
+
const to = parseDay(filters.to);
|
|
2509
|
+
return { from: from ?? void 0, to: to ? endOfDay(to) : void 0 };
|
|
2510
|
+
}
|
|
2511
|
+
default:
|
|
2512
|
+
return {};
|
|
2725
2513
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2514
|
+
}
|
|
2515
|
+
function filtersToApiParams(filters, page, now = /* @__PURE__ */ new Date()) {
|
|
2516
|
+
const params = new URLSearchParams();
|
|
2517
|
+
params.set("limit", String(page.limit));
|
|
2518
|
+
params.set("offset", String(page.offset));
|
|
2519
|
+
if (filters.q) params.set("q", filters.q);
|
|
2520
|
+
if (filters.entity) {
|
|
2521
|
+
params.set("table_name", filters.entity);
|
|
2522
|
+
} else if (filters.category) {
|
|
2523
|
+
const tables = getTablesForCategory(filters.category);
|
|
2524
|
+
if (tables.length) params.set("table_names", tables.join(","));
|
|
2728
2525
|
}
|
|
2729
|
-
|
|
2730
|
-
|
|
2526
|
+
const range = resolveDateRange(filters, now);
|
|
2527
|
+
if (range.from) params.set("date_from", range.from.toISOString());
|
|
2528
|
+
if (range.to) params.set("date_to", range.to.toISOString());
|
|
2529
|
+
if (filters.source) params.set("source", filters.source);
|
|
2530
|
+
if (filters.deletedBy) params.set("deleted_by", filters.deletedBy);
|
|
2531
|
+
return params;
|
|
2532
|
+
}
|
|
2533
|
+
const PAGE_SIZE = 50;
|
|
2534
|
+
const RESTORE_PAGE_SIZE = 100;
|
|
2535
|
+
const MAX_RESTORE_ROWS = 500;
|
|
2536
|
+
const ALL = "__all__";
|
|
2537
|
+
const UNKNOWN_SOURCE = "unknown";
|
|
2538
|
+
const LOADED_COUNT_KEY_PREFIX = "om.deleted-records-audit.loaded:";
|
|
2539
|
+
const LAST_VIEWED_KEY = "om.deleted-records-audit.last-viewed";
|
|
2540
|
+
function readSession(key) {
|
|
2541
|
+
try {
|
|
2542
|
+
return window.sessionStorage.getItem(key);
|
|
2543
|
+
} catch {
|
|
2544
|
+
return null;
|
|
2731
2545
|
}
|
|
2732
|
-
|
|
2733
|
-
|
|
2546
|
+
}
|
|
2547
|
+
function writeSession(key, value) {
|
|
2548
|
+
try {
|
|
2549
|
+
window.sessionStorage.setItem(key, value);
|
|
2550
|
+
} catch {
|
|
2734
2551
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
const ReturnsPage = () => {
|
|
2552
|
+
}
|
|
2553
|
+
const DeletedRecordsPage = () => {
|
|
2738
2554
|
const navigate = useNavigate();
|
|
2555
|
+
const location = useLocation();
|
|
2556
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
2557
|
+
const filters = useMemo(() => filtersFromSearchParams(searchParams), [searchParams]);
|
|
2558
|
+
const filterKey = filtersToSearchParams(filters).toString();
|
|
2559
|
+
const filtersActive = hasActiveFilters(filters);
|
|
2560
|
+
const [searchText, setSearchText] = useState(filters.q);
|
|
2739
2561
|
const [items, setItems] = useState([]);
|
|
2740
|
-
const [
|
|
2741
|
-
const [createdByFilter, setCreatedByFilter] = useState("all");
|
|
2742
|
-
const [searchQuery, setSearchQuery] = useState("");
|
|
2743
|
-
const debouncedSearchQuery = useDebounce$1(searchQuery, 300);
|
|
2562
|
+
const [count, setCount] = useState(0);
|
|
2744
2563
|
const [isLoading, setIsLoading] = useState(true);
|
|
2745
2564
|
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
2746
2565
|
const [error, setError] = useState(null);
|
|
2747
|
-
const [
|
|
2748
|
-
const [
|
|
2749
|
-
const
|
|
2750
|
-
const
|
|
2751
|
-
|
|
2566
|
+
const [stats, setStats] = useState(null);
|
|
2567
|
+
const [statsLoading, setStatsLoading] = useState(true);
|
|
2568
|
+
const [statsFailed, setStatsFailed] = useState(false);
|
|
2569
|
+
const [reloadToken, setReloadToken] = useState(0);
|
|
2570
|
+
const [highlightId, setHighlightId] = useState(null);
|
|
2571
|
+
const restoredScrollRef = useRef(false);
|
|
2572
|
+
const updateFilters = useCallback(
|
|
2573
|
+
(patch) => {
|
|
2574
|
+
const next = { ...filters, ...patch };
|
|
2575
|
+
setSearchParams(filtersToSearchParams(next), { replace: true });
|
|
2576
|
+
},
|
|
2577
|
+
[filters, setSearchParams]
|
|
2578
|
+
);
|
|
2579
|
+
useEffect(() => {
|
|
2580
|
+
if (searchText.trim() === filters.q) return;
|
|
2581
|
+
const handle = setTimeout(() => updateFilters({ q: searchText.trim() }), 300);
|
|
2582
|
+
return () => clearTimeout(handle);
|
|
2583
|
+
}, [searchText, filters.q, updateFilters]);
|
|
2584
|
+
useEffect(() => {
|
|
2585
|
+
setSearchText((current) => current.trim() === filters.q ? current : filters.q);
|
|
2586
|
+
}, [filters.q]);
|
|
2587
|
+
useEffect(() => {
|
|
2588
|
+
writeSession(LAST_LIST_URL_KEY, location.search);
|
|
2589
|
+
}, [location.search]);
|
|
2590
|
+
const loadStats = useCallback(async (signal) => {
|
|
2591
|
+
setStatsLoading(true);
|
|
2592
|
+
setStatsFailed(false);
|
|
2593
|
+
try {
|
|
2594
|
+
setStats(await fetchAuditStats(signal));
|
|
2595
|
+
} catch (e) {
|
|
2596
|
+
if (!signal?.aborted) setStatsFailed(true);
|
|
2597
|
+
} finally {
|
|
2598
|
+
if (!signal?.aborted) setStatsLoading(false);
|
|
2599
|
+
}
|
|
2600
|
+
}, []);
|
|
2601
|
+
useEffect(() => {
|
|
2602
|
+
const controller = new AbortController();
|
|
2603
|
+
void loadStats(controller.signal);
|
|
2604
|
+
return () => controller.abort();
|
|
2605
|
+
}, [loadStats, reloadToken]);
|
|
2606
|
+
useEffect(() => {
|
|
2607
|
+
const controller = new AbortController();
|
|
2608
|
+
const restoreTarget = Math.min(
|
|
2609
|
+
MAX_RESTORE_ROWS,
|
|
2610
|
+
Math.max(PAGE_SIZE, Number(readSession(LOADED_COUNT_KEY_PREFIX + filterKey)) || 0)
|
|
2611
|
+
);
|
|
2612
|
+
setIsLoading(true);
|
|
2613
|
+
setError(null);
|
|
2614
|
+
(async () => {
|
|
2752
2615
|
try {
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
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");
|
|
2616
|
+
const collected = [];
|
|
2617
|
+
let total = 0;
|
|
2618
|
+
while (collected.length < restoreTarget) {
|
|
2619
|
+
const limit = restoreTarget > PAGE_SIZE ? RESTORE_PAGE_SIZE : PAGE_SIZE;
|
|
2620
|
+
const page = await fetchAuditList(
|
|
2621
|
+
filtersToApiParams(filters, { limit, offset: collected.length }),
|
|
2622
|
+
controller.signal
|
|
2623
|
+
);
|
|
2624
|
+
total = page.count;
|
|
2625
|
+
collected.push(...page.audits);
|
|
2626
|
+
if (page.audits.length < limit || collected.length >= total) break;
|
|
2779
2627
|
}
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
);
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
setError(message);
|
|
2628
|
+
if (controller.signal.aborted) return;
|
|
2629
|
+
setItems(collected.slice(0, restoreTarget));
|
|
2630
|
+
setCount(total);
|
|
2631
|
+
} catch (e) {
|
|
2632
|
+
if (controller.signal.aborted) return;
|
|
2633
|
+
setItems([]);
|
|
2634
|
+
setCount(0);
|
|
2635
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
2789
2636
|
} finally {
|
|
2790
|
-
setIsLoading(false);
|
|
2791
|
-
setIsFetchingMore(false);
|
|
2637
|
+
if (!controller.signal.aborted) setIsLoading(false);
|
|
2792
2638
|
}
|
|
2793
|
-
}
|
|
2794
|
-
|
|
2795
|
-
);
|
|
2639
|
+
})();
|
|
2640
|
+
return () => controller.abort();
|
|
2641
|
+
}, [filterKey, reloadToken]);
|
|
2796
2642
|
useEffect(() => {
|
|
2797
|
-
|
|
2798
|
-
}, [
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2643
|
+
if (!isLoading) writeSession(LOADED_COUNT_KEY_PREFIX + filterKey, String(items.length));
|
|
2644
|
+
}, [items.length, isLoading, filterKey]);
|
|
2645
|
+
useEffect(() => {
|
|
2646
|
+
if (isLoading || restoredScrollRef.current) return;
|
|
2647
|
+
restoredScrollRef.current = true;
|
|
2648
|
+
const lastViewed = readSession(LAST_VIEWED_KEY);
|
|
2649
|
+
if (!lastViewed || !items.some((item) => item.id === lastViewed)) return;
|
|
2650
|
+
setHighlightId(lastViewed);
|
|
2651
|
+
requestAnimationFrame(() => {
|
|
2652
|
+
const visible = Array.from(document.querySelectorAll(`[data-audit-row="${lastViewed}"]`)).find(
|
|
2653
|
+
(el) => el.offsetParent !== null
|
|
2654
|
+
);
|
|
2655
|
+
visible?.scrollIntoView({ block: "center" });
|
|
2656
|
+
});
|
|
2657
|
+
const handle = setTimeout(() => setHighlightId(null), 2500);
|
|
2658
|
+
return () => clearTimeout(handle);
|
|
2659
|
+
}, [isLoading, items]);
|
|
2660
|
+
const loadMore = async () => {
|
|
2661
|
+
setIsFetchingMore(true);
|
|
2662
|
+
try {
|
|
2663
|
+
const page = await fetchAuditList(filtersToApiParams(filters, { limit: PAGE_SIZE, offset: items.length }));
|
|
2664
|
+
setItems((prev) => [...prev, ...page.audits]);
|
|
2665
|
+
setCount(page.count);
|
|
2666
|
+
} catch (e) {
|
|
2667
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
2668
|
+
} finally {
|
|
2669
|
+
setIsFetchingMore(false);
|
|
2670
|
+
}
|
|
2671
|
+
};
|
|
2672
|
+
const openDetail = (id) => {
|
|
2673
|
+
writeSession(LAST_VIEWED_KEY, id);
|
|
2674
|
+
navigate(`/deleted-records-audit/${id}`, { state: { fromList: true } });
|
|
2675
|
+
};
|
|
2676
|
+
const clearFilters = () => {
|
|
2677
|
+
setSearchText("");
|
|
2678
|
+
setSearchParams(filtersToSearchParams(EMPTY_FILTERS), { replace: true });
|
|
2679
|
+
};
|
|
2680
|
+
const refresh = () => setReloadToken((t) => t + 1);
|
|
2681
|
+
const hasMore = items.length < count;
|
|
2682
|
+
const knownSources = stats?.sources ?? [];
|
|
2683
|
+
const knownDeletedBy = stats?.deleted_by ?? [];
|
|
2684
|
+
const attributionMissing = !!stats && stats.total > 0 && knownSources.length === 0 && knownDeletedBy.length === 0;
|
|
2685
|
+
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: [
|
|
2686
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [
|
|
2807
2687
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2808
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "
|
|
2809
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
2688
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Deleted Records" }),
|
|
2689
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Review records that were permanently deleted from the system." })
|
|
2810
2690
|
] }),
|
|
2811
|
-
/* @__PURE__ */
|
|
2691
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: refresh, isLoading: isLoading && items.length > 0, children: [
|
|
2692
|
+
/* @__PURE__ */ jsx(ArrowPath, {}),
|
|
2693
|
+
"Refresh"
|
|
2694
|
+
] })
|
|
2812
2695
|
] }),
|
|
2813
|
-
/* @__PURE__ */
|
|
2696
|
+
/* @__PURE__ */ jsx(SummaryCards, { stats, loading: statsLoading, failed: statsFailed }),
|
|
2697
|
+
/* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-3", "aria-label": "Search and filters", children: [
|
|
2814
2698
|
/* @__PURE__ */ jsx(
|
|
2815
2699
|
Input,
|
|
2816
2700
|
{
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2701
|
+
type: "search",
|
|
2702
|
+
size: "base",
|
|
2703
|
+
placeholder: "Search by record ID, e.g. order_01J…, prod_…, cus_…",
|
|
2704
|
+
value: searchText,
|
|
2705
|
+
onChange: (e) => setSearchText(e.target.value),
|
|
2706
|
+
"aria-label": "Search by record ID",
|
|
2707
|
+
className: "w-full"
|
|
2821
2708
|
}
|
|
2822
2709
|
),
|
|
2823
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-
|
|
2824
|
-
/* @__PURE__ */
|
|
2825
|
-
|
|
2710
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 md:flex-row md:flex-wrap md:items-center", children: [
|
|
2711
|
+
/* @__PURE__ */ jsx(
|
|
2712
|
+
EntityPicker,
|
|
2826
2713
|
{
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2714
|
+
entity: filters.entity,
|
|
2715
|
+
category: filters.category,
|
|
2716
|
+
onChange: (next) => updateFilters(next)
|
|
2717
|
+
}
|
|
2718
|
+
),
|
|
2719
|
+
/* @__PURE__ */ jsx("div", { className: "md:w-[160px]", children: /* @__PURE__ */ jsxs(
|
|
2720
|
+
Select,
|
|
2721
|
+
{
|
|
2722
|
+
size: "small",
|
|
2723
|
+
value: filters.date,
|
|
2724
|
+
onValueChange: (value) => updateFilters({ date: value }),
|
|
2830
2725
|
children: [
|
|
2831
|
-
/* @__PURE__ */ jsx(
|
|
2832
|
-
/* @__PURE__ */ jsx(
|
|
2833
|
-
/* @__PURE__ */ jsx("option", { value: "admin", children: "Admin" })
|
|
2726
|
+
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": "Filter by date", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
2727
|
+
/* @__PURE__ */ jsx(Select.Content, { children: DATE_PRESETS.map((preset) => /* @__PURE__ */ jsx(Select.Item, { value: preset.value, children: preset.label }, preset.value)) })
|
|
2834
2728
|
]
|
|
2835
2729
|
}
|
|
2836
|
-
),
|
|
2837
|
-
/* @__PURE__ */ jsxs(
|
|
2838
|
-
|
|
2730
|
+
) }),
|
|
2731
|
+
filters.date === "custom" ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2732
|
+
/* @__PURE__ */ jsx(
|
|
2733
|
+
Input,
|
|
2734
|
+
{
|
|
2735
|
+
type: "date",
|
|
2736
|
+
size: "small",
|
|
2737
|
+
value: filters.from,
|
|
2738
|
+
max: filters.to || void 0,
|
|
2739
|
+
onChange: (e) => updateFilters({ from: e.target.value }),
|
|
2740
|
+
"aria-label": "From date"
|
|
2741
|
+
}
|
|
2742
|
+
),
|
|
2743
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "to" }),
|
|
2744
|
+
/* @__PURE__ */ jsx(
|
|
2745
|
+
Input,
|
|
2746
|
+
{
|
|
2747
|
+
type: "date",
|
|
2748
|
+
size: "small",
|
|
2749
|
+
value: filters.to,
|
|
2750
|
+
min: filters.from || void 0,
|
|
2751
|
+
onChange: (e) => updateFilters({ to: e.target.value }),
|
|
2752
|
+
"aria-label": "To date"
|
|
2753
|
+
}
|
|
2754
|
+
)
|
|
2755
|
+
] }) : null,
|
|
2756
|
+
knownSources.length > 0 || filters.source ? /* @__PURE__ */ jsx("div", { className: "md:w-[170px]", children: /* @__PURE__ */ jsxs(
|
|
2757
|
+
Select,
|
|
2839
2758
|
{
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2759
|
+
size: "small",
|
|
2760
|
+
value: filters.source || ALL,
|
|
2761
|
+
onValueChange: (value) => updateFilters({ source: value === ALL ? "" : value }),
|
|
2843
2762
|
children: [
|
|
2844
|
-
/* @__PURE__ */ jsx(
|
|
2845
|
-
|
|
2763
|
+
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": "Filter by source", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
2764
|
+
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
2765
|
+
/* @__PURE__ */ jsx(Select.Item, { value: ALL, children: "All sources" }),
|
|
2766
|
+
knownSources.map((source) => /* @__PURE__ */ jsx(Select.Item, { value: source, children: describeSource(source).label }, source)),
|
|
2767
|
+
/* @__PURE__ */ jsx(Select.Item, { value: UNKNOWN_SOURCE, children: "Unknown" })
|
|
2768
|
+
] })
|
|
2846
2769
|
]
|
|
2847
2770
|
}
|
|
2848
|
-
)
|
|
2771
|
+
) }) : null,
|
|
2772
|
+
knownDeletedBy.length > 0 || filters.deletedBy ? /* @__PURE__ */ jsxs("div", { className: "md:w-[200px]", children: [
|
|
2773
|
+
/* @__PURE__ */ jsx(
|
|
2774
|
+
Input,
|
|
2775
|
+
{
|
|
2776
|
+
size: "small",
|
|
2777
|
+
list: "deleted-records-audit-deleted-by",
|
|
2778
|
+
placeholder: "Deleted by (all users)",
|
|
2779
|
+
defaultValue: filters.deletedBy,
|
|
2780
|
+
onBlur: (e) => updateFilters({ deletedBy: e.target.value.trim() }),
|
|
2781
|
+
onKeyDown: (e) => {
|
|
2782
|
+
if (e.key === "Enter") updateFilters({ deletedBy: e.currentTarget.value.trim() });
|
|
2783
|
+
},
|
|
2784
|
+
"aria-label": "Filter by who deleted the record"
|
|
2785
|
+
},
|
|
2786
|
+
filters.deletedBy
|
|
2787
|
+
),
|
|
2788
|
+
/* @__PURE__ */ jsx("datalist", { id: "deleted-records-audit-deleted-by", children: knownDeletedBy.map((value) => /* @__PURE__ */ jsx("option", { value }, value)) })
|
|
2789
|
+
] }) : null,
|
|
2790
|
+
filtersActive ? /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: clearFilters, children: "Clear filters" }) : null
|
|
2849
2791
|
] })
|
|
2850
2792
|
] }),
|
|
2851
|
-
|
|
2852
|
-
/* @__PURE__ */ jsx(
|
|
2853
|
-
/* @__PURE__ */ jsx(
|
|
2854
|
-
Button,
|
|
2855
|
-
{
|
|
2856
|
-
variant: "secondary",
|
|
2857
|
-
onClick: () => loadReturns(0, true),
|
|
2858
|
-
children: "Try again"
|
|
2859
|
-
}
|
|
2860
|
-
) })
|
|
2793
|
+
attributionMissing ? /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-ui-border-base bg-ui-bg-subtle px-3 py-2", children: [
|
|
2794
|
+
/* @__PURE__ */ jsx(InformationCircle, { className: "mt-0.5 shrink-0 text-ui-fg-muted" }),
|
|
2795
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Who deleted a record and where the deletion came from are not being recorded yet, so those columns show “Unknown”. Every deleted record is still captured in full." })
|
|
2861
2796
|
] }) : null,
|
|
2862
|
-
isLoading
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
2874
|
-
] }) }),
|
|
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", {
|
|
2912
|
-
year: "numeric",
|
|
2913
|
-
month: "short",
|
|
2914
|
-
day: "numeric",
|
|
2915
|
-
hour: "numeric",
|
|
2916
|
-
minute: "2-digit",
|
|
2917
|
-
hour12: true
|
|
2918
|
-
}) }),
|
|
2919
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
2920
|
-
Button,
|
|
2921
|
-
{
|
|
2922
|
-
variant: "transparent",
|
|
2923
|
-
size: "small",
|
|
2924
|
-
onClick: (e) => {
|
|
2925
|
-
e.stopPropagation();
|
|
2926
|
-
navigate(`/app/orders/${returnOrder.order_id}`);
|
|
2927
|
-
},
|
|
2928
|
-
children: "Go to order"
|
|
2929
|
-
}
|
|
2930
|
-
) })
|
|
2931
|
-
]
|
|
2932
|
-
},
|
|
2933
|
-
returnOrder.id
|
|
2934
|
-
)) })
|
|
2935
|
-
] }) }),
|
|
2936
|
-
hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
2937
|
-
Button,
|
|
2797
|
+
!isLoading && !error && items.length > 0 ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", "aria-live": "polite", children: [
|
|
2798
|
+
"Showing ",
|
|
2799
|
+
formatNumber(items.length),
|
|
2800
|
+
" of ",
|
|
2801
|
+
formatNumber(count),
|
|
2802
|
+
" ",
|
|
2803
|
+
count === 1 ? "record" : "records",
|
|
2804
|
+
filtersActive ? " matching your filters" : ""
|
|
2805
|
+
] }) : null,
|
|
2806
|
+
error ? /* @__PURE__ */ jsx(ErrorState, { onRetry: refresh, detail: error }) : isLoading ? /* @__PURE__ */ jsx(ListSkeleton, {}) : items.length === 0 ? filtersActive ? /* @__PURE__ */ jsx(
|
|
2807
|
+
EmptyState,
|
|
2938
2808
|
{
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
children: "Load more"
|
|
2809
|
+
title: "No deleted records found",
|
|
2810
|
+
body: "There are no audit records matching your current filters.",
|
|
2811
|
+
action: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: clearFilters, children: "Clear filters" })
|
|
2943
2812
|
}
|
|
2944
|
-
)
|
|
2813
|
+
) : /* @__PURE__ */ jsx(
|
|
2814
|
+
EmptyState,
|
|
2815
|
+
{
|
|
2816
|
+
title: "No deleted records yet",
|
|
2817
|
+
body: "Hard-deleted records will appear here automatically when a monitored database record is permanently deleted."
|
|
2818
|
+
}
|
|
2819
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2820
|
+
/* @__PURE__ */ jsx(AuditTable, { items, highlightId, onOpen: openDetail }),
|
|
2821
|
+
/* @__PURE__ */ jsx(AuditCards, { items, highlightId, onOpen: openDetail })
|
|
2822
|
+
] }),
|
|
2823
|
+
!error && !isLoading && hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: isFetchingMore, onClick: loadMore, children: "Load more" }) }) : null
|
|
2945
2824
|
] }) });
|
|
2946
2825
|
};
|
|
2826
|
+
const HEADER_CELL = "px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted";
|
|
2827
|
+
const DeletedWhen = ({ occurredAt }) => /* @__PURE__ */ jsx(Tooltip, { content: formatExactDateTime(occurredAt), children: /* @__PURE__ */ jsx("span", { className: "cursor-default text-sm text-ui-fg-base", children: formatRelativeTime(occurredAt) }) });
|
|
2828
|
+
const SourceBadge = ({ source }) => {
|
|
2829
|
+
const info = describeSource(source);
|
|
2830
|
+
if (info.kind === "unknown") {
|
|
2831
|
+
return /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Unknown" });
|
|
2832
|
+
}
|
|
2833
|
+
return /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: sourceBadgeColor(info.kind), className: "shrink-0 whitespace-nowrap", children: info.label });
|
|
2834
|
+
};
|
|
2835
|
+
const AuditTable = ({ items, highlightId, onOpen }) => /* @__PURE__ */ jsx("div", { className: "hidden w-full overflow-hidden rounded-xl border border-ui-border-base md:block", children: /* @__PURE__ */ jsxs("table", { className: "w-full table-fixed divide-y divide-ui-border-base", children: [
|
|
2836
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2837
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[22%]"), children: "Entity" }),
|
|
2838
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[24%]"), children: "Record" }),
|
|
2839
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[13%]"), children: "Deleted" }),
|
|
2840
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[13%]"), children: "Deleted by" }),
|
|
2841
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[11%]"), children: "Source" }),
|
|
2842
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[8%]"), children: "Status" }),
|
|
2843
|
+
/* @__PURE__ */ jsx("th", { className: clx(HEADER_CELL, "w-[9%]"), children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Action" }) })
|
|
2844
|
+
] }) }),
|
|
2845
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle", children: items.map((item) => {
|
|
2846
|
+
const entity = getEntityInfo(item.table_name);
|
|
2847
|
+
return /* @__PURE__ */ jsxs(
|
|
2848
|
+
"tr",
|
|
2849
|
+
{
|
|
2850
|
+
"data-audit-row": item.id,
|
|
2851
|
+
tabIndex: 0,
|
|
2852
|
+
onClick: () => onOpen(item.id),
|
|
2853
|
+
onKeyDown: (e) => {
|
|
2854
|
+
if (e.key === "Enter") onOpen(item.id);
|
|
2855
|
+
},
|
|
2856
|
+
className: clx(
|
|
2857
|
+
"cursor-pointer outline-none transition-colors hover:bg-ui-bg-subtle/60 focus-visible:bg-ui-bg-subtle",
|
|
2858
|
+
highlightId === item.id && "bg-ui-bg-highlight"
|
|
2859
|
+
),
|
|
2860
|
+
children: [
|
|
2861
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col", children: [
|
|
2862
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-ui-fg-base", title: entity.label, children: entity.label }),
|
|
2863
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-xs text-ui-fg-muted", children: entity.category.label })
|
|
2864
|
+
] }) }),
|
|
2865
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(CopyableId, { value: item.record_id }) }),
|
|
2866
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(DeletedWhen, { occurredAt: item.occurred_at }) }),
|
|
2867
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-sm", title: item.deleted_by ?? void 0, children: item.deleted_by ? /* @__PURE__ */ jsx("span", { className: "text-ui-fg-base", children: item.deleted_by }) : /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "Unknown" }) }),
|
|
2868
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(SourceBadge, { source: item.source }) }),
|
|
2869
|
+
/* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "red", children: "Deleted" }) }),
|
|
2870
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-3 text-right", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-0.5 whitespace-nowrap text-sm font-medium text-ui-fg-interactive", children: [
|
|
2871
|
+
"View",
|
|
2872
|
+
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
2873
|
+
] }) })
|
|
2874
|
+
]
|
|
2875
|
+
},
|
|
2876
|
+
item.id
|
|
2877
|
+
);
|
|
2878
|
+
}) })
|
|
2879
|
+
] }) });
|
|
2880
|
+
const AuditCards = ({ items, highlightId, onOpen }) => /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2 md:hidden", children: items.map((item) => {
|
|
2881
|
+
const entity = getEntityInfo(item.table_name);
|
|
2882
|
+
return /* @__PURE__ */ jsx("li", { "data-audit-row": item.id, children: /* @__PURE__ */ jsxs(
|
|
2883
|
+
"div",
|
|
2884
|
+
{
|
|
2885
|
+
role: "button",
|
|
2886
|
+
tabIndex: 0,
|
|
2887
|
+
onClick: () => onOpen(item.id),
|
|
2888
|
+
onKeyDown: (e) => {
|
|
2889
|
+
if (e.key === "Enter") onOpen(item.id);
|
|
2890
|
+
},
|
|
2891
|
+
className: clx(
|
|
2892
|
+
"flex w-full flex-col gap-2 rounded-lg border border-ui-border-base p-3 text-left outline-none hover:bg-ui-bg-subtle/60 focus-visible:bg-ui-bg-subtle",
|
|
2893
|
+
highlightId === item.id && "bg-ui-bg-highlight"
|
|
2894
|
+
),
|
|
2895
|
+
children: [
|
|
2896
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2897
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col", children: [
|
|
2898
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-ui-fg-base", children: entity.label }),
|
|
2899
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-muted", children: entity.category.label })
|
|
2900
|
+
] }),
|
|
2901
|
+
/* @__PURE__ */ jsx(DeletedWhen, { occurredAt: item.occurred_at })
|
|
2902
|
+
] }),
|
|
2903
|
+
/* @__PURE__ */ jsx(CopyableId, { value: item.record_id }),
|
|
2904
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2905
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2906
|
+
/* @__PURE__ */ jsx(SourceBadge, { source: item.source }),
|
|
2907
|
+
item.deleted_by ? /* @__PURE__ */ jsxs("span", { className: "truncate text-xs text-ui-fg-subtle", children: [
|
|
2908
|
+
"by ",
|
|
2909
|
+
item.deleted_by
|
|
2910
|
+
] }) : null
|
|
2911
|
+
] }),
|
|
2912
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center whitespace-nowrap text-sm font-medium text-ui-fg-interactive", children: [
|
|
2913
|
+
"View details",
|
|
2914
|
+
/* @__PURE__ */ jsx(ChevronRightMini, {})
|
|
2915
|
+
] })
|
|
2916
|
+
] })
|
|
2917
|
+
]
|
|
2918
|
+
}
|
|
2919
|
+
) }, item.id);
|
|
2920
|
+
}) });
|
|
2921
|
+
const ListSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0 overflow-hidden rounded-xl border border-ui-border-base", "aria-busy": "true", children: [
|
|
2922
|
+
/* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle px-3 py-3", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-40" }) }),
|
|
2923
|
+
Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 border-t border-ui-border-subtle px-3 py-4", children: [
|
|
2924
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-[22%] flex-col gap-1.5", children: [
|
|
2925
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-28" }),
|
|
2926
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-16" })
|
|
2927
|
+
] }),
|
|
2928
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-[20%]" }),
|
|
2929
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-[10%]" }),
|
|
2930
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "hidden h-3.5 w-[10%] md:block" }),
|
|
2931
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "hidden h-5 w-14 rounded-full md:block" })
|
|
2932
|
+
] }, i))
|
|
2933
|
+
] });
|
|
2934
|
+
const EmptyState = ({ title, body, action }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 rounded-lg border border-dashed border-ui-border-strong px-6 py-12 text-center", children: [
|
|
2935
|
+
/* @__PURE__ */ jsx(MagnifierAlert, { className: "text-ui-fg-muted" }),
|
|
2936
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", children: title }),
|
|
2937
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "max-w-md text-ui-fg-subtle", children: body }),
|
|
2938
|
+
action ? /* @__PURE__ */ jsx("div", { className: "mt-2", children: action }) : null
|
|
2939
|
+
] });
|
|
2940
|
+
const ErrorState = ({ onRetry, detail }) => /* @__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: [
|
|
2941
|
+
/* @__PURE__ */ jsx(ExclamationCircle, { className: "text-ui-fg-error" }),
|
|
2942
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", children: "Unable to load deleted records" }),
|
|
2943
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "max-w-md text-ui-fg-subtle", children: "We couldn’t retrieve the audit records right now. Check your connection and try again." }),
|
|
2944
|
+
/* @__PURE__ */ jsx(Text, { size: "xsmall", className: "max-w-md font-mono text-ui-fg-muted", children: detail }),
|
|
2945
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", className: "mt-2", onClick: onRetry, children: "Try again" })
|
|
2946
|
+
] });
|
|
2947
2947
|
const config$6 = defineRouteConfig({
|
|
2948
|
-
label: "
|
|
2949
|
-
icon:
|
|
2948
|
+
label: "Deleted Records",
|
|
2949
|
+
icon: Trash
|
|
2950
2950
|
});
|
|
2951
2951
|
const useDebounce = (value, delay) => {
|
|
2952
2952
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
@@ -3144,38 +3144,347 @@ const SwapsPage = () => {
|
|
|
3144
3144
|
hour: "numeric",
|
|
3145
3145
|
minute: "2-digit",
|
|
3146
3146
|
hour12: true
|
|
3147
|
-
}) }),
|
|
3148
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
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 getStatusBadgeClass$3 = (status) => {
|
|
3181
|
+
const s2 = status.toLowerCase();
|
|
3182
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3183
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
3184
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
3185
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
3186
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3187
|
+
};
|
|
3188
|
+
const PaymentDetailPage = () => {
|
|
3189
|
+
const navigate = useNavigate();
|
|
3190
|
+
const params = useParams();
|
|
3191
|
+
const id = params?.id?.trim();
|
|
3192
|
+
const [detail, setDetail] = useState(null);
|
|
3193
|
+
const [loading, setLoading] = useState(!!id);
|
|
3194
|
+
const [error, setError] = useState(null);
|
|
3195
|
+
useEffect(() => {
|
|
3196
|
+
if (!id) {
|
|
3197
|
+
setLoading(false);
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
let cancelled = false;
|
|
3201
|
+
setLoading(true);
|
|
3202
|
+
setError(null);
|
|
3203
|
+
fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
|
|
3204
|
+
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
3205
|
+
return res.json();
|
|
3206
|
+
}).then((data) => {
|
|
3207
|
+
if (!cancelled) setDetail(data);
|
|
3208
|
+
}).catch((e) => {
|
|
3209
|
+
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
3210
|
+
}).finally(() => {
|
|
3211
|
+
if (!cancelled) setLoading(false);
|
|
3212
|
+
});
|
|
3213
|
+
return () => {
|
|
3214
|
+
cancelled = true;
|
|
3215
|
+
};
|
|
3216
|
+
}, [id]);
|
|
3217
|
+
const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
|
|
3218
|
+
const sessionStatusRaw = detail?.session_status ?? "—";
|
|
3219
|
+
const paymentStatusRaw = detail?.payment_id != null ? detail?.payment_status ?? "—" : "—";
|
|
3220
|
+
const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
|
|
3221
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 p-6", children: [
|
|
3222
|
+
/* @__PURE__ */ jsx("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3223
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
|
|
3224
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
|
|
3225
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
|
|
3226
|
+
] }) }),
|
|
3227
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3228
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3229
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
|
|
3230
|
+
] }) : loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading…" }) }) : detail ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
3231
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6 flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3232
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3233
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
|
|
3234
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
|
|
3235
|
+
Button,
|
|
3236
|
+
{
|
|
3237
|
+
variant: "transparent",
|
|
3238
|
+
size: "small",
|
|
3239
|
+
onClick: () => navigate(`/orders/${detail.order_id}`),
|
|
3240
|
+
children: detail.order_id
|
|
3241
|
+
}
|
|
3242
|
+
) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
|
|
3243
|
+
] }),
|
|
3244
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3245
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
3246
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
|
|
3247
|
+
] }),
|
|
3248
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3249
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
3250
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
|
|
3251
|
+
] }),
|
|
3252
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3253
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
3254
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
3255
|
+
Badge,
|
|
3256
|
+
{
|
|
3257
|
+
size: "2xsmall",
|
|
3258
|
+
className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
|
|
3259
|
+
children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
|
|
3260
|
+
}
|
|
3261
|
+
) })
|
|
3262
|
+
] }),
|
|
3263
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3264
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
|
|
3265
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
|
|
3266
|
+
] }),
|
|
3267
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3268
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
|
|
3269
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
|
|
3270
|
+
] }),
|
|
3271
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3272
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
|
|
3273
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
|
|
3274
|
+
] }),
|
|
3275
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3276
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
|
|
3277
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
|
|
3278
|
+
year: "numeric",
|
|
3279
|
+
month: "short",
|
|
3280
|
+
day: "numeric",
|
|
3281
|
+
hour: "numeric",
|
|
3282
|
+
minute: "2-digit",
|
|
3283
|
+
hour12: true
|
|
3284
|
+
}) })
|
|
3285
|
+
] })
|
|
3286
|
+
] }) }),
|
|
3287
|
+
Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3288
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
|
|
3289
|
+
/* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.data, null, 2) })
|
|
3290
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No provider data for this session." }) })
|
|
3291
|
+
] }) : null
|
|
3292
|
+
] }) });
|
|
3293
|
+
};
|
|
3294
|
+
const config$4 = defineRouteConfig({
|
|
3295
|
+
label: "Payment details",
|
|
3296
|
+
icon: CreditCard
|
|
3297
|
+
});
|
|
3298
|
+
const getStatusBadgeClass$2 = (status) => {
|
|
3299
|
+
const s2 = status.toLowerCase();
|
|
3300
|
+
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
3301
|
+
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
3302
|
+
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
3303
|
+
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
3304
|
+
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
3305
|
+
};
|
|
3306
|
+
const formatAmount = (value) => {
|
|
3307
|
+
return String(value);
|
|
3308
|
+
};
|
|
3309
|
+
const RefundDetailPage = () => {
|
|
3310
|
+
const navigate = useNavigate();
|
|
3311
|
+
const params = useParams();
|
|
3312
|
+
const id = params?.id?.trim();
|
|
3313
|
+
const [detail, setDetail] = useState(null);
|
|
3314
|
+
const [loading, setLoading] = useState(!!id);
|
|
3315
|
+
const [error, setError] = useState(null);
|
|
3316
|
+
const [gatewayExpanded, setGatewayExpanded] = useState(false);
|
|
3317
|
+
useEffect(() => {
|
|
3318
|
+
if (!id) {
|
|
3319
|
+
setLoading(false);
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
let cancelled = false;
|
|
3323
|
+
setLoading(true);
|
|
3324
|
+
setError(null);
|
|
3325
|
+
fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
|
|
3326
|
+
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
3327
|
+
return res.json();
|
|
3328
|
+
}).then((data) => {
|
|
3329
|
+
if (!cancelled) setDetail(data);
|
|
3330
|
+
}).catch((e) => {
|
|
3331
|
+
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
3332
|
+
}).finally(() => {
|
|
3333
|
+
if (!cancelled) setLoading(false);
|
|
3334
|
+
});
|
|
3335
|
+
return () => {
|
|
3336
|
+
cancelled = true;
|
|
3337
|
+
};
|
|
3338
|
+
}, [id]);
|
|
3339
|
+
const paymentStatus = detail?.payment?.status ?? "—";
|
|
3340
|
+
const hasGatewayData = detail?.payment?.payment_data && typeof detail.payment.payment_data === "object" && Object.keys(detail.payment.payment_data).length > 0;
|
|
3341
|
+
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: [
|
|
3342
|
+
/* @__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: [
|
|
3343
|
+
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
|
|
3344
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
|
|
3345
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
|
|
3346
|
+
] }) }),
|
|
3347
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
3348
|
+
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
3349
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
|
|
3350
|
+
] }) : 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: [
|
|
3351
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3352
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
|
|
3353
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3354
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3355
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund ID" }),
|
|
3356
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.id })
|
|
3357
|
+
] }),
|
|
3358
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3359
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
3360
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.refund.amount) })
|
|
3361
|
+
] }),
|
|
3362
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3363
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Note" }),
|
|
3364
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.refund.note ?? "—" })
|
|
3365
|
+
] }),
|
|
3366
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3367
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created at" }),
|
|
3368
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.refund.created_at).toLocaleDateString("en-US", {
|
|
3369
|
+
year: "numeric",
|
|
3370
|
+
month: "short",
|
|
3371
|
+
day: "numeric",
|
|
3372
|
+
hour: "numeric",
|
|
3373
|
+
minute: "2-digit",
|
|
3374
|
+
hour12: true
|
|
3375
|
+
}) })
|
|
3376
|
+
] }),
|
|
3377
|
+
detail.refund.created_by ? /* @__PURE__ */ jsxs("div", { children: [
|
|
3378
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created by" }),
|
|
3379
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.created_by })
|
|
3380
|
+
] }) : null
|
|
3381
|
+
] })
|
|
3382
|
+
] }),
|
|
3383
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3384
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
|
|
3385
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3386
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3387
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
|
|
3388
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
|
|
3389
|
+
] }),
|
|
3390
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3391
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
|
|
3392
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
|
|
3393
|
+
] }),
|
|
3394
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3395
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
|
|
3396
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
|
|
3397
|
+
] }),
|
|
3398
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3399
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
3400
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
|
|
3401
|
+
] }),
|
|
3402
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3403
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
3404
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
3405
|
+
Badge,
|
|
3406
|
+
{
|
|
3407
|
+
size: "2xsmall",
|
|
3408
|
+
className: `uppercase ${getStatusBadgeClass$2(paymentStatus)}`,
|
|
3409
|
+
children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
|
|
3410
|
+
}
|
|
3411
|
+
) })
|
|
3412
|
+
] }),
|
|
3413
|
+
detail.computed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3414
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3415
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Full refund" }),
|
|
3416
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.computed.is_full_refund ? "Yes" : "No" })
|
|
3417
|
+
] }),
|
|
3418
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3419
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Remaining refundable" }),
|
|
3420
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.computed.remaining_refundable_amount) })
|
|
3421
|
+
] }),
|
|
3422
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3423
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund %" }),
|
|
3424
|
+
/* @__PURE__ */ jsxs(Text, { className: "mt-1 block", children: [
|
|
3425
|
+
detail.computed.refund_percentage.toFixed(1),
|
|
3426
|
+
"%"
|
|
3427
|
+
] })
|
|
3428
|
+
] })
|
|
3429
|
+
] }) : null
|
|
3430
|
+
] })
|
|
3431
|
+
] }),
|
|
3432
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3433
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Order summary" }),
|
|
3434
|
+
detail.order ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
3435
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3436
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order" }),
|
|
3437
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
3149
3438
|
Button,
|
|
3150
3439
|
{
|
|
3151
3440
|
variant: "transparent",
|
|
3152
3441
|
size: "small",
|
|
3153
|
-
onClick: (
|
|
3154
|
-
|
|
3155
|
-
navigate(`/app/orders/${swap.order_id}`);
|
|
3156
|
-
},
|
|
3157
|
-
children: "Go to order"
|
|
3442
|
+
onClick: () => navigate(`/orders/${detail.order.order_id}`),
|
|
3443
|
+
children: detail.order.order_number ?? detail.order.order_id
|
|
3158
3444
|
}
|
|
3159
3445
|
) })
|
|
3160
|
-
]
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3446
|
+
] }),
|
|
3447
|
+
detail.order.total != null ? /* @__PURE__ */ jsxs("div", { children: [
|
|
3448
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Total" }),
|
|
3449
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.order.total) })
|
|
3450
|
+
] }) : null,
|
|
3451
|
+
detail.order.customer_id ? /* @__PURE__ */ jsxs("div", { children: [
|
|
3452
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Customer ID" }),
|
|
3453
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.order.customer_id })
|
|
3454
|
+
] }) : null,
|
|
3455
|
+
detail.order.region ? /* @__PURE__ */ jsxs("div", { children: [
|
|
3456
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Region" }),
|
|
3457
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.region })
|
|
3458
|
+
] }) : null,
|
|
3459
|
+
detail.order.fulfillment_status ? /* @__PURE__ */ jsxs("div", { children: [
|
|
3460
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
|
|
3461
|
+
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
|
|
3462
|
+
] }) : null
|
|
3463
|
+
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
|
|
3464
|
+
] }),
|
|
3465
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
3466
|
+
/* @__PURE__ */ jsxs(
|
|
3467
|
+
"button",
|
|
3468
|
+
{
|
|
3469
|
+
type: "button",
|
|
3470
|
+
className: "flex w-full items-center justify-between text-left",
|
|
3471
|
+
onClick: () => setGatewayExpanded((prev) => !prev),
|
|
3472
|
+
"aria-expanded": gatewayExpanded,
|
|
3473
|
+
"aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
|
|
3474
|
+
children: [
|
|
3475
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
|
|
3476
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
|
|
3477
|
+
]
|
|
3478
|
+
}
|
|
3479
|
+
),
|
|
3480
|
+
gatewayExpanded && /* @__PURE__ */ jsx("div", { className: "mt-4", children: hasGatewayData ? /* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.payment.payment_data, null, 2) }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No gateway payload for this payment." }) })
|
|
3481
|
+
] })
|
|
3482
|
+
] }) : null
|
|
3174
3483
|
] }) });
|
|
3175
3484
|
};
|
|
3176
|
-
const config$
|
|
3177
|
-
label: "
|
|
3178
|
-
icon:
|
|
3485
|
+
const config$3 = defineRouteConfig({
|
|
3486
|
+
label: "Refund details",
|
|
3487
|
+
icon: Receipt
|
|
3179
3488
|
});
|
|
3180
3489
|
const MASKED_VALUE = "••••••••••••";
|
|
3181
3490
|
const SENSITIVE_KEY_PATTERNS = [
|
|
@@ -3918,126 +4227,8 @@ const DetailError = ({
|
|
|
3918
4227
|
!notFound ? /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: onRetry, children: "Try again" }) : null
|
|
3919
4228
|
] })
|
|
3920
4229
|
] });
|
|
3921
|
-
const config$
|
|
3922
|
-
const getStatusBadgeClass$
|
|
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) => {
|
|
4230
|
+
const config$2 = defineRouteConfig({});
|
|
4231
|
+
const getStatusBadgeClass$1 = (status) => {
|
|
4041
4232
|
const statusLower = status.toLowerCase();
|
|
4042
4233
|
if (statusLower === "requested") {
|
|
4043
4234
|
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
@@ -4170,7 +4361,7 @@ const ReturnDetailPage = () => {
|
|
|
4170
4361
|
Badge,
|
|
4171
4362
|
{
|
|
4172
4363
|
size: "small",
|
|
4173
|
-
className: `uppercase ${getStatusBadgeClass$
|
|
4364
|
+
className: `uppercase ${getStatusBadgeClass$1(returnOrder.status)}`,
|
|
4174
4365
|
children: returnOrder.status.replace(/_/g, " ")
|
|
4175
4366
|
}
|
|
4176
4367
|
)
|
|
@@ -4253,7 +4444,7 @@ const ReturnDetailPage = () => {
|
|
|
4253
4444
|
Badge,
|
|
4254
4445
|
{
|
|
4255
4446
|
size: "2xsmall",
|
|
4256
|
-
className: `uppercase ${getStatusBadgeClass$
|
|
4447
|
+
className: `uppercase ${getStatusBadgeClass$1(entry.status)}`,
|
|
4257
4448
|
children: entry.status.replace(/_/g, " ")
|
|
4258
4449
|
}
|
|
4259
4450
|
) }),
|
|
@@ -4315,11 +4506,11 @@ const ReturnDetailPage = () => {
|
|
|
4315
4506
|
updateSuccess && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-ui-border-success bg-ui-bg-success-subtle p-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-success", children: "Action completed successfully" }) })
|
|
4316
4507
|
] }) });
|
|
4317
4508
|
};
|
|
4318
|
-
const config$
|
|
4509
|
+
const config$1 = defineRouteConfig({
|
|
4319
4510
|
label: "Return Order Details",
|
|
4320
4511
|
icon: CheckCircle
|
|
4321
4512
|
});
|
|
4322
|
-
const getStatusBadgeClass
|
|
4513
|
+
const getStatusBadgeClass = (status) => {
|
|
4323
4514
|
const statusLower = status.toLowerCase();
|
|
4324
4515
|
if (statusLower === "requested") {
|
|
4325
4516
|
return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
@@ -4456,7 +4647,7 @@ const SwapDetailPage = () => {
|
|
|
4456
4647
|
Badge,
|
|
4457
4648
|
{
|
|
4458
4649
|
size: "small",
|
|
4459
|
-
className: `uppercase ${getStatusBadgeClass
|
|
4650
|
+
className: `uppercase ${getStatusBadgeClass(swap.status)}`,
|
|
4460
4651
|
children: swap.status.replace(/_/g, " ")
|
|
4461
4652
|
}
|
|
4462
4653
|
)
|
|
@@ -4524,7 +4715,7 @@ const SwapDetailPage = () => {
|
|
|
4524
4715
|
Badge,
|
|
4525
4716
|
{
|
|
4526
4717
|
size: "2xsmall",
|
|
4527
|
-
className: `uppercase ${getStatusBadgeClass
|
|
4718
|
+
className: `uppercase ${getStatusBadgeClass(entry.status)}`,
|
|
4528
4719
|
children: entry.status.replace(/_/g, " ")
|
|
4529
4720
|
}
|
|
4530
4721
|
) }),
|
|
@@ -4593,201 +4784,10 @@ const SwapDetailPage = () => {
|
|
|
4593
4784
|
] })
|
|
4594
4785
|
] }) });
|
|
4595
4786
|
};
|
|
4596
|
-
const config
|
|
4787
|
+
const config = defineRouteConfig({
|
|
4597
4788
|
label: "Swap Details",
|
|
4598
4789
|
icon: ArrowPath
|
|
4599
4790
|
});
|
|
4600
|
-
const getStatusBadgeClass = (status) => {
|
|
4601
|
-
const s2 = status.toLowerCase();
|
|
4602
|
-
if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
|
|
4603
|
-
if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
|
|
4604
|
-
if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
|
|
4605
|
-
if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
|
|
4606
|
-
return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
|
|
4607
|
-
};
|
|
4608
|
-
const formatAmount = (value) => {
|
|
4609
|
-
return String(value);
|
|
4610
|
-
};
|
|
4611
|
-
const RefundDetailPage = () => {
|
|
4612
|
-
const navigate = useNavigate();
|
|
4613
|
-
const params = useParams();
|
|
4614
|
-
const id = params?.id?.trim();
|
|
4615
|
-
const [detail, setDetail] = useState(null);
|
|
4616
|
-
const [loading, setLoading] = useState(!!id);
|
|
4617
|
-
const [error, setError] = useState(null);
|
|
4618
|
-
const [gatewayExpanded, setGatewayExpanded] = useState(false);
|
|
4619
|
-
useEffect(() => {
|
|
4620
|
-
if (!id) {
|
|
4621
|
-
setLoading(false);
|
|
4622
|
-
return;
|
|
4623
|
-
}
|
|
4624
|
-
let cancelled = false;
|
|
4625
|
-
setLoading(true);
|
|
4626
|
-
setError(null);
|
|
4627
|
-
fetch(`/admin/refunds/${id}`, { credentials: "include" }).then((res) => {
|
|
4628
|
-
if (!res.ok) throw new Error(res.statusText || "Failed to load");
|
|
4629
|
-
return res.json();
|
|
4630
|
-
}).then((data) => {
|
|
4631
|
-
if (!cancelled) setDetail(data);
|
|
4632
|
-
}).catch((e) => {
|
|
4633
|
-
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
|
|
4634
|
-
}).finally(() => {
|
|
4635
|
-
if (!cancelled) setLoading(false);
|
|
4636
|
-
});
|
|
4637
|
-
return () => {
|
|
4638
|
-
cancelled = true;
|
|
4639
|
-
};
|
|
4640
|
-
}, [id]);
|
|
4641
|
-
const paymentStatus = detail?.payment?.status ?? "—";
|
|
4642
|
-
const hasGatewayData = detail?.payment?.payment_data && typeof detail.payment.payment_data === "object" && Object.keys(detail.payment.payment_data).length > 0;
|
|
4643
|
-
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: [
|
|
4644
|
-
/* @__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: [
|
|
4645
|
-
/* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/refunds"), children: "← Refunds" }),
|
|
4646
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Refund details" }),
|
|
4647
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle font-mono", children: id ?? "—" })
|
|
4648
|
-
] }) }),
|
|
4649
|
-
error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
|
|
4650
|
-
/* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
|
|
4651
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/refunds"), children: "Back to list" })
|
|
4652
|
-
] }) : 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: [
|
|
4653
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4654
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Refund summary" }),
|
|
4655
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4656
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4657
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund ID" }),
|
|
4658
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.id })
|
|
4659
|
-
] }),
|
|
4660
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4661
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
|
|
4662
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.refund.amount) })
|
|
4663
|
-
] }),
|
|
4664
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4665
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Note" }),
|
|
4666
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.refund.note ?? "—" })
|
|
4667
|
-
] }),
|
|
4668
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4669
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created at" }),
|
|
4670
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.refund.created_at).toLocaleDateString("en-US", {
|
|
4671
|
-
year: "numeric",
|
|
4672
|
-
month: "short",
|
|
4673
|
-
day: "numeric",
|
|
4674
|
-
hour: "numeric",
|
|
4675
|
-
minute: "2-digit",
|
|
4676
|
-
hour12: true
|
|
4677
|
-
}) })
|
|
4678
|
-
] }),
|
|
4679
|
-
detail.refund.created_by ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4680
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created by" }),
|
|
4681
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.refund.created_by })
|
|
4682
|
-
] }) : null
|
|
4683
|
-
] })
|
|
4684
|
-
] }),
|
|
4685
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4686
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Payment summary" }),
|
|
4687
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4688
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4689
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment amount" }),
|
|
4690
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.payment_amount) })
|
|
4691
|
-
] }),
|
|
4692
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4693
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Captured amount" }),
|
|
4694
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.captured_amount) })
|
|
4695
|
-
] }),
|
|
4696
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4697
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refunded amount" }),
|
|
4698
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.payment.refunded_amount) })
|
|
4699
|
-
] }),
|
|
4700
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4701
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
|
|
4702
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment.provider_id || "—" })
|
|
4703
|
-
] }),
|
|
4704
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4705
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
|
|
4706
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
4707
|
-
Badge,
|
|
4708
|
-
{
|
|
4709
|
-
size: "2xsmall",
|
|
4710
|
-
className: `uppercase ${getStatusBadgeClass(paymentStatus)}`,
|
|
4711
|
-
children: paymentStatus !== "—" ? paymentStatus.replace(/_/g, " ") : "—"
|
|
4712
|
-
}
|
|
4713
|
-
) })
|
|
4714
|
-
] }),
|
|
4715
|
-
detail.computed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4716
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4717
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Full refund" }),
|
|
4718
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.computed.is_full_refund ? "Yes" : "No" })
|
|
4719
|
-
] }),
|
|
4720
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4721
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Remaining refundable" }),
|
|
4722
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.computed.remaining_refundable_amount) })
|
|
4723
|
-
] }),
|
|
4724
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4725
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Refund %" }),
|
|
4726
|
-
/* @__PURE__ */ jsxs(Text, { className: "mt-1 block", children: [
|
|
4727
|
-
detail.computed.refund_percentage.toFixed(1),
|
|
4728
|
-
"%"
|
|
4729
|
-
] })
|
|
4730
|
-
] })
|
|
4731
|
-
] }) : null
|
|
4732
|
-
] })
|
|
4733
|
-
] }),
|
|
4734
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4735
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Order summary" }),
|
|
4736
|
-
detail.order ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
|
|
4737
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4738
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order" }),
|
|
4739
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
4740
|
-
Button,
|
|
4741
|
-
{
|
|
4742
|
-
variant: "transparent",
|
|
4743
|
-
size: "small",
|
|
4744
|
-
onClick: () => navigate(`/orders/${detail.order.order_id}`),
|
|
4745
|
-
children: detail.order.order_number ?? detail.order.order_id
|
|
4746
|
-
}
|
|
4747
|
-
) })
|
|
4748
|
-
] }),
|
|
4749
|
-
detail.order.total != null ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4750
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Total" }),
|
|
4751
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: formatAmount(detail.order.total) })
|
|
4752
|
-
] }) : null,
|
|
4753
|
-
detail.order.customer_id ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4754
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Customer ID" }),
|
|
4755
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block font-mono text-sm", children: detail.order.customer_id })
|
|
4756
|
-
] }) : null,
|
|
4757
|
-
detail.order.region ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4758
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Region" }),
|
|
4759
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.region })
|
|
4760
|
-
] }) : null,
|
|
4761
|
-
detail.order.fulfillment_status ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4762
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Fulfillment status" }),
|
|
4763
|
-
/* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.order.fulfillment_status })
|
|
4764
|
-
] }) : null
|
|
4765
|
-
] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No order linked to this refund." })
|
|
4766
|
-
] }),
|
|
4767
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
|
|
4768
|
-
/* @__PURE__ */ jsxs(
|
|
4769
|
-
"button",
|
|
4770
|
-
{
|
|
4771
|
-
type: "button",
|
|
4772
|
-
className: "flex w-full items-center justify-between text-left",
|
|
4773
|
-
onClick: () => setGatewayExpanded((prev) => !prev),
|
|
4774
|
-
"aria-expanded": gatewayExpanded,
|
|
4775
|
-
"aria-label": gatewayExpanded ? "Collapse gateway data" : "Expand gateway data",
|
|
4776
|
-
children: [
|
|
4777
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg", children: "Gateway data" }),
|
|
4778
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: gatewayExpanded ? "Collapse" : "Expand" })
|
|
4779
|
-
]
|
|
4780
|
-
}
|
|
4781
|
-
),
|
|
4782
|
-
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." }) })
|
|
4783
|
-
] })
|
|
4784
|
-
] }) : null
|
|
4785
|
-
] }) });
|
|
4786
|
-
};
|
|
4787
|
-
const config = defineRouteConfig({
|
|
4788
|
-
label: "Refund details",
|
|
4789
|
-
icon: Receipt
|
|
4790
|
-
});
|
|
4791
4791
|
const i18nTranslations0 = {};
|
|
4792
4792
|
const widgetModule = { widgets: [
|
|
4793
4793
|
{
|
|
@@ -4803,24 +4803,24 @@ const widgetModule = { widgets: [
|
|
|
4803
4803
|
] };
|
|
4804
4804
|
const routeModule = {
|
|
4805
4805
|
routes: [
|
|
4806
|
-
{
|
|
4807
|
-
Component: DeletedRecordsPage,
|
|
4808
|
-
path: "/deleted-records-audit",
|
|
4809
|
-
handle: { label: config$9.label, translationNs: config$9.translationNs }
|
|
4810
|
-
},
|
|
4811
4806
|
{
|
|
4812
4807
|
Component: PaymentsPage,
|
|
4813
4808
|
path: "/payments",
|
|
4814
|
-
handle: { label: config$
|
|
4809
|
+
handle: { label: config$9.label, translationNs: config$9.translationNs }
|
|
4815
4810
|
},
|
|
4816
4811
|
{
|
|
4817
4812
|
Component: RefundsPage,
|
|
4818
4813
|
path: "/refunds",
|
|
4819
|
-
handle: { label: config$
|
|
4814
|
+
handle: { label: config$8.label, translationNs: config$8.translationNs }
|
|
4820
4815
|
},
|
|
4821
4816
|
{
|
|
4822
4817
|
Component: ReturnsPage,
|
|
4823
4818
|
path: "/returns",
|
|
4819
|
+
handle: { label: config$7.label, translationNs: config$7.translationNs }
|
|
4820
|
+
},
|
|
4821
|
+
{
|
|
4822
|
+
Component: DeletedRecordsPage,
|
|
4823
|
+
path: "/deleted-records-audit",
|
|
4824
4824
|
handle: { label: config$6.label, translationNs: config$6.translationNs }
|
|
4825
4825
|
},
|
|
4826
4826
|
{
|
|
@@ -4829,28 +4829,28 @@ const routeModule = {
|
|
|
4829
4829
|
handle: { label: config$5.label, translationNs: config$5.translationNs }
|
|
4830
4830
|
},
|
|
4831
4831
|
{
|
|
4832
|
-
Component:
|
|
4833
|
-
path: "/
|
|
4832
|
+
Component: PaymentDetailPage,
|
|
4833
|
+
path: "/payments/:id",
|
|
4834
4834
|
handle: { label: config$4.label, translationNs: config$4.translationNs }
|
|
4835
4835
|
},
|
|
4836
4836
|
{
|
|
4837
|
-
Component:
|
|
4838
|
-
path: "/
|
|
4837
|
+
Component: RefundDetailPage,
|
|
4838
|
+
path: "/refunds/:id",
|
|
4839
4839
|
handle: { label: config$3.label, translationNs: config$3.translationNs }
|
|
4840
4840
|
},
|
|
4841
4841
|
{
|
|
4842
|
-
Component:
|
|
4843
|
-
path: "/
|
|
4842
|
+
Component: DeletedRecordDetailPage,
|
|
4843
|
+
path: "/deleted-records-audit/:id",
|
|
4844
4844
|
handle: { label: config$2.label, translationNs: config$2.translationNs }
|
|
4845
4845
|
},
|
|
4846
4846
|
{
|
|
4847
|
-
Component:
|
|
4848
|
-
path: "/
|
|
4847
|
+
Component: ReturnDetailPage,
|
|
4848
|
+
path: "/returns/:id",
|
|
4849
4849
|
handle: { label: config$1.label, translationNs: config$1.translationNs }
|
|
4850
4850
|
},
|
|
4851
4851
|
{
|
|
4852
|
-
Component:
|
|
4853
|
-
path: "/
|
|
4852
|
+
Component: SwapDetailPage,
|
|
4853
|
+
path: "/swaps/:id",
|
|
4854
4854
|
handle: { label: config.label, translationNs: config.translationNs }
|
|
4855
4855
|
}
|
|
4856
4856
|
]
|
|
@@ -4858,32 +4858,32 @@ const routeModule = {
|
|
|
4858
4858
|
const menuItemModule = {
|
|
4859
4859
|
menuItems: [
|
|
4860
4860
|
{
|
|
4861
|
-
label: config$
|
|
4862
|
-
icon: config$
|
|
4861
|
+
label: config$6.label,
|
|
4862
|
+
icon: config$6.icon,
|
|
4863
4863
|
path: "/deleted-records-audit",
|
|
4864
4864
|
nested: void 0,
|
|
4865
4865
|
rank: void 0,
|
|
4866
4866
|
translationNs: void 0
|
|
4867
4867
|
},
|
|
4868
4868
|
{
|
|
4869
|
-
label: config$
|
|
4870
|
-
icon: config$
|
|
4869
|
+
label: config$9.label,
|
|
4870
|
+
icon: config$9.icon,
|
|
4871
4871
|
path: "/payments",
|
|
4872
4872
|
nested: void 0,
|
|
4873
4873
|
rank: void 0,
|
|
4874
4874
|
translationNs: void 0
|
|
4875
4875
|
},
|
|
4876
4876
|
{
|
|
4877
|
-
label: config$
|
|
4878
|
-
icon: config$
|
|
4877
|
+
label: config$8.label,
|
|
4878
|
+
icon: config$8.icon,
|
|
4879
4879
|
path: "/refunds",
|
|
4880
4880
|
nested: void 0,
|
|
4881
4881
|
rank: void 0,
|
|
4882
4882
|
translationNs: void 0
|
|
4883
4883
|
},
|
|
4884
4884
|
{
|
|
4885
|
-
label: config$
|
|
4886
|
-
icon: config$
|
|
4885
|
+
label: config$7.label,
|
|
4886
|
+
icon: config$7.icon,
|
|
4887
4887
|
path: "/returns",
|
|
4888
4888
|
nested: void 0,
|
|
4889
4889
|
rank: void 0,
|
|
@@ -4898,32 +4898,32 @@ const menuItemModule = {
|
|
|
4898
4898
|
translationNs: void 0
|
|
4899
4899
|
},
|
|
4900
4900
|
{
|
|
4901
|
-
label: config$
|
|
4902
|
-
icon: config$
|
|
4901
|
+
label: config$4.label,
|
|
4902
|
+
icon: config$4.icon,
|
|
4903
4903
|
path: "/payments/:id",
|
|
4904
4904
|
nested: void 0,
|
|
4905
4905
|
rank: void 0,
|
|
4906
4906
|
translationNs: void 0
|
|
4907
4907
|
},
|
|
4908
4908
|
{
|
|
4909
|
-
label: config.label,
|
|
4910
|
-
icon: config.icon,
|
|
4909
|
+
label: config$3.label,
|
|
4910
|
+
icon: config$3.icon,
|
|
4911
4911
|
path: "/refunds/:id",
|
|
4912
4912
|
nested: void 0,
|
|
4913
4913
|
rank: void 0,
|
|
4914
4914
|
translationNs: void 0
|
|
4915
4915
|
},
|
|
4916
4916
|
{
|
|
4917
|
-
label: config$
|
|
4918
|
-
icon: config$
|
|
4917
|
+
label: config$1.label,
|
|
4918
|
+
icon: config$1.icon,
|
|
4919
4919
|
path: "/returns/:id",
|
|
4920
4920
|
nested: void 0,
|
|
4921
4921
|
rank: void 0,
|
|
4922
4922
|
translationNs: void 0
|
|
4923
4923
|
},
|
|
4924
4924
|
{
|
|
4925
|
-
label: config
|
|
4926
|
-
icon: config
|
|
4925
|
+
label: config.label,
|
|
4926
|
+
icon: config.icon,
|
|
4927
4927
|
path: "/swaps/:id",
|
|
4928
4928
|
nested: void 0,
|
|
4929
4929
|
rank: void 0,
|