@retinalabsllc/zairusjs 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +230 -3
- package/dist/index.d.ts +230 -3
- package/dist/index.js +554 -3
- package/dist/index.mjs +563 -3
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1167,11 +1167,12 @@ var TextInput = ({
|
|
|
1167
1167
|
maxLength,
|
|
1168
1168
|
disabled,
|
|
1169
1169
|
readOnly,
|
|
1170
|
+
type = "text",
|
|
1170
1171
|
onClick
|
|
1171
|
-
}) => /* @__PURE__ */ React21.createElement("div", { className: "space-y-2 flex-1 w-full", onClick }, /* @__PURE__ */ React21.createElement("label", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block uppercase" }, label), /* @__PURE__ */ React21.createElement(
|
|
1172
|
+
}) => /* @__PURE__ */ React21.createElement("div", { className: "space-y-2 flex-1 w-full", onClick }, label && /* @__PURE__ */ React21.createElement("label", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block uppercase" }, label), /* @__PURE__ */ React21.createElement(
|
|
1172
1173
|
"input",
|
|
1173
1174
|
{
|
|
1174
|
-
type
|
|
1175
|
+
type,
|
|
1175
1176
|
value,
|
|
1176
1177
|
onChange: (e) => onChange(e.target.value.substring(0, maxLength || 100)),
|
|
1177
1178
|
placeholder,
|
|
@@ -1189,7 +1190,7 @@ var NumberInput = ({
|
|
|
1189
1190
|
placeholder,
|
|
1190
1191
|
maxLength,
|
|
1191
1192
|
disabled
|
|
1192
|
-
}) => /* @__PURE__ */ React21.createElement("div", { className: "space-y-2 flex-1 w-full" }, /* @__PURE__ */ React21.createElement("label", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block uppercase" }, label), /* @__PURE__ */ React21.createElement(
|
|
1193
|
+
}) => /* @__PURE__ */ React21.createElement("div", { className: "space-y-2 flex-1 w-full" }, label && /* @__PURE__ */ React21.createElement("label", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block uppercase" }, label), /* @__PURE__ */ React21.createElement(
|
|
1193
1194
|
"input",
|
|
1194
1195
|
{
|
|
1195
1196
|
type: "text",
|
|
@@ -2319,6 +2320,558 @@ var UniversalProfileSettings = ({
|
|
|
2319
2320
|
"Cancel"
|
|
2320
2321
|
)))));
|
|
2321
2322
|
};
|
|
2323
|
+
|
|
2324
|
+
// src/components/UniversalBillingPage.tsx
|
|
2325
|
+
import React31, { useState as useState15 } from "react";
|
|
2326
|
+
import { HugeiconsIcon as HugeiconsIcon17 } from "@hugeicons/react";
|
|
2327
|
+
import {
|
|
2328
|
+
ArrowLeft01Icon as ArrowLeft01Icon4,
|
|
2329
|
+
ArrowRight01Icon as ArrowRight01Icon4,
|
|
2330
|
+
Loading03Icon as Loading03Icon7,
|
|
2331
|
+
ArrowDown01Icon as ArrowDown01Icon4
|
|
2332
|
+
} from "@hugeicons/core-free-icons";
|
|
2333
|
+
var PageSpinner3 = () => /* @__PURE__ */ React31.createElement("div", { className: "flex justify-center items-center py-12" }, /* @__PURE__ */ React31.createElement(HugeiconsIcon17, { icon: Loading03Icon7, size: 32, className: "animate-spin mb-4 text-neutral-400" }));
|
|
2334
|
+
var ButtonSpinner4 = () => /* @__PURE__ */ React31.createElement(HugeiconsIcon17, { icon: Loading03Icon7, size: 16, className: "animate-spin text-neutral-500" });
|
|
2335
|
+
var formatDate = (dateString) => {
|
|
2336
|
+
if (!dateString) return "N/A";
|
|
2337
|
+
return new Date(dateString).toLocaleDateString("en-US", {
|
|
2338
|
+
month: "long",
|
|
2339
|
+
day: "numeric",
|
|
2340
|
+
year: "numeric"
|
|
2341
|
+
});
|
|
2342
|
+
};
|
|
2343
|
+
var formatNaira = (amount) => {
|
|
2344
|
+
return `\u20A6${(amount || 0).toLocaleString("en-NG", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
2345
|
+
};
|
|
2346
|
+
var UniversalBillingPage = ({
|
|
2347
|
+
headerTitle,
|
|
2348
|
+
headerDescription,
|
|
2349
|
+
isReadOnly = false,
|
|
2350
|
+
isModMode = false,
|
|
2351
|
+
metricPrimaryLabel,
|
|
2352
|
+
metricPrimaryValue,
|
|
2353
|
+
metricPrimarySubtext,
|
|
2354
|
+
metricSecondaryLabel,
|
|
2355
|
+
metricSecondaryValue,
|
|
2356
|
+
metricSecondarySubtext,
|
|
2357
|
+
showBillingOverview = false,
|
|
2358
|
+
billingStatus,
|
|
2359
|
+
nextBillingDate,
|
|
2360
|
+
lastPaidDate,
|
|
2361
|
+
showUsageMetrics = false,
|
|
2362
|
+
usageMetrics = [],
|
|
2363
|
+
showSearchAndFilter = false,
|
|
2364
|
+
searchQuery = "",
|
|
2365
|
+
onSearchChange,
|
|
2366
|
+
timeframe = "ALL",
|
|
2367
|
+
onTimeframeChange,
|
|
2368
|
+
invoices,
|
|
2369
|
+
isLoading,
|
|
2370
|
+
currentPage,
|
|
2371
|
+
totalPages,
|
|
2372
|
+
onPageChange,
|
|
2373
|
+
onPayInvoice,
|
|
2374
|
+
onUpdateInvoiceStatus
|
|
2375
|
+
}) => {
|
|
2376
|
+
const [currentView, setCurrentView] = useState15("list");
|
|
2377
|
+
const [selectedInvoice, setSelectedInvoice] = useState15(null);
|
|
2378
|
+
const [isTimeframeModalOpen, setIsTimeframeModalOpen] = useState15(false);
|
|
2379
|
+
const [isPaying, setIsPaying] = useState15(false);
|
|
2380
|
+
const [isActionModalOpen, setIsActionModalOpen] = useState15(false);
|
|
2381
|
+
const [isUpdating, setIsUpdating] = useState15(false);
|
|
2382
|
+
const [twoFactorCode, setTwoFactorCode] = useState15("");
|
|
2383
|
+
const handlePayment = async () => {
|
|
2384
|
+
if (!selectedInvoice || isReadOnly || !onPayInvoice || isPaying) return;
|
|
2385
|
+
setIsPaying(true);
|
|
2386
|
+
try {
|
|
2387
|
+
await onPayInvoice(selectedInvoice.id);
|
|
2388
|
+
setSelectedInvoice({ ...selectedInvoice, status: "PAID" });
|
|
2389
|
+
} finally {
|
|
2390
|
+
setIsPaying(false);
|
|
2391
|
+
}
|
|
2392
|
+
};
|
|
2393
|
+
const handleStatusUpdate = async (newStatus) => {
|
|
2394
|
+
if (!selectedInvoice || !twoFactorCode || isUpdating || !onUpdateInvoiceStatus) return;
|
|
2395
|
+
setIsUpdating(true);
|
|
2396
|
+
try {
|
|
2397
|
+
const res = await onUpdateInvoiceStatus(selectedInvoice.id, newStatus, twoFactorCode);
|
|
2398
|
+
if (res.success) {
|
|
2399
|
+
setIsActionModalOpen(false);
|
|
2400
|
+
setTwoFactorCode("");
|
|
2401
|
+
setSelectedInvoice({ ...selectedInvoice, status: newStatus });
|
|
2402
|
+
}
|
|
2403
|
+
} finally {
|
|
2404
|
+
setIsUpdating(false);
|
|
2405
|
+
}
|
|
2406
|
+
};
|
|
2407
|
+
return /* @__PURE__ */ React31.createElement("div", { className: "flex max-w-3xl rounded-2xl bg-white p-6 flex-col gap-8 animate-in fade-in duration-300 min-h-full" }, /* @__PURE__ */ React31.createElement(ManagedToaster, null), /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col sm:flex-row sm:items-start justify-between gap-3 sm:gap-4" }, currentView === "list" ? /* @__PURE__ */ React31.createElement("div", { className: "min-w-0 w-full" }, /* @__PURE__ */ React31.createElement("h1", { className: "text-xl text-black mb-1 truncate tracking-tight" }, headerTitle), /* @__PURE__ */ React31.createElement("p", { className: "text-xs text-neutral-500 truncate mb-6" }, headerDescription), showSearchAndFilter && onSearchChange && onTimeframeChange && /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col sm:flex-row gap-4 mb-4" }, /* @__PURE__ */ React31.createElement(
|
|
2408
|
+
TextInput,
|
|
2409
|
+
{
|
|
2410
|
+
placeholder: "Search by ID or Name...",
|
|
2411
|
+
value: searchQuery,
|
|
2412
|
+
onChange: onSearchChange
|
|
2413
|
+
}
|
|
2414
|
+
), /* @__PURE__ */ React31.createElement(
|
|
2415
|
+
"button",
|
|
2416
|
+
{
|
|
2417
|
+
type: "button",
|
|
2418
|
+
onClick: () => setIsTimeframeModalOpen(true),
|
|
2419
|
+
className: "px-4 py-3 text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black shrink-0 text-left"
|
|
2420
|
+
},
|
|
2421
|
+
timeframe === "ALL" ? "All Time" : timeframe === "24H" ? "Past 24 Hours" : timeframe === "7D" ? "Past 7 Days" : "Past 30 Days"
|
|
2422
|
+
))) : /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col items-start gap-3" }, /* @__PURE__ */ React31.createElement("button", { onClick: () => setCurrentView("list"), className: "text-[10px] text-neutral-400 hover:text-black tracking-[0.2em] flex items-center gap-1.5 transition-colors outline-none" }, /* @__PURE__ */ React31.createElement(HugeiconsIcon17, { icon: ArrowLeft01Icon4, size: 12 }), " Back")), isReadOnly && currentView === "list" && /* @__PURE__ */ React31.createElement("span", { className: "px-3 py-1 bg-neutral-50 text-neutral-500 rounded-full text-[10px] tracking-[0.2em] shrink-0 w-fit" }, "Read Only Access")), currentView === "list" && /* @__PURE__ */ React31.createElement("div", { className: "w-full max-w-2xl" }, /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col gap-8 w-full" }, (metricPrimaryLabel || metricSecondaryLabel) && /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col sm:flex-row sm:justify-between sm:items-start pb-8 border-b border-neutral-100 gap-6 sm:gap-0" }, metricPrimaryLabel && /* @__PURE__ */ React31.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-2 truncate block uppercase" }, metricPrimaryLabel), /* @__PURE__ */ React31.createElement("div", { className: "text-xl text-black tracking-tight truncate" }, formatNaira(metricPrimaryValue)), metricPrimarySubtext && /* @__PURE__ */ React31.createElement("p", { className: "text-[10px] text-neutral-500 mt-1 tracking-widest uppercase" }, metricPrimarySubtext)), metricSecondaryLabel && /* @__PURE__ */ React31.createElement("div", { className: "min-w-0 sm:text-right" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-2 truncate block uppercase" }, metricSecondaryLabel), /* @__PURE__ */ React31.createElement("div", { className: "text-xl text-emerald-600 tracking-tight truncate" }, formatNaira(metricSecondaryValue)), metricSecondarySubtext && /* @__PURE__ */ React31.createElement("p", { className: "text-[10px] text-neutral-500 mt-1 tracking-widest uppercase" }, metricSecondarySubtext))), !isReadOnly && showBillingOverview && /* @__PURE__ */ React31.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-8 sm:gap-4" }, /* @__PURE__ */ React31.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-3 truncate block uppercase" }, "Billing Status"), /* @__PURE__ */ React31.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React31.createElement("div", { className: `w-2 h-2 rounded-full shrink-0 ${billingStatus === "ACTIVE" ? "bg-green-500" : "bg-neutral-300"}` }), /* @__PURE__ */ React31.createElement("p", { className: "text-xs text-black tracking-widest truncate" }, billingStatus || "UNKNOWN"))), /* @__PURE__ */ React31.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-3 truncate block uppercase" }, "Next Billing Date"), /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-black truncate" }, formatDate(nextBillingDate))), lastPaidDate && /* @__PURE__ */ React31.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-3 truncate block uppercase" }, "Last Paid Date"), /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-neutral-600 truncate" }, formatDate(lastPaidDate)))), !isReadOnly && showUsageMetrics && usageMetrics.length > 0 && /* @__PURE__ */ React31.createElement("div", { className: "pt-8 border-t border-neutral-100" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-6 truncate block uppercase" }, "Usage & Limits"), /* @__PURE__ */ React31.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-4 text-sm text-black" }, usageMetrics.map((metric, idx) => /* @__PURE__ */ React31.createElement("div", { key: idx, className: "flex justify-between border-b border-neutral-50 pb-2" }, /* @__PURE__ */ React31.createElement("span", { className: "text-neutral-500 text-xs" }, metric.label), /* @__PURE__ */ React31.createElement("span", { className: "text-xs text-black" }, metric.value))))), /* @__PURE__ */ React31.createElement("div", { className: "pt-8 border-t border-neutral-100" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-4 truncate block uppercase" }, "Transaction History"), isLoading ? /* @__PURE__ */ React31.createElement(PageSpinner3, null) : invoices.length === 0 ? /* @__PURE__ */ React31.createElement("p", { className: "text-xs text-neutral-500 py-4" }, "No records found.") : /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ React31.createElement("div", { className: "divide-y divide-neutral-100" }, invoices.map((inv) => /* @__PURE__ */ React31.createElement("div", { key: inv.id, onClick: () => {
|
|
2423
|
+
setSelectedInvoice(inv);
|
|
2424
|
+
setCurrentView("details");
|
|
2425
|
+
}, className: "flex items-center justify-between py-4 hover:bg-neutral-50/50 cursor-pointer group min-w-0 px-2 transition-colors" }, /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col gap-1 min-w-0 flex-1" }, /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-black truncate pr-4" }, inv.name), /* @__PURE__ */ React31.createElement("p", { className: "text-xs text-neutral-500 truncate" }, inv.subtext)), /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col items-end gap-1 shrink-0 pl-4" }, /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-black" }, formatNaira(inv.amountDue)), /* @__PURE__ */ React31.createElement("span", { className: `text-[9px] tracking-widest px-2 py-0.5 rounded-full ${inv.status === "PAID" ? "bg-emerald-50 text-emerald-600" : "bg-neutral-50 text-neutral-600"}` }, inv.status))))), totalPages > 1 && /* @__PURE__ */ React31.createElement("div", { className: "flex items-center justify-between pt-4 mt-2" }, /* @__PURE__ */ React31.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em]" }, "Page ", currentPage, " of ", totalPages), /* @__PURE__ */ React31.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React31.createElement("button", { onClick: () => onPageChange(currentPage - 1), disabled: currentPage === 1 || isLoading, className: "p-2 border border-neutral-200 rounded-full bg-white text-neutral-500 hover:text-black outline-none disabled:opacity-30" }, /* @__PURE__ */ React31.createElement(HugeiconsIcon17, { icon: ArrowLeft01Icon4, size: 14 })), /* @__PURE__ */ React31.createElement("button", { onClick: () => onPageChange(currentPage + 1), disabled: currentPage >= totalPages || isLoading, className: "p-2 border border-neutral-200 rounded-full bg-white text-neutral-500 hover:text-black outline-none disabled:opacity-30" }, /* @__PURE__ */ React31.createElement(HugeiconsIcon17, { icon: ArrowRight01Icon4, size: 14 })))))))), currentView === "details" && selectedInvoice && /* @__PURE__ */ React31.createElement("div", { className: "w-full max-w-2xl animate-in fade-in duration-300" }, /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col gap-6 w-full" }, /* @__PURE__ */ React31.createElement("div", null, /* @__PURE__ */ React31.createElement("span", { className: "text-[10px] tracking-[0.2em] text-neutral-400 block mb-1 uppercase" }, "Breakdown"), /* @__PURE__ */ React31.createElement("h2", { className: "text-xl text-black mb-1" }, selectedInvoice.name), /* @__PURE__ */ React31.createElement("p", { className: "text-xs text-neutral-500" }, "Generated on ", formatDate(selectedInvoice.createdAt))), /* @__PURE__ */ React31.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6 p-6 sm:p-8 rounded-2xl border border-neutral-100" }, /* @__PURE__ */ React31.createElement("div", null, /* @__PURE__ */ React31.createElement("span", { className: "text-[10px] tracking-[0.2em] text-neutral-400 block mb-1 uppercase" }, "Amount"), /* @__PURE__ */ React31.createElement("p", { className: "text-xl text-black" }, formatNaira(selectedInvoice.amountDue))), /* @__PURE__ */ React31.createElement("div", null, /* @__PURE__ */ React31.createElement("span", { className: "text-[10px] tracking-[0.2em] text-neutral-400 block mb-1 uppercase" }, "Status"), isModMode ? /* @__PURE__ */ React31.createElement(
|
|
2426
|
+
"button",
|
|
2427
|
+
{
|
|
2428
|
+
onClick: () => !isUpdating && setIsActionModalOpen(true),
|
|
2429
|
+
disabled: isUpdating,
|
|
2430
|
+
className: `flex items-center gap-3 text-xs text-black px-3 py-1.5 mt-1 border rounded-full transition-colors disabled:opacity-50 outline-none ${isActionModalOpen ? "bg-neutral-50 border-neutral-300" : "bg-white border-neutral-200 hover:bg-neutral-50"}`
|
|
2431
|
+
},
|
|
2432
|
+
selectedInvoice.status,
|
|
2433
|
+
isUpdating ? /* @__PURE__ */ React31.createElement(ButtonSpinner4, null) : /* @__PURE__ */ React31.createElement(HugeiconsIcon17, { icon: ArrowDown01Icon4, size: 14, className: "text-neutral-400" })
|
|
2434
|
+
) : /* @__PURE__ */ React31.createElement("span", { className: `text-[10px] tracking-widest px-3 py-1 mt-1 inline-block rounded-full ${selectedInvoice.status === "PAID" ? "bg-emerald-100 text-emerald-700" : "bg-neutral-100 text-neutral-700"}` }, selectedInvoice.status)), /* @__PURE__ */ React31.createElement("div", { className: "md:col-span-2 pt-4 border-t border-neutral-200/60 mt-2" }, /* @__PURE__ */ React31.createElement("span", { className: "text-[10px] tracking-[0.2em] text-neutral-400 block mb-1 uppercase" }, "Reference ID"), /* @__PURE__ */ React31.createElement("p", { className: "text-xs text-neutral-500 bg-white px-3 py-2 rounded-full border border-neutral-200 inline-block" }, selectedInvoice.id))), /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-end gap-4 pt-4" }, !isModMode && selectedInvoice.status === "SCHEDULED" && onPayInvoice && /* @__PURE__ */ React31.createElement("div", { className: "flex flex-col items-end gap-2 w-full sm:w-auto" }, /* @__PURE__ */ React31.createElement(
|
|
2435
|
+
ThreeDActionButton,
|
|
2436
|
+
{
|
|
2437
|
+
onClick: handlePayment,
|
|
2438
|
+
disabled: isReadOnly || isPaying,
|
|
2439
|
+
isLoading: isPaying,
|
|
2440
|
+
className: "w-full sm:w-auto"
|
|
2441
|
+
},
|
|
2442
|
+
"Pay Invoice"
|
|
2443
|
+
)), !isModMode && selectedInvoice.status === "PAID" && /* @__PURE__ */ React31.createElement("span", { className: "text-[11px] tracking-widest text-emerald-600 px-6 py-3 bg-emerald-50 rounded-full" }, "Invoice Completed")))), isTimeframeModalOpen && showSearchAndFilter && onTimeframeChange && /* @__PURE__ */ React31.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React31.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => setIsTimeframeModalOpen(false) }), /* @__PURE__ */ React31.createElement("div", { className: "relative w-80 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React31.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[14px] text-black tracking-tight mb-2" }, "Select Timeframe"), /* @__PURE__ */ React31.createElement("p", { className: "text-[12px] text-neutral-500" }, "Choose the range of transactions to display.")), /* @__PURE__ */ React31.createElement("div", { className: "w-full flex flex-col pl-2 pr-2" }, [
|
|
2444
|
+
{ value: "ALL", label: "All Time" },
|
|
2445
|
+
{ value: "24H", label: "Past 24 Hours" },
|
|
2446
|
+
{ value: "7D", label: "Past 7 Days" },
|
|
2447
|
+
{ value: "30D", label: "Past 30 Days" }
|
|
2448
|
+
].map((option) => /* @__PURE__ */ React31.createElement(
|
|
2449
|
+
"button",
|
|
2450
|
+
{
|
|
2451
|
+
key: option.value,
|
|
2452
|
+
type: "button",
|
|
2453
|
+
onClick: () => {
|
|
2454
|
+
onTimeframeChange(option.value);
|
|
2455
|
+
setIsTimeframeModalOpen(false);
|
|
2456
|
+
},
|
|
2457
|
+
className: `text-left px-4 py-3 text-[12px] tracking-wide transition-colors rounded-full flex items-center justify-between outline-none ${timeframe === option.value ? "bg-neutral-100 text-black" : "text-neutral-500 hover:bg-neutral-50 hover:text-black"}`
|
|
2458
|
+
},
|
|
2459
|
+
/* @__PURE__ */ React31.createElement("span", { className: "truncate pr-2" }, option.label),
|
|
2460
|
+
timeframe === option.value && /* @__PURE__ */ React31.createElement("div", { className: "w-1.5 h-1.5 bg-black rounded-full shrink-0" })
|
|
2461
|
+
))), /* @__PURE__ */ React31.createElement("div", { className: "w-full flex mt-2" }, /* @__PURE__ */ React31.createElement("button", { onClick: () => setIsTimeframeModalOpen(false), className: "w-full py-2.5 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors outline-none" }, "Cancel")))), isActionModalOpen && isModMode && /* @__PURE__ */ React31.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React31.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => !isUpdating && setIsActionModalOpen(false) }), /* @__PURE__ */ React31.createElement("div", { className: "relative w-80 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React31.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ React31.createElement("h3", { className: "text-[14px] text-black tracking-tight mb-2" }, "Update Invoice Status"), /* @__PURE__ */ React31.createElement(
|
|
2462
|
+
TextInput,
|
|
2463
|
+
{
|
|
2464
|
+
placeholder: "Enter 2FA Code...",
|
|
2465
|
+
value: twoFactorCode,
|
|
2466
|
+
onChange: setTwoFactorCode,
|
|
2467
|
+
type: "password"
|
|
2468
|
+
}
|
|
2469
|
+
)), /* @__PURE__ */ React31.createElement("div", { className: "w-full flex flex-col pl-2 pr-2" }, ["SCHEDULED", "PAID", "FAILED", "CANCELED"].map((statusOption) => /* @__PURE__ */ React31.createElement(
|
|
2470
|
+
"button",
|
|
2471
|
+
{
|
|
2472
|
+
key: statusOption,
|
|
2473
|
+
onClick: () => handleStatusUpdate(statusOption),
|
|
2474
|
+
disabled: isUpdating || !twoFactorCode,
|
|
2475
|
+
className: `text-left px-4 py-3 text-[12px] tracking-wide transition-colors rounded-full flex items-center justify-between outline-none ${selectedInvoice?.status === statusOption ? "bg-neutral-100 text-black" : "text-neutral-500 hover:bg-neutral-50 hover:text-black"}`
|
|
2476
|
+
},
|
|
2477
|
+
/* @__PURE__ */ React31.createElement("span", { className: "truncate pr-2" }, statusOption),
|
|
2478
|
+
selectedInvoice?.status === statusOption && /* @__PURE__ */ React31.createElement("div", { className: "w-1.5 h-1.5 bg-black rounded-full shrink-0" })
|
|
2479
|
+
))), /* @__PURE__ */ React31.createElement("div", { className: "w-full flex mt-2" }, /* @__PURE__ */ React31.createElement("button", { onClick: () => setIsActionModalOpen(false), disabled: isUpdating, className: "w-full py-2.5 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors disabled:opacity-50 outline-none" }, "Cancel")))));
|
|
2480
|
+
};
|
|
2481
|
+
|
|
2482
|
+
// src/components/UniversalDashboardPage.tsx
|
|
2483
|
+
import React32, { useState as useState16 } from "react";
|
|
2484
|
+
import { HugeiconsIcon as HugeiconsIcon18 } from "@hugeicons/react";
|
|
2485
|
+
import { ArrowDown01Icon as ArrowDown01Icon5, Loading03Icon as Loading03Icon8 } from "@hugeicons/core-free-icons";
|
|
2486
|
+
var UniversalDashboardPage = ({
|
|
2487
|
+
headerTitle,
|
|
2488
|
+
headerDescription,
|
|
2489
|
+
timeframes = [],
|
|
2490
|
+
activeTimeframe,
|
|
2491
|
+
onTimeframeChange,
|
|
2492
|
+
stats,
|
|
2493
|
+
lists,
|
|
2494
|
+
isLoading = false
|
|
2495
|
+
}) => {
|
|
2496
|
+
const [isTimeframeModalOpen, setIsTimeframeModalOpen] = useState16(false);
|
|
2497
|
+
const selectedTimeframe = timeframes.find((t) => t.id === activeTimeframe) || timeframes[0];
|
|
2498
|
+
if (isLoading) {
|
|
2499
|
+
return /* @__PURE__ */ React32.createElement("div", { className: "flex justify-center items-center py-12" }, /* @__PURE__ */ React32.createElement(HugeiconsIcon18, { icon: Loading03Icon8, size: 32, className: "animate-spin mb-4 text-black" }));
|
|
2500
|
+
}
|
|
2501
|
+
return /* @__PURE__ */ React32.createElement("div", { className: "flex flex-col gap-8 animate-in fade-in duration-300 min-h-full pb-10" }, /* @__PURE__ */ React32.createElement(ManagedToaster, null), /* @__PURE__ */ React32.createElement("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4" }, /* @__PURE__ */ React32.createElement("div", null, /* @__PURE__ */ React32.createElement("h1", { className: "text-xl text-black mb-1 tracking-tight" }, headerTitle), /* @__PURE__ */ React32.createElement("p", { className: "text-xs text-neutral-500" }, headerDescription)), timeframes.length > 0 && selectedTimeframe && onTimeframeChange && /* @__PURE__ */ React32.createElement(
|
|
2502
|
+
"button",
|
|
2503
|
+
{
|
|
2504
|
+
onClick: () => setIsTimeframeModalOpen(true),
|
|
2505
|
+
className: "flex items-center gap-3 px-4 py-2 text-xs bg-white text-black outline-none rounded-full transition-colors hover:bg-neutral-50 shrink-0"
|
|
2506
|
+
},
|
|
2507
|
+
/* @__PURE__ */ React32.createElement("span", null, selectedTimeframe.label),
|
|
2508
|
+
/* @__PURE__ */ React32.createElement(HugeiconsIcon18, { icon: ArrowDown01Icon5, size: 14, className: "text-neutral-400" })
|
|
2509
|
+
)), stats.length > 0 && /* @__PURE__ */ React32.createElement("div", { className: "w-full rounded-2xl overflow-hidden bg-white" }, /* @__PURE__ */ React32.createElement("div", { className: "grid grid-cols-2 md:grid-cols-5 divide-y md:divide-y-0 md:divide-x divide-neutral-100" }, stats.map((stat, idx) => /* @__PURE__ */ React32.createElement("div", { key: idx, className: "p-6 flex flex-col gap-1 min-w-0" }, /* @__PURE__ */ React32.createElement("p", { className: "text-[10px] tracking-[0.2em] text-neutral-400 truncate uppercase" }, stat.label), /* @__PURE__ */ React32.createElement("p", { className: `text-xl tracking-tight truncate ${stat.valueClass || "text-black"}` }, stat.value))))), lists.length > 0 && /* @__PURE__ */ React32.createElement("div", { className: "flex flex-col gap-8 w-full max-w-4xl" }, lists.map((list, idx) => /* @__PURE__ */ React32.createElement("div", { key: idx, className: "bg-white rounded-2xl p-6 flex flex-col min-w-0" }, /* @__PURE__ */ React32.createElement("div", { className: "flex items-center gap-3 mb-6" }, /* @__PURE__ */ React32.createElement("div", { className: "text-neutral-400" }, list.icon), /* @__PURE__ */ React32.createElement("h2", { className: "text-[11px] text-black tracking-[0.2em] uppercase" }, list.title)), /* @__PURE__ */ React32.createElement("div", { className: "divide-y divide-neutral-100 flex-1 overflow-y-auto" }, list.items.length === 0 ? /* @__PURE__ */ React32.createElement("p", { className: "text-xs text-neutral-500 py-4" }, list.emptyMessage) : list.items.map((item) => /* @__PURE__ */ React32.createElement("div", { key: item.id, className: "flex flex-col sm:flex-row sm:items-center justify-between py-4 gap-2 min-w-0 group" }, /* @__PURE__ */ React32.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React32.createElement("p", { className: "text-sm text-black truncate pr-4" }, item.primaryText), /* @__PURE__ */ React32.createElement("p", { className: "text-[10px] text-neutral-500 truncate tracking-widest mt-0.5" }, item.secondaryText)), /* @__PURE__ */ React32.createElement("div", { className: "flex items-center gap-4 shrink-0 pl-4" }, item.rightText && /* @__PURE__ */ React32.createElement("p", { className: "text-xs text-black" }, item.rightText), item.rightBadge && /* @__PURE__ */ React32.createElement("span", { className: `text-[9px] tracking-widest px-2.5 py-1 rounded-full ${item.rightBadgeClass || "bg-neutral-50 text-neutral-600"}` }, item.rightBadge)))))))), isTimeframeModalOpen && timeframes.length > 0 && onTimeframeChange && /* @__PURE__ */ React32.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React32.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => setIsTimeframeModalOpen(false) }), /* @__PURE__ */ React32.createElement("div", { className: "relative w-72 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React32.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ React32.createElement("h3", { className: "text-[14px] text-black tracking-tight" }, "Select Timeframe")), /* @__PURE__ */ React32.createElement("div", { className: "w-full flex flex-col pl-2 pr-2 pb-2" }, timeframes.map((tf) => /* @__PURE__ */ React32.createElement(
|
|
2510
|
+
"button",
|
|
2511
|
+
{
|
|
2512
|
+
key: tf.id,
|
|
2513
|
+
onClick: () => {
|
|
2514
|
+
onTimeframeChange(tf.id);
|
|
2515
|
+
setIsTimeframeModalOpen(false);
|
|
2516
|
+
},
|
|
2517
|
+
className: `text-left px-4 py-3 text-[12px] tracking-wide transition-colors rounded-full flex items-center justify-between outline-none ${activeTimeframe === tf.id ? "bg-neutral-100 text-black" : "text-neutral-500 hover:bg-neutral-50 hover:text-black"}`
|
|
2518
|
+
},
|
|
2519
|
+
/* @__PURE__ */ React32.createElement("span", { className: "truncate pr-2" }, tf.label),
|
|
2520
|
+
activeTimeframe === tf.id && /* @__PURE__ */ React32.createElement("div", { className: "w-1.5 h-1.5 bg-black rounded-full shrink-0" })
|
|
2521
|
+
))), /* @__PURE__ */ React32.createElement("div", { className: "w-full flex border-t border-neutral-50" }, /* @__PURE__ */ React32.createElement(
|
|
2522
|
+
"button",
|
|
2523
|
+
{
|
|
2524
|
+
onClick: () => setIsTimeframeModalOpen(false),
|
|
2525
|
+
className: "w-full py-2.5 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors outline-none"
|
|
2526
|
+
},
|
|
2527
|
+
"Cancel"
|
|
2528
|
+
)))));
|
|
2529
|
+
};
|
|
2530
|
+
|
|
2531
|
+
// src/components/UniversalAgentConsole.tsx
|
|
2532
|
+
import React33, { useState as useState17, useRef as useRef5 } from "react";
|
|
2533
|
+
import { HugeiconsIcon as HugeiconsIcon19 } from "@hugeicons/react";
|
|
2534
|
+
import {
|
|
2535
|
+
ArrowLeft01Icon as ArrowLeft01Icon5,
|
|
2536
|
+
ArrowRight01Icon as ArrowRight01Icon5,
|
|
2537
|
+
Loading03Icon as Loading03Icon9,
|
|
2538
|
+
AttachmentIcon,
|
|
2539
|
+
Cancel01Icon as Cancel01Icon2,
|
|
2540
|
+
Upload01Icon,
|
|
2541
|
+
Download01Icon,
|
|
2542
|
+
ArrowDown01Icon as ArrowDown01Icon6,
|
|
2543
|
+
Delete02Icon,
|
|
2544
|
+
File02Icon
|
|
2545
|
+
} from "@hugeicons/core-free-icons";
|
|
2546
|
+
var formatKeyName = (key) => key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
|
|
2547
|
+
var toTitleCaseSafe = (str) => {
|
|
2548
|
+
if (!str) return "";
|
|
2549
|
+
return str.toLowerCase().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
2550
|
+
};
|
|
2551
|
+
var IGNORED_KEYS = ["id", "fileName", "contentType", "fileSizeInBytes", "categoryCode", "specificCode", "iAgree"];
|
|
2552
|
+
var UniversalAgentConsole = ({
|
|
2553
|
+
headerTitle,
|
|
2554
|
+
headerDescription,
|
|
2555
|
+
stats,
|
|
2556
|
+
tabs,
|
|
2557
|
+
activeTab,
|
|
2558
|
+
onTabChange,
|
|
2559
|
+
listData,
|
|
2560
|
+
isLoadingList,
|
|
2561
|
+
currentPage,
|
|
2562
|
+
totalPages,
|
|
2563
|
+
onPageChange,
|
|
2564
|
+
onRowClick,
|
|
2565
|
+
currentView,
|
|
2566
|
+
onBackToList,
|
|
2567
|
+
selectedApp,
|
|
2568
|
+
currentAgentId,
|
|
2569
|
+
onAcceptApplication,
|
|
2570
|
+
onUpdateStatus,
|
|
2571
|
+
onUploadArchives,
|
|
2572
|
+
onDeleteArchive
|
|
2573
|
+
}) => {
|
|
2574
|
+
const archiveRef = useRef5(null);
|
|
2575
|
+
const [pendingFiles, setPendingFiles] = useState17([]);
|
|
2576
|
+
const [isUploading, setIsUploading] = useState17(false);
|
|
2577
|
+
const [isActioning, setIsActioning] = useState17(false);
|
|
2578
|
+
const [actionModal, setActionModal] = useState17(null);
|
|
2579
|
+
const [actionMessage, setActionMessage] = useState17("");
|
|
2580
|
+
const [archiveToDelete, setArchiveToDelete] = useState17(null);
|
|
2581
|
+
const handleFileSelect = (e) => {
|
|
2582
|
+
if (e.target.files && e.target.files.length > 0) {
|
|
2583
|
+
setPendingFiles((prev) => [...prev, ...Array.from(e.target.files)]);
|
|
2584
|
+
}
|
|
2585
|
+
setTimeout(() => {
|
|
2586
|
+
if (archiveRef.current) archiveRef.current.value = "";
|
|
2587
|
+
}, 0);
|
|
2588
|
+
};
|
|
2589
|
+
const executeUpload = async () => {
|
|
2590
|
+
if (pendingFiles.length === 0 || !selectedApp) return;
|
|
2591
|
+
setIsUploading(true);
|
|
2592
|
+
try {
|
|
2593
|
+
const payloads = await Promise.all(pendingFiles.map(async (file) => {
|
|
2594
|
+
const base64data = await new Promise((resolve, reject) => {
|
|
2595
|
+
const reader = new FileReader();
|
|
2596
|
+
reader.readAsDataURL(file);
|
|
2597
|
+
reader.onload = () => resolve(reader.result);
|
|
2598
|
+
reader.onerror = (error) => reject(error);
|
|
2599
|
+
});
|
|
2600
|
+
return { imageBase64: base64data, fileName: file.name, fileType: file.type, fileSize: file.size };
|
|
2601
|
+
}));
|
|
2602
|
+
const res = await onUploadArchives(selectedApp.id, payloads);
|
|
2603
|
+
if (res.success) setPendingFiles([]);
|
|
2604
|
+
} finally {
|
|
2605
|
+
setIsUploading(false);
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2608
|
+
const DynamicArrayAccordion = ({ items, parentKey }) => {
|
|
2609
|
+
const [activeFAQ, setActiveFAQ] = useState17(null);
|
|
2610
|
+
return /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col relative z-10 bg-transparent w-full mt-2 border-t border-neutral-100" }, items.map((item, index) => {
|
|
2611
|
+
const isOpen = activeFAQ === index;
|
|
2612
|
+
let label = `${parentKey ? formatKeyName(parentKey) : "Item"} ${index + 1}`;
|
|
2613
|
+
if (item.fullName) label = toTitleCaseSafe(item.fullName);
|
|
2614
|
+
else if (item.role) label = item.role;
|
|
2615
|
+
else if (item.proposedName) label = toTitleCaseSafe(item.proposedName);
|
|
2616
|
+
return /* @__PURE__ */ React33.createElement("div", { key: index, className: `transition-all duration-300 ${index !== items.length - 1 ? "border-b border-neutral-100" : ""}` }, /* @__PURE__ */ React33.createElement("button", { className: "flex items-center justify-between w-full gap-4 text-left py-5 md:py-6 group outline-none bg-transparent", onClick: () => setActiveFAQ(isOpen ? null : index) }, /* @__PURE__ */ React33.createElement("span", { className: `text-[13px] md:text-[14px] transition-colors ${isOpen ? "text-black" : "text-neutral-700 group-hover:text-black"}` }, label), /* @__PURE__ */ React33.createElement("div", { className: `shrink-0 flex items-center justify-center w-8 h-8 rounded-full border transition-all duration-300 ${isOpen ? "rotate-180 border-black text-black" : "border-neutral-300 text-neutral-500"}` }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: ArrowDown01Icon6, size: 16 }))), /* @__PURE__ */ React33.createElement("div", { className: `grid transition-all duration-300 ease-in-out ${isOpen ? "grid-rows-[1fr] pb-6 md:pb-8 opacity-100" : "grid-rows-[0fr] opacity-0"}` }, /* @__PURE__ */ React33.createElement("div", { className: "overflow-hidden" }, /* @__PURE__ */ React33.createElement("div", { className: "pt-2 flex flex-col gap-3 pr-4 md:pr-12" }, renderDynamicObject(item)))));
|
|
2617
|
+
}));
|
|
2618
|
+
};
|
|
2619
|
+
const renderValue = (key, value) => {
|
|
2620
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
2621
|
+
if (typeof value === "string") {
|
|
2622
|
+
if (value.startsWith("http") || value.startsWith("data:image")) return /* @__PURE__ */ React33.createElement("a", { href: value, download: true, target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-2 px-5 py-2 bg-white border border-neutral-200 text-black text-[11px] tracking-widest rounded-full hover:bg-neutral-50 transition-colors w-fit outline-none mt-2" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: Download01Icon, size: 14 }), " Download File");
|
|
2623
|
+
if (key.toLowerCase().includes("name") && !value.includes("@")) return /* @__PURE__ */ React33.createElement("p", { className: "text-[12px] md:text-[13px] leading-[1.8] text-neutral-600" }, toTitleCaseSafe(value));
|
|
2624
|
+
return /* @__PURE__ */ React33.createElement("p", { className: "text-[12px] md:text-[13px] leading-[1.8] text-neutral-600" }, value);
|
|
2625
|
+
}
|
|
2626
|
+
if (Array.isArray(value)) {
|
|
2627
|
+
const validItems = value.filter((item) => item !== null && item !== void 0 && item !== "");
|
|
2628
|
+
if (validItems.length === 0) return null;
|
|
2629
|
+
if (typeof validItems[0] === "string") return /* @__PURE__ */ React33.createElement("ul", { className: "list-disc pl-4 mt-1" }, validItems.map((v, i) => /* @__PURE__ */ React33.createElement("li", { key: i, className: "text-[12px] md:text-[13px] leading-[1.8] text-neutral-600" }, toTitleCaseSafe(v))));
|
|
2630
|
+
return /* @__PURE__ */ React33.createElement(DynamicArrayAccordion, { items: validItems, parentKey: key });
|
|
2631
|
+
}
|
|
2632
|
+
if (typeof value === "object") {
|
|
2633
|
+
if (Object.keys(value).length === 0) return null;
|
|
2634
|
+
const renderedObj = renderDynamicObject(value);
|
|
2635
|
+
if (!renderedObj || Array.isArray(renderedObj) && renderedObj.length === 0) return null;
|
|
2636
|
+
return /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-3 mt-1 w-full border-l border-neutral-100 pl-4 py-2" }, renderedObj);
|
|
2637
|
+
}
|
|
2638
|
+
return /* @__PURE__ */ React33.createElement("span", { className: "text-sm text-black" }, String(value));
|
|
2639
|
+
};
|
|
2640
|
+
const renderDynamicObject = (obj) => {
|
|
2641
|
+
if (!obj) return null;
|
|
2642
|
+
const entries = Object.entries(obj).filter(([k, v]) => {
|
|
2643
|
+
if (IGNORED_KEYS.includes(k) || v === null || v === "" || v === void 0) return false;
|
|
2644
|
+
if (Array.isArray(v) && v.filter((item) => item !== null && item !== "").length === 0) return false;
|
|
2645
|
+
if (typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 0) return false;
|
|
2646
|
+
return true;
|
|
2647
|
+
});
|
|
2648
|
+
if (entries.length === 0) return null;
|
|
2649
|
+
return entries.map(([k, v]) => /* @__PURE__ */ React33.createElement("div", { key: k, className: "flex flex-col items-start min-w-0 wrap-break-word w-full mb-3 last:mb-0" }, /* @__PURE__ */ React33.createElement("span", { className: "text-[10px] tracking-[0.2em] text-neutral-400 mb-1 uppercase" }, formatKeyName(k)), renderValue(k, v)));
|
|
2650
|
+
};
|
|
2651
|
+
return /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-8 animate-in fade-in duration-300 min-h-full pb-10" }, /* @__PURE__ */ React33.createElement(ManagedToaster, null), currentView === "list" && /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col items-start gap-1" }, /* @__PURE__ */ React33.createElement("h1", { className: "text-xl text-black tracking-tight" }, headerTitle), /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-neutral-500" }, headerDescription)), stats.length > 0 && /* @__PURE__ */ React33.createElement("div", { className: "w-full rounded-2xl max-w-3xl overflow-hidden bg-white" }, /* @__PURE__ */ React33.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 divide-y md:divide-y-0 md:divide-x divide-neutral-100" }, stats.map((stat, idx) => /* @__PURE__ */ React33.createElement("div", { key: idx, className: "p-6 flex items-center gap-4 hover:bg-neutral-50/50 transition-colors min-w-0" }, /* @__PURE__ */ React33.createElement("div", { className: "w-12 h-12 rounded-full border border-neutral-200 bg-white flex items-center justify-center text-black shrink-0" }, stat.icon), /* @__PURE__ */ React33.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React33.createElement("p", { className: "text-[10px] tracking-[0.2em] text-neutral-400 mb-1 truncate uppercase" }, stat.label), /* @__PURE__ */ React33.createElement("p", { className: "text-xl text-black tracking-tight truncate" }, stat.value)))))), tabs.length > 0 && /* @__PURE__ */ React33.createElement("div", { className: "flex items-center gap-6" }, tabs.map((tab) => /* @__PURE__ */ React33.createElement("button", { key: tab.id, onClick: () => onTabChange(tab.id), className: `pb-3 text-sm transition-colors outline-none ${activeTab === tab.id ? "text-black border-b border-black" : "text-neutral-400 hover:text-black"}` }, tab.label))), /* @__PURE__ */ React33.createElement("div", { className: "w-full bg-white rounded-2xl max-w-3xl overflow-hidden flex flex-col min-h-100" }, isLoadingList ? /* @__PURE__ */ React33.createElement("div", { className: "flex justify-center items-center py-12" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: Loading03Icon9, size: 32, className: "animate-spin text-black" })) : listData.length === 0 ? /* @__PURE__ */ React33.createElement("div", { className: "flex-1 flex justify-center items-center text-neutral-500 text-sm py-20" }, "No matching applications found.") : /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement("div", { className: "divide-y divide-neutral-100 flex-1" }, listData.map((item) => /* @__PURE__ */ React33.createElement("div", { key: item.id, onClick: () => onRowClick(item.id), className: "flex items-center justify-between p-5 hover:bg-neutral-50/50 transition-colors cursor-pointer group min-w-0" }, /* @__PURE__ */ React33.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-black truncate pr-4" }, item.title), /* @__PURE__ */ React33.createElement("p", { className: "text-xs text-neutral-500 truncate mt-1" }, item.subtitle)), /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col items-end gap-1 shrink-0 pl-4" }, /* @__PURE__ */ React33.createElement("span", { className: `text-[10px] tracking-widest px-3 py-1 rounded-full uppercase ${item.status === "COMPLETED" ? "bg-emerald-50 text-emerald-600" : "bg-neutral-50 text-neutral-600"}` }, item.status.replace(/_/g, " ")), /* @__PURE__ */ React33.createElement("span", { className: "text-[10px] text-neutral-400 mt-1" }, item.date))))), totalPages > 1 && /* @__PURE__ */ React33.createElement("div", { className: "flex items-center justify-between p-5 bg-neutral-50/50" }, /* @__PURE__ */ React33.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em]" }, "Page ", currentPage, " of ", totalPages), /* @__PURE__ */ React33.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => onPageChange(currentPage - 1), disabled: currentPage === 1, className: "p-2 border border-neutral-200 rounded-full bg-white text-neutral-500 hover:text-black outline-none disabled:opacity-30" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: ArrowLeft01Icon5, size: 14 })), /* @__PURE__ */ React33.createElement("button", { onClick: () => onPageChange(currentPage + 1), disabled: currentPage >= totalPages, className: "p-2 border border-neutral-200 rounded-full bg-white text-neutral-500 hover:text-black outline-none disabled:opacity-30" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: ArrowRight01Icon5, size: 14 }))))))), currentView === "details" && selectedApp && /* @__PURE__ */ React33.createElement("div", { className: "w-full bg-white rounded-2xl p-6 sm:p-10 animate-in fade-in duration-300 max-w-3xl flex flex-col" }, /* @__PURE__ */ React33.createElement("div", { className: "flex items-center justify-between gap-4 pb-6" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => {
|
|
2652
|
+
onBackToList();
|
|
2653
|
+
setPendingFiles([]);
|
|
2654
|
+
}, className: "flex items-center gap-2 text-[10px] text-neutral-400 hover:text-black tracking-widest transition-colors outline-none uppercase" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: ArrowLeft01Icon5, size: 14 }), " Back to List"), /* @__PURE__ */ React33.createElement("span", { className: `text-[10px] tracking-widest px-4 py-1.5 rounded-full uppercase ${selectedApp.status === "COMPLETED" ? "bg-emerald-50 text-emerald-600" : "bg-neutral-50 text-neutral-600"}` }, selectedApp.status.replace(/_/g, " "))), /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-2 mb-8" }, /* @__PURE__ */ React33.createElement("h2", { className: "text-xl text-black tracking-tight" }, selectedApp.name || selectedApp.title), /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-neutral-500" }, selectedApp.type ? selectedApp.type.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (c) => c.toUpperCase()) : selectedApp.subtitle)), selectedApp.agentId === currentAgentId && selectedApp.metadata && Object.keys(selectedApp.metadata).length > 0 ? /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-5" }, renderDynamicObject(selectedApp.metadata)) : selectedApp.agentId === currentAgentId ? /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-5" }, /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-neutral-500" }, "No application data extracted.")) : null, selectedApp.agentId && /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-4 pt-8 mt-4 border-t border-neutral-100" }, /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col gap-1 mb-4" }, /* @__PURE__ */ React33.createElement("h3", { className: "text-sm text-black" }, "Official Archives"), /* @__PURE__ */ React33.createElement("p", { className: "text-xs text-neutral-500 leading-relaxed" }, "Upload final certificates or documents. Once marked completed, the archive unlocks for the user.")), selectedApp.archives?.map((arch) => /* @__PURE__ */ React33.createElement("div", { key: arch.id, className: "flex items-center justify-between p-4 bg-emerald-50 rounded-full text-emerald-800 text-sm w-full" }, /* @__PURE__ */ React33.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: File02Icon, size: 18, className: "shrink-0" }), /* @__PURE__ */ React33.createElement("span", { className: "truncate pr-2" }, arch.name)), /* @__PURE__ */ React33.createElement("button", { onClick: () => setArchiveToDelete(arch), className: "text-emerald-700 hover:text-red-500 transition-colors p-1 outline-none shrink-0" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: Delete02Icon, size: 16 })))), pendingFiles.map((file, idx) => /* @__PURE__ */ React33.createElement("div", { key: idx, className: "flex items-center justify-between text-neutral-600 text-sm w-full" }, /* @__PURE__ */ React33.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: AttachmentIcon, size: 18, className: "shrink-0" }), /* @__PURE__ */ React33.createElement("span", { className: "truncate pr-2" }, file.name)), /* @__PURE__ */ React33.createElement("button", { onClick: () => setPendingFiles((p) => p.filter((_, i) => i !== idx)), className: "text-neutral-400 hover:text-red-500 transition-colors p-1 outline-none shrink-0" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: Cancel01Icon2, size: 16 })))), /* @__PURE__ */ React33.createElement("input", { type: "file", multiple: true, ref: archiveRef, onChange: handleFileSelect, className: "hidden", accept: "application/pdf,image/*" }), /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col sm:flex-row items-center gap-3 w-full" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => archiveRef.current?.click(), disabled: selectedApp.status !== "COMPLETED" || isUploading, className: "flex items-center justify-center gap-3 p-4 border border-neutral-200 rounded-full hover:bg-neutral-50 transition-colors text-black text-sm w-full outline-none disabled:opacity-50" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: Upload01Icon, size: 18, className: "text-neutral-400" }), " Select Files to Upload"), pendingFiles.length > 0 && /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col sm:flex-row items-center gap-3 w-full sm:w-auto shrink-0" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => setPendingFiles([]), disabled: isUploading, className: "px-6 py-2 text-neutral-600 text-[11px] tracking-widest rounded-full hover:bg-neutral-200 outline-none w-full sm:w-auto uppercase" }, "Clear All"), /* @__PURE__ */ React33.createElement(ThreeDActionButton, { onClick: executeUpload, disabled: isUploading, isLoading: isUploading, className: "w-full sm:w-auto" }, "Upload ", pendingFiles.length, " File(s)")))), /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-4 mt-8 pt-6" }, !selectedApp.agentId ? /* @__PURE__ */ React33.createElement(ThreeDActionButton, { onClick: async () => {
|
|
2655
|
+
setIsActioning(true);
|
|
2656
|
+
await onAcceptApplication(selectedApp.id);
|
|
2657
|
+
setIsActioning(false);
|
|
2658
|
+
}, disabled: isActioning, isLoading: isActioning, className: "w-full sm:w-auto" }, "Accept Application") : selectedApp.agentId !== currentAgentId ? /* @__PURE__ */ React33.createElement("div", { className: "w-full p-4 border border-red-100 bg-red-50/30 rounded-xl flex items-start gap-3" }, /* @__PURE__ */ React33.createElement(HugeiconsIcon19, { icon: Cancel01Icon2, size: 16, className: "text-red-500 shrink-0 mt-0.5" }), /* @__PURE__ */ React33.createElement("div", null, /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-red-700" }, "Application Taken"), /* @__PURE__ */ React33.createElement("p", { className: "text-xs text-red-600 mt-1" }, "Currently handled by ", selectedApp.agentName || "another agent", "."))) : /* @__PURE__ */ React33.createElement("div", { className: "w-full flex flex-col sm:flex-row items-center gap-4 justify-between" }, /* @__PURE__ */ React33.createElement("p", { className: "text-xs text-neutral-500" }, "You are the assigned agent."), /* @__PURE__ */ React33.createElement("div", { className: "flex flex-col sm:flex-row items-center justify-end gap-3 w-full sm:w-auto" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => setActionModal("query"), disabled: selectedApp.status === "COMPLETED", className: "w-full sm:w-auto px-6 py-2 bg-white border border-neutral-200 text-neutral-600 text-[11px] tracking-widest rounded-full hover:bg-neutral-50 transition-colors outline-none disabled:opacity-30 uppercase" }, "Query"), /* @__PURE__ */ React33.createElement("button", { onClick: () => setActionModal("reject"), disabled: selectedApp.status === "COMPLETED", className: "w-full sm:w-auto px-6 py-2 bg-white border border-neutral-200 text-neutral-600 text-[11px] tracking-widest rounded-full hover:bg-neutral-50 transition-colors outline-none disabled:opacity-30 uppercase" }, "Reject"), /* @__PURE__ */ React33.createElement(ThreeDActionButton, { onClick: () => setActionModal("success"), disabled: selectedApp.status === "COMPLETED", className: "w-full sm:w-auto" }, "Mark Success"))))), actionModal && /* @__PURE__ */ React33.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React33.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => !isActioning && setActionModal(null) }), /* @__PURE__ */ React33.createElement("div", { className: "relative w-full max-w-md bg-white rounded-3xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200 text-left" }, /* @__PURE__ */ React33.createElement("div", { className: "p-6" }, /* @__PURE__ */ React33.createElement("h3", { className: "text-lg text-black tracking-tight capitalize mb-2" }, actionModal === "success" ? "Complete Application" : `${actionModal} Application`), /* @__PURE__ */ React33.createElement("p", { className: "text-xs text-neutral-500" }, actionModal === "success" ? "Are you sure you want to mark this application as successfully completed?" : `Please provide a clear reason for the user. They will see this message and be asked to fix their application.`)), (actionModal === "query" || actionModal === "reject") && /* @__PURE__ */ React33.createElement("div", { className: "p-6 pb-2" }, /* @__PURE__ */ React33.createElement(TextInput, { label: "Reason for Action", value: actionMessage, onChange: setActionMessage, placeholder: "Enter your reason here...", disabled: isActioning })), /* @__PURE__ */ React33.createElement("div", { className: "flex items-center p-6 pt-4 gap-3" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => setActionModal(null), disabled: isActioning, className: "flex-1 py-3 text-[11px] tracking-widest uppercase text-neutral-600 rounded-full hover:bg-neutral-50 transition-colors outline-none disabled:opacity-50" }, "Cancel"), /* @__PURE__ */ React33.createElement(ThreeDActionButton, { onClick: async () => {
|
|
2659
|
+
setIsActioning(true);
|
|
2660
|
+
await onUpdateStatus(selectedApp.id, actionModal === "success" ? "COMPLETED" : actionModal === "reject" ? "REJECTED" : "QUEUED", actionMessage);
|
|
2661
|
+
setIsActioning(false);
|
|
2662
|
+
setActionModal(null);
|
|
2663
|
+
setActionMessage("");
|
|
2664
|
+
}, disabled: isActioning || (actionModal === "query" || actionModal === "reject") && actionMessage.trim().length < 5, isLoading: isActioning, className: "flex-1" }, "Confirm ", actionModal)))), archiveToDelete && /* @__PURE__ */ React33.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React33.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => !isActioning && setArchiveToDelete(null) }), /* @__PURE__ */ React33.createElement("div", { className: "relative w-full max-w-md bg-white rounded-3xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200 text-left" }, /* @__PURE__ */ React33.createElement("div", { className: "p-6" }, /* @__PURE__ */ React33.createElement("h3", { className: "text-lg text-black tracking-tight mb-2" }, "Delete Document?"), /* @__PURE__ */ React33.createElement("p", { className: "text-xs text-neutral-500" }, 'Are you sure you want to permanently delete "', archiveToDelete.name, '"?')), /* @__PURE__ */ React33.createElement("div", { className: "flex items-center p-6 gap-3" }, /* @__PURE__ */ React33.createElement("button", { onClick: () => setArchiveToDelete(null), disabled: isActioning, className: "flex-1 py-3 text-[11px] tracking-widest uppercase text-neutral-600 rounded-full hover:bg-neutral-50 transition-colors outline-none disabled:opacity-50" }, "Cancel"), /* @__PURE__ */ React33.createElement(ThreeDActionButton, { onClick: async () => {
|
|
2665
|
+
setIsActioning(true);
|
|
2666
|
+
await onDeleteArchive(selectedApp.id, archiveToDelete.id);
|
|
2667
|
+
setIsActioning(false);
|
|
2668
|
+
setArchiveToDelete(null);
|
|
2669
|
+
}, isLoading: isActioning, className: "flex-1" }, "Delete Document")))));
|
|
2670
|
+
};
|
|
2671
|
+
|
|
2672
|
+
// src/components/UniversalOverviewPage.tsx
|
|
2673
|
+
import React34 from "react";
|
|
2674
|
+
var UniversalOverviewPage = ({
|
|
2675
|
+
headerTitle,
|
|
2676
|
+
headerDescription,
|
|
2677
|
+
quickStats,
|
|
2678
|
+
detailsTitle = "Details",
|
|
2679
|
+
details,
|
|
2680
|
+
primaryAction,
|
|
2681
|
+
alerts = []
|
|
2682
|
+
}) => {
|
|
2683
|
+
return /* @__PURE__ */ React34.createElement("div", { className: "flex flex-col gap-8 animate-in fade-in duration-300 min-h-full pb-10" }, /* @__PURE__ */ React34.createElement("div", { className: "flex items-center justify-between gap-4" }, /* @__PURE__ */ React34.createElement("div", null, /* @__PURE__ */ React34.createElement("h1", { className: "text-xl text-black mb-1 tracking-tight" }, headerTitle), /* @__PURE__ */ React34.createElement("p", { className: "text-xs text-neutral-500" }, headerDescription))), quickStats.length > 0 && /* @__PURE__ */ React34.createElement("div", { className: "w-full rounded-2xl overflow-hidden max-w-3xl bg-white" }, /* @__PURE__ */ React34.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 divide-y md:divide-y-0 md:divide-x divide-neutral-100" }, quickStats.map((stat, idx) => /* @__PURE__ */ React34.createElement("div", { key: idx, className: "p-6 flex items-center gap-4 hover:bg-neutral-50/50 transition-colors min-w-0" }, /* @__PURE__ */ React34.createElement("div", { className: "w-12 h-12 rounded-full border border-neutral-200 bg-white flex items-center justify-center text-black shrink-0" }, stat.icon), /* @__PURE__ */ React34.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React34.createElement("p", { className: "text-[10px] tracking-[0.2em] text-neutral-400 mb-1 truncate uppercase" }, stat.label), /* @__PURE__ */ React34.createElement("p", { className: "text-lg md:text-xl text-black tracking-tight truncate" }, stat.value)))))), /* @__PURE__ */ React34.createElement("div", { className: "w-full rounded-2xl max-w-3xl overflow-hidden bg-white min-w-0" }, /* @__PURE__ */ React34.createElement("div", { className: "p-6 sm:p-8 flex flex-col h-full min-w-0 gap-6" }, /* @__PURE__ */ React34.createElement("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b border-neutral-100 pb-4" }, /* @__PURE__ */ React34.createElement("h3", { className: "text-[11px] text-black tracking-[0.2em] uppercase" }, detailsTitle), primaryAction && (primaryAction.href ? /* @__PURE__ */ React34.createElement(
|
|
2684
|
+
ThreeDButton,
|
|
2685
|
+
{
|
|
2686
|
+
href: primaryAction.href,
|
|
2687
|
+
onClick: primaryAction.onClick,
|
|
2688
|
+
className: "w-fit shrink-0 gap-2"
|
|
2689
|
+
},
|
|
2690
|
+
primaryAction.label,
|
|
2691
|
+
primaryAction.icon
|
|
2692
|
+
) : /* @__PURE__ */ React34.createElement(
|
|
2693
|
+
ThreeDActionButton,
|
|
2694
|
+
{
|
|
2695
|
+
onClick: primaryAction.onClick,
|
|
2696
|
+
isLoading: primaryAction.isLoading,
|
|
2697
|
+
className: "w-fit shrink-0 gap-2"
|
|
2698
|
+
},
|
|
2699
|
+
primaryAction.label,
|
|
2700
|
+
primaryAction.icon
|
|
2701
|
+
))), /* @__PURE__ */ React34.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-8" }, details.map((detail, idx) => /* @__PURE__ */ React34.createElement("div", { key: idx, className: "min-w-0" }, /* @__PURE__ */ React34.createElement("p", { className: "text-[10px] tracking-[0.2em] text-neutral-400 mb-1.5 uppercase" }, detail.label), /* @__PURE__ */ React34.createElement("p", { className: "text-[13px] text-black truncate" }, detail.value)))), alerts.map((alert, idx) => {
|
|
2702
|
+
const bgClass = alert.type === "warning" ? "bg-amber-50/50" : alert.type === "info" ? "bg-blue-50/50" : "bg-red-50/50";
|
|
2703
|
+
const textClass = alert.type === "warning" ? "text-amber-600" : alert.type === "info" ? "text-blue-600" : "text-red-600";
|
|
2704
|
+
const valClass = alert.type === "warning" ? "text-amber-700" : alert.type === "info" ? "text-blue-700" : "text-red-700";
|
|
2705
|
+
const lblClass = alert.type === "warning" ? "text-amber-400" : alert.type === "info" ? "text-blue-400" : "text-red-400";
|
|
2706
|
+
return /* @__PURE__ */ React34.createElement("div", { key: idx, className: `mt-4 p-5 rounded-xl flex flex-col gap-4 ${bgClass}` }, /* @__PURE__ */ React34.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React34.createElement("span", { className: `text-[11px] tracking-widest uppercase ${textClass}` }, alert.title)), alert.items.map((item, itemIdx) => /* @__PURE__ */ React34.createElement("div", { key: itemIdx }, /* @__PURE__ */ React34.createElement("span", { className: `text-[10px] tracking-[0.2em] block mb-1 uppercase ${lblClass}` }, item.label), /* @__PURE__ */ React34.createElement("p", { className: `text-[13px] leading-relaxed ${valClass}` }, item.text))));
|
|
2707
|
+
}))));
|
|
2708
|
+
};
|
|
2709
|
+
|
|
2710
|
+
// src/components/UniversalErrorView.tsx
|
|
2711
|
+
import React35 from "react";
|
|
2712
|
+
import { HugeiconsIcon as HugeiconsIcon20 } from "@hugeicons/react";
|
|
2713
|
+
import { ConfusedIcon } from "@hugeicons/core-free-icons";
|
|
2714
|
+
var UniversalErrorView = ({
|
|
2715
|
+
isBooting,
|
|
2716
|
+
isLoading,
|
|
2717
|
+
activeData,
|
|
2718
|
+
activeError,
|
|
2719
|
+
envName,
|
|
2720
|
+
onRetry,
|
|
2721
|
+
returnUrl = "/app",
|
|
2722
|
+
returnLabel = "Return to Workspace"
|
|
2723
|
+
}) => {
|
|
2724
|
+
if (isBooting || isLoading && !activeData) {
|
|
2725
|
+
return /* @__PURE__ */ React35.createElement("div", { className: "flex items-center justify-center h-screen w-full bg-transparent" }, /* @__PURE__ */ React35.createElement(PageSpinner, null));
|
|
2726
|
+
}
|
|
2727
|
+
if (!isLoading && (!activeData || activeError)) {
|
|
2728
|
+
const errorString = typeof activeError === "string" ? activeError : JSON.stringify(activeError || "");
|
|
2729
|
+
const errorMsg = errorString.toLowerCase();
|
|
2730
|
+
const isPermissionError = errorMsg.includes("forbidden") || errorMsg.includes("unauthorized") || errorMsg.includes("permission");
|
|
2731
|
+
const isNetworkError = errorMsg.includes("network") || errorMsg.includes("connection") || errorMsg.includes("fetch");
|
|
2732
|
+
const isNotFoundError = errorMsg.includes("not found") || errorMsg.includes("404") || errorMsg.includes("does not exist") || !activeData && !isPermissionError && !isNetworkError;
|
|
2733
|
+
const apiMessage = typeof activeError === "string" && activeError.trim() !== "" ? activeError : null;
|
|
2734
|
+
let title = "Oops Connection Error";
|
|
2735
|
+
let description = apiMessage || `We could not load your request. Please check your connection and try again.`;
|
|
2736
|
+
let IconComponent = ConfusedIcon;
|
|
2737
|
+
if (isNotFoundError) {
|
|
2738
|
+
title = "Oops its not your fault";
|
|
2739
|
+
description = apiMessage || `We could not reach the ${envName} you just loaded. Our team has been notified.`;
|
|
2740
|
+
} else if (isPermissionError) {
|
|
2741
|
+
title = "Access Restricted";
|
|
2742
|
+
description = apiMessage || `You have insufficient permissions to view this ${envName}. Please contact your administrator.`;
|
|
2743
|
+
}
|
|
2744
|
+
return /* @__PURE__ */ React35.createElement("div", { className: "flex flex-col items-center justify-center h-screen w-full px-4 animate-in fade-in duration-500" }, /* @__PURE__ */ React35.createElement("div", { className: "mb-4 flex justify-center" }, /* @__PURE__ */ React35.createElement(HugeiconsIcon20, { icon: IconComponent, size: 48, className: "text-neutral-300" })), /* @__PURE__ */ React35.createElement("h2", { className: "text-lg text-black tracking-tight " }, title), /* @__PURE__ */ React35.createElement("p", { className: "text-xs mt-2 mb-8 text-neutral-500 max-w-sm text-center leading-relaxed" }, description), /* @__PURE__ */ React35.createElement("div", { className: "flex flex-col sm:flex-row items-center gap-3 w-full justify-center sm:w-auto" }, isNotFoundError || isPermissionError ? /* @__PURE__ */ React35.createElement(
|
|
2745
|
+
"button",
|
|
2746
|
+
{
|
|
2747
|
+
onClick: () => window.location.href = returnUrl,
|
|
2748
|
+
className: "px-6 py-2 bg-neutral-100 hover:bg-neutral-200 text-black rounded-full text-[11px] tracking-widest transition-colors w-full sm:w-auto outline-none"
|
|
2749
|
+
},
|
|
2750
|
+
returnLabel
|
|
2751
|
+
) : (
|
|
2752
|
+
// Soft errors (Network timeouts) allow them to retry or optionally retreat
|
|
2753
|
+
/* @__PURE__ */ React35.createElement(React35.Fragment, null, envName.toLowerCase().includes("application") && /* @__PURE__ */ React35.createElement(
|
|
2754
|
+
"button",
|
|
2755
|
+
{
|
|
2756
|
+
onClick: () => window.location.href = returnUrl,
|
|
2757
|
+
className: "px-6 py-2 bg-transparent border border-neutral-200 hover:bg-neutral-50 text-neutral-600 hover:text-black rounded-full text-[11px] tracking-widest transition-colors w-full sm:w-auto outline-none"
|
|
2758
|
+
},
|
|
2759
|
+
"Back Home"
|
|
2760
|
+
), /* @__PURE__ */ React35.createElement(
|
|
2761
|
+
"button",
|
|
2762
|
+
{
|
|
2763
|
+
onClick: onRetry,
|
|
2764
|
+
className: "px-6 py-2 bg-black hover:bg-neutral-800 text-white rounded-full text-[11px] tracking-widest transition-colors w-full sm:w-auto outline-none capitalize"
|
|
2765
|
+
},
|
|
2766
|
+
"Refresh ",
|
|
2767
|
+
envName
|
|
2768
|
+
))
|
|
2769
|
+
)));
|
|
2770
|
+
}
|
|
2771
|
+
return null;
|
|
2772
|
+
};
|
|
2773
|
+
|
|
2774
|
+
// src/components/UniversalLookupPage.tsx
|
|
2775
|
+
import React36, { useState as useState18 } from "react";
|
|
2776
|
+
import { HugeiconsIcon as HugeiconsIcon21 } from "@hugeicons/react";
|
|
2777
|
+
import { Search01Icon } from "@hugeicons/core-free-icons";
|
|
2778
|
+
var UniversalLookupPage = ({
|
|
2779
|
+
headerTitle,
|
|
2780
|
+
headerDescription,
|
|
2781
|
+
searchOptions,
|
|
2782
|
+
selectedSearchType,
|
|
2783
|
+
onSearchTypeChange,
|
|
2784
|
+
searchQuery,
|
|
2785
|
+
onSearchQueryChange,
|
|
2786
|
+
isSearching,
|
|
2787
|
+
onSearch,
|
|
2788
|
+
resultContent,
|
|
2789
|
+
modals
|
|
2790
|
+
}) => {
|
|
2791
|
+
const [isTypeModalOpen, setIsTypeModalOpen] = useState18(false);
|
|
2792
|
+
const currentOptionLabel = searchOptions.find((opt) => opt.value === selectedSearchType)?.label || "Select Type";
|
|
2793
|
+
return /* @__PURE__ */ React36.createElement("div", { className: "flex flex-col max-w-3xl rounded-2xl p-6 bg-white gap-8 animate-in fade-in duration-300 min-h-full pb-20" }, /* @__PURE__ */ React36.createElement(ManagedToaster, null), /* @__PURE__ */ React36.createElement("div", { className: "flex flex-col sm:flex-row sm:items-start justify-between gap-3 sm:gap-4" }, /* @__PURE__ */ React36.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React36.createElement("h1", { className: "text-xl text-black mb-1 truncate tracking-tight" }, headerTitle), /* @__PURE__ */ React36.createElement("p", { className: "text-xs text-neutral-500 truncate" }, headerDescription))), /* @__PURE__ */ React36.createElement("div", { className: "w-full max-w-2xl pb-8" }, /* @__PURE__ */ React36.createElement("form", { className: "flex flex-col gap-6", onSubmit: onSearch, autoComplete: "off" }, /* @__PURE__ */ React36.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ React36.createElement(
|
|
2794
|
+
"button",
|
|
2795
|
+
{
|
|
2796
|
+
type: "button",
|
|
2797
|
+
onClick: () => setIsTypeModalOpen(true),
|
|
2798
|
+
className: "mt-2 text-[12px] tracking-widest bg-transparent border-b border-neutral-200 text-black text-left outline-none focus:border-black shrink-0 uppercase"
|
|
2799
|
+
},
|
|
2800
|
+
currentOptionLabel
|
|
2801
|
+
), /* @__PURE__ */ React36.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React36.createElement(
|
|
2802
|
+
TextInput,
|
|
2803
|
+
{
|
|
2804
|
+
placeholder: "Enter Exact ID, Email, or Slug...",
|
|
2805
|
+
value: searchQuery,
|
|
2806
|
+
onChange: onSearchQueryChange,
|
|
2807
|
+
disabled: isSearching
|
|
2808
|
+
}
|
|
2809
|
+
))), /* @__PURE__ */ React36.createElement("div", { className: "flex justify-end" }, /* @__PURE__ */ React36.createElement(
|
|
2810
|
+
ThreeDActionButton,
|
|
2811
|
+
{
|
|
2812
|
+
type: "submit",
|
|
2813
|
+
disabled: isSearching || !searchQuery,
|
|
2814
|
+
isLoading: isSearching,
|
|
2815
|
+
className: "min-w-32"
|
|
2816
|
+
},
|
|
2817
|
+
/* @__PURE__ */ React36.createElement(HugeiconsIcon21, { icon: Search01Icon, size: 14, className: "mr-2" }),
|
|
2818
|
+
" Lookup"
|
|
2819
|
+
)))), resultContent && /* @__PURE__ */ React36.createElement("div", { className: "w-full max-w-2xl bg-white text-left animate-in fade-in slide-in-from-bottom-4" }, /* @__PURE__ */ React36.createElement("h3", { className: "text-[10px] text-neutral-400 tracking-[0.2em] mb-6 uppercase" }, "Entity Record Found"), resultContent), isTypeModalOpen && /* @__PURE__ */ React36.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React36.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => setIsTypeModalOpen(false) }), /* @__PURE__ */ React36.createElement("div", { className: "relative w-80 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React36.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ React36.createElement("h3", { className: "text-[14px] text-black tracking-tight mb-2" }, "Select Entity Type")), /* @__PURE__ */ React36.createElement("div", { className: "w-full flex flex-col pl-2 pr-2 pb-2" }, searchOptions.map((option) => /* @__PURE__ */ React36.createElement(
|
|
2820
|
+
"button",
|
|
2821
|
+
{
|
|
2822
|
+
key: option.value,
|
|
2823
|
+
type: "button",
|
|
2824
|
+
onClick: () => {
|
|
2825
|
+
onSearchTypeChange(option.value);
|
|
2826
|
+
setIsTypeModalOpen(false);
|
|
2827
|
+
},
|
|
2828
|
+
className: `text-left px-4 py-3 text-[12px] tracking-wide transition-colors rounded-full flex items-center justify-between outline-none ${selectedSearchType === option.value ? "bg-neutral-100 text-black" : "text-neutral-500 hover:bg-neutral-50 hover:text-black"}`
|
|
2829
|
+
},
|
|
2830
|
+
/* @__PURE__ */ React36.createElement("span", { className: "truncate pr-2" }, option.label),
|
|
2831
|
+
selectedSearchType === option.value && /* @__PURE__ */ React36.createElement("div", { className: "w-1.5 h-1.5 bg-black rounded-full shrink-0" })
|
|
2832
|
+
))), /* @__PURE__ */ React36.createElement("div", { className: "w-full flex" }, /* @__PURE__ */ React36.createElement("button", { type: "button", onClick: () => setIsTypeModalOpen(false), className: "w-full py-2.5 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors outline-none" }, "Cancel")))), modals);
|
|
2833
|
+
};
|
|
2834
|
+
|
|
2835
|
+
// src/components/UniversalDirectoryPage.tsx
|
|
2836
|
+
import React37 from "react";
|
|
2837
|
+
import { HugeiconsIcon as HugeiconsIcon22 } from "@hugeicons/react";
|
|
2838
|
+
import { ArrowLeft01Icon as ArrowLeft01Icon6, ArrowRight01Icon as ArrowRight01Icon6, Loading03Icon as Loading03Icon10 } from "@hugeicons/core-free-icons";
|
|
2839
|
+
var PageSpinner4 = () => /* @__PURE__ */ React37.createElement("div", { className: "flex justify-center items-center py-12" }, /* @__PURE__ */ React37.createElement(HugeiconsIcon22, { icon: Loading03Icon10, size: 32, className: "animate-spin mb-4 text-black" }));
|
|
2840
|
+
var UniversalDirectoryPage = ({
|
|
2841
|
+
headerTitle,
|
|
2842
|
+
headerDescription,
|
|
2843
|
+
searchPlaceholder = "Search...",
|
|
2844
|
+
searchQuery,
|
|
2845
|
+
onSearchChange,
|
|
2846
|
+
currentView,
|
|
2847
|
+
onBackToList,
|
|
2848
|
+
items,
|
|
2849
|
+
isLoading,
|
|
2850
|
+
currentPage,
|
|
2851
|
+
totalPages,
|
|
2852
|
+
onPageChange,
|
|
2853
|
+
onRowClick,
|
|
2854
|
+
detailsContent,
|
|
2855
|
+
modals
|
|
2856
|
+
}) => {
|
|
2857
|
+
return /* @__PURE__ */ React37.createElement("div", { className: "flex flex-col gap-8 animate-in max-w-3xl fade-in duration-300 p-6 rounded-2xl bg-white min-h-full" }, /* @__PURE__ */ React37.createElement(ManagedToaster, null), /* @__PURE__ */ React37.createElement("div", { className: "flex flex-col sm:flex-row sm:items-start justify-between gap-4" }, currentView === "list" ? /* @__PURE__ */ React37.createElement("div", { className: "w-full" }, /* @__PURE__ */ React37.createElement("h1", { className: "text-xl text-black mb-1 tracking-tight" }, headerTitle), /* @__PURE__ */ React37.createElement("p", { className: "text-xs text-neutral-500 mb-6" }, headerDescription), /* @__PURE__ */ React37.createElement(
|
|
2858
|
+
TextInput,
|
|
2859
|
+
{
|
|
2860
|
+
placeholder: searchPlaceholder,
|
|
2861
|
+
value: searchQuery,
|
|
2862
|
+
onChange: onSearchChange
|
|
2863
|
+
}
|
|
2864
|
+
)) : /* @__PURE__ */ React37.createElement("div", { className: "flex flex-col items-start gap-3" }, /* @__PURE__ */ React37.createElement("button", { onClick: onBackToList, className: "text-[10px] text-neutral-400 hover:text-black tracking-[0.2em] flex items-center gap-1.5 transition-colors outline-none uppercase" }, /* @__PURE__ */ React37.createElement(HugeiconsIcon22, { icon: ArrowLeft01Icon6, size: 12 }), " Back"))), currentView === "list" && /* @__PURE__ */ React37.createElement("div", { className: "w-full overflow-hidden pt-2" }, isLoading ? /* @__PURE__ */ React37.createElement(PageSpinner4, null) : /* @__PURE__ */ React37.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ React37.createElement("div", { className: "divide-y divide-neutral-100" }, items.length === 0 ? /* @__PURE__ */ React37.createElement("p", { className: "text-xs text-neutral-500 py-6 text-center" }, "No records found.") : items.map((item) => /* @__PURE__ */ React37.createElement(
|
|
2865
|
+
"div",
|
|
2866
|
+
{
|
|
2867
|
+
key: item.id,
|
|
2868
|
+
onClick: () => onRowClick(item.id),
|
|
2869
|
+
className: "flex items-center justify-between p-4 sm:p-5 hover:bg-neutral-50/50 transition-colors cursor-pointer group min-w-0"
|
|
2870
|
+
},
|
|
2871
|
+
/* @__PURE__ */ React37.createElement("div", { className: "flex items-center gap-3 sm:gap-4 min-w-0 flex-1" }, /* @__PURE__ */ React37.createElement("div", { className: "w-10 h-10 shrink-0 rounded-full flex items-center justify-center bg-neutral-100 text-black text-xs" }, item.icon), /* @__PURE__ */ React37.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React37.createElement("div", { className: "text-sm text-black truncate pr-2" }, item.primaryText), /* @__PURE__ */ React37.createElement("div", { className: "text-xs text-neutral-500 truncate pr-2 mt-0.5" }, item.secondaryText))),
|
|
2872
|
+
item.rightBadge && /* @__PURE__ */ React37.createElement("div", { className: "shrink-0 pl-2" }, /* @__PURE__ */ React37.createElement("span", { className: `text-[10px] tracking-[0.2em] px-3 py-1 rounded-full whitespace-nowrap uppercase ${item.rightBadgeClass || "text-neutral-500 border border-neutral-200 bg-white"}` }, item.rightBadge))
|
|
2873
|
+
))), totalPages > 1 && /* @__PURE__ */ React37.createElement("div", { className: "flex items-center justify-between p-4 sm:p-5" }, /* @__PURE__ */ React37.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em] uppercase" }, "Page ", currentPage, " of ", totalPages), /* @__PURE__ */ React37.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React37.createElement("button", { onClick: () => onPageChange(currentPage - 1), disabled: currentPage === 1 || isLoading, className: "p-2 border border-neutral-200 rounded-full bg-white text-neutral-500 hover:text-black outline-none disabled:opacity-30" }, /* @__PURE__ */ React37.createElement(HugeiconsIcon22, { icon: ArrowLeft01Icon6, size: 14 })), /* @__PURE__ */ React37.createElement("button", { onClick: () => onPageChange(currentPage + 1), disabled: currentPage >= totalPages || isLoading, className: "p-2 border border-neutral-200 rounded-full bg-white text-neutral-500 hover:text-black outline-none disabled:opacity-30" }, /* @__PURE__ */ React37.createElement(HugeiconsIcon22, { icon: ArrowRight01Icon6, size: 14 })))))), currentView === "details" && detailsContent, modals);
|
|
2874
|
+
};
|
|
2322
2875
|
export {
|
|
2323
2876
|
AITranscriptionFeature,
|
|
2324
2877
|
AppBento2,
|
|
@@ -2344,10 +2897,17 @@ export {
|
|
|
2344
2897
|
TextInput,
|
|
2345
2898
|
ThreeDActionButton,
|
|
2346
2899
|
ThreeDButton,
|
|
2900
|
+
UniversalAgentConsole,
|
|
2901
|
+
UniversalBillingPage,
|
|
2902
|
+
UniversalDashboardPage,
|
|
2903
|
+
UniversalDirectoryPage,
|
|
2904
|
+
UniversalErrorView,
|
|
2347
2905
|
UniversalHeader,
|
|
2348
2906
|
UniversalIdentityPage,
|
|
2907
|
+
UniversalLookupPage,
|
|
2349
2908
|
UniversalMembersPage,
|
|
2350
2909
|
UniversalOrganizationPage,
|
|
2910
|
+
UniversalOverviewPage,
|
|
2351
2911
|
UniversalProfileSettings,
|
|
2352
2912
|
UniversalSidebar,
|
|
2353
2913
|
ZairusAuth
|