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, useMemo, useCallback } from "react";
4
- import { Text, Container, Heading, Badge, Button, Label, Select, Textarea, Popover, clx, Input, Copy, Skeleton, Tooltip, toast } from "@medusajs/ui";
5
- import { CashSolid, PencilSquareSolid, Trash, ChevronDownMini, Check, ArrowPath, InformationCircle, ExclamationCircle, MagnifierAlert, ChevronRightMini, CreditCard, Receipt, ArrowLeft, ClockSolid, ShieldCheck, SquareTwoStack, CheckCircle } from "@medusajs/icons";
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$8 = defineRouteConfig({
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: "cursor-pointer hover:bg-ui-bg-subtle/60",
2640
- onClick: () => navigate(`/refunds/${r.refund_id}`),
1589
+ className: "hover:bg-ui-bg-subtle/60 cursor-pointer",
1590
+ onClick: () => navigate(`/returns/${returnOrder.id}`),
2641
1591
  children: [
2642
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-base", title: r.refund_id, children: r.refund_id }),
2643
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-medium text-ui-fg-base", title: r.order_id ?? void 0, children: r.order_id ?? "—" }),
2644
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 font-mono text-sm text-ui-fg-subtle", title: r.payment_id, children: r.payment_id }),
2645
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", children: displayAmount(r) }),
2646
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle uppercase", children: r.currency_code || "—" }),
2647
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.provider_id || void 0, children: r.provider_id || "—" }),
2648
- /* @__PURE__ */ jsx("td", { className: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsx(
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$6(displayStatus(r))}`,
2653
- children: displayStatus(r) !== "—" ? displayStatus(r).replace(/_/g, " ") : "—"
1599
+ className: `uppercase ${getStatusBadgeClass$5(returnOrder.status)}`,
1600
+ children: returnOrder.status.replace(/_/g, " ")
2654
1601
  }
2655
1602
  ) }),
2656
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle", title: r.note ?? void 0, children: r.note ?? "—" }),
2657
- /* @__PURE__ */ jsx("td", { className: "min-w-0 truncate px-3 py-3 text-ui-fg-subtle text-xs", children: new Date(r.created_at).toLocaleDateString("en-US", {
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: "min-w-0 px-3 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
2665
- /* @__PURE__ */ jsx(
2666
- Button,
2667
- {
2668
- variant: "transparent",
2669
- size: "small",
2670
- onClick: (e) => {
2671
- e.stopPropagation();
2672
- navigate(`/refunds/${r.refund_id}`);
2673
- },
2674
- children: "Details"
2675
- }
2676
- ),
2677
- r.order_id ? /* @__PURE__ */ jsx(
2678
- Button,
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
- variant: "transparent",
2174
+ ref: searchRef,
2681
2175
  size: "small",
2682
- onClick: (e) => {
2683
- e.stopPropagation();
2684
- navigate(`/orders/${r.order_id}`);
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
- children: "Order"
2186
+ "aria-label": "Search entities"
2687
2187
  }
2688
- ) : null
2689
- ] }) })
2690
- ]
2691
- },
2692
- r.refund_id
2693
- )) })
2694
- ] }) }),
2695
- hasMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
2696
- Button,
2697
- {
2698
- variant: "secondary",
2699
- isLoading: isFetchingMore,
2700
- onClick: () => loadRefunds(offset, false),
2701
- children: "Load more"
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
- ) }) : null
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 config$7 = defineRouteConfig({
2707
- label: "Refunds",
2708
- icon: Receipt
2709
- });
2710
- const useDebounce$1 = (value, delay) => {
2711
- const [debouncedValue, setDebouncedValue] = useState(value);
2712
- useEffect(() => {
2713
- const handler = setTimeout(() => setDebouncedValue(value), delay);
2714
- return () => clearTimeout(handler);
2715
- }, [value, delay]);
2716
- return debouncedValue;
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 getStatusBadgeClass$5 = (status) => {
2719
- const statusLower = status.toLowerCase();
2720
- if (statusLower === "requested") {
2721
- return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
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
- if (statusLower === "received") {
2724
- return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
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
- if (statusLower === "requires_action") {
2727
- return "bg-ui-tag-red-bg text-ui-tag-red-text";
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
- if (statusLower === "completed") {
2730
- return "bg-ui-tag-green-bg text-ui-tag-green-text";
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
- if (statusLower === "canceled") {
2733
- return "bg-ui-tag-grey-bg text-ui-tag-grey-text";
2546
+ }
2547
+ function writeSession(key, value) {
2548
+ try {
2549
+ window.sessionStorage.setItem(key, value);
2550
+ } catch {
2734
2551
  }
2735
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
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 [statusFilter, setStatusFilter] = useState("all");
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 [offset, setOffset] = useState(0);
2748
- const [count, setCount] = useState(0);
2749
- const limit = 50;
2750
- const loadReturns = useCallback(
2751
- async (nextOffset, replace = false) => {
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
- if (replace) {
2754
- setIsLoading(true);
2755
- } else {
2756
- setIsFetchingMore(true);
2757
- }
2758
- setError(null);
2759
- const params = new URLSearchParams();
2760
- params.set("limit", String(limit));
2761
- params.set("offset", String(nextOffset));
2762
- if (statusFilter !== "all") {
2763
- params.set("status", statusFilter);
2764
- }
2765
- if (debouncedSearchQuery.trim()) {
2766
- params.set("q", debouncedSearchQuery.trim());
2767
- }
2768
- if (createdByFilter !== "all") {
2769
- params.set("created_by", createdByFilter);
2770
- }
2771
- params.set("order", "created_at");
2772
- const response = await fetch(
2773
- `/admin/return?${params.toString()}`,
2774
- { credentials: "include" }
2775
- );
2776
- if (!response.ok) {
2777
- const message = await response.text();
2778
- throw new Error(message || "Unable to load return orders");
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
- const payload = await response.json();
2781
- setCount(payload.count ?? 0);
2782
- setOffset(nextOffset + (payload.returns?.length ?? 0));
2783
- setItems(
2784
- (prev) => replace ? payload.returns ?? [] : [...prev, ...payload.returns ?? []]
2785
- );
2786
- } catch (loadError) {
2787
- const message = loadError instanceof Error ? loadError.message : "Unable to load return orders";
2788
- setError(message);
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
- [statusFilter, createdByFilter, debouncedSearchQuery]
2795
- );
2639
+ })();
2640
+ return () => controller.abort();
2641
+ }, [filterKey, reloadToken]);
2796
2642
  useEffect(() => {
2797
- void loadReturns(0, true);
2798
- }, [statusFilter, createdByFilter, debouncedSearchQuery, loadReturns]);
2799
- const hasMore = useMemo(() => offset < count, [offset, count]);
2800
- const availableStatuses = useMemo(() => {
2801
- const statuses = /* @__PURE__ */ new Set();
2802
- items.forEach((item) => statuses.add(item.status));
2803
- return Array.from(statuses).sort();
2804
- }, [items]);
2805
- return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-7xl flex-col gap-6 p-6", children: [
2806
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
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: "Return Orders" }),
2809
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "View and manage all customer return orders" })
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__ */ jsx(Button, { variant: "primary", onClick: () => loadReturns(0, true), children: "Refresh" })
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__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
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
- placeholder: "Search by return ID, order ID, or customer email",
2818
- value: searchQuery,
2819
- onChange: (event) => setSearchQuery(event.target.value),
2820
- className: "md:max-w-sm"
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-3", children: [
2824
- /* @__PURE__ */ jsxs(
2825
- "select",
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
- value: createdByFilter,
2828
- onChange: (event) => setCreatedByFilter(event.target.value),
2829
- className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive md:max-w-xs",
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("option", { value: "all", children: "All (Created by)" }),
2832
- /* @__PURE__ */ jsx("option", { value: "customer", children: "Customer" }),
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
- "select",
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
- value: statusFilter,
2841
- onChange: (event) => setStatusFilter(event.target.value),
2842
- className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive md:max-w-xs",
2759
+ size: "small",
2760
+ value: filters.source || ALL,
2761
+ onValueChange: (value) => updateFilters({ source: value === ALL ? "" : value }),
2843
2762
  children: [
2844
- /* @__PURE__ */ jsx("option", { value: "all", children: "All Statuses" }),
2845
- availableStatuses.map((status) => /* @__PURE__ */ jsx("option", { value: status, children: status.replace(/_/g, " ").toUpperCase() }, status))
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
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
2852
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
2853
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsx(
2854
- Button,
2855
- {
2856
- variant: "secondary",
2857
- onClick: () => loadReturns(0, true),
2858
- children: "Try again"
2859
- }
2860
- ) })
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 ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading return orders..." }) }) : items.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-dashed border-ui-border-strong p-10 text-center", children: [
2863
- /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-xl", children: "No return orders yet" }),
2864
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-2 text-ui-fg-subtle", children: "Return orders created by customers will appear here." })
2865
- ] }) : /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
2866
- /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2867
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Return ID" }),
2868
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Order ID" }),
2869
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Customer" }),
2870
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
2871
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Refund Amount" }),
2872
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
2873
- /* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
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
- variant: "secondary",
2940
- isLoading: isFetchingMore,
2941
- onClick: () => loadReturns(offset, false),
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
- ) }) : null
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: "Return Orders",
2949
- icon: ArrowPath
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: (e) => {
3154
- e.stopPropagation();
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
- 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
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$5 = defineRouteConfig({
3177
- label: "Exchanges",
3178
- icon: ArrowPath
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$4 = defineRouteConfig({});
3922
- const getStatusBadgeClass$3 = (status) => {
3923
- const s2 = status.toLowerCase();
3924
- if (s2 === "captured" || s2 === "completed") return "bg-ui-tag-green-bg text-ui-tag-green-text";
3925
- if (s2 === "authorized") return "bg-ui-tag-blue-bg text-ui-tag-blue-text";
3926
- if (s2 === "error" || s2 === "canceled" || s2 === "cancelled") return "bg-ui-tag-red-bg text-ui-tag-red-text";
3927
- if (s2 === "pending" || s2 === "requires_more") return "bg-ui-tag-orange-bg text-ui-tag-orange-text";
3928
- return "bg-ui-tag-purple-bg text-ui-tag-purple-text";
3929
- };
3930
- const PaymentDetailPage = () => {
3931
- const navigate = useNavigate();
3932
- const params = useParams();
3933
- const id = params?.id?.trim();
3934
- const [detail, setDetail] = useState(null);
3935
- const [loading, setLoading] = useState(!!id);
3936
- const [error, setError] = useState(null);
3937
- useEffect(() => {
3938
- if (!id) {
3939
- setLoading(false);
3940
- return;
3941
- }
3942
- let cancelled = false;
3943
- setLoading(true);
3944
- setError(null);
3945
- fetch(`/admin/payment-transactions/${id}`, { credentials: "include" }).then((res) => {
3946
- if (!res.ok) throw new Error(res.statusText || "Failed to load");
3947
- return res.json();
3948
- }).then((data) => {
3949
- if (!cancelled) setDetail(data);
3950
- }).catch((e) => {
3951
- if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load");
3952
- }).finally(() => {
3953
- if (!cancelled) setLoading(false);
3954
- });
3955
- return () => {
3956
- cancelled = true;
3957
- };
3958
- }, [id]);
3959
- const displayStatus = detail ? (detail.payment_id != null && detail.payment_status != null && detail.payment_status !== "" ? detail.payment_status : detail.session_status ?? "") || "—" : "";
3960
- const sessionStatusRaw = detail?.session_status ?? "—";
3961
- const paymentStatusRaw = detail?.payment_id != null ? detail?.payment_status ?? "—" : "—";
3962
- const displayAmount = detail ? `${(detail.currency_code ?? "USD").toUpperCase()} ${Number(detail.amount)}` : "";
3963
- return /* @__PURE__ */ jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxs(Container, { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 p-6", children: [
3964
- /* @__PURE__ */ jsx("header", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3965
- /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: () => navigate("/payments"), children: "← Payments" }),
3966
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Payment session" }),
3967
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: id ?? "—" })
3968
- ] }) }),
3969
- error ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-strong p-6 text-center", children: [
3970
- /* @__PURE__ */ jsx(Text, { weight: "plus", className: "text-ui-fg-error", children: error }),
3971
- /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: () => navigate("/payments"), children: "Back to list" })
3972
- ] }) : loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsx(Text, { children: "Loading…" }) }) : detail ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
3973
- /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6 flex flex-col gap-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
3974
- /* @__PURE__ */ jsxs("div", { children: [
3975
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Order ID" }),
3976
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: detail.order_id ? /* @__PURE__ */ jsx(
3977
- Button,
3978
- {
3979
- variant: "transparent",
3980
- size: "small",
3981
- onClick: () => navigate(`/orders/${detail.order_id}`),
3982
- children: detail.order_id
3983
- }
3984
- ) : /* @__PURE__ */ jsx(Text, { children: "—" }) })
3985
- ] }),
3986
- /* @__PURE__ */ jsxs("div", { children: [
3987
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Amount" }),
3988
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: displayAmount })
3989
- ] }),
3990
- /* @__PURE__ */ jsxs("div", { children: [
3991
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Provider" }),
3992
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.provider_id })
3993
- ] }),
3994
- /* @__PURE__ */ jsxs("div", { children: [
3995
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Status" }),
3996
- /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
3997
- Badge,
3998
- {
3999
- size: "2xsmall",
4000
- className: `uppercase ${getStatusBadgeClass$3(displayStatus)}`,
4001
- children: displayStatus !== "—" ? displayStatus.replace(/_/g, " ") : "—"
4002
- }
4003
- ) })
4004
- ] }),
4005
- /* @__PURE__ */ jsxs("div", { children: [
4006
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Session status (DB)" }),
4007
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: sessionStatusRaw })
4008
- ] }),
4009
- /* @__PURE__ */ jsxs("div", { children: [
4010
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Payment status (DB)" }),
4011
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: paymentStatusRaw })
4012
- ] }),
4013
- /* @__PURE__ */ jsxs("div", { children: [
4014
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Finalized" }),
4015
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: detail.payment_id != null ? "Yes" : "No" })
4016
- ] }),
4017
- /* @__PURE__ */ jsxs("div", { children: [
4018
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Created" }),
4019
- /* @__PURE__ */ jsx(Text, { className: "mt-1 block", children: new Date(detail.created_at).toLocaleDateString("en-US", {
4020
- year: "numeric",
4021
- month: "short",
4022
- day: "numeric",
4023
- hour: "numeric",
4024
- minute: "2-digit",
4025
- hour12: true
4026
- }) })
4027
- ] })
4028
- ] }) }),
4029
- Object.keys(detail.data ?? {}).length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base p-6", children: [
4030
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-lg mb-4", children: "Provider data" }),
4031
- /* @__PURE__ */ jsx("pre", { className: "text-xs bg-ui-bg-subtle p-4 rounded-lg overflow-auto max-h-96", children: JSON.stringify(detail.data, null, 2) })
4032
- ] }) : /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base p-6", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "No provider data for this session." }) })
4033
- ] }) : null
4034
- ] }) });
4035
- };
4036
- const config$3 = defineRouteConfig({
4037
- label: "Payment details",
4038
- icon: CreditCard
4039
- });
4040
- const getStatusBadgeClass$2 = (status) => {
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$2(returnOrder.status)}`,
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$2(entry.status)}`,
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$2 = defineRouteConfig({
4509
+ const config$1 = defineRouteConfig({
4319
4510
  label: "Return Order Details",
4320
4511
  icon: CheckCircle
4321
4512
  });
4322
- const getStatusBadgeClass$1 = (status) => {
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$1(swap.status)}`,
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$1(entry.status)}`,
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$1 = defineRouteConfig({
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$8.label, translationNs: config$8.translationNs }
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$7.label, translationNs: config$7.translationNs }
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: DeletedRecordDetailPage,
4833
- path: "/deleted-records-audit/:id",
4832
+ Component: PaymentDetailPage,
4833
+ path: "/payments/:id",
4834
4834
  handle: { label: config$4.label, translationNs: config$4.translationNs }
4835
4835
  },
4836
4836
  {
4837
- Component: PaymentDetailPage,
4838
- path: "/payments/:id",
4837
+ Component: RefundDetailPage,
4838
+ path: "/refunds/:id",
4839
4839
  handle: { label: config$3.label, translationNs: config$3.translationNs }
4840
4840
  },
4841
4841
  {
4842
- Component: ReturnDetailPage,
4843
- path: "/returns/:id",
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: SwapDetailPage,
4848
- path: "/swaps/:id",
4847
+ Component: ReturnDetailPage,
4848
+ path: "/returns/:id",
4849
4849
  handle: { label: config$1.label, translationNs: config$1.translationNs }
4850
4850
  },
4851
4851
  {
4852
- Component: RefundDetailPage,
4853
- path: "/refunds/:id",
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$9.label,
4862
- icon: config$9.icon,
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$8.label,
4870
- icon: config$8.icon,
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$7.label,
4878
- icon: config$7.icon,
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$6.label,
4886
- icon: config$6.icon,
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$3.label,
4902
- icon: config$3.icon,
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$2.label,
4918
- icon: config$2.icon,
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$1.label,
4926
- icon: config$1.icon,
4925
+ label: config.label,
4926
+ icon: config.icon,
4927
4927
  path: "/swaps/:id",
4928
4928
  nested: void 0,
4929
4929
  rank: void 0,