@quanticjs/notification-ui 8.0.0 → 9.0.0
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/README.md +2 -1
- package/dist/index.cjs +1062 -952
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +1042 -933
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -363,7 +363,7 @@ function NotificationBell({
|
|
|
363
363
|
"span",
|
|
364
364
|
{
|
|
365
365
|
"aria-hidden": "true",
|
|
366
|
-
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-
|
|
366
|
+
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background",
|
|
367
367
|
children: count > 99 ? "99+" : count
|
|
368
368
|
}
|
|
369
369
|
)
|
|
@@ -451,7 +451,7 @@ function InboxRow({
|
|
|
451
451
|
),
|
|
452
452
|
children: [
|
|
453
453
|
/* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2 text-sm font-medium", children: [
|
|
454
|
-
!item.isRead && /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "h-2 w-2 rounded-full bg-
|
|
454
|
+
!item.isRead && /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "h-2 w-2 rounded-full bg-coral" }),
|
|
455
455
|
item.title
|
|
456
456
|
] }),
|
|
457
457
|
item.body && /* @__PURE__ */ jsx5("span", { className: "text-xs text-muted-foreground", children: item.body })
|
|
@@ -460,9 +460,117 @@ function InboxRow({
|
|
|
460
460
|
) });
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
+
// src/notification-center.tsx
|
|
464
|
+
import { useCallback, useEffect as useEffect4, useRef as useRef2, useState as useState3 } from "react";
|
|
465
|
+
import { cn as cn4, useExitAnimation, useFocusTrap } from "@quanticjs/react-ui";
|
|
466
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
467
|
+
function BellIcon() {
|
|
468
|
+
return /* @__PURE__ */ jsxs4(
|
|
469
|
+
"svg",
|
|
470
|
+
{
|
|
471
|
+
"aria-hidden": true,
|
|
472
|
+
viewBox: "0 0 24 24",
|
|
473
|
+
fill: "none",
|
|
474
|
+
stroke: "currentColor",
|
|
475
|
+
strokeWidth: "2",
|
|
476
|
+
strokeLinecap: "round",
|
|
477
|
+
strokeLinejoin: "round",
|
|
478
|
+
className: "h-5 w-5",
|
|
479
|
+
children: [
|
|
480
|
+
/* @__PURE__ */ jsx6("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
481
|
+
/* @__PURE__ */ jsx6("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
482
|
+
]
|
|
483
|
+
}
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
function NotificationCenter({
|
|
487
|
+
appId,
|
|
488
|
+
basePath,
|
|
489
|
+
pollIntervalMs,
|
|
490
|
+
className,
|
|
491
|
+
panelClassName
|
|
492
|
+
}) {
|
|
493
|
+
const [open, setOpen] = useState3(false);
|
|
494
|
+
const containerRef = useRef2(null);
|
|
495
|
+
const panelRef = useRef2(null);
|
|
496
|
+
const { data } = useUnreadCount({ appId, basePath, pollIntervalMs });
|
|
497
|
+
const unreadCount = data?.count ?? 0;
|
|
498
|
+
const badge = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
499
|
+
const label = unreadCount === 0 ? "No unread notifications" : `${unreadCount} unread notifications`;
|
|
500
|
+
const close = useCallback(() => setOpen(false), []);
|
|
501
|
+
useEffect4(() => {
|
|
502
|
+
if (!open) return;
|
|
503
|
+
const onKey = (e) => {
|
|
504
|
+
if (e.key === "Escape") close();
|
|
505
|
+
};
|
|
506
|
+
const onPointer = (e) => {
|
|
507
|
+
const c = containerRef.current;
|
|
508
|
+
if (c && e.target instanceof Node && !c.contains(e.target)) close();
|
|
509
|
+
};
|
|
510
|
+
document.addEventListener("keydown", onKey);
|
|
511
|
+
document.addEventListener("mousedown", onPointer);
|
|
512
|
+
return () => {
|
|
513
|
+
document.removeEventListener("keydown", onKey);
|
|
514
|
+
document.removeEventListener("mousedown", onPointer);
|
|
515
|
+
};
|
|
516
|
+
}, [open, close]);
|
|
517
|
+
useFocusTrap(panelRef, open);
|
|
518
|
+
const panelExit = useExitAnimation(open);
|
|
519
|
+
return /* @__PURE__ */ jsxs4("div", { ref: containerRef, className: cn4("relative inline-block", className), children: [
|
|
520
|
+
/* @__PURE__ */ jsxs4(
|
|
521
|
+
"button",
|
|
522
|
+
{
|
|
523
|
+
type: "button",
|
|
524
|
+
"aria-label": label,
|
|
525
|
+
"aria-haspopup": "dialog",
|
|
526
|
+
"aria-expanded": open,
|
|
527
|
+
onClick: () => setOpen((p) => !p),
|
|
528
|
+
className: "relative inline-flex h-10 w-10 items-center justify-center rounded-full text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
529
|
+
children: [
|
|
530
|
+
/* @__PURE__ */ jsx6(BellIcon, {}),
|
|
531
|
+
/* @__PURE__ */ jsx6("span", { role: "status", className: "sr-only", children: label }),
|
|
532
|
+
unreadCount > 0 && /* @__PURE__ */ jsx6(
|
|
533
|
+
"span",
|
|
534
|
+
{
|
|
535
|
+
"aria-hidden": true,
|
|
536
|
+
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background",
|
|
537
|
+
children: badge
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
]
|
|
541
|
+
}
|
|
542
|
+
),
|
|
543
|
+
panelExit.mounted && /* @__PURE__ */ jsx6(
|
|
544
|
+
"div",
|
|
545
|
+
{
|
|
546
|
+
ref: panelRef,
|
|
547
|
+
role: "dialog",
|
|
548
|
+
"aria-label": "Notifications",
|
|
549
|
+
tabIndex: -1,
|
|
550
|
+
"data-state": panelExit.state,
|
|
551
|
+
onAnimationEnd: panelExit.onAnimationEnd,
|
|
552
|
+
className: cn4(
|
|
553
|
+
"absolute end-0 z-(--z-popover) mt-2 w-96 overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-raised",
|
|
554
|
+
panelExit.state === "open" ? "animate-pop-in" : "animate-pop-out [animation-fill-mode:forwards]",
|
|
555
|
+
panelClassName
|
|
556
|
+
),
|
|
557
|
+
children: /* @__PURE__ */ jsx6(
|
|
558
|
+
NotificationInbox,
|
|
559
|
+
{
|
|
560
|
+
appId,
|
|
561
|
+
basePath,
|
|
562
|
+
pollIntervalMs,
|
|
563
|
+
className: "max-h-[28rem] overflow-y-auto"
|
|
564
|
+
}
|
|
565
|
+
)
|
|
566
|
+
}
|
|
567
|
+
)
|
|
568
|
+
] });
|
|
569
|
+
}
|
|
570
|
+
|
|
463
571
|
// src/delivery-analytics-page.tsx
|
|
464
|
-
import { useState as
|
|
465
|
-
import { cn as
|
|
572
|
+
import { useState as useState4 } from "react";
|
|
573
|
+
import { cn as cn8 } from "@quanticjs/react-ui";
|
|
466
574
|
|
|
467
575
|
// src/use-delivery-analytics.ts
|
|
468
576
|
import { useApiQuery as useApiQuery4 } from "@quanticjs/react-query";
|
|
@@ -514,8 +622,8 @@ function useDeliveryTypes({
|
|
|
514
622
|
}
|
|
515
623
|
|
|
516
624
|
// src/funnel-stats.tsx
|
|
517
|
-
import { cn as
|
|
518
|
-
import { jsx as
|
|
625
|
+
import { cn as cn5 } from "@quanticjs/react-ui";
|
|
626
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
519
627
|
var pct = (n) => `${(n * 100).toFixed(1)}%`;
|
|
520
628
|
function FunnelStats({ funnel, className }) {
|
|
521
629
|
const cards = [
|
|
@@ -528,13 +636,13 @@ function FunnelStats({ funnel, className }) {
|
|
|
528
636
|
{ label: "Bounce rate", value: pct(funnel.bounceRate) },
|
|
529
637
|
{ label: "Delivery rate", value: pct(funnel.deliveryRate) }
|
|
530
638
|
];
|
|
531
|
-
return /* @__PURE__ */
|
|
639
|
+
return /* @__PURE__ */ jsx7("ul", { className: cn5("grid grid-cols-2 gap-3 sm:grid-cols-4", className), "aria-label": "Delivery funnel", children: cards.map((c) => /* @__PURE__ */ jsxs5(
|
|
532
640
|
"li",
|
|
533
641
|
{
|
|
534
642
|
className: "flex flex-col gap-1 rounded-lg border border-border bg-card p-4",
|
|
535
643
|
children: [
|
|
536
|
-
/* @__PURE__ */
|
|
537
|
-
/* @__PURE__ */
|
|
644
|
+
/* @__PURE__ */ jsx7("span", { className: "text-xs font-medium text-muted-foreground", children: c.label }),
|
|
645
|
+
/* @__PURE__ */ jsx7("span", { className: "text-2xl font-semibold text-foreground", children: c.value })
|
|
538
646
|
]
|
|
539
647
|
},
|
|
540
648
|
c.label
|
|
@@ -542,7 +650,7 @@ function FunnelStats({ funnel, className }) {
|
|
|
542
650
|
}
|
|
543
651
|
|
|
544
652
|
// src/trend-chart.tsx
|
|
545
|
-
import { cn as
|
|
653
|
+
import { cn as cn6 } from "@quanticjs/react-ui";
|
|
546
654
|
import {
|
|
547
655
|
CartesianGrid,
|
|
548
656
|
Line,
|
|
@@ -552,46 +660,46 @@ import {
|
|
|
552
660
|
XAxis,
|
|
553
661
|
YAxis
|
|
554
662
|
} from "recharts";
|
|
555
|
-
import { jsx as
|
|
663
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
556
664
|
function TrendChart({ data, className }) {
|
|
557
|
-
return /* @__PURE__ */
|
|
558
|
-
/* @__PURE__ */
|
|
559
|
-
/* @__PURE__ */
|
|
560
|
-
/* @__PURE__ */
|
|
561
|
-
/* @__PURE__ */
|
|
562
|
-
/* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
564
|
-
/* @__PURE__ */
|
|
565
|
-
/* @__PURE__ */
|
|
665
|
+
return /* @__PURE__ */ jsx8("div", { className: cn6("h-72 w-full", className), role: "img", "aria-label": "Delivery trend over time", children: /* @__PURE__ */ jsx8(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs6(LineChart, { data, margin: { top: 8, right: 16, bottom: 8, left: 0 }, children: [
|
|
666
|
+
/* @__PURE__ */ jsx8(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--border)" }),
|
|
667
|
+
/* @__PURE__ */ jsx8(XAxis, { dataKey: "day", stroke: "var(--muted-foreground)", fontSize: 12 }),
|
|
668
|
+
/* @__PURE__ */ jsx8(YAxis, { stroke: "var(--muted-foreground)", fontSize: 12, allowDecimals: false }),
|
|
669
|
+
/* @__PURE__ */ jsx8(Tooltip, {}),
|
|
670
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "sends", stroke: "var(--primary)", dot: false }),
|
|
671
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "delivered", stroke: "var(--chart-2, var(--primary))", dot: false }),
|
|
672
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "opened", stroke: "var(--chart-3, var(--primary))", dot: false }),
|
|
673
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "clicked", stroke: "var(--chart-4, var(--primary))", dot: false })
|
|
566
674
|
] }) }) });
|
|
567
675
|
}
|
|
568
676
|
|
|
569
677
|
// src/type-table.tsx
|
|
570
|
-
import { cn as
|
|
571
|
-
import { jsx as
|
|
678
|
+
import { cn as cn7 } from "@quanticjs/react-ui";
|
|
679
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
572
680
|
var pct2 = (n) => `${(n * 100).toFixed(1)}%`;
|
|
573
681
|
function TypeTable({ rows, className }) {
|
|
574
|
-
return /* @__PURE__ */
|
|
575
|
-
/* @__PURE__ */
|
|
576
|
-
/* @__PURE__ */
|
|
577
|
-
/* @__PURE__ */
|
|
578
|
-
/* @__PURE__ */
|
|
579
|
-
/* @__PURE__ */
|
|
580
|
-
/* @__PURE__ */
|
|
581
|
-
/* @__PURE__ */
|
|
682
|
+
return /* @__PURE__ */ jsxs7("table", { className: cn7("w-full border-collapse text-sm", className), children: [
|
|
683
|
+
/* @__PURE__ */ jsx9("caption", { className: "sr-only", children: "Delivery breakdown by notification type" }),
|
|
684
|
+
/* @__PURE__ */ jsx9("thead", { children: /* @__PURE__ */ jsxs7("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
685
|
+
/* @__PURE__ */ jsx9("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
|
|
686
|
+
/* @__PURE__ */ jsx9("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Sends" }),
|
|
687
|
+
/* @__PURE__ */ jsx9("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivered" }),
|
|
688
|
+
/* @__PURE__ */ jsx9("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Open rate" }),
|
|
689
|
+
/* @__PURE__ */ jsx9("th", { scope: "col", className: "py-2 font-medium", children: "Click rate" })
|
|
582
690
|
] }) }),
|
|
583
|
-
/* @__PURE__ */
|
|
584
|
-
/* @__PURE__ */
|
|
585
|
-
/* @__PURE__ */
|
|
586
|
-
/* @__PURE__ */
|
|
587
|
-
/* @__PURE__ */
|
|
588
|
-
/* @__PURE__ */
|
|
691
|
+
/* @__PURE__ */ jsx9("tbody", { children: rows.map((r) => /* @__PURE__ */ jsxs7("tr", { className: "border-b border-border/50", children: [
|
|
692
|
+
/* @__PURE__ */ jsx9("td", { className: "py-2 pe-4 font-medium text-foreground", children: r.type }),
|
|
693
|
+
/* @__PURE__ */ jsx9("td", { className: "py-2 pe-4 text-foreground", children: r.sends }),
|
|
694
|
+
/* @__PURE__ */ jsx9("td", { className: "py-2 pe-4 text-foreground", children: r.delivered }),
|
|
695
|
+
/* @__PURE__ */ jsx9("td", { className: "py-2 pe-4 text-foreground", children: pct2(r.openRate) }),
|
|
696
|
+
/* @__PURE__ */ jsx9("td", { className: "py-2 text-foreground", children: pct2(r.clickRate) })
|
|
589
697
|
] }, r.type)) })
|
|
590
698
|
] });
|
|
591
699
|
}
|
|
592
700
|
|
|
593
701
|
// src/delivery-analytics-page.tsx
|
|
594
|
-
import { jsx as
|
|
702
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
595
703
|
var DEFAULT_FROM = "2026-06-01";
|
|
596
704
|
var DEFAULT_TO = "2026-06-30";
|
|
597
705
|
var CHANNELS = ["", "email", "inapp", "push", "sms"];
|
|
@@ -600,36 +708,36 @@ function DeliveryAnalyticsPage({
|
|
|
600
708
|
organizationId,
|
|
601
709
|
className
|
|
602
710
|
}) {
|
|
603
|
-
const [channel, setChannel] =
|
|
604
|
-
const [from, setFrom] =
|
|
605
|
-
const [to, setTo] =
|
|
711
|
+
const [channel, setChannel] = useState4("");
|
|
712
|
+
const [from, setFrom] = useState4(DEFAULT_FROM);
|
|
713
|
+
const [to, setTo] = useState4(DEFAULT_TO);
|
|
606
714
|
const filters = { from, to, channel: channel || void 0, organizationId, basePath };
|
|
607
715
|
const summary = useDeliveryAnalytics(filters);
|
|
608
716
|
const funnel = useFunnelStats(filters);
|
|
609
717
|
const types = useDeliveryTypes({ from, to, organizationId, basePath });
|
|
610
718
|
const isLoading = summary.isLoading || funnel.isLoading || types.isLoading;
|
|
611
719
|
const isError = summary.isError || funnel.isError || types.isError;
|
|
612
|
-
return /* @__PURE__ */
|
|
613
|
-
/* @__PURE__ */
|
|
614
|
-
/* @__PURE__ */
|
|
615
|
-
/* @__PURE__ */
|
|
720
|
+
return /* @__PURE__ */ jsxs8("main", { className: cn8("flex flex-col gap-6 p-4 sm:p-6", className), children: [
|
|
721
|
+
/* @__PURE__ */ jsxs8("header", { className: "flex flex-col gap-1", children: [
|
|
722
|
+
/* @__PURE__ */ jsx10("h1", { className: "text-xl font-semibold text-foreground", children: "Delivery Analytics" }),
|
|
723
|
+
/* @__PURE__ */ jsx10("p", { className: "text-sm text-muted-foreground", children: "Cross-channel send, open, and click performance." })
|
|
616
724
|
] }),
|
|
617
|
-
/* @__PURE__ */
|
|
618
|
-
/* @__PURE__ */
|
|
619
|
-
/* @__PURE__ */
|
|
620
|
-
/* @__PURE__ */
|
|
725
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-end gap-3", children: [
|
|
726
|
+
/* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1 text-sm", children: [
|
|
727
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium text-foreground", children: "Channel" }),
|
|
728
|
+
/* @__PURE__ */ jsx10(
|
|
621
729
|
"select",
|
|
622
730
|
{
|
|
623
731
|
value: channel,
|
|
624
732
|
onChange: (e) => setChannel(e.target.value),
|
|
625
733
|
className: "rounded border border-border bg-background px-2 py-1.5 text-foreground",
|
|
626
|
-
children: CHANNELS.map((c) => /* @__PURE__ */
|
|
734
|
+
children: CHANNELS.map((c) => /* @__PURE__ */ jsx10("option", { value: c, children: c === "" ? "All channels" : c }, c || "all"))
|
|
627
735
|
}
|
|
628
736
|
)
|
|
629
737
|
] }),
|
|
630
|
-
/* @__PURE__ */
|
|
631
|
-
/* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */
|
|
738
|
+
/* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1 text-sm", children: [
|
|
739
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium text-foreground", children: "From" }),
|
|
740
|
+
/* @__PURE__ */ jsx10(
|
|
633
741
|
"input",
|
|
634
742
|
{
|
|
635
743
|
type: "date",
|
|
@@ -639,9 +747,9 @@ function DeliveryAnalyticsPage({
|
|
|
639
747
|
}
|
|
640
748
|
)
|
|
641
749
|
] }),
|
|
642
|
-
/* @__PURE__ */
|
|
643
|
-
/* @__PURE__ */
|
|
644
|
-
/* @__PURE__ */
|
|
750
|
+
/* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1 text-sm", children: [
|
|
751
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium text-foreground", children: "To" }),
|
|
752
|
+
/* @__PURE__ */ jsx10(
|
|
645
753
|
"input",
|
|
646
754
|
{
|
|
647
755
|
type: "date",
|
|
@@ -652,13 +760,13 @@ function DeliveryAnalyticsPage({
|
|
|
652
760
|
)
|
|
653
761
|
] })
|
|
654
762
|
] }),
|
|
655
|
-
isLoading ? /* @__PURE__ */
|
|
656
|
-
/* @__PURE__ */
|
|
657
|
-
/* @__PURE__ */
|
|
658
|
-
/* @__PURE__ */
|
|
659
|
-
] }) : isError ? /* @__PURE__ */
|
|
660
|
-
/* @__PURE__ */
|
|
661
|
-
/* @__PURE__ */
|
|
763
|
+
isLoading ? /* @__PURE__ */ jsxs8("div", { role: "status", "aria-label": "Loading delivery analytics", className: "flex flex-col gap-3", children: [
|
|
764
|
+
/* @__PURE__ */ jsx10("span", { className: "sr-only", children: "Loading delivery analytics" }),
|
|
765
|
+
/* @__PURE__ */ jsx10("div", { "aria-hidden": "true", className: "h-24 animate-pulse rounded bg-muted" }),
|
|
766
|
+
/* @__PURE__ */ jsx10("div", { "aria-hidden": "true", className: "h-72 animate-pulse rounded bg-muted" })
|
|
767
|
+
] }) : isError ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-start gap-3", children: [
|
|
768
|
+
/* @__PURE__ */ jsx10("p", { className: "text-sm text-foreground", children: "Failed to load delivery analytics" }),
|
|
769
|
+
/* @__PURE__ */ jsx10(
|
|
662
770
|
"button",
|
|
663
771
|
{
|
|
664
772
|
type: "button",
|
|
@@ -671,23 +779,23 @@ function DeliveryAnalyticsPage({
|
|
|
671
779
|
children: "Try again"
|
|
672
780
|
}
|
|
673
781
|
)
|
|
674
|
-
] }) : (summary.data?.length ?? 0) === 0 ? /* @__PURE__ */
|
|
675
|
-
funnel.data ? /* @__PURE__ */
|
|
676
|
-
/* @__PURE__ */
|
|
677
|
-
/* @__PURE__ */
|
|
678
|
-
/* @__PURE__ */
|
|
782
|
+
] }) : (summary.data?.length ?? 0) === 0 ? /* @__PURE__ */ jsx10("p", { className: "rounded border border-border p-6 text-center text-sm text-muted-foreground", children: "No delivery data for the selected range" }) : /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-6", children: [
|
|
783
|
+
funnel.data ? /* @__PURE__ */ jsx10(FunnelStats, { funnel: funnel.data }) : null,
|
|
784
|
+
/* @__PURE__ */ jsxs8("section", { "aria-label": "Delivery trend", className: "rounded-lg border border-border p-4", children: [
|
|
785
|
+
/* @__PURE__ */ jsx10("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: "Trend" }),
|
|
786
|
+
/* @__PURE__ */ jsx10(TrendChart, { data: summary.data ?? [] })
|
|
679
787
|
] }),
|
|
680
|
-
/* @__PURE__ */
|
|
681
|
-
/* @__PURE__ */
|
|
682
|
-
/* @__PURE__ */
|
|
788
|
+
/* @__PURE__ */ jsxs8("section", { "aria-label": "Delivery by type", className: "rounded-lg border border-border p-4", children: [
|
|
789
|
+
/* @__PURE__ */ jsx10("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: "By type" }),
|
|
790
|
+
/* @__PURE__ */ jsx10(TypeTable, { rows: types.data ?? [] })
|
|
683
791
|
] })
|
|
684
792
|
] })
|
|
685
793
|
] });
|
|
686
794
|
}
|
|
687
795
|
|
|
688
796
|
// src/template-status-badge.tsx
|
|
689
|
-
import { cn as
|
|
690
|
-
import { jsx as
|
|
797
|
+
import { cn as cn9 } from "@quanticjs/react-ui";
|
|
798
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
691
799
|
var STATUS_STYLES = {
|
|
692
800
|
draft: "bg-muted text-muted-foreground",
|
|
693
801
|
published: "bg-primary text-primary-foreground",
|
|
@@ -698,10 +806,10 @@ function TemplateStatusBadge({
|
|
|
698
806
|
className
|
|
699
807
|
}) {
|
|
700
808
|
const style = STATUS_STYLES[status] ?? "bg-muted text-muted-foreground";
|
|
701
|
-
return /* @__PURE__ */
|
|
809
|
+
return /* @__PURE__ */ jsx11(
|
|
702
810
|
"span",
|
|
703
811
|
{
|
|
704
|
-
className:
|
|
812
|
+
className: cn9(
|
|
705
813
|
"inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize",
|
|
706
814
|
style,
|
|
707
815
|
className
|
|
@@ -712,32 +820,32 @@ function TemplateStatusBadge({
|
|
|
712
820
|
}
|
|
713
821
|
|
|
714
822
|
// src/template-list.tsx
|
|
715
|
-
import { cn as
|
|
823
|
+
import { cn as cn10 } from "@quanticjs/react-ui";
|
|
716
824
|
import { useApiQuery as useApiQuery7 } from "@quanticjs/react-query";
|
|
717
|
-
import { jsx as
|
|
825
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
718
826
|
function TemplateList({ basePath = "/api/templates", className }) {
|
|
719
827
|
const { data, isLoading, isError, refetch } = useApiQuery7(
|
|
720
828
|
["templates", basePath],
|
|
721
829
|
(client) => client.get(basePath)
|
|
722
830
|
);
|
|
723
831
|
if (isLoading) {
|
|
724
|
-
return /* @__PURE__ */
|
|
832
|
+
return /* @__PURE__ */ jsxs9(
|
|
725
833
|
"div",
|
|
726
834
|
{
|
|
727
835
|
role: "status",
|
|
728
836
|
"aria-label": "Loading templates",
|
|
729
|
-
className:
|
|
837
|
+
className: cn10("flex flex-col gap-2 p-4", className),
|
|
730
838
|
children: [
|
|
731
|
-
/* @__PURE__ */
|
|
732
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
839
|
+
/* @__PURE__ */ jsx12("span", { className: "sr-only", children: "Loading templates" }),
|
|
840
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx12("div", { "aria-hidden": "true", className: "h-12 animate-pulse rounded bg-muted" }, i))
|
|
733
841
|
]
|
|
734
842
|
}
|
|
735
843
|
);
|
|
736
844
|
}
|
|
737
845
|
if (isError) {
|
|
738
|
-
return /* @__PURE__ */
|
|
739
|
-
/* @__PURE__ */
|
|
740
|
-
/* @__PURE__ */
|
|
846
|
+
return /* @__PURE__ */ jsxs9("div", { className: cn10("flex flex-col items-start gap-3 p-4", className), children: [
|
|
847
|
+
/* @__PURE__ */ jsx12("p", { className: "text-sm text-foreground", children: "Failed to load templates" }),
|
|
848
|
+
/* @__PURE__ */ jsx12(
|
|
741
849
|
"button",
|
|
742
850
|
{
|
|
743
851
|
type: "button",
|
|
@@ -750,29 +858,29 @@ function TemplateList({ basePath = "/api/templates", className }) {
|
|
|
750
858
|
}
|
|
751
859
|
const items = data ?? [];
|
|
752
860
|
if (items.length === 0) {
|
|
753
|
-
return /* @__PURE__ */
|
|
861
|
+
return /* @__PURE__ */ jsx12("div", { className: cn10("p-6 text-center text-sm text-muted-foreground", className), children: "No templates found" });
|
|
754
862
|
}
|
|
755
|
-
return /* @__PURE__ */
|
|
756
|
-
/* @__PURE__ */
|
|
757
|
-
/* @__PURE__ */
|
|
758
|
-
/* @__PURE__ */
|
|
759
|
-
/* @__PURE__ */
|
|
760
|
-
/* @__PURE__ */
|
|
863
|
+
return /* @__PURE__ */ jsx12("section", { "aria-label": "Templates", className: cn10("flex flex-col", className), children: /* @__PURE__ */ jsxs9("table", { className: "w-full text-sm", children: [
|
|
864
|
+
/* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsxs9("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
865
|
+
/* @__PURE__ */ jsx12("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Template" }),
|
|
866
|
+
/* @__PURE__ */ jsx12("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
867
|
+
/* @__PURE__ */ jsx12("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locales" }),
|
|
868
|
+
/* @__PURE__ */ jsx12("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Versions" })
|
|
761
869
|
] }) }),
|
|
762
|
-
/* @__PURE__ */
|
|
763
|
-
/* @__PURE__ */
|
|
764
|
-
/* @__PURE__ */
|
|
765
|
-
/* @__PURE__ */
|
|
766
|
-
/* @__PURE__ */
|
|
870
|
+
/* @__PURE__ */ jsx12("tbody", { children: items.map((item) => /* @__PURE__ */ jsxs9("tr", { className: "border-b border-border", children: [
|
|
871
|
+
/* @__PURE__ */ jsx12("td", { className: "py-3 pe-4 font-medium text-foreground", children: item.templateId }),
|
|
872
|
+
/* @__PURE__ */ jsx12("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx12(TemplateStatusBadge, { status: item.latestStatus }) }),
|
|
873
|
+
/* @__PURE__ */ jsx12("td", { className: "px-4 py-3 text-muted-foreground", children: item.locales.join(", ") }),
|
|
874
|
+
/* @__PURE__ */ jsx12("td", { className: "px-4 py-3 text-muted-foreground", children: item.versionCount })
|
|
767
875
|
] }, item.templateId)) })
|
|
768
876
|
] }) });
|
|
769
877
|
}
|
|
770
878
|
|
|
771
879
|
// src/template-editor.tsx
|
|
772
|
-
import { useState as
|
|
773
|
-
import { cn as
|
|
880
|
+
import { useState as useState5 } from "react";
|
|
881
|
+
import { cn as cn11, useToast as useToast3 } from "@quanticjs/react-ui";
|
|
774
882
|
import { useApiMutation as useApiMutation3 } from "@quanticjs/react-query";
|
|
775
|
-
import { jsx as
|
|
883
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
776
884
|
var FIELD_DEFS = [
|
|
777
885
|
{ key: "subject", label: "Subject", multiline: false },
|
|
778
886
|
{ key: "heading", label: "Heading", multiline: false },
|
|
@@ -794,16 +902,16 @@ function TemplateEditor({
|
|
|
794
902
|
className
|
|
795
903
|
}) {
|
|
796
904
|
const toast = useToast3();
|
|
797
|
-
const [fields, setFields] =
|
|
905
|
+
const [fields, setFields] = useState5({
|
|
798
906
|
subject: initialFields?.subject ?? "",
|
|
799
907
|
heading: initialFields?.heading ?? "",
|
|
800
908
|
body: initialFields?.body ?? "",
|
|
801
909
|
cta: initialFields?.cta ?? "",
|
|
802
910
|
html: initialFields?.html ?? ""
|
|
803
911
|
});
|
|
804
|
-
const [errors, setErrors] =
|
|
805
|
-
const [status, setStatus] =
|
|
806
|
-
const [activeVersionId, setActiveVersionId] =
|
|
912
|
+
const [errors, setErrors] = useState5({});
|
|
913
|
+
const [status, setStatus] = useState5(initialStatus);
|
|
914
|
+
const [activeVersionId, setActiveVersionId] = useState5(versionId);
|
|
807
915
|
const save = useApiMutation3(
|
|
808
916
|
(client, payload) => client.put(`${basePath}/${templateId}`, payload),
|
|
809
917
|
{
|
|
@@ -847,21 +955,21 @@ function TemplateEditor({
|
|
|
847
955
|
if (!validate()) return;
|
|
848
956
|
save.mutate(fields);
|
|
849
957
|
};
|
|
850
|
-
return /* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
852
|
-
/* @__PURE__ */
|
|
958
|
+
return /* @__PURE__ */ jsxs10("form", { onSubmit, className: cn11("flex flex-col gap-4", className), noValidate: true, children: [
|
|
959
|
+
/* @__PURE__ */ jsxs10("header", { className: "flex items-center justify-between", children: [
|
|
960
|
+
/* @__PURE__ */ jsxs10("h2", { className: "text-sm font-semibold text-foreground", children: [
|
|
853
961
|
"Edit template: ",
|
|
854
962
|
templateId
|
|
855
963
|
] }),
|
|
856
|
-
/* @__PURE__ */
|
|
964
|
+
/* @__PURE__ */ jsx13(TemplateStatusBadge, { status })
|
|
857
965
|
] }),
|
|
858
966
|
FIELD_DEFS.map(({ key, label, multiline }) => {
|
|
859
967
|
const fieldId = `template-${key}`;
|
|
860
968
|
const errorId = `${fieldId}-error`;
|
|
861
969
|
const error = errors[key];
|
|
862
|
-
return /* @__PURE__ */
|
|
863
|
-
/* @__PURE__ */
|
|
864
|
-
multiline ? /* @__PURE__ */
|
|
970
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-1", children: [
|
|
971
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: fieldId, className: "text-sm font-medium text-foreground", children: label }),
|
|
972
|
+
multiline ? /* @__PURE__ */ jsx13(
|
|
865
973
|
"textarea",
|
|
866
974
|
{
|
|
867
975
|
id: fieldId,
|
|
@@ -872,7 +980,7 @@ function TemplateEditor({
|
|
|
872
980
|
onChange: (e) => setFields((prev) => ({ ...prev, [key]: e.target.value })),
|
|
873
981
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
874
982
|
}
|
|
875
|
-
) : /* @__PURE__ */
|
|
983
|
+
) : /* @__PURE__ */ jsx13(
|
|
876
984
|
"input",
|
|
877
985
|
{
|
|
878
986
|
id: fieldId,
|
|
@@ -884,11 +992,11 @@ function TemplateEditor({
|
|
|
884
992
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
885
993
|
}
|
|
886
994
|
),
|
|
887
|
-
error && /* @__PURE__ */
|
|
995
|
+
error && /* @__PURE__ */ jsx13("p", { id: errorId, className: "text-xs text-destructive", children: error })
|
|
888
996
|
] }, key);
|
|
889
997
|
}),
|
|
890
|
-
/* @__PURE__ */
|
|
891
|
-
/* @__PURE__ */
|
|
998
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3", children: [
|
|
999
|
+
/* @__PURE__ */ jsx13(
|
|
892
1000
|
"button",
|
|
893
1001
|
{
|
|
894
1002
|
type: "submit",
|
|
@@ -897,7 +1005,7 @@ function TemplateEditor({
|
|
|
897
1005
|
children: save.isPending ? "Saving\u2026" : "Save draft"
|
|
898
1006
|
}
|
|
899
1007
|
),
|
|
900
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsx13(
|
|
901
1009
|
"button",
|
|
902
1010
|
{
|
|
903
1011
|
type: "button",
|
|
@@ -912,10 +1020,10 @@ function TemplateEditor({
|
|
|
912
1020
|
}
|
|
913
1021
|
|
|
914
1022
|
// src/template-preview-pane.tsx
|
|
915
|
-
import { useEffect as
|
|
916
|
-
import { cn as
|
|
1023
|
+
import { useEffect as useEffect5 } from "react";
|
|
1024
|
+
import { cn as cn12 } from "@quanticjs/react-ui";
|
|
917
1025
|
import { useApiMutation as useApiMutation4 } from "@quanticjs/react-query";
|
|
918
|
-
import { jsx as
|
|
1026
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
919
1027
|
function TemplatePreviewPane({
|
|
920
1028
|
templateId,
|
|
921
1029
|
versionId,
|
|
@@ -927,28 +1035,28 @@ function TemplatePreviewPane({
|
|
|
927
1035
|
(client, payload) => client.post(`${basePath}/${templateId}/preview`, payload)
|
|
928
1036
|
);
|
|
929
1037
|
const { mutate, data, isPending, isError } = preview;
|
|
930
|
-
|
|
1038
|
+
useEffect5(() => {
|
|
931
1039
|
mutate({ versionId, vars });
|
|
932
1040
|
}, [templateId, versionId]);
|
|
933
1041
|
if (isPending) {
|
|
934
|
-
return /* @__PURE__ */
|
|
1042
|
+
return /* @__PURE__ */ jsxs11(
|
|
935
1043
|
"div",
|
|
936
1044
|
{
|
|
937
1045
|
role: "status",
|
|
938
1046
|
"aria-label": "Loading preview",
|
|
939
|
-
className:
|
|
1047
|
+
className: cn12("flex flex-col gap-2 p-4", className),
|
|
940
1048
|
children: [
|
|
941
|
-
/* @__PURE__ */
|
|
942
|
-
/* @__PURE__ */
|
|
943
|
-
/* @__PURE__ */
|
|
1049
|
+
/* @__PURE__ */ jsx14("span", { className: "sr-only", children: "Loading preview" }),
|
|
1050
|
+
/* @__PURE__ */ jsx14("div", { "aria-hidden": "true", className: "h-6 w-1/2 animate-pulse rounded bg-muted" }),
|
|
1051
|
+
/* @__PURE__ */ jsx14("div", { "aria-hidden": "true", className: "h-40 animate-pulse rounded bg-muted" })
|
|
944
1052
|
]
|
|
945
1053
|
}
|
|
946
1054
|
);
|
|
947
1055
|
}
|
|
948
1056
|
if (isError || !data) {
|
|
949
|
-
return /* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
951
|
-
/* @__PURE__ */
|
|
1057
|
+
return /* @__PURE__ */ jsxs11("div", { className: cn12("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1058
|
+
/* @__PURE__ */ jsx14("p", { className: "text-sm text-foreground", children: "Failed to load preview" }),
|
|
1059
|
+
/* @__PURE__ */ jsx14(
|
|
952
1060
|
"button",
|
|
953
1061
|
{
|
|
954
1062
|
type: "button",
|
|
@@ -959,9 +1067,9 @@ function TemplatePreviewPane({
|
|
|
959
1067
|
)
|
|
960
1068
|
] });
|
|
961
1069
|
}
|
|
962
|
-
return /* @__PURE__ */
|
|
963
|
-
/* @__PURE__ */
|
|
964
|
-
/* @__PURE__ */
|
|
1070
|
+
return /* @__PURE__ */ jsxs11("section", { "aria-label": "Template preview", className: cn12("flex flex-col gap-4", className), children: [
|
|
1071
|
+
/* @__PURE__ */ jsx14("h2", { className: "text-sm font-semibold text-foreground", children: data.subject }),
|
|
1072
|
+
/* @__PURE__ */ jsx14(
|
|
965
1073
|
"iframe",
|
|
966
1074
|
{
|
|
967
1075
|
title: "Email preview",
|
|
@@ -970,17 +1078,17 @@ function TemplatePreviewPane({
|
|
|
970
1078
|
className: "h-96 w-full rounded-md border border-border bg-background"
|
|
971
1079
|
}
|
|
972
1080
|
),
|
|
973
|
-
/* @__PURE__ */
|
|
974
|
-
/* @__PURE__ */
|
|
975
|
-
/* @__PURE__ */
|
|
1081
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-1", children: [
|
|
1082
|
+
/* @__PURE__ */ jsx14("h3", { className: "text-xs font-medium text-muted-foreground", children: "Plain text" }),
|
|
1083
|
+
/* @__PURE__ */ jsx14("pre", { className: "overflow-auto whitespace-pre-wrap rounded-md border border-border bg-muted p-3 text-xs text-foreground", children: data.text })
|
|
976
1084
|
] })
|
|
977
1085
|
] });
|
|
978
1086
|
}
|
|
979
1087
|
|
|
980
1088
|
// src/template-version-history.tsx
|
|
981
|
-
import { cn as
|
|
1089
|
+
import { cn as cn13, useToast as useToast4 } from "@quanticjs/react-ui";
|
|
982
1090
|
import { useApiQuery as useApiQuery8, useApiMutation as useApiMutation5 } from "@quanticjs/react-query";
|
|
983
|
-
import { jsx as
|
|
1091
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
984
1092
|
function TemplateVersionHistory({
|
|
985
1093
|
templateId,
|
|
986
1094
|
basePath = "/api/templates",
|
|
@@ -1005,23 +1113,23 @@ function TemplateVersionHistory({
|
|
|
1005
1113
|
}
|
|
1006
1114
|
);
|
|
1007
1115
|
if (isLoading) {
|
|
1008
|
-
return /* @__PURE__ */
|
|
1116
|
+
return /* @__PURE__ */ jsxs12(
|
|
1009
1117
|
"div",
|
|
1010
1118
|
{
|
|
1011
1119
|
role: "status",
|
|
1012
1120
|
"aria-label": "Loading versions",
|
|
1013
|
-
className:
|
|
1121
|
+
className: cn13("flex flex-col gap-2 p-4", className),
|
|
1014
1122
|
children: [
|
|
1015
|
-
/* @__PURE__ */
|
|
1016
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
1123
|
+
/* @__PURE__ */ jsx15("span", { className: "sr-only", children: "Loading versions" }),
|
|
1124
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx15("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
1017
1125
|
]
|
|
1018
1126
|
}
|
|
1019
1127
|
);
|
|
1020
1128
|
}
|
|
1021
1129
|
if (isError) {
|
|
1022
|
-
return /* @__PURE__ */
|
|
1023
|
-
/* @__PURE__ */
|
|
1024
|
-
/* @__PURE__ */
|
|
1130
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn13("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1131
|
+
/* @__PURE__ */ jsx15("p", { className: "text-sm text-foreground", children: "Failed to load versions" }),
|
|
1132
|
+
/* @__PURE__ */ jsx15(
|
|
1025
1133
|
"button",
|
|
1026
1134
|
{
|
|
1027
1135
|
type: "button",
|
|
@@ -1034,25 +1142,25 @@ function TemplateVersionHistory({
|
|
|
1034
1142
|
}
|
|
1035
1143
|
const versions = data ?? [];
|
|
1036
1144
|
if (versions.length === 0) {
|
|
1037
|
-
return /* @__PURE__ */
|
|
1145
|
+
return /* @__PURE__ */ jsx15("div", { className: cn13("p-6 text-center text-sm text-muted-foreground", className), children: "No versions" });
|
|
1038
1146
|
}
|
|
1039
|
-
return /* @__PURE__ */
|
|
1040
|
-
/* @__PURE__ */
|
|
1041
|
-
/* @__PURE__ */
|
|
1042
|
-
/* @__PURE__ */
|
|
1043
|
-
/* @__PURE__ */
|
|
1044
|
-
/* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
1147
|
+
return /* @__PURE__ */ jsx15("section", { "aria-label": "Version history", className: cn13("flex flex-col", className), children: /* @__PURE__ */ jsxs12("table", { className: "w-full text-sm", children: [
|
|
1148
|
+
/* @__PURE__ */ jsx15("thead", { children: /* @__PURE__ */ jsxs12("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
1149
|
+
/* @__PURE__ */ jsx15("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Version" }),
|
|
1150
|
+
/* @__PURE__ */ jsx15("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
1151
|
+
/* @__PURE__ */ jsx15("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Author" }),
|
|
1152
|
+
/* @__PURE__ */ jsx15("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Date" }),
|
|
1153
|
+
/* @__PURE__ */ jsx15("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx15("span", { className: "sr-only", children: "Actions" }) })
|
|
1046
1154
|
] }) }),
|
|
1047
|
-
/* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1155
|
+
/* @__PURE__ */ jsx15("tbody", { children: versions.map((version) => /* @__PURE__ */ jsxs12("tr", { className: "border-b border-border", children: [
|
|
1156
|
+
/* @__PURE__ */ jsxs12("td", { className: "py-3 pe-4 font-medium text-foreground", children: [
|
|
1049
1157
|
"v",
|
|
1050
1158
|
version.versionNumber
|
|
1051
1159
|
] }),
|
|
1052
|
-
/* @__PURE__ */
|
|
1053
|
-
/* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1055
|
-
/* @__PURE__ */
|
|
1160
|
+
/* @__PURE__ */ jsx15("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx15(TemplateStatusBadge, { status: version.status }) }),
|
|
1161
|
+
/* @__PURE__ */ jsx15("td", { className: "px-4 py-3 text-muted-foreground", children: version.createdBy }),
|
|
1162
|
+
/* @__PURE__ */ jsx15("td", { className: "px-4 py-3 text-muted-foreground", children: version.createdAt }),
|
|
1163
|
+
/* @__PURE__ */ jsx15("td", { className: "px-4 py-3 text-end", children: canRollback && version.status === "archived" && /* @__PURE__ */ jsx15(
|
|
1056
1164
|
"button",
|
|
1057
1165
|
{
|
|
1058
1166
|
type: "button",
|
|
@@ -1067,39 +1175,39 @@ function TemplateVersionHistory({
|
|
|
1067
1175
|
}
|
|
1068
1176
|
|
|
1069
1177
|
// src/delivery-log-viewer.tsx
|
|
1070
|
-
import { useState as
|
|
1071
|
-
import { cn as
|
|
1178
|
+
import { useState as useState6 } from "react";
|
|
1179
|
+
import { cn as cn14 } from "@quanticjs/react-ui";
|
|
1072
1180
|
import { useApiQuery as useApiQuery9 } from "@quanticjs/react-query";
|
|
1073
|
-
import { jsx as
|
|
1181
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1074
1182
|
var LIMIT = 20;
|
|
1075
1183
|
function DeliveryLogViewer({
|
|
1076
1184
|
templateId,
|
|
1077
1185
|
basePath = "/api/templates",
|
|
1078
1186
|
className
|
|
1079
1187
|
}) {
|
|
1080
|
-
const [page, setPage] =
|
|
1188
|
+
const [page, setPage] = useState6(1);
|
|
1081
1189
|
const { data, isLoading, isError, refetch } = useApiQuery9(
|
|
1082
1190
|
["templates", templateId, "delivery-logs", page],
|
|
1083
1191
|
(client) => client.get(`${basePath}/${templateId}/delivery-logs?page=${page}&limit=${LIMIT}`)
|
|
1084
1192
|
);
|
|
1085
1193
|
if (isLoading) {
|
|
1086
|
-
return /* @__PURE__ */
|
|
1194
|
+
return /* @__PURE__ */ jsxs13(
|
|
1087
1195
|
"div",
|
|
1088
1196
|
{
|
|
1089
1197
|
role: "status",
|
|
1090
1198
|
"aria-label": "Loading delivery logs",
|
|
1091
|
-
className:
|
|
1199
|
+
className: cn14("flex flex-col gap-2 p-4", className),
|
|
1092
1200
|
children: [
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
1201
|
+
/* @__PURE__ */ jsx16("span", { className: "sr-only", children: "Loading delivery logs" }),
|
|
1202
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx16("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
1095
1203
|
]
|
|
1096
1204
|
}
|
|
1097
1205
|
);
|
|
1098
1206
|
}
|
|
1099
1207
|
if (isError) {
|
|
1100
|
-
return /* @__PURE__ */
|
|
1101
|
-
/* @__PURE__ */
|
|
1102
|
-
/* @__PURE__ */
|
|
1208
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn14("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1209
|
+
/* @__PURE__ */ jsx16("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
|
|
1210
|
+
/* @__PURE__ */ jsx16(
|
|
1103
1211
|
"button",
|
|
1104
1212
|
{
|
|
1105
1213
|
type: "button",
|
|
@@ -1113,25 +1221,25 @@ function DeliveryLogViewer({
|
|
|
1113
1221
|
const rows = data?.items ?? [];
|
|
1114
1222
|
const totalPages = data?.totalPages ?? 1;
|
|
1115
1223
|
if (rows.length === 0) {
|
|
1116
|
-
return /* @__PURE__ */
|
|
1224
|
+
return /* @__PURE__ */ jsx16("div", { className: cn14("p-6 text-center text-sm text-muted-foreground", className), children: "No delivery logs" });
|
|
1117
1225
|
}
|
|
1118
|
-
return /* @__PURE__ */
|
|
1119
|
-
/* @__PURE__ */
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
/* @__PURE__ */
|
|
1122
|
-
/* @__PURE__ */
|
|
1123
|
-
/* @__PURE__ */
|
|
1124
|
-
/* @__PURE__ */
|
|
1226
|
+
return /* @__PURE__ */ jsxs13("section", { "aria-label": "Delivery logs", className: cn14("flex flex-col gap-3", className), children: [
|
|
1227
|
+
/* @__PURE__ */ jsxs13("table", { className: "w-full text-sm", children: [
|
|
1228
|
+
/* @__PURE__ */ jsx16("thead", { children: /* @__PURE__ */ jsxs13("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
1229
|
+
/* @__PURE__ */ jsx16("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Recipient" }),
|
|
1230
|
+
/* @__PURE__ */ jsx16("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
1231
|
+
/* @__PURE__ */ jsx16("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
|
|
1232
|
+
/* @__PURE__ */ jsx16("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last error" })
|
|
1125
1233
|
] }) }),
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
/* @__PURE__ */
|
|
1129
|
-
/* @__PURE__ */
|
|
1130
|
-
/* @__PURE__ */
|
|
1234
|
+
/* @__PURE__ */ jsx16("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs13("tr", { className: "border-b border-border", children: [
|
|
1235
|
+
/* @__PURE__ */ jsx16("td", { className: "py-3 pe-4 text-foreground", children: row.recipientEmail }),
|
|
1236
|
+
/* @__PURE__ */ jsx16("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx16(TemplateStatusBadge, { status: row.status }) }),
|
|
1237
|
+
/* @__PURE__ */ jsx16("td", { className: "px-4 py-3 text-muted-foreground", children: row.attempts }),
|
|
1238
|
+
/* @__PURE__ */ jsx16("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastError ?? "\u2014" })
|
|
1131
1239
|
] }, row.id)) })
|
|
1132
1240
|
] }),
|
|
1133
|
-
/* @__PURE__ */
|
|
1134
|
-
/* @__PURE__ */
|
|
1241
|
+
/* @__PURE__ */ jsxs13("nav", { "aria-label": "Delivery log pagination", className: "flex items-center justify-between", children: [
|
|
1242
|
+
/* @__PURE__ */ jsx16(
|
|
1135
1243
|
"button",
|
|
1136
1244
|
{
|
|
1137
1245
|
type: "button",
|
|
@@ -1141,13 +1249,13 @@ function DeliveryLogViewer({
|
|
|
1141
1249
|
children: "Previous"
|
|
1142
1250
|
}
|
|
1143
1251
|
),
|
|
1144
|
-
/* @__PURE__ */
|
|
1252
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-xs text-muted-foreground", children: [
|
|
1145
1253
|
"Page ",
|
|
1146
1254
|
page,
|
|
1147
1255
|
" of ",
|
|
1148
1256
|
totalPages
|
|
1149
1257
|
] }),
|
|
1150
|
-
/* @__PURE__ */
|
|
1258
|
+
/* @__PURE__ */ jsx16(
|
|
1151
1259
|
"button",
|
|
1152
1260
|
{
|
|
1153
1261
|
type: "button",
|
|
@@ -1173,9 +1281,9 @@ function useBroadcasts({ page = 1, status, basePath = "/api" } = {}) {
|
|
|
1173
1281
|
}
|
|
1174
1282
|
|
|
1175
1283
|
// src/broadcast-list.tsx
|
|
1176
|
-
import { useState as
|
|
1177
|
-
import { cn as
|
|
1178
|
-
import { jsx as
|
|
1284
|
+
import { useState as useState7 } from "react";
|
|
1285
|
+
import { cn as cn15, formatDateTime, StatusBadge } from "@quanticjs/react-ui";
|
|
1286
|
+
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1179
1287
|
function statusVariant(status) {
|
|
1180
1288
|
switch (status) {
|
|
1181
1289
|
case "completed":
|
|
@@ -1200,26 +1308,26 @@ function BroadcastList({
|
|
|
1200
1308
|
onSelect,
|
|
1201
1309
|
className
|
|
1202
1310
|
}) {
|
|
1203
|
-
const [page, setPage] =
|
|
1311
|
+
const [page, setPage] = useState7(1);
|
|
1204
1312
|
const { data, isLoading, isError, refetch } = useBroadcasts({ page, status, basePath });
|
|
1205
1313
|
if (isLoading) {
|
|
1206
|
-
return /* @__PURE__ */
|
|
1314
|
+
return /* @__PURE__ */ jsxs14(
|
|
1207
1315
|
"div",
|
|
1208
1316
|
{
|
|
1209
1317
|
role: "status",
|
|
1210
1318
|
"aria-label": "Loading broadcasts",
|
|
1211
|
-
className:
|
|
1319
|
+
className: cn15("flex flex-col gap-2 p-4", className),
|
|
1212
1320
|
children: [
|
|
1213
|
-
/* @__PURE__ */
|
|
1214
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
1321
|
+
/* @__PURE__ */ jsx17("span", { className: "sr-only", children: "Loading broadcasts" }),
|
|
1322
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx17("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
1215
1323
|
]
|
|
1216
1324
|
}
|
|
1217
1325
|
);
|
|
1218
1326
|
}
|
|
1219
1327
|
if (isError) {
|
|
1220
|
-
return /* @__PURE__ */
|
|
1221
|
-
/* @__PURE__ */
|
|
1222
|
-
/* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ jsxs14("div", { className: cn15("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1329
|
+
/* @__PURE__ */ jsx17("p", { className: "text-sm text-foreground", children: "Failed to load broadcasts" }),
|
|
1330
|
+
/* @__PURE__ */ jsx17(
|
|
1223
1331
|
"button",
|
|
1224
1332
|
{
|
|
1225
1333
|
type: "button",
|
|
@@ -1233,9 +1341,9 @@ function BroadcastList({
|
|
|
1233
1341
|
const rows = data?.items ?? [];
|
|
1234
1342
|
const totalPages = data?.totalPages ?? 1;
|
|
1235
1343
|
if (rows.length === 0) {
|
|
1236
|
-
return /* @__PURE__ */
|
|
1344
|
+
return /* @__PURE__ */ jsx17("div", { className: cn15("p-6 text-center text-sm text-muted-foreground", className), children: "No broadcasts" });
|
|
1237
1345
|
}
|
|
1238
|
-
const renderTemplateCell = (row) => onSelect ? /* @__PURE__ */
|
|
1346
|
+
const renderTemplateCell = (row) => onSelect ? /* @__PURE__ */ jsx17(
|
|
1239
1347
|
"button",
|
|
1240
1348
|
{
|
|
1241
1349
|
type: "button",
|
|
@@ -1243,34 +1351,34 @@ function BroadcastList({
|
|
|
1243
1351
|
className: "rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
1244
1352
|
children: row.templateId
|
|
1245
1353
|
}
|
|
1246
|
-
) : /* @__PURE__ */
|
|
1247
|
-
return /* @__PURE__ */
|
|
1248
|
-
/* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
/* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1253
|
-
/* @__PURE__ */
|
|
1254
|
-
/* @__PURE__ */
|
|
1255
|
-
/* @__PURE__ */
|
|
1354
|
+
) : /* @__PURE__ */ jsx17("span", { className: "text-foreground", children: row.templateId });
|
|
1355
|
+
return /* @__PURE__ */ jsxs14("section", { "aria-label": "Broadcasts", className: cn15("flex flex-col gap-3", className), children: [
|
|
1356
|
+
/* @__PURE__ */ jsxs14("table", { className: "w-full text-sm", children: [
|
|
1357
|
+
/* @__PURE__ */ jsx17("thead", { children: /* @__PURE__ */ jsxs14("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
1358
|
+
/* @__PURE__ */ jsx17("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Template" }),
|
|
1359
|
+
/* @__PURE__ */ jsx17("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
1360
|
+
/* @__PURE__ */ jsx17("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Channels" }),
|
|
1361
|
+
/* @__PURE__ */ jsx17("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Sent / Failed / Skipped" }),
|
|
1362
|
+
/* @__PURE__ */ jsx17("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created by" }),
|
|
1363
|
+
/* @__PURE__ */ jsx17("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
1256
1364
|
] }) }),
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1259
|
-
/* @__PURE__ */
|
|
1260
|
-
/* @__PURE__ */
|
|
1261
|
-
/* @__PURE__ */
|
|
1365
|
+
/* @__PURE__ */ jsx17("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs14("tr", { className: "border-b border-border", children: [
|
|
1366
|
+
/* @__PURE__ */ jsx17("td", { className: "py-3 pe-4", children: renderTemplateCell(row) }),
|
|
1367
|
+
/* @__PURE__ */ jsx17("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx17(StatusBadge, { variant: statusVariant(row.status), children: row.status }) }),
|
|
1368
|
+
/* @__PURE__ */ jsx17("td", { className: "px-4 py-3 text-muted-foreground", children: row.channels.length > 0 ? row.channels.join(", ") : "\u2014" }),
|
|
1369
|
+
/* @__PURE__ */ jsxs14("td", { className: "px-4 py-3 text-muted-foreground", children: [
|
|
1262
1370
|
row.sentCount,
|
|
1263
1371
|
" / ",
|
|
1264
1372
|
row.failedCount,
|
|
1265
1373
|
" / ",
|
|
1266
1374
|
row.skippedCount
|
|
1267
1375
|
] }),
|
|
1268
|
-
/* @__PURE__ */
|
|
1269
|
-
/* @__PURE__ */
|
|
1376
|
+
/* @__PURE__ */ jsx17("td", { className: "px-4 py-3 text-muted-foreground", children: row.createdBy }),
|
|
1377
|
+
/* @__PURE__ */ jsx17("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime(row.createdAt) })
|
|
1270
1378
|
] }, row.id)) })
|
|
1271
1379
|
] }),
|
|
1272
|
-
/* @__PURE__ */
|
|
1273
|
-
/* @__PURE__ */
|
|
1380
|
+
/* @__PURE__ */ jsxs14("nav", { "aria-label": "Broadcast pagination", className: "flex items-center justify-between", children: [
|
|
1381
|
+
/* @__PURE__ */ jsx17(
|
|
1274
1382
|
"button",
|
|
1275
1383
|
{
|
|
1276
1384
|
type: "button",
|
|
@@ -1280,13 +1388,13 @@ function BroadcastList({
|
|
|
1280
1388
|
children: "Previous"
|
|
1281
1389
|
}
|
|
1282
1390
|
),
|
|
1283
|
-
/* @__PURE__ */
|
|
1391
|
+
/* @__PURE__ */ jsxs14("span", { className: "text-xs text-muted-foreground", children: [
|
|
1284
1392
|
"Page ",
|
|
1285
1393
|
page,
|
|
1286
1394
|
" of ",
|
|
1287
1395
|
totalPages
|
|
1288
1396
|
] }),
|
|
1289
|
-
/* @__PURE__ */
|
|
1397
|
+
/* @__PURE__ */ jsx17(
|
|
1290
1398
|
"button",
|
|
1291
1399
|
{
|
|
1292
1400
|
type: "button",
|
|
@@ -1301,9 +1409,9 @@ function BroadcastList({
|
|
|
1301
1409
|
}
|
|
1302
1410
|
|
|
1303
1411
|
// src/broadcast-progress.tsx
|
|
1304
|
-
import { cn as
|
|
1412
|
+
import { cn as cn16, useToast as useToast5, StatusBadge as StatusBadge2 } from "@quanticjs/react-ui";
|
|
1305
1413
|
import { useApiQuery as useApiQuery11, useApiMutation as useApiMutation6 } from "@quanticjs/react-query";
|
|
1306
|
-
import { jsx as
|
|
1414
|
+
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1307
1415
|
var TERMINAL_STATUSES = ["completed", "completed_with_errors", "failed", "cancelled"];
|
|
1308
1416
|
function isTerminalStatus(status) {
|
|
1309
1417
|
return status !== void 0 && TERMINAL_STATUSES.includes(status);
|
|
@@ -1350,23 +1458,23 @@ function BroadcastProgress({
|
|
|
1350
1458
|
}
|
|
1351
1459
|
);
|
|
1352
1460
|
if (isLoading) {
|
|
1353
|
-
return /* @__PURE__ */
|
|
1461
|
+
return /* @__PURE__ */ jsxs15(
|
|
1354
1462
|
"div",
|
|
1355
1463
|
{
|
|
1356
1464
|
role: "status",
|
|
1357
1465
|
"aria-label": "Loading broadcast",
|
|
1358
|
-
className:
|
|
1466
|
+
className: cn16("flex flex-col gap-2 p-4", className),
|
|
1359
1467
|
children: [
|
|
1360
|
-
/* @__PURE__ */
|
|
1361
|
-
[0, 1].map((i) => /* @__PURE__ */
|
|
1468
|
+
/* @__PURE__ */ jsx18("span", { className: "sr-only", children: "Loading broadcast" }),
|
|
1469
|
+
[0, 1].map((i) => /* @__PURE__ */ jsx18("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
1362
1470
|
]
|
|
1363
1471
|
}
|
|
1364
1472
|
);
|
|
1365
1473
|
}
|
|
1366
1474
|
if (isError) {
|
|
1367
|
-
return /* @__PURE__ */
|
|
1368
|
-
/* @__PURE__ */
|
|
1369
|
-
/* @__PURE__ */
|
|
1475
|
+
return /* @__PURE__ */ jsxs15("div", { className: cn16("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1476
|
+
/* @__PURE__ */ jsx18("p", { className: "text-sm text-foreground", children: "Failed to load broadcast" }),
|
|
1477
|
+
/* @__PURE__ */ jsx18(
|
|
1370
1478
|
"button",
|
|
1371
1479
|
{
|
|
1372
1480
|
type: "button",
|
|
@@ -1378,21 +1486,21 @@ function BroadcastProgress({
|
|
|
1378
1486
|
] });
|
|
1379
1487
|
}
|
|
1380
1488
|
if (!data) {
|
|
1381
|
-
return /* @__PURE__ */
|
|
1489
|
+
return /* @__PURE__ */ jsx18("div", { className: cn16("p-6 text-center text-sm text-muted-foreground", className), children: "No broadcast" });
|
|
1382
1490
|
}
|
|
1383
1491
|
const total = data.totalRecipients;
|
|
1384
1492
|
const processed = data.sentCount + data.failedCount + data.skippedCount;
|
|
1385
1493
|
const pct3 = total > 0 ? Math.min(100, Math.round(processed / total * 100)) : 0;
|
|
1386
1494
|
const terminal = isTerminalStatus(data.status);
|
|
1387
|
-
return /* @__PURE__ */
|
|
1388
|
-
/* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1495
|
+
return /* @__PURE__ */ jsxs15("section", { "aria-label": "Broadcast progress", className: cn16("flex flex-col gap-4 p-4", className), children: [
|
|
1496
|
+
/* @__PURE__ */ jsxs15("header", { className: "flex items-center justify-between", children: [
|
|
1497
|
+
/* @__PURE__ */ jsxs15("h2", { className: "text-sm font-semibold text-foreground", children: [
|
|
1390
1498
|
"Broadcast ",
|
|
1391
1499
|
data.templateId
|
|
1392
1500
|
] }),
|
|
1393
|
-
/* @__PURE__ */
|
|
1501
|
+
/* @__PURE__ */ jsx18(StatusBadge2, { variant: statusVariant2(data.status), appearance: "solid", children: data.status })
|
|
1394
1502
|
] }),
|
|
1395
|
-
/* @__PURE__ */
|
|
1503
|
+
/* @__PURE__ */ jsx18(
|
|
1396
1504
|
"div",
|
|
1397
1505
|
{
|
|
1398
1506
|
role: "progressbar",
|
|
@@ -1401,10 +1509,10 @@ function BroadcastProgress({
|
|
|
1401
1509
|
"aria-valuemax": 100,
|
|
1402
1510
|
"aria-label": "Broadcast completion",
|
|
1403
1511
|
className: "h-2 w-full overflow-hidden rounded-full bg-muted",
|
|
1404
|
-
children: /* @__PURE__ */
|
|
1512
|
+
children: /* @__PURE__ */ jsx18("div", { className: "h-full rounded-full bg-primary", style: { width: `${pct3}%` } })
|
|
1405
1513
|
}
|
|
1406
1514
|
),
|
|
1407
|
-
/* @__PURE__ */
|
|
1515
|
+
/* @__PURE__ */ jsxs15("p", { className: "text-xs text-muted-foreground", children: [
|
|
1408
1516
|
processed,
|
|
1409
1517
|
" of ",
|
|
1410
1518
|
total,
|
|
@@ -1412,25 +1520,25 @@ function BroadcastProgress({
|
|
|
1412
1520
|
pct3,
|
|
1413
1521
|
"%)"
|
|
1414
1522
|
] }),
|
|
1415
|
-
/* @__PURE__ */
|
|
1416
|
-
/* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
1418
|
-
/* @__PURE__ */
|
|
1523
|
+
/* @__PURE__ */ jsxs15("dl", { className: "grid grid-cols-2 gap-3 text-sm sm:grid-cols-4", children: [
|
|
1524
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
|
|
1525
|
+
/* @__PURE__ */ jsx18("dt", { className: "text-xs text-muted-foreground", children: "Sent" }),
|
|
1526
|
+
/* @__PURE__ */ jsx18("dd", { className: "text-foreground", children: data.sentCount })
|
|
1419
1527
|
] }),
|
|
1420
|
-
/* @__PURE__ */
|
|
1421
|
-
/* @__PURE__ */
|
|
1422
|
-
/* @__PURE__ */
|
|
1528
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
|
|
1529
|
+
/* @__PURE__ */ jsx18("dt", { className: "text-xs text-muted-foreground", children: "Failed" }),
|
|
1530
|
+
/* @__PURE__ */ jsx18("dd", { className: "text-foreground", children: data.failedCount })
|
|
1423
1531
|
] }),
|
|
1424
|
-
/* @__PURE__ */
|
|
1425
|
-
/* @__PURE__ */
|
|
1426
|
-
/* @__PURE__ */
|
|
1532
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
|
|
1533
|
+
/* @__PURE__ */ jsx18("dt", { className: "text-xs text-muted-foreground", children: "Skipped" }),
|
|
1534
|
+
/* @__PURE__ */ jsx18("dd", { className: "text-foreground", children: data.skippedCount })
|
|
1427
1535
|
] }),
|
|
1428
|
-
/* @__PURE__ */
|
|
1429
|
-
/* @__PURE__ */
|
|
1430
|
-
/* @__PURE__ */
|
|
1536
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
|
|
1537
|
+
/* @__PURE__ */ jsx18("dt", { className: "text-xs text-muted-foreground", children: "Total" }),
|
|
1538
|
+
/* @__PURE__ */ jsx18("dd", { className: "text-foreground", children: total })
|
|
1431
1539
|
] })
|
|
1432
1540
|
] }),
|
|
1433
|
-
/* @__PURE__ */
|
|
1541
|
+
/* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(
|
|
1434
1542
|
"button",
|
|
1435
1543
|
{
|
|
1436
1544
|
type: "button",
|
|
@@ -1444,10 +1552,10 @@ function BroadcastProgress({
|
|
|
1444
1552
|
}
|
|
1445
1553
|
|
|
1446
1554
|
// src/broadcast-composer.tsx
|
|
1447
|
-
import { useState as
|
|
1448
|
-
import { cn as
|
|
1555
|
+
import { useState as useState8 } from "react";
|
|
1556
|
+
import { cn as cn17, useToast as useToast6 } from "@quanticjs/react-ui";
|
|
1449
1557
|
import { useApiQuery as useApiQuery12, useApiMutation as useApiMutation7 } from "@quanticjs/react-query";
|
|
1450
|
-
import { jsx as
|
|
1558
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1451
1559
|
var CHANNELS2 = ["inapp", "email", "push", "sms", "webhook", "slack", "teams"];
|
|
1452
1560
|
function normalizeList(data) {
|
|
1453
1561
|
if (!data) return [];
|
|
@@ -1463,14 +1571,14 @@ function BroadcastComposer({
|
|
|
1463
1571
|
className
|
|
1464
1572
|
}) {
|
|
1465
1573
|
const toast = useToast6();
|
|
1466
|
-
const [idempotencyKey] =
|
|
1467
|
-
const [templateId, setTemplateId] =
|
|
1468
|
-
const [channels, setChannels] =
|
|
1469
|
-
const [audienceMode, setAudienceMode] =
|
|
1470
|
-
const [segmentId, setSegmentId] =
|
|
1471
|
-
const [recipientsRaw, setRecipientsRaw] =
|
|
1472
|
-
const [type, setType] =
|
|
1473
|
-
const [errors, setErrors] =
|
|
1574
|
+
const [idempotencyKey] = useState8(() => crypto.randomUUID());
|
|
1575
|
+
const [templateId, setTemplateId] = useState8("");
|
|
1576
|
+
const [channels, setChannels] = useState8([]);
|
|
1577
|
+
const [audienceMode, setAudienceMode] = useState8("segment");
|
|
1578
|
+
const [segmentId, setSegmentId] = useState8("");
|
|
1579
|
+
const [recipientsRaw, setRecipientsRaw] = useState8("");
|
|
1580
|
+
const [type, setType] = useState8("");
|
|
1581
|
+
const [errors, setErrors] = useState8({});
|
|
1474
1582
|
const templatesQuery = useApiQuery12(
|
|
1475
1583
|
["templates"],
|
|
1476
1584
|
(client) => client.get(`${basePath}/templates`)
|
|
@@ -1495,23 +1603,23 @@ function BroadcastComposer({
|
|
|
1495
1603
|
const isLoading = templatesQuery.isLoading || segmentsQuery.isLoading;
|
|
1496
1604
|
const isError = templatesQuery.isError || segmentsQuery.isError;
|
|
1497
1605
|
if (isLoading) {
|
|
1498
|
-
return /* @__PURE__ */
|
|
1606
|
+
return /* @__PURE__ */ jsxs16(
|
|
1499
1607
|
"div",
|
|
1500
1608
|
{
|
|
1501
1609
|
role: "status",
|
|
1502
1610
|
"aria-label": "Loading broadcast composer",
|
|
1503
|
-
className:
|
|
1611
|
+
className: cn17("flex flex-col gap-2 p-4", className),
|
|
1504
1612
|
children: [
|
|
1505
|
-
/* @__PURE__ */
|
|
1506
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
1613
|
+
/* @__PURE__ */ jsx19("span", { className: "sr-only", children: "Loading broadcast composer" }),
|
|
1614
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx19("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
1507
1615
|
]
|
|
1508
1616
|
}
|
|
1509
1617
|
);
|
|
1510
1618
|
}
|
|
1511
1619
|
if (isError) {
|
|
1512
|
-
return /* @__PURE__ */
|
|
1513
|
-
/* @__PURE__ */
|
|
1514
|
-
/* @__PURE__ */
|
|
1620
|
+
return /* @__PURE__ */ jsxs16("div", { className: cn17("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1621
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sm text-foreground", children: "Failed to load broadcast composer" }),
|
|
1622
|
+
/* @__PURE__ */ jsx19(
|
|
1515
1623
|
"button",
|
|
1516
1624
|
{
|
|
1517
1625
|
type: "button",
|
|
@@ -1558,11 +1666,11 @@ function BroadcastComposer({
|
|
|
1558
1666
|
idempotencyKey
|
|
1559
1667
|
});
|
|
1560
1668
|
};
|
|
1561
|
-
return /* @__PURE__ */
|
|
1562
|
-
/* @__PURE__ */
|
|
1563
|
-
/* @__PURE__ */
|
|
1564
|
-
/* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1669
|
+
return /* @__PURE__ */ jsxs16("form", { onSubmit, className: cn17("flex flex-col gap-4 p-4", className), noValidate: true, children: [
|
|
1670
|
+
/* @__PURE__ */ jsx19("h2", { className: "text-sm font-semibold text-foreground", children: "New broadcast" }),
|
|
1671
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1", children: [
|
|
1672
|
+
/* @__PURE__ */ jsx19("label", { htmlFor: "composer-template", className: "text-sm font-medium text-foreground", children: "Template" }),
|
|
1673
|
+
/* @__PURE__ */ jsxs16(
|
|
1566
1674
|
"select",
|
|
1567
1675
|
{
|
|
1568
1676
|
id: "composer-template",
|
|
@@ -1572,30 +1680,30 @@ function BroadcastComposer({
|
|
|
1572
1680
|
onChange: (e) => setTemplateId(e.target.value),
|
|
1573
1681
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
1574
1682
|
children: [
|
|
1575
|
-
/* @__PURE__ */
|
|
1576
|
-
templates.map((t) => /* @__PURE__ */
|
|
1683
|
+
/* @__PURE__ */ jsx19("option", { value: "", children: "Select a template\u2026" }),
|
|
1684
|
+
templates.map((t) => /* @__PURE__ */ jsx19("option", { value: t.id, children: t.name ?? t.id }, t.id))
|
|
1577
1685
|
]
|
|
1578
1686
|
}
|
|
1579
1687
|
),
|
|
1580
|
-
errors.templateId && /* @__PURE__ */
|
|
1688
|
+
errors.templateId && /* @__PURE__ */ jsx19("p", { id: "composer-template-error", className: "text-xs text-destructive", children: errors.templateId })
|
|
1581
1689
|
] }),
|
|
1582
|
-
/* @__PURE__ */
|
|
1690
|
+
/* @__PURE__ */ jsxs16(
|
|
1583
1691
|
"fieldset",
|
|
1584
1692
|
{
|
|
1585
1693
|
className: "flex flex-col gap-2",
|
|
1586
1694
|
"aria-invalid": errors.channels ? "true" : void 0,
|
|
1587
1695
|
"aria-describedby": errors.channels ? "composer-channels-error" : void 0,
|
|
1588
1696
|
children: [
|
|
1589
|
-
/* @__PURE__ */
|
|
1590
|
-
/* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ jsx19("legend", { className: "text-sm font-medium text-foreground", children: "Channels" }),
|
|
1698
|
+
/* @__PURE__ */ jsx19("div", { className: "flex flex-wrap gap-3", children: CHANNELS2.map((channel) => {
|
|
1591
1699
|
const checkboxId = `composer-channel-${channel}`;
|
|
1592
|
-
return /* @__PURE__ */
|
|
1700
|
+
return /* @__PURE__ */ jsxs16(
|
|
1593
1701
|
"label",
|
|
1594
1702
|
{
|
|
1595
1703
|
htmlFor: checkboxId,
|
|
1596
1704
|
className: "flex items-center gap-2 text-sm text-foreground",
|
|
1597
1705
|
children: [
|
|
1598
|
-
/* @__PURE__ */
|
|
1706
|
+
/* @__PURE__ */ jsx19(
|
|
1599
1707
|
"input",
|
|
1600
1708
|
{
|
|
1601
1709
|
id: checkboxId,
|
|
@@ -1611,20 +1719,20 @@ function BroadcastComposer({
|
|
|
1611
1719
|
channel
|
|
1612
1720
|
);
|
|
1613
1721
|
}) }),
|
|
1614
|
-
errors.channels && /* @__PURE__ */
|
|
1722
|
+
errors.channels && /* @__PURE__ */ jsx19("p", { id: "composer-channels-error", className: "text-xs text-destructive", children: errors.channels })
|
|
1615
1723
|
]
|
|
1616
1724
|
}
|
|
1617
1725
|
),
|
|
1618
|
-
/* @__PURE__ */
|
|
1619
|
-
/* @__PURE__ */
|
|
1620
|
-
/* @__PURE__ */
|
|
1621
|
-
/* @__PURE__ */
|
|
1726
|
+
/* @__PURE__ */ jsxs16("fieldset", { className: "flex flex-col gap-2", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx19("legend", { className: "text-sm font-medium text-foreground", children: "Audience" }),
|
|
1728
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex gap-4", children: [
|
|
1729
|
+
/* @__PURE__ */ jsxs16(
|
|
1622
1730
|
"label",
|
|
1623
1731
|
{
|
|
1624
1732
|
htmlFor: "composer-audience-segment",
|
|
1625
1733
|
className: "flex items-center gap-2 text-sm text-foreground",
|
|
1626
1734
|
children: [
|
|
1627
|
-
/* @__PURE__ */
|
|
1735
|
+
/* @__PURE__ */ jsx19(
|
|
1628
1736
|
"input",
|
|
1629
1737
|
{
|
|
1630
1738
|
id: "composer-audience-segment",
|
|
@@ -1639,13 +1747,13 @@ function BroadcastComposer({
|
|
|
1639
1747
|
]
|
|
1640
1748
|
}
|
|
1641
1749
|
),
|
|
1642
|
-
/* @__PURE__ */
|
|
1750
|
+
/* @__PURE__ */ jsxs16(
|
|
1643
1751
|
"label",
|
|
1644
1752
|
{
|
|
1645
1753
|
htmlFor: "composer-audience-recipients",
|
|
1646
1754
|
className: "flex items-center gap-2 text-sm text-foreground",
|
|
1647
1755
|
children: [
|
|
1648
|
-
/* @__PURE__ */
|
|
1756
|
+
/* @__PURE__ */ jsx19(
|
|
1649
1757
|
"input",
|
|
1650
1758
|
{
|
|
1651
1759
|
id: "composer-audience-recipients",
|
|
@@ -1661,7 +1769,7 @@ function BroadcastComposer({
|
|
|
1661
1769
|
}
|
|
1662
1770
|
)
|
|
1663
1771
|
] }),
|
|
1664
|
-
audienceMode === "segment" ? /* @__PURE__ */
|
|
1772
|
+
audienceMode === "segment" ? /* @__PURE__ */ jsxs16(
|
|
1665
1773
|
"select",
|
|
1666
1774
|
{
|
|
1667
1775
|
id: "composer-segment",
|
|
@@ -1672,11 +1780,11 @@ function BroadcastComposer({
|
|
|
1672
1780
|
onChange: (e) => setSegmentId(e.target.value),
|
|
1673
1781
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
1674
1782
|
children: [
|
|
1675
|
-
/* @__PURE__ */
|
|
1676
|
-
segments.map((s) => /* @__PURE__ */
|
|
1783
|
+
/* @__PURE__ */ jsx19("option", { value: "", children: "Select a segment\u2026" }),
|
|
1784
|
+
segments.map((s) => /* @__PURE__ */ jsx19("option", { value: s.id, children: s.name }, s.id))
|
|
1677
1785
|
]
|
|
1678
1786
|
}
|
|
1679
|
-
) : /* @__PURE__ */
|
|
1787
|
+
) : /* @__PURE__ */ jsx19(
|
|
1680
1788
|
"textarea",
|
|
1681
1789
|
{
|
|
1682
1790
|
id: "composer-recipients",
|
|
@@ -1690,11 +1798,11 @@ function BroadcastComposer({
|
|
|
1690
1798
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
1691
1799
|
}
|
|
1692
1800
|
),
|
|
1693
|
-
errors.audience && /* @__PURE__ */
|
|
1801
|
+
errors.audience && /* @__PURE__ */ jsx19("p", { id: "composer-audience-error", className: "text-xs text-destructive", children: errors.audience })
|
|
1694
1802
|
] }),
|
|
1695
|
-
/* @__PURE__ */
|
|
1696
|
-
/* @__PURE__ */
|
|
1697
|
-
/* @__PURE__ */
|
|
1803
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1", children: [
|
|
1804
|
+
/* @__PURE__ */ jsx19("label", { htmlFor: "composer-type", className: "text-sm font-medium text-foreground", children: "Type (optional)" }),
|
|
1805
|
+
/* @__PURE__ */ jsx19(
|
|
1698
1806
|
"input",
|
|
1699
1807
|
{
|
|
1700
1808
|
id: "composer-type",
|
|
@@ -1705,7 +1813,7 @@ function BroadcastComposer({
|
|
|
1705
1813
|
}
|
|
1706
1814
|
)
|
|
1707
1815
|
] }),
|
|
1708
|
-
/* @__PURE__ */
|
|
1816
|
+
/* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(
|
|
1709
1817
|
"button",
|
|
1710
1818
|
{
|
|
1711
1819
|
type: "submit",
|
|
@@ -1718,9 +1826,9 @@ function BroadcastComposer({
|
|
|
1718
1826
|
}
|
|
1719
1827
|
|
|
1720
1828
|
// src/segment-list.tsx
|
|
1721
|
-
import { cn as
|
|
1829
|
+
import { cn as cn18, formatDateTime as formatDateTime2, StatusBadge as StatusBadge3 } from "@quanticjs/react-ui";
|
|
1722
1830
|
import { useApiQuery as useApiQuery13 } from "@quanticjs/react-query";
|
|
1723
|
-
import { jsx as
|
|
1831
|
+
import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1724
1832
|
function normalize(data) {
|
|
1725
1833
|
if (Array.isArray(data)) return data;
|
|
1726
1834
|
return data?.items ?? [];
|
|
@@ -1746,23 +1854,23 @@ function SegmentList({
|
|
|
1746
1854
|
(client) => client.get(`${basePath}/v1/segments`)
|
|
1747
1855
|
);
|
|
1748
1856
|
if (isLoading) {
|
|
1749
|
-
return /* @__PURE__ */
|
|
1857
|
+
return /* @__PURE__ */ jsxs17(
|
|
1750
1858
|
"div",
|
|
1751
1859
|
{
|
|
1752
1860
|
role: "status",
|
|
1753
1861
|
"aria-label": "Loading segments",
|
|
1754
|
-
className:
|
|
1862
|
+
className: cn18("flex flex-col gap-2 p-4", className),
|
|
1755
1863
|
children: [
|
|
1756
|
-
/* @__PURE__ */
|
|
1757
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
1864
|
+
/* @__PURE__ */ jsx20("span", { className: "sr-only", children: "Loading segments" }),
|
|
1865
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx20("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
1758
1866
|
]
|
|
1759
1867
|
}
|
|
1760
1868
|
);
|
|
1761
1869
|
}
|
|
1762
1870
|
if (isError) {
|
|
1763
|
-
return /* @__PURE__ */
|
|
1764
|
-
/* @__PURE__ */
|
|
1765
|
-
/* @__PURE__ */
|
|
1871
|
+
return /* @__PURE__ */ jsxs17("div", { className: cn18("flex flex-col items-start gap-3 p-4", className), children: [
|
|
1872
|
+
/* @__PURE__ */ jsx20("p", { className: "text-sm text-foreground", children: "Failed to load segments" }),
|
|
1873
|
+
/* @__PURE__ */ jsx20(
|
|
1766
1874
|
"button",
|
|
1767
1875
|
{
|
|
1768
1876
|
type: "button",
|
|
@@ -1774,7 +1882,7 @@ function SegmentList({
|
|
|
1774
1882
|
] });
|
|
1775
1883
|
}
|
|
1776
1884
|
const rows = normalize(data);
|
|
1777
|
-
const header = onCreate ? /* @__PURE__ */
|
|
1885
|
+
const header = onCreate ? /* @__PURE__ */ jsx20("header", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsx20(
|
|
1778
1886
|
"button",
|
|
1779
1887
|
{
|
|
1780
1888
|
type: "button",
|
|
@@ -1784,12 +1892,12 @@ function SegmentList({
|
|
|
1784
1892
|
}
|
|
1785
1893
|
) }) : null;
|
|
1786
1894
|
if (rows.length === 0) {
|
|
1787
|
-
return /* @__PURE__ */
|
|
1895
|
+
return /* @__PURE__ */ jsxs17("section", { "aria-label": "Segments", className: cn18("flex flex-col gap-3", className), children: [
|
|
1788
1896
|
header,
|
|
1789
|
-
/* @__PURE__ */
|
|
1897
|
+
/* @__PURE__ */ jsx20("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No segments" })
|
|
1790
1898
|
] });
|
|
1791
1899
|
}
|
|
1792
|
-
const renderNameCell = (row) => onSelect ? /* @__PURE__ */
|
|
1900
|
+
const renderNameCell = (row) => onSelect ? /* @__PURE__ */ jsx20(
|
|
1793
1901
|
"button",
|
|
1794
1902
|
{
|
|
1795
1903
|
type: "button",
|
|
@@ -1797,33 +1905,33 @@ function SegmentList({
|
|
|
1797
1905
|
className: "rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
1798
1906
|
children: row.name
|
|
1799
1907
|
}
|
|
1800
|
-
) : /* @__PURE__ */
|
|
1801
|
-
return /* @__PURE__ */
|
|
1908
|
+
) : /* @__PURE__ */ jsx20("span", { className: "text-foreground", children: row.name });
|
|
1909
|
+
return /* @__PURE__ */ jsxs17("section", { "aria-label": "Segments", className: cn18("flex flex-col gap-3", className), children: [
|
|
1802
1910
|
header,
|
|
1803
|
-
/* @__PURE__ */
|
|
1804
|
-
/* @__PURE__ */
|
|
1805
|
-
/* @__PURE__ */
|
|
1806
|
-
/* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
1808
|
-
/* @__PURE__ */
|
|
1809
|
-
/* @__PURE__ */
|
|
1911
|
+
/* @__PURE__ */ jsxs17("table", { className: "w-full text-sm", children: [
|
|
1912
|
+
/* @__PURE__ */ jsx20("thead", { children: /* @__PURE__ */ jsxs17("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
1913
|
+
/* @__PURE__ */ jsx20("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
|
|
1914
|
+
/* @__PURE__ */ jsx20("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" }),
|
|
1915
|
+
/* @__PURE__ */ jsx20("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Description" }),
|
|
1916
|
+
/* @__PURE__ */ jsx20("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipients" }),
|
|
1917
|
+
/* @__PURE__ */ jsx20("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
1810
1918
|
] }) }),
|
|
1811
|
-
/* @__PURE__ */
|
|
1812
|
-
/* @__PURE__ */
|
|
1813
|
-
/* @__PURE__ */
|
|
1814
|
-
/* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
/* @__PURE__ */
|
|
1919
|
+
/* @__PURE__ */ jsx20("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs17("tr", { className: "border-b border-border", children: [
|
|
1920
|
+
/* @__PURE__ */ jsx20("td", { className: "py-3 pe-4", children: renderNameCell(row) }),
|
|
1921
|
+
/* @__PURE__ */ jsx20("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx20(StatusBadge3, { variant: typeVariant(row.type), appearance: "dot", children: row.type }) }),
|
|
1922
|
+
/* @__PURE__ */ jsx20("td", { className: "px-4 py-3 text-muted-foreground", children: row.description ?? "\u2014" }),
|
|
1923
|
+
/* @__PURE__ */ jsx20("td", { className: "px-4 py-3 text-muted-foreground", children: row.recipientIds?.length ?? "\u2014" }),
|
|
1924
|
+
/* @__PURE__ */ jsx20("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime2(row.createdAt) })
|
|
1817
1925
|
] }, row.id)) })
|
|
1818
1926
|
] })
|
|
1819
1927
|
] });
|
|
1820
1928
|
}
|
|
1821
1929
|
|
|
1822
1930
|
// src/segment-builder.tsx
|
|
1823
|
-
import { useState as
|
|
1824
|
-
import { cn as
|
|
1931
|
+
import { useState as useState9 } from "react";
|
|
1932
|
+
import { cn as cn19, useToast as useToast7 } from "@quanticjs/react-ui";
|
|
1825
1933
|
import { useApiMutation as useApiMutation8 } from "@quanticjs/react-query";
|
|
1826
|
-
import { jsx as
|
|
1934
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1827
1935
|
function parseRecipientIds(value) {
|
|
1828
1936
|
return value.split(/[\n,]/).map((id) => id.trim()).filter((id) => id.length > 0);
|
|
1829
1937
|
}
|
|
@@ -1836,11 +1944,11 @@ function SegmentBuilder({
|
|
|
1836
1944
|
className
|
|
1837
1945
|
}) {
|
|
1838
1946
|
const toast = useToast7();
|
|
1839
|
-
const [name, setName] =
|
|
1840
|
-
const [type, setType] =
|
|
1841
|
-
const [description, setDescription] =
|
|
1842
|
-
const [recipientText, setRecipientText] =
|
|
1843
|
-
const [errors, setErrors] =
|
|
1947
|
+
const [name, setName] = useState9(initial?.name ?? "");
|
|
1948
|
+
const [type, setType] = useState9(initial?.type ?? "static");
|
|
1949
|
+
const [description, setDescription] = useState9(initial?.description ?? "");
|
|
1950
|
+
const [recipientText, setRecipientText] = useState9((initial?.recipientIds ?? []).join("\n"));
|
|
1951
|
+
const [errors, setErrors] = useState9({});
|
|
1844
1952
|
const isEdit = Boolean(segmentId);
|
|
1845
1953
|
const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
|
|
1846
1954
|
description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
|
|
@@ -1889,11 +1997,11 @@ function SegmentBuilder({
|
|
|
1889
1997
|
if (!window.confirm("Delete this segment? This cannot be undone.")) return;
|
|
1890
1998
|
remove.mutate();
|
|
1891
1999
|
};
|
|
1892
|
-
return /* @__PURE__ */
|
|
1893
|
-
/* @__PURE__ */
|
|
1894
|
-
/* @__PURE__ */
|
|
1895
|
-
/* @__PURE__ */
|
|
1896
|
-
/* @__PURE__ */
|
|
2000
|
+
return /* @__PURE__ */ jsxs18("form", { onSubmit, className: cn19("flex flex-col gap-4", className), noValidate: true, children: [
|
|
2001
|
+
/* @__PURE__ */ jsx21("header", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx21("h2", { className: "text-sm font-semibold text-foreground", children: isEdit ? `Edit segment: ${segmentId}` : "New segment" }) }),
|
|
2002
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-1", children: [
|
|
2003
|
+
/* @__PURE__ */ jsx21("label", { htmlFor: "segment-name", className: "text-sm font-medium text-foreground", children: "Name" }),
|
|
2004
|
+
/* @__PURE__ */ jsx21(
|
|
1897
2005
|
"input",
|
|
1898
2006
|
{
|
|
1899
2007
|
id: "segment-name",
|
|
@@ -1905,11 +2013,11 @@ function SegmentBuilder({
|
|
|
1905
2013
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
1906
2014
|
}
|
|
1907
2015
|
),
|
|
1908
|
-
errors.name && /* @__PURE__ */
|
|
2016
|
+
errors.name && /* @__PURE__ */ jsx21("p", { id: "segment-name-error", className: "text-xs text-destructive", children: errors.name })
|
|
1909
2017
|
] }),
|
|
1910
|
-
/* @__PURE__ */
|
|
1911
|
-
/* @__PURE__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
2018
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-1", children: [
|
|
2019
|
+
/* @__PURE__ */ jsx21("label", { htmlFor: "segment-type", className: "text-sm font-medium text-foreground", children: "Type" }),
|
|
2020
|
+
/* @__PURE__ */ jsxs18(
|
|
1913
2021
|
"select",
|
|
1914
2022
|
{
|
|
1915
2023
|
id: "segment-type",
|
|
@@ -1917,15 +2025,15 @@ function SegmentBuilder({
|
|
|
1917
2025
|
onChange: (e) => setType(e.target.value),
|
|
1918
2026
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
1919
2027
|
children: [
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
2028
|
+
/* @__PURE__ */ jsx21("option", { value: "static", children: "static" }),
|
|
2029
|
+
/* @__PURE__ */ jsx21("option", { value: "dynamic", children: "dynamic" })
|
|
1922
2030
|
]
|
|
1923
2031
|
}
|
|
1924
2032
|
)
|
|
1925
2033
|
] }),
|
|
1926
|
-
/* @__PURE__ */
|
|
1927
|
-
/* @__PURE__ */
|
|
1928
|
-
/* @__PURE__ */
|
|
2034
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-1", children: [
|
|
2035
|
+
/* @__PURE__ */ jsx21("label", { htmlFor: "segment-description", className: "text-sm font-medium text-foreground", children: "Description" }),
|
|
2036
|
+
/* @__PURE__ */ jsx21(
|
|
1929
2037
|
"textarea",
|
|
1930
2038
|
{
|
|
1931
2039
|
id: "segment-description",
|
|
@@ -1936,9 +2044,9 @@ function SegmentBuilder({
|
|
|
1936
2044
|
}
|
|
1937
2045
|
)
|
|
1938
2046
|
] }),
|
|
1939
|
-
type === "static" && /* @__PURE__ */
|
|
1940
|
-
/* @__PURE__ */
|
|
1941
|
-
/* @__PURE__ */
|
|
2047
|
+
type === "static" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-1", children: [
|
|
2048
|
+
/* @__PURE__ */ jsx21("label", { htmlFor: "segment-recipients", className: "text-sm font-medium text-foreground", children: "Recipient ids" }),
|
|
2049
|
+
/* @__PURE__ */ jsx21(
|
|
1942
2050
|
"textarea",
|
|
1943
2051
|
{
|
|
1944
2052
|
id: "segment-recipients",
|
|
@@ -1951,10 +2059,10 @@ function SegmentBuilder({
|
|
|
1951
2059
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
1952
2060
|
}
|
|
1953
2061
|
),
|
|
1954
|
-
errors.recipientIds && /* @__PURE__ */
|
|
2062
|
+
errors.recipientIds && /* @__PURE__ */ jsx21("p", { id: "segment-recipients-error", className: "text-xs text-destructive", children: errors.recipientIds })
|
|
1955
2063
|
] }),
|
|
1956
|
-
/* @__PURE__ */
|
|
1957
|
-
/* @__PURE__ */
|
|
2064
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-3", children: [
|
|
2065
|
+
/* @__PURE__ */ jsx21(
|
|
1958
2066
|
"button",
|
|
1959
2067
|
{
|
|
1960
2068
|
type: "submit",
|
|
@@ -1963,7 +2071,7 @@ function SegmentBuilder({
|
|
|
1963
2071
|
children: save.isPending ? "Saving\u2026" : isEdit ? "Save changes" : "Create segment"
|
|
1964
2072
|
}
|
|
1965
2073
|
),
|
|
1966
|
-
isEdit && /* @__PURE__ */
|
|
2074
|
+
isEdit && /* @__PURE__ */ jsx21(
|
|
1967
2075
|
"button",
|
|
1968
2076
|
{
|
|
1969
2077
|
type: "button",
|
|
@@ -1978,18 +2086,18 @@ function SegmentBuilder({
|
|
|
1978
2086
|
}
|
|
1979
2087
|
|
|
1980
2088
|
// src/suppression-manager.tsx
|
|
1981
|
-
import { useState as
|
|
1982
|
-
import { cn as
|
|
2089
|
+
import { useState as useState10 } from "react";
|
|
2090
|
+
import { cn as cn20, formatDateTime as formatDateTime3, useToast as useToast8 } from "@quanticjs/react-ui";
|
|
1983
2091
|
import { useApiMutation as useApiMutation9, useApiQuery as useApiQuery14 } from "@quanticjs/react-query";
|
|
1984
|
-
import { Fragment, jsx as
|
|
2092
|
+
import { Fragment, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1985
2093
|
var LIMIT3 = 20;
|
|
1986
2094
|
var CHANNELS3 = ["inapp", "email", "push", "sms"];
|
|
1987
2095
|
function SuppressionManager({ basePath = "/api", className }) {
|
|
1988
2096
|
const toast = useToast8();
|
|
1989
|
-
const [page, setPage] =
|
|
1990
|
-
const [channel, setChannel] =
|
|
1991
|
-
const [address, setAddress] =
|
|
1992
|
-
const [reason, setReason] =
|
|
2097
|
+
const [page, setPage] = useState10(1);
|
|
2098
|
+
const [channel, setChannel] = useState10("email");
|
|
2099
|
+
const [address, setAddress] = useState10("");
|
|
2100
|
+
const [reason, setReason] = useState10("");
|
|
1993
2101
|
const { data, isLoading, isError, refetch } = useApiQuery14(
|
|
1994
2102
|
["suppression", page],
|
|
1995
2103
|
(client) => client.get(`${basePath}/v1/admin/suppression?page=${page}&limit=${LIMIT3}`)
|
|
@@ -2025,23 +2133,23 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2025
2133
|
event.preventDefault();
|
|
2026
2134
|
add.mutate({ channel, address: address.trim(), reason: reason.trim() });
|
|
2027
2135
|
};
|
|
2028
|
-
const addForm = /* @__PURE__ */
|
|
2029
|
-
/* @__PURE__ */
|
|
2030
|
-
/* @__PURE__ */
|
|
2031
|
-
/* @__PURE__ */
|
|
2136
|
+
const addForm = /* @__PURE__ */ jsxs19("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
2137
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
|
|
2138
|
+
/* @__PURE__ */ jsx22("label", { htmlFor: "suppression-channel", className: "text-sm font-medium text-foreground", children: "Channel" }),
|
|
2139
|
+
/* @__PURE__ */ jsx22(
|
|
2032
2140
|
"select",
|
|
2033
2141
|
{
|
|
2034
2142
|
id: "suppression-channel",
|
|
2035
2143
|
value: channel,
|
|
2036
2144
|
onChange: (e) => setChannel(e.target.value),
|
|
2037
2145
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
2038
|
-
children: CHANNELS3.map((c) => /* @__PURE__ */
|
|
2146
|
+
children: CHANNELS3.map((c) => /* @__PURE__ */ jsx22("option", { value: c, children: c }, c))
|
|
2039
2147
|
}
|
|
2040
2148
|
)
|
|
2041
2149
|
] }),
|
|
2042
|
-
/* @__PURE__ */
|
|
2043
|
-
/* @__PURE__ */
|
|
2044
|
-
/* @__PURE__ */
|
|
2150
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
|
|
2151
|
+
/* @__PURE__ */ jsx22("label", { htmlFor: "suppression-address", className: "text-sm font-medium text-foreground", children: "Address" }),
|
|
2152
|
+
/* @__PURE__ */ jsx22(
|
|
2045
2153
|
"input",
|
|
2046
2154
|
{
|
|
2047
2155
|
id: "suppression-address",
|
|
@@ -2052,9 +2160,9 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2052
2160
|
}
|
|
2053
2161
|
)
|
|
2054
2162
|
] }),
|
|
2055
|
-
/* @__PURE__ */
|
|
2056
|
-
/* @__PURE__ */
|
|
2057
|
-
/* @__PURE__ */
|
|
2163
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
|
|
2164
|
+
/* @__PURE__ */ jsx22("label", { htmlFor: "suppression-reason", className: "text-sm font-medium text-foreground", children: "Reason" }),
|
|
2165
|
+
/* @__PURE__ */ jsx22(
|
|
2058
2166
|
"input",
|
|
2059
2167
|
{
|
|
2060
2168
|
id: "suppression-reason",
|
|
@@ -2065,7 +2173,7 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2065
2173
|
}
|
|
2066
2174
|
)
|
|
2067
2175
|
] }),
|
|
2068
|
-
/* @__PURE__ */
|
|
2176
|
+
/* @__PURE__ */ jsx22(
|
|
2069
2177
|
"button",
|
|
2070
2178
|
{
|
|
2071
2179
|
type: "submit",
|
|
@@ -2077,14 +2185,14 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2077
2185
|
] });
|
|
2078
2186
|
let body;
|
|
2079
2187
|
if (isLoading) {
|
|
2080
|
-
body = /* @__PURE__ */
|
|
2081
|
-
/* @__PURE__ */
|
|
2082
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2188
|
+
body = /* @__PURE__ */ jsxs19("div", { role: "status", "aria-label": "Loading suppressions", className: "flex flex-col gap-2 p-4", children: [
|
|
2189
|
+
/* @__PURE__ */ jsx22("span", { className: "sr-only", children: "Loading suppressions" }),
|
|
2190
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx22("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2083
2191
|
] });
|
|
2084
2192
|
} else if (isError) {
|
|
2085
|
-
body = /* @__PURE__ */
|
|
2086
|
-
/* @__PURE__ */
|
|
2087
|
-
/* @__PURE__ */
|
|
2193
|
+
body = /* @__PURE__ */ jsxs19("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2194
|
+
/* @__PURE__ */ jsx22("p", { className: "text-sm text-foreground", children: "Failed to load suppressions" }),
|
|
2195
|
+
/* @__PURE__ */ jsx22(
|
|
2088
2196
|
"button",
|
|
2089
2197
|
{
|
|
2090
2198
|
type: "button",
|
|
@@ -2098,23 +2206,23 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2098
2206
|
const rows = data?.items ?? [];
|
|
2099
2207
|
const totalPages = data?.totalPages ?? 1;
|
|
2100
2208
|
if (rows.length === 0) {
|
|
2101
|
-
body = /* @__PURE__ */
|
|
2209
|
+
body = /* @__PURE__ */ jsx22("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No suppressions" });
|
|
2102
2210
|
} else {
|
|
2103
|
-
body = /* @__PURE__ */
|
|
2104
|
-
/* @__PURE__ */
|
|
2105
|
-
/* @__PURE__ */
|
|
2106
|
-
/* @__PURE__ */
|
|
2107
|
-
/* @__PURE__ */
|
|
2108
|
-
/* @__PURE__ */
|
|
2109
|
-
/* @__PURE__ */
|
|
2110
|
-
/* @__PURE__ */
|
|
2211
|
+
body = /* @__PURE__ */ jsxs19(Fragment, { children: [
|
|
2212
|
+
/* @__PURE__ */ jsxs19("table", { className: "w-full text-sm", children: [
|
|
2213
|
+
/* @__PURE__ */ jsx22("thead", { children: /* @__PURE__ */ jsxs19("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2214
|
+
/* @__PURE__ */ jsx22("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
|
|
2215
|
+
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Address" }),
|
|
2216
|
+
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Reason" }),
|
|
2217
|
+
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
2218
|
+
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx22("span", { className: "sr-only", children: "Actions" }) })
|
|
2111
2219
|
] }) }),
|
|
2112
|
-
/* @__PURE__ */
|
|
2113
|
-
/* @__PURE__ */
|
|
2114
|
-
/* @__PURE__ */
|
|
2115
|
-
/* @__PURE__ */
|
|
2116
|
-
/* @__PURE__ */
|
|
2117
|
-
/* @__PURE__ */
|
|
2220
|
+
/* @__PURE__ */ jsx22("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs19("tr", { className: "border-b border-border", children: [
|
|
2221
|
+
/* @__PURE__ */ jsx22("td", { className: "py-3 pe-4 text-foreground", children: row.channel }),
|
|
2222
|
+
/* @__PURE__ */ jsx22("td", { className: "px-4 py-3 text-foreground", children: row.address }),
|
|
2223
|
+
/* @__PURE__ */ jsx22("td", { className: "px-4 py-3 text-muted-foreground", children: row.reason }),
|
|
2224
|
+
/* @__PURE__ */ jsx22("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime3(row.createdAt) }),
|
|
2225
|
+
/* @__PURE__ */ jsx22("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx22(
|
|
2118
2226
|
"button",
|
|
2119
2227
|
{
|
|
2120
2228
|
type: "button",
|
|
@@ -2126,8 +2234,8 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2126
2234
|
) })
|
|
2127
2235
|
] }, row.id)) })
|
|
2128
2236
|
] }),
|
|
2129
|
-
/* @__PURE__ */
|
|
2130
|
-
/* @__PURE__ */
|
|
2237
|
+
/* @__PURE__ */ jsxs19("nav", { "aria-label": "Suppression pagination", className: "flex items-center justify-between", children: [
|
|
2238
|
+
/* @__PURE__ */ jsx22(
|
|
2131
2239
|
"button",
|
|
2132
2240
|
{
|
|
2133
2241
|
type: "button",
|
|
@@ -2137,13 +2245,13 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2137
2245
|
children: "Previous"
|
|
2138
2246
|
}
|
|
2139
2247
|
),
|
|
2140
|
-
/* @__PURE__ */
|
|
2248
|
+
/* @__PURE__ */ jsxs19("span", { className: "text-xs text-muted-foreground", children: [
|
|
2141
2249
|
"Page ",
|
|
2142
2250
|
page,
|
|
2143
2251
|
" of ",
|
|
2144
2252
|
totalPages
|
|
2145
2253
|
] }),
|
|
2146
|
-
/* @__PURE__ */
|
|
2254
|
+
/* @__PURE__ */ jsx22(
|
|
2147
2255
|
"button",
|
|
2148
2256
|
{
|
|
2149
2257
|
type: "button",
|
|
@@ -2157,22 +2265,22 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2157
2265
|
] });
|
|
2158
2266
|
}
|
|
2159
2267
|
}
|
|
2160
|
-
return /* @__PURE__ */
|
|
2268
|
+
return /* @__PURE__ */ jsxs19("section", { "aria-label": "Suppression list", className: cn20("flex flex-col gap-4", className), children: [
|
|
2161
2269
|
addForm,
|
|
2162
2270
|
body
|
|
2163
2271
|
] });
|
|
2164
2272
|
}
|
|
2165
2273
|
|
|
2166
2274
|
// src/dlq-console.tsx
|
|
2167
|
-
import { Fragment as Fragment2, useState as
|
|
2275
|
+
import { Fragment as Fragment2, useState as useState11 } from "react";
|
|
2168
2276
|
import {
|
|
2169
|
-
cn as
|
|
2277
|
+
cn as cn21,
|
|
2170
2278
|
formatDateTime as formatDateTime4,
|
|
2171
2279
|
StatusBadge as StatusBadge4,
|
|
2172
2280
|
useToast as useToast9
|
|
2173
2281
|
} from "@quanticjs/react-ui";
|
|
2174
2282
|
import { useApiMutation as useApiMutation10, useApiQuery as useApiQuery15 } from "@quanticjs/react-query";
|
|
2175
|
-
import { Fragment as Fragment3, jsx as
|
|
2283
|
+
import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2176
2284
|
var LIMIT4 = 20;
|
|
2177
2285
|
var STATUS_FILTERS = ["queued", "replayed", "discarded"];
|
|
2178
2286
|
function buildErrorDescription(error) {
|
|
@@ -2196,15 +2304,15 @@ function DlqMessageDetailRow({ id, basePath }) {
|
|
|
2196
2304
|
(client) => client.get(`${basePath}/admin/dlq/${id}`)
|
|
2197
2305
|
);
|
|
2198
2306
|
if (isLoading) {
|
|
2199
|
-
return /* @__PURE__ */
|
|
2200
|
-
/* @__PURE__ */
|
|
2201
|
-
/* @__PURE__ */
|
|
2307
|
+
return /* @__PURE__ */ jsxs20("div", { role: "status", "aria-label": "Loading message detail", className: "flex flex-col gap-2 p-3", children: [
|
|
2308
|
+
/* @__PURE__ */ jsx23("span", { className: "sr-only", children: "Loading message detail" }),
|
|
2309
|
+
/* @__PURE__ */ jsx23("div", { "aria-hidden": "true", className: "h-16 animate-pulse rounded bg-muted" })
|
|
2202
2310
|
] });
|
|
2203
2311
|
}
|
|
2204
2312
|
if (isError) {
|
|
2205
|
-
return /* @__PURE__ */
|
|
2206
|
-
/* @__PURE__ */
|
|
2207
|
-
/* @__PURE__ */
|
|
2313
|
+
return /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-start gap-3 p-3", children: [
|
|
2314
|
+
/* @__PURE__ */ jsx23("p", { className: "text-sm text-foreground", children: "Failed to load message detail" }),
|
|
2315
|
+
/* @__PURE__ */ jsx23(
|
|
2208
2316
|
"button",
|
|
2209
2317
|
{
|
|
2210
2318
|
type: "button",
|
|
@@ -2215,19 +2323,19 @@ function DlqMessageDetailRow({ id, basePath }) {
|
|
|
2215
2323
|
)
|
|
2216
2324
|
] });
|
|
2217
2325
|
}
|
|
2218
|
-
return /* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2326
|
+
return /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-2 p-3 text-sm", children: [
|
|
2327
|
+
/* @__PURE__ */ jsxs20("p", { className: "text-muted-foreground", children: [
|
|
2220
2328
|
"Error: ",
|
|
2221
|
-
/* @__PURE__ */
|
|
2329
|
+
/* @__PURE__ */ jsx23("span", { className: "text-foreground", children: data?.errorMessage ?? "\u2014" })
|
|
2222
2330
|
] }),
|
|
2223
|
-
/* @__PURE__ */
|
|
2331
|
+
/* @__PURE__ */ jsx23("pre", { className: "max-h-64 overflow-auto rounded bg-muted p-3 text-xs text-foreground", children: JSON.stringify(data?.payload ?? {}, null, 2) })
|
|
2224
2332
|
] });
|
|
2225
2333
|
}
|
|
2226
2334
|
function DlqConsole({ basePath = "/api", className }) {
|
|
2227
2335
|
const toast = useToast9();
|
|
2228
|
-
const [page, setPage] =
|
|
2229
|
-
const [statusFilter, setStatusFilter] =
|
|
2230
|
-
const [expandedId, setExpandedId] =
|
|
2336
|
+
const [page, setPage] = useState11(1);
|
|
2337
|
+
const [statusFilter, setStatusFilter] = useState11("");
|
|
2338
|
+
const [expandedId, setExpandedId] = useState11(null);
|
|
2231
2339
|
const statusQuery = statusFilter ? `&status=${statusFilter}` : "";
|
|
2232
2340
|
const { data, isLoading, isError, refetch } = useApiQuery15(
|
|
2233
2341
|
["dlq", page, statusFilter],
|
|
@@ -2268,9 +2376,9 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2268
2376
|
})
|
|
2269
2377
|
}
|
|
2270
2378
|
);
|
|
2271
|
-
const filterControl = /* @__PURE__ */
|
|
2272
|
-
/* @__PURE__ */
|
|
2273
|
-
/* @__PURE__ */
|
|
2379
|
+
const filterControl = /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
|
|
2380
|
+
/* @__PURE__ */ jsx23("label", { htmlFor: "dlq-status", className: "text-sm font-medium text-foreground", children: "Status" }),
|
|
2381
|
+
/* @__PURE__ */ jsxs20(
|
|
2274
2382
|
"select",
|
|
2275
2383
|
{
|
|
2276
2384
|
id: "dlq-status",
|
|
@@ -2281,30 +2389,30 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2281
2389
|
},
|
|
2282
2390
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
2283
2391
|
children: [
|
|
2284
|
-
/* @__PURE__ */
|
|
2285
|
-
STATUS_FILTERS.map((s) => /* @__PURE__ */
|
|
2392
|
+
/* @__PURE__ */ jsx23("option", { value: "", children: "All" }),
|
|
2393
|
+
STATUS_FILTERS.map((s) => /* @__PURE__ */ jsx23("option", { value: s, children: s }, s))
|
|
2286
2394
|
]
|
|
2287
2395
|
}
|
|
2288
2396
|
)
|
|
2289
2397
|
] });
|
|
2290
2398
|
let body;
|
|
2291
2399
|
if (isLoading) {
|
|
2292
|
-
body = /* @__PURE__ */
|
|
2400
|
+
body = /* @__PURE__ */ jsxs20(
|
|
2293
2401
|
"div",
|
|
2294
2402
|
{
|
|
2295
2403
|
role: "status",
|
|
2296
2404
|
"aria-label": "Loading dead-letter messages",
|
|
2297
2405
|
className: "flex flex-col gap-2 p-4",
|
|
2298
2406
|
children: [
|
|
2299
|
-
/* @__PURE__ */
|
|
2300
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2407
|
+
/* @__PURE__ */ jsx23("span", { className: "sr-only", children: "Loading dead-letter messages" }),
|
|
2408
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx23("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2301
2409
|
]
|
|
2302
2410
|
}
|
|
2303
2411
|
);
|
|
2304
2412
|
} else if (isError) {
|
|
2305
|
-
body = /* @__PURE__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2307
|
-
/* @__PURE__ */
|
|
2413
|
+
body = /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2414
|
+
/* @__PURE__ */ jsx23("p", { className: "text-sm text-foreground", children: "Failed to load dead-letter messages" }),
|
|
2415
|
+
/* @__PURE__ */ jsx23(
|
|
2308
2416
|
"button",
|
|
2309
2417
|
{
|
|
2310
2418
|
type: "button",
|
|
@@ -2318,23 +2426,23 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2318
2426
|
const rows = data?.items ?? [];
|
|
2319
2427
|
const totalPages = data?.totalPages ?? 1;
|
|
2320
2428
|
if (rows.length === 0) {
|
|
2321
|
-
body = /* @__PURE__ */
|
|
2429
|
+
body = /* @__PURE__ */ jsx23("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No dead-letter messages" });
|
|
2322
2430
|
} else {
|
|
2323
|
-
body = /* @__PURE__ */
|
|
2324
|
-
/* @__PURE__ */
|
|
2325
|
-
/* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2327
|
-
/* @__PURE__ */
|
|
2328
|
-
/* @__PURE__ */
|
|
2329
|
-
/* @__PURE__ */
|
|
2330
|
-
/* @__PURE__ */
|
|
2331
|
-
/* @__PURE__ */
|
|
2431
|
+
body = /* @__PURE__ */ jsxs20(Fragment3, { children: [
|
|
2432
|
+
/* @__PURE__ */ jsxs20("table", { className: "w-full text-sm", children: [
|
|
2433
|
+
/* @__PURE__ */ jsx23("thead", { children: /* @__PURE__ */ jsxs20("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2434
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Request" }),
|
|
2435
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Failure reason" }),
|
|
2436
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
2437
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
|
|
2438
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "First seen" }),
|
|
2439
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx23("span", { className: "sr-only", children: "Actions" }) })
|
|
2332
2440
|
] }) }),
|
|
2333
|
-
/* @__PURE__ */
|
|
2441
|
+
/* @__PURE__ */ jsx23("tbody", { children: rows.map((row) => {
|
|
2334
2442
|
const isExpanded = expandedId === row.id;
|
|
2335
|
-
return /* @__PURE__ */
|
|
2336
|
-
/* @__PURE__ */
|
|
2337
|
-
/* @__PURE__ */
|
|
2443
|
+
return /* @__PURE__ */ jsxs20(Fragment2, { children: [
|
|
2444
|
+
/* @__PURE__ */ jsxs20("tr", { className: "border-b border-border", children: [
|
|
2445
|
+
/* @__PURE__ */ jsx23("td", { className: "py-3 pe-4", children: /* @__PURE__ */ jsx23(
|
|
2338
2446
|
"button",
|
|
2339
2447
|
{
|
|
2340
2448
|
type: "button",
|
|
@@ -2344,12 +2452,12 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2344
2452
|
children: row.requestId ?? row.id
|
|
2345
2453
|
}
|
|
2346
2454
|
) }),
|
|
2347
|
-
/* @__PURE__ */
|
|
2348
|
-
/* @__PURE__ */
|
|
2349
|
-
/* @__PURE__ */
|
|
2350
|
-
/* @__PURE__ */
|
|
2351
|
-
/* @__PURE__ */
|
|
2352
|
-
/* @__PURE__ */
|
|
2455
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-muted-foreground", children: row.failureReason }),
|
|
2456
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx23(StatusBadge4, { variant: statusVariant3(row.status), appearance: "dot", children: row.status }) }),
|
|
2457
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-muted-foreground", children: row.attemptCount }),
|
|
2458
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime4(row.firstSeenAt) }),
|
|
2459
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
|
|
2460
|
+
/* @__PURE__ */ jsx23(
|
|
2353
2461
|
"button",
|
|
2354
2462
|
{
|
|
2355
2463
|
type: "button",
|
|
@@ -2359,7 +2467,7 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2359
2467
|
children: "Replay"
|
|
2360
2468
|
}
|
|
2361
2469
|
),
|
|
2362
|
-
/* @__PURE__ */
|
|
2470
|
+
/* @__PURE__ */ jsx23(
|
|
2363
2471
|
"button",
|
|
2364
2472
|
{
|
|
2365
2473
|
type: "button",
|
|
@@ -2371,12 +2479,12 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2371
2479
|
)
|
|
2372
2480
|
] }) })
|
|
2373
2481
|
] }),
|
|
2374
|
-
isExpanded && /* @__PURE__ */
|
|
2482
|
+
isExpanded && /* @__PURE__ */ jsx23("tr", { className: "border-b border-border", children: /* @__PURE__ */ jsx23("td", { colSpan: 6, className: "bg-muted/40", children: /* @__PURE__ */ jsx23(DlqMessageDetailRow, { id: row.id, basePath }) }) })
|
|
2375
2483
|
] }, row.id);
|
|
2376
2484
|
}) })
|
|
2377
2485
|
] }),
|
|
2378
|
-
/* @__PURE__ */
|
|
2379
|
-
/* @__PURE__ */
|
|
2486
|
+
/* @__PURE__ */ jsxs20("nav", { "aria-label": "Dead-letter pagination", className: "flex items-center justify-between", children: [
|
|
2487
|
+
/* @__PURE__ */ jsx23(
|
|
2380
2488
|
"button",
|
|
2381
2489
|
{
|
|
2382
2490
|
type: "button",
|
|
@@ -2386,13 +2494,13 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2386
2494
|
children: "Previous"
|
|
2387
2495
|
}
|
|
2388
2496
|
),
|
|
2389
|
-
/* @__PURE__ */
|
|
2497
|
+
/* @__PURE__ */ jsxs20("span", { className: "text-xs text-muted-foreground", children: [
|
|
2390
2498
|
"Page ",
|
|
2391
2499
|
page,
|
|
2392
2500
|
" of ",
|
|
2393
2501
|
totalPages
|
|
2394
2502
|
] }),
|
|
2395
|
-
/* @__PURE__ */
|
|
2503
|
+
/* @__PURE__ */ jsx23(
|
|
2396
2504
|
"button",
|
|
2397
2505
|
{
|
|
2398
2506
|
type: "button",
|
|
@@ -2406,9 +2514,9 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2406
2514
|
] });
|
|
2407
2515
|
}
|
|
2408
2516
|
}
|
|
2409
|
-
return /* @__PURE__ */
|
|
2410
|
-
/* @__PURE__ */
|
|
2411
|
-
/* @__PURE__ */
|
|
2517
|
+
return /* @__PURE__ */ jsxs20("section", { "aria-label": "Dead-letter queue", className: cn21("flex flex-col gap-4", className), children: [
|
|
2518
|
+
/* @__PURE__ */ jsxs20("header", { className: "flex items-center justify-between", children: [
|
|
2519
|
+
/* @__PURE__ */ jsx23("h2", { className: "text-sm font-semibold text-foreground", children: "Dead-letter queue" }),
|
|
2412
2520
|
filterControl
|
|
2413
2521
|
] }),
|
|
2414
2522
|
body
|
|
@@ -2416,10 +2524,10 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2416
2524
|
}
|
|
2417
2525
|
|
|
2418
2526
|
// src/catalog-editor.tsx
|
|
2419
|
-
import { useMemo as useMemo3, useState as
|
|
2420
|
-
import { cn as
|
|
2527
|
+
import { useMemo as useMemo3, useState as useState12 } from "react";
|
|
2528
|
+
import { cn as cn22, useToast as useToast10 } from "@quanticjs/react-ui";
|
|
2421
2529
|
import { useApiMutation as useApiMutation11, useApiQuery as useApiQuery16 } from "@quanticjs/react-query";
|
|
2422
|
-
import { Fragment as Fragment4, jsx as
|
|
2530
|
+
import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2423
2531
|
function normalize2(data) {
|
|
2424
2532
|
if (!data) return [];
|
|
2425
2533
|
if (Array.isArray(data)) return data;
|
|
@@ -2432,12 +2540,12 @@ function normalize2(data) {
|
|
|
2432
2540
|
}
|
|
2433
2541
|
function CatalogEditor({ basePath = "/api", className }) {
|
|
2434
2542
|
const toast = useToast10();
|
|
2435
|
-
const [filter, setFilter] =
|
|
2436
|
-
const [editingId, setEditingId] =
|
|
2437
|
-
const [editValue, setEditValue] =
|
|
2438
|
-
const [newKey, setNewKey] =
|
|
2439
|
-
const [newLocale, setNewLocale] =
|
|
2440
|
-
const [newValue, setNewValue] =
|
|
2543
|
+
const [filter, setFilter] = useState12("");
|
|
2544
|
+
const [editingId, setEditingId] = useState12(null);
|
|
2545
|
+
const [editValue, setEditValue] = useState12("");
|
|
2546
|
+
const [newKey, setNewKey] = useState12("");
|
|
2547
|
+
const [newLocale, setNewLocale] = useState12("");
|
|
2548
|
+
const [newValue, setNewValue] = useState12("");
|
|
2441
2549
|
const { data, isLoading, isError, refetch } = useApiQuery16(["i18n-catalog"], (client) => client.get(`${basePath}/i18n/catalog/export`));
|
|
2442
2550
|
const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
|
|
2443
2551
|
description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
|
|
@@ -2501,10 +2609,10 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2501
2609
|
setEditingId(`${entry.key}:${entry.locale}`);
|
|
2502
2610
|
setEditValue(entry.value);
|
|
2503
2611
|
};
|
|
2504
|
-
const addForm = /* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
/* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
2612
|
+
const addForm = /* @__PURE__ */ jsxs21("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
2613
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-1", children: [
|
|
2614
|
+
/* @__PURE__ */ jsx24("label", { htmlFor: "catalog-new-key", className: "text-sm font-medium text-foreground", children: "Key" }),
|
|
2615
|
+
/* @__PURE__ */ jsx24(
|
|
2508
2616
|
"input",
|
|
2509
2617
|
{
|
|
2510
2618
|
id: "catalog-new-key",
|
|
@@ -2515,9 +2623,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2515
2623
|
}
|
|
2516
2624
|
)
|
|
2517
2625
|
] }),
|
|
2518
|
-
/* @__PURE__ */
|
|
2519
|
-
/* @__PURE__ */
|
|
2520
|
-
/* @__PURE__ */
|
|
2626
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-1", children: [
|
|
2627
|
+
/* @__PURE__ */ jsx24("label", { htmlFor: "catalog-new-locale", className: "text-sm font-medium text-foreground", children: "Locale" }),
|
|
2628
|
+
/* @__PURE__ */ jsx24(
|
|
2521
2629
|
"input",
|
|
2522
2630
|
{
|
|
2523
2631
|
id: "catalog-new-locale",
|
|
@@ -2528,9 +2636,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2528
2636
|
}
|
|
2529
2637
|
)
|
|
2530
2638
|
] }),
|
|
2531
|
-
/* @__PURE__ */
|
|
2532
|
-
/* @__PURE__ */
|
|
2533
|
-
/* @__PURE__ */
|
|
2639
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-1", children: [
|
|
2640
|
+
/* @__PURE__ */ jsx24("label", { htmlFor: "catalog-new-value", className: "text-sm font-medium text-foreground", children: "Value" }),
|
|
2641
|
+
/* @__PURE__ */ jsx24(
|
|
2534
2642
|
"input",
|
|
2535
2643
|
{
|
|
2536
2644
|
id: "catalog-new-value",
|
|
@@ -2541,7 +2649,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2541
2649
|
}
|
|
2542
2650
|
)
|
|
2543
2651
|
] }),
|
|
2544
|
-
/* @__PURE__ */
|
|
2652
|
+
/* @__PURE__ */ jsx24(
|
|
2545
2653
|
"button",
|
|
2546
2654
|
{
|
|
2547
2655
|
type: "submit",
|
|
@@ -2551,9 +2659,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2551
2659
|
}
|
|
2552
2660
|
)
|
|
2553
2661
|
] });
|
|
2554
|
-
const filterInput = /* @__PURE__ */
|
|
2555
|
-
/* @__PURE__ */
|
|
2556
|
-
/* @__PURE__ */
|
|
2662
|
+
const filterInput = /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-1", children: [
|
|
2663
|
+
/* @__PURE__ */ jsx24("label", { htmlFor: "catalog-filter", className: "text-sm font-medium text-foreground", children: "Filter by key" }),
|
|
2664
|
+
/* @__PURE__ */ jsx24(
|
|
2557
2665
|
"input",
|
|
2558
2666
|
{
|
|
2559
2667
|
id: "catalog-filter",
|
|
@@ -2566,14 +2674,14 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2566
2674
|
] });
|
|
2567
2675
|
let body;
|
|
2568
2676
|
if (isLoading) {
|
|
2569
|
-
body = /* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2677
|
+
body = /* @__PURE__ */ jsxs21("div", { role: "status", "aria-label": "Loading catalog", className: "flex flex-col gap-2 p-4", children: [
|
|
2678
|
+
/* @__PURE__ */ jsx24("span", { className: "sr-only", children: "Loading catalog" }),
|
|
2679
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx24("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2572
2680
|
] });
|
|
2573
2681
|
} else if (isError) {
|
|
2574
|
-
body = /* @__PURE__ */
|
|
2575
|
-
/* @__PURE__ */
|
|
2576
|
-
/* @__PURE__ */
|
|
2682
|
+
body = /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2683
|
+
/* @__PURE__ */ jsx24("p", { className: "text-sm text-foreground", children: "Failed to load catalog" }),
|
|
2684
|
+
/* @__PURE__ */ jsx24(
|
|
2577
2685
|
"button",
|
|
2578
2686
|
{
|
|
2579
2687
|
type: "button",
|
|
@@ -2584,22 +2692,22 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2584
2692
|
)
|
|
2585
2693
|
] });
|
|
2586
2694
|
} else if (filtered.length === 0) {
|
|
2587
|
-
body = /* @__PURE__ */
|
|
2695
|
+
body = /* @__PURE__ */ jsx24("div", { className: "p-6 text-center text-sm text-muted-foreground", children: entries.length === 0 ? "No catalog entries" : "No entries match your filter" });
|
|
2588
2696
|
} else {
|
|
2589
|
-
body = /* @__PURE__ */
|
|
2590
|
-
/* @__PURE__ */
|
|
2591
|
-
/* @__PURE__ */
|
|
2592
|
-
/* @__PURE__ */
|
|
2593
|
-
/* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
2697
|
+
body = /* @__PURE__ */ jsxs21("table", { className: "w-full text-sm", children: [
|
|
2698
|
+
/* @__PURE__ */ jsx24("thead", { children: /* @__PURE__ */ jsxs21("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2699
|
+
/* @__PURE__ */ jsx24("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
|
|
2700
|
+
/* @__PURE__ */ jsx24("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
|
|
2701
|
+
/* @__PURE__ */ jsx24("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Value" }),
|
|
2702
|
+
/* @__PURE__ */ jsx24("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx24("span", { className: "sr-only", children: "Actions" }) })
|
|
2595
2703
|
] }) }),
|
|
2596
|
-
/* @__PURE__ */
|
|
2704
|
+
/* @__PURE__ */ jsx24("tbody", { children: filtered.map((entry) => {
|
|
2597
2705
|
const rowId = `${entry.key}:${entry.locale}`;
|
|
2598
2706
|
const isEditing = editingId === rowId;
|
|
2599
|
-
return /* @__PURE__ */
|
|
2600
|
-
/* @__PURE__ */
|
|
2601
|
-
/* @__PURE__ */
|
|
2602
|
-
/* @__PURE__ */
|
|
2707
|
+
return /* @__PURE__ */ jsxs21("tr", { className: "border-b border-border", children: [
|
|
2708
|
+
/* @__PURE__ */ jsx24("td", { className: "py-3 pe-4 font-mono text-foreground", children: entry.key }),
|
|
2709
|
+
/* @__PURE__ */ jsx24("td", { className: "px-4 py-3 text-foreground", children: entry.locale }),
|
|
2710
|
+
/* @__PURE__ */ jsx24("td", { className: "px-4 py-3 text-foreground", children: isEditing ? /* @__PURE__ */ jsx24(
|
|
2603
2711
|
"input",
|
|
2604
2712
|
{
|
|
2605
2713
|
type: "text",
|
|
@@ -2609,8 +2717,8 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2609
2717
|
className: "w-full rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
2610
2718
|
}
|
|
2611
2719
|
) : entry.value }),
|
|
2612
|
-
/* @__PURE__ */
|
|
2613
|
-
/* @__PURE__ */
|
|
2720
|
+
/* @__PURE__ */ jsx24("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx24("div", { className: "flex items-center gap-2", children: isEditing ? /* @__PURE__ */ jsxs21(Fragment4, { children: [
|
|
2721
|
+
/* @__PURE__ */ jsx24(
|
|
2614
2722
|
"button",
|
|
2615
2723
|
{
|
|
2616
2724
|
type: "button",
|
|
@@ -2624,7 +2732,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2624
2732
|
children: "Save"
|
|
2625
2733
|
}
|
|
2626
2734
|
),
|
|
2627
|
-
/* @__PURE__ */
|
|
2735
|
+
/* @__PURE__ */ jsx24(
|
|
2628
2736
|
"button",
|
|
2629
2737
|
{
|
|
2630
2738
|
type: "button",
|
|
@@ -2633,8 +2741,8 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2633
2741
|
children: "Cancel"
|
|
2634
2742
|
}
|
|
2635
2743
|
)
|
|
2636
|
-
] }) : /* @__PURE__ */
|
|
2637
|
-
/* @__PURE__ */
|
|
2744
|
+
] }) : /* @__PURE__ */ jsxs21(Fragment4, { children: [
|
|
2745
|
+
/* @__PURE__ */ jsx24(
|
|
2638
2746
|
"button",
|
|
2639
2747
|
{
|
|
2640
2748
|
type: "button",
|
|
@@ -2643,7 +2751,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2643
2751
|
children: "Edit"
|
|
2644
2752
|
}
|
|
2645
2753
|
),
|
|
2646
|
-
/* @__PURE__ */
|
|
2754
|
+
/* @__PURE__ */ jsx24(
|
|
2647
2755
|
"button",
|
|
2648
2756
|
{
|
|
2649
2757
|
type: "button",
|
|
@@ -2658,7 +2766,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2658
2766
|
}) })
|
|
2659
2767
|
] });
|
|
2660
2768
|
}
|
|
2661
|
-
return /* @__PURE__ */
|
|
2769
|
+
return /* @__PURE__ */ jsxs21("section", { "aria-label": "Catalog editor", className: cn22("flex flex-col gap-4", className), children: [
|
|
2662
2770
|
addForm,
|
|
2663
2771
|
filterInput,
|
|
2664
2772
|
body
|
|
@@ -2666,9 +2774,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2666
2774
|
}
|
|
2667
2775
|
|
|
2668
2776
|
// src/missing-translations-panel.tsx
|
|
2669
|
-
import { cn as
|
|
2777
|
+
import { cn as cn23 } from "@quanticjs/react-ui";
|
|
2670
2778
|
import { useApiQuery as useApiQuery17 } from "@quanticjs/react-query";
|
|
2671
|
-
import { jsx as
|
|
2779
|
+
import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2672
2780
|
function normalize3(data) {
|
|
2673
2781
|
if (Array.isArray(data)) return data;
|
|
2674
2782
|
return data?.missing ?? [];
|
|
@@ -2682,23 +2790,23 @@ function MissingTranslationsPanel({
|
|
|
2682
2790
|
(client) => client.get(`${basePath}/i18n/catalog/missing`)
|
|
2683
2791
|
);
|
|
2684
2792
|
if (isLoading) {
|
|
2685
|
-
return /* @__PURE__ */
|
|
2793
|
+
return /* @__PURE__ */ jsxs22(
|
|
2686
2794
|
"div",
|
|
2687
2795
|
{
|
|
2688
2796
|
role: "status",
|
|
2689
2797
|
"aria-label": "Loading missing translations",
|
|
2690
|
-
className:
|
|
2798
|
+
className: cn23("flex flex-col gap-2 p-4", className),
|
|
2691
2799
|
children: [
|
|
2692
|
-
/* @__PURE__ */
|
|
2693
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2800
|
+
/* @__PURE__ */ jsx25("span", { className: "sr-only", children: "Loading missing translations" }),
|
|
2801
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx25("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2694
2802
|
]
|
|
2695
2803
|
}
|
|
2696
2804
|
);
|
|
2697
2805
|
}
|
|
2698
2806
|
if (isError) {
|
|
2699
|
-
return /* @__PURE__ */
|
|
2700
|
-
/* @__PURE__ */
|
|
2701
|
-
/* @__PURE__ */
|
|
2807
|
+
return /* @__PURE__ */ jsxs22("div", { className: cn23("flex flex-col items-start gap-3 p-4", className), children: [
|
|
2808
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm text-foreground", children: "Failed to load missing translations" }),
|
|
2809
|
+
/* @__PURE__ */ jsx25(
|
|
2702
2810
|
"button",
|
|
2703
2811
|
{
|
|
2704
2812
|
type: "button",
|
|
@@ -2711,26 +2819,26 @@ function MissingTranslationsPanel({
|
|
|
2711
2819
|
}
|
|
2712
2820
|
const rows = normalize3(data);
|
|
2713
2821
|
if (rows.length === 0) {
|
|
2714
|
-
return /* @__PURE__ */
|
|
2822
|
+
return /* @__PURE__ */ jsx25("div", { className: cn23("p-6 text-center text-sm text-muted-foreground", className), children: "No missing translations" });
|
|
2715
2823
|
}
|
|
2716
|
-
return /* @__PURE__ */
|
|
2717
|
-
/* @__PURE__ */
|
|
2718
|
-
/* @__PURE__ */
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
/* @__PURE__ */
|
|
2824
|
+
return /* @__PURE__ */ jsx25("section", { "aria-label": "Missing translations", className: cn23("flex flex-col gap-3", className), children: /* @__PURE__ */ jsxs22("table", { className: "w-full text-sm", children: [
|
|
2825
|
+
/* @__PURE__ */ jsx25("thead", { children: /* @__PURE__ */ jsxs22("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2826
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
|
|
2827
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
|
|
2828
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" })
|
|
2721
2829
|
] }) }),
|
|
2722
|
-
/* @__PURE__ */
|
|
2723
|
-
/* @__PURE__ */
|
|
2724
|
-
/* @__PURE__ */
|
|
2725
|
-
/* @__PURE__ */
|
|
2830
|
+
/* @__PURE__ */ jsx25("tbody", { children: rows.map((row, i) => /* @__PURE__ */ jsxs22("tr", { className: "border-b border-border", children: [
|
|
2831
|
+
/* @__PURE__ */ jsx25("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
|
|
2832
|
+
/* @__PURE__ */ jsx25("td", { className: "px-4 py-3 text-foreground", children: row.locale }),
|
|
2833
|
+
/* @__PURE__ */ jsx25("td", { className: "px-4 py-3 text-muted-foreground", children: row.type ?? "\u2014" })
|
|
2726
2834
|
] }, `${row.key}:${row.locale}:${i}`)) })
|
|
2727
2835
|
] }) });
|
|
2728
2836
|
}
|
|
2729
2837
|
|
|
2730
2838
|
// src/fallback-report-panel.tsx
|
|
2731
|
-
import { cn as
|
|
2839
|
+
import { cn as cn24 } from "@quanticjs/react-ui";
|
|
2732
2840
|
import { useApiQuery as useApiQuery18 } from "@quanticjs/react-query";
|
|
2733
|
-
import { jsx as
|
|
2841
|
+
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2734
2842
|
function normalize4(data) {
|
|
2735
2843
|
if (Array.isArray(data)) return data;
|
|
2736
2844
|
return data?.entries ?? [];
|
|
@@ -2741,23 +2849,23 @@ function FallbackReportPanel({ basePath = "/api", className }) {
|
|
|
2741
2849
|
(client) => client.get(`${basePath}/i18n/catalog/fallback-report`)
|
|
2742
2850
|
);
|
|
2743
2851
|
if (isLoading) {
|
|
2744
|
-
return /* @__PURE__ */
|
|
2852
|
+
return /* @__PURE__ */ jsxs23(
|
|
2745
2853
|
"div",
|
|
2746
2854
|
{
|
|
2747
2855
|
role: "status",
|
|
2748
2856
|
"aria-label": "Loading fallback report",
|
|
2749
|
-
className:
|
|
2857
|
+
className: cn24("flex flex-col gap-2 p-4", className),
|
|
2750
2858
|
children: [
|
|
2751
|
-
/* @__PURE__ */
|
|
2752
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2859
|
+
/* @__PURE__ */ jsx26("span", { className: "sr-only", children: "Loading fallback report" }),
|
|
2860
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx26("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2753
2861
|
]
|
|
2754
2862
|
}
|
|
2755
2863
|
);
|
|
2756
2864
|
}
|
|
2757
2865
|
if (isError) {
|
|
2758
|
-
return /* @__PURE__ */
|
|
2759
|
-
/* @__PURE__ */
|
|
2760
|
-
/* @__PURE__ */
|
|
2866
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn24("flex flex-col items-start gap-3 p-4", className), children: [
|
|
2867
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm text-foreground", children: "Failed to load fallback report" }),
|
|
2868
|
+
/* @__PURE__ */ jsx26(
|
|
2761
2869
|
"button",
|
|
2762
2870
|
{
|
|
2763
2871
|
type: "button",
|
|
@@ -2770,38 +2878,38 @@ function FallbackReportPanel({ basePath = "/api", className }) {
|
|
|
2770
2878
|
}
|
|
2771
2879
|
const rows = normalize4(data);
|
|
2772
2880
|
if (rows.length === 0) {
|
|
2773
|
-
return /* @__PURE__ */
|
|
2881
|
+
return /* @__PURE__ */ jsx26("div", { className: cn24("p-6 text-center text-sm text-muted-foreground", className), children: "No fallbacks reported" });
|
|
2774
2882
|
}
|
|
2775
|
-
return /* @__PURE__ */
|
|
2776
|
-
/* @__PURE__ */
|
|
2777
|
-
/* @__PURE__ */
|
|
2778
|
-
/* @__PURE__ */
|
|
2779
|
-
/* @__PURE__ */
|
|
2780
|
-
/* @__PURE__ */
|
|
2883
|
+
return /* @__PURE__ */ jsx26("section", { "aria-label": "Fallback report", className: cn24("flex flex-col gap-3", className), children: /* @__PURE__ */ jsxs23("table", { className: "w-full text-sm", children: [
|
|
2884
|
+
/* @__PURE__ */ jsx26("thead", { children: /* @__PURE__ */ jsxs23("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2885
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
|
|
2886
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Requested" }),
|
|
2887
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Resolved" }),
|
|
2888
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Chain" })
|
|
2781
2889
|
] }) }),
|
|
2782
|
-
/* @__PURE__ */
|
|
2783
|
-
/* @__PURE__ */
|
|
2784
|
-
/* @__PURE__ */
|
|
2785
|
-
/* @__PURE__ */
|
|
2786
|
-
/* @__PURE__ */
|
|
2787
|
-
/* @__PURE__ */
|
|
2788
|
-
si < (row.steps?.length ?? 0) - 1 && /* @__PURE__ */
|
|
2890
|
+
/* @__PURE__ */ jsx26("tbody", { children: rows.map((row, i) => /* @__PURE__ */ jsxs23("tr", { className: "border-b border-border", children: [
|
|
2891
|
+
/* @__PURE__ */ jsx26("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
|
|
2892
|
+
/* @__PURE__ */ jsx26("td", { className: "px-4 py-3 text-foreground", children: row.requestedLocale }),
|
|
2893
|
+
/* @__PURE__ */ jsx26("td", { className: "px-4 py-3 text-foreground", children: row.resolvedLocale }),
|
|
2894
|
+
/* @__PURE__ */ jsx26("td", { className: "px-4 py-3 text-muted-foreground", children: row.steps && row.steps.length > 0 ? /* @__PURE__ */ jsx26("ol", { className: "flex flex-wrap items-center gap-1", children: row.steps.map((step, si) => /* @__PURE__ */ jsxs23("li", { className: "flex items-center gap-1", children: [
|
|
2895
|
+
/* @__PURE__ */ jsx26("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-foreground", children: step }),
|
|
2896
|
+
si < (row.steps?.length ?? 0) - 1 && /* @__PURE__ */ jsx26("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2192" })
|
|
2789
2897
|
] }, `${step}:${si}`)) }) : "\u2014" })
|
|
2790
2898
|
] }, `${row.key}:${row.requestedLocale}:${i}`)) })
|
|
2791
2899
|
] }) });
|
|
2792
2900
|
}
|
|
2793
2901
|
|
|
2794
2902
|
// src/recipient-admin-panel.tsx
|
|
2795
|
-
import { useState as
|
|
2796
|
-
import { cn as
|
|
2903
|
+
import { useState as useState13 } from "react";
|
|
2904
|
+
import { cn as cn25, formatDateTime as formatDateTime5, useToast as useToast11 } from "@quanticjs/react-ui";
|
|
2797
2905
|
import { useApiMutation as useApiMutation12, useApiQuery as useApiQuery19 } from "@quanticjs/react-query";
|
|
2798
|
-
import { Fragment as Fragment5, jsx as
|
|
2906
|
+
import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2799
2907
|
var LIMIT5 = 20;
|
|
2800
2908
|
function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
2801
2909
|
const toast = useToast11();
|
|
2802
|
-
const [page, setPage] =
|
|
2803
|
-
const [search, setSearch] =
|
|
2804
|
-
const [query, setQuery] =
|
|
2910
|
+
const [page, setPage] = useState13(1);
|
|
2911
|
+
const [search, setSearch] = useState13("");
|
|
2912
|
+
const [query, setQuery] = useState13("");
|
|
2805
2913
|
const { data, isLoading, isError, refetch } = useApiQuery19(
|
|
2806
2914
|
["recipients", page, query],
|
|
2807
2915
|
(client) => client.get(
|
|
@@ -2846,10 +2954,10 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2846
2954
|
if (row.consentSms) active.push("sms");
|
|
2847
2955
|
return active.length > 0 ? active.join(", ") : "none";
|
|
2848
2956
|
};
|
|
2849
|
-
const searchForm = /* @__PURE__ */
|
|
2850
|
-
/* @__PURE__ */
|
|
2851
|
-
/* @__PURE__ */
|
|
2852
|
-
/* @__PURE__ */
|
|
2957
|
+
const searchForm = /* @__PURE__ */ jsxs24("form", { onSubmit: onSearch, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
2958
|
+
/* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-1", children: [
|
|
2959
|
+
/* @__PURE__ */ jsx27("label", { htmlFor: "recipient-search", className: "text-sm font-medium text-foreground", children: "Search recipients" }),
|
|
2960
|
+
/* @__PURE__ */ jsx27(
|
|
2853
2961
|
"input",
|
|
2854
2962
|
{
|
|
2855
2963
|
id: "recipient-search",
|
|
@@ -2860,7 +2968,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2860
2968
|
}
|
|
2861
2969
|
)
|
|
2862
2970
|
] }),
|
|
2863
|
-
/* @__PURE__ */
|
|
2971
|
+
/* @__PURE__ */ jsx27(
|
|
2864
2972
|
"button",
|
|
2865
2973
|
{
|
|
2866
2974
|
type: "submit",
|
|
@@ -2871,14 +2979,14 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2871
2979
|
] });
|
|
2872
2980
|
let body;
|
|
2873
2981
|
if (isLoading) {
|
|
2874
|
-
body = /* @__PURE__ */
|
|
2875
|
-
/* @__PURE__ */
|
|
2876
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2982
|
+
body = /* @__PURE__ */ jsxs24("div", { role: "status", "aria-label": "Loading recipients", className: "flex flex-col gap-2 p-4", children: [
|
|
2983
|
+
/* @__PURE__ */ jsx27("span", { className: "sr-only", children: "Loading recipients" }),
|
|
2984
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx27("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2877
2985
|
] });
|
|
2878
2986
|
} else if (isError) {
|
|
2879
|
-
body = /* @__PURE__ */
|
|
2880
|
-
/* @__PURE__ */
|
|
2881
|
-
/* @__PURE__ */
|
|
2987
|
+
body = /* @__PURE__ */ jsxs24("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2988
|
+
/* @__PURE__ */ jsx27("p", { className: "text-sm text-foreground", children: "Failed to load recipients" }),
|
|
2989
|
+
/* @__PURE__ */ jsx27(
|
|
2882
2990
|
"button",
|
|
2883
2991
|
{
|
|
2884
2992
|
type: "button",
|
|
@@ -2892,26 +3000,26 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2892
3000
|
const rows = data?.items ?? [];
|
|
2893
3001
|
const totalPages = data?.totalPages ?? 1;
|
|
2894
3002
|
if (rows.length === 0) {
|
|
2895
|
-
body = /* @__PURE__ */
|
|
3003
|
+
body = /* @__PURE__ */ jsx27("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No recipients" });
|
|
2896
3004
|
} else {
|
|
2897
|
-
body = /* @__PURE__ */
|
|
2898
|
-
/* @__PURE__ */
|
|
2899
|
-
/* @__PURE__ */
|
|
2900
|
-
/* @__PURE__ */
|
|
2901
|
-
/* @__PURE__ */
|
|
2902
|
-
/* @__PURE__ */
|
|
2903
|
-
/* @__PURE__ */
|
|
2904
|
-
/* @__PURE__ */
|
|
2905
|
-
/* @__PURE__ */
|
|
3005
|
+
body = /* @__PURE__ */ jsxs24(Fragment5, { children: [
|
|
3006
|
+
/* @__PURE__ */ jsxs24("table", { className: "w-full text-sm", children: [
|
|
3007
|
+
/* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsxs24("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3008
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "User" }),
|
|
3009
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Email" }),
|
|
3010
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Phone" }),
|
|
3011
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Consents" }),
|
|
3012
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
3013
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx27("span", { className: "sr-only", children: "Actions" }) })
|
|
2906
3014
|
] }) }),
|
|
2907
|
-
/* @__PURE__ */
|
|
2908
|
-
/* @__PURE__ */
|
|
2909
|
-
/* @__PURE__ */
|
|
2910
|
-
/* @__PURE__ */
|
|
2911
|
-
/* @__PURE__ */
|
|
2912
|
-
/* @__PURE__ */
|
|
2913
|
-
/* @__PURE__ */
|
|
2914
|
-
/* @__PURE__ */
|
|
3015
|
+
/* @__PURE__ */ jsx27("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs24("tr", { className: "border-b border-border", children: [
|
|
3016
|
+
/* @__PURE__ */ jsx27("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.userId }),
|
|
3017
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-foreground", children: row.email ?? "\u2014" }),
|
|
3018
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-foreground", children: row.phone ?? "\u2014" }),
|
|
3019
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-muted-foreground", children: consents(row) }),
|
|
3020
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime5(row.createdAt) }),
|
|
3021
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs24("div", { className: "flex items-center gap-2", children: [
|
|
3022
|
+
/* @__PURE__ */ jsx27(
|
|
2915
3023
|
"button",
|
|
2916
3024
|
{
|
|
2917
3025
|
type: "button",
|
|
@@ -2921,7 +3029,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2921
3029
|
children: "Export"
|
|
2922
3030
|
}
|
|
2923
3031
|
),
|
|
2924
|
-
/* @__PURE__ */
|
|
3032
|
+
/* @__PURE__ */ jsx27(
|
|
2925
3033
|
"button",
|
|
2926
3034
|
{
|
|
2927
3035
|
type: "button",
|
|
@@ -2934,8 +3042,8 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2934
3042
|
] }) })
|
|
2935
3043
|
] }, row.userId)) })
|
|
2936
3044
|
] }),
|
|
2937
|
-
/* @__PURE__ */
|
|
2938
|
-
/* @__PURE__ */
|
|
3045
|
+
/* @__PURE__ */ jsxs24("nav", { "aria-label": "Recipient pagination", className: "flex items-center justify-between", children: [
|
|
3046
|
+
/* @__PURE__ */ jsx27(
|
|
2939
3047
|
"button",
|
|
2940
3048
|
{
|
|
2941
3049
|
type: "button",
|
|
@@ -2945,13 +3053,13 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2945
3053
|
children: "Previous"
|
|
2946
3054
|
}
|
|
2947
3055
|
),
|
|
2948
|
-
/* @__PURE__ */
|
|
3056
|
+
/* @__PURE__ */ jsxs24("span", { className: "text-xs text-muted-foreground", children: [
|
|
2949
3057
|
"Page ",
|
|
2950
3058
|
page,
|
|
2951
3059
|
" of ",
|
|
2952
3060
|
totalPages
|
|
2953
3061
|
] }),
|
|
2954
|
-
/* @__PURE__ */
|
|
3062
|
+
/* @__PURE__ */ jsx27(
|
|
2955
3063
|
"button",
|
|
2956
3064
|
{
|
|
2957
3065
|
type: "button",
|
|
@@ -2965,17 +3073,17 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2965
3073
|
] });
|
|
2966
3074
|
}
|
|
2967
3075
|
}
|
|
2968
|
-
return /* @__PURE__ */
|
|
3076
|
+
return /* @__PURE__ */ jsxs24("section", { "aria-label": "Recipient administration", className: cn25("flex flex-col gap-4", className), children: [
|
|
2969
3077
|
searchForm,
|
|
2970
3078
|
body
|
|
2971
3079
|
] });
|
|
2972
3080
|
}
|
|
2973
3081
|
|
|
2974
3082
|
// src/webhook-endpoint-manager.tsx
|
|
2975
|
-
import { Fragment as Fragment6, useState as
|
|
2976
|
-
import { cn as
|
|
3083
|
+
import { Fragment as Fragment6, useState as useState14 } from "react";
|
|
3084
|
+
import { cn as cn26, formatDateTime as formatDateTime6, useToast as useToast12, StatusBadge as StatusBadge5 } from "@quanticjs/react-ui";
|
|
2977
3085
|
import { useApiMutation as useApiMutation13, useApiQuery as useApiQuery20 } from "@quanticjs/react-query";
|
|
2978
|
-
import { jsx as
|
|
3086
|
+
import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2979
3087
|
var EVENT_TYPES = [
|
|
2980
3088
|
"notification.sent",
|
|
2981
3089
|
"notification.delivered",
|
|
@@ -3001,15 +3109,15 @@ function WebhookDeliveries({ endpointId, basePath }) {
|
|
|
3001
3109
|
(client) => client.get(`${basePath}/webhook-endpoints/${endpointId}/deliveries`)
|
|
3002
3110
|
);
|
|
3003
3111
|
if (isLoading) {
|
|
3004
|
-
return /* @__PURE__ */
|
|
3005
|
-
/* @__PURE__ */
|
|
3006
|
-
[0, 1].map((i) => /* @__PURE__ */
|
|
3112
|
+
return /* @__PURE__ */ jsxs25("div", { role: "status", "aria-label": "Loading deliveries", className: "flex flex-col gap-2 p-3", children: [
|
|
3113
|
+
/* @__PURE__ */ jsx28("span", { className: "sr-only", children: "Loading deliveries" }),
|
|
3114
|
+
[0, 1].map((i) => /* @__PURE__ */ jsx28("div", { "aria-hidden": "true", className: "h-8 animate-pulse rounded bg-muted" }, i))
|
|
3007
3115
|
] });
|
|
3008
3116
|
}
|
|
3009
3117
|
if (isError) {
|
|
3010
|
-
return /* @__PURE__ */
|
|
3011
|
-
/* @__PURE__ */
|
|
3012
|
-
/* @__PURE__ */
|
|
3118
|
+
return /* @__PURE__ */ jsxs25("div", { className: "flex flex-col items-start gap-2 p-3", children: [
|
|
3119
|
+
/* @__PURE__ */ jsx28("p", { className: "text-sm text-foreground", children: "Failed to load deliveries" }),
|
|
3120
|
+
/* @__PURE__ */ jsx28(
|
|
3013
3121
|
"button",
|
|
3014
3122
|
{
|
|
3015
3123
|
type: "button",
|
|
@@ -3022,18 +3130,18 @@ function WebhookDeliveries({ endpointId, basePath }) {
|
|
|
3022
3130
|
}
|
|
3023
3131
|
const rows = normalizeDeliveries(data);
|
|
3024
3132
|
if (rows.length === 0) {
|
|
3025
|
-
return /* @__PURE__ */
|
|
3133
|
+
return /* @__PURE__ */ jsx28("div", { className: "p-3 text-center text-sm text-muted-foreground", children: "No deliveries" });
|
|
3026
3134
|
}
|
|
3027
|
-
return /* @__PURE__ */
|
|
3028
|
-
/* @__PURE__ */
|
|
3029
|
-
/* @__PURE__ */
|
|
3030
|
-
/* @__PURE__ */
|
|
3031
|
-
/* @__PURE__ */
|
|
3135
|
+
return /* @__PURE__ */ jsxs25("table", { className: "w-full text-sm", children: [
|
|
3136
|
+
/* @__PURE__ */ jsx28("thead", { children: /* @__PURE__ */ jsxs25("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3137
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivery" }),
|
|
3138
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
3139
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
3032
3140
|
] }) }),
|
|
3033
|
-
/* @__PURE__ */
|
|
3034
|
-
/* @__PURE__ */
|
|
3035
|
-
/* @__PURE__ */
|
|
3036
|
-
/* @__PURE__ */
|
|
3141
|
+
/* @__PURE__ */ jsx28("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs25("tr", { className: "border-b border-border", children: [
|
|
3142
|
+
/* @__PURE__ */ jsx28("td", { className: "py-2 pe-4 font-mono text-foreground", children: row.id }),
|
|
3143
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-2 text-muted-foreground", children: row.status }),
|
|
3144
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-2 text-muted-foreground", children: formatDateTime6(row.createdAt) })
|
|
3037
3145
|
] }, row.id)) })
|
|
3038
3146
|
] });
|
|
3039
3147
|
}
|
|
@@ -3042,11 +3150,11 @@ function WebhookEndpointManager({
|
|
|
3042
3150
|
className
|
|
3043
3151
|
}) {
|
|
3044
3152
|
const toast = useToast12();
|
|
3045
|
-
const [url, setUrl] =
|
|
3046
|
-
const [events, setEvents] =
|
|
3047
|
-
const [active, setActive] =
|
|
3048
|
-
const [urlError, setUrlError] =
|
|
3049
|
-
const [expandedId, setExpandedId] =
|
|
3153
|
+
const [url, setUrl] = useState14("");
|
|
3154
|
+
const [events, setEvents] = useState14([]);
|
|
3155
|
+
const [active, setActive] = useState14(true);
|
|
3156
|
+
const [urlError, setUrlError] = useState14();
|
|
3157
|
+
const [expandedId, setExpandedId] = useState14(null);
|
|
3050
3158
|
const { data, isLoading, isError, refetch } = useApiQuery20(["webhook-endpoints"], (client) => client.get(`${basePath}/webhook-endpoints`));
|
|
3051
3159
|
const create = useApiMutation13(
|
|
3052
3160
|
(client, payload) => client.post(`${basePath}/webhook-endpoints`, payload),
|
|
@@ -3108,10 +3216,10 @@ function WebhookEndpointManager({
|
|
|
3108
3216
|
remove.mutate(id);
|
|
3109
3217
|
}
|
|
3110
3218
|
};
|
|
3111
|
-
const createForm = /* @__PURE__ */
|
|
3112
|
-
/* @__PURE__ */
|
|
3113
|
-
/* @__PURE__ */
|
|
3114
|
-
/* @__PURE__ */
|
|
3219
|
+
const createForm = /* @__PURE__ */ jsxs25("form", { onSubmit: onCreate, className: "flex flex-col gap-3", noValidate: true, children: [
|
|
3220
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex flex-col gap-1", children: [
|
|
3221
|
+
/* @__PURE__ */ jsx28("label", { htmlFor: "webhook-url", className: "text-sm font-medium text-foreground", children: "Endpoint URL" }),
|
|
3222
|
+
/* @__PURE__ */ jsx28(
|
|
3115
3223
|
"input",
|
|
3116
3224
|
{
|
|
3117
3225
|
id: "webhook-url",
|
|
@@ -3123,19 +3231,19 @@ function WebhookEndpointManager({
|
|
|
3123
3231
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
3124
3232
|
}
|
|
3125
3233
|
),
|
|
3126
|
-
urlError && /* @__PURE__ */
|
|
3234
|
+
urlError && /* @__PURE__ */ jsx28("p", { id: "webhook-url-error", className: "text-xs text-destructive", children: urlError })
|
|
3127
3235
|
] }),
|
|
3128
|
-
/* @__PURE__ */
|
|
3129
|
-
/* @__PURE__ */
|
|
3130
|
-
/* @__PURE__ */
|
|
3236
|
+
/* @__PURE__ */ jsxs25("fieldset", { className: "flex flex-col gap-2", children: [
|
|
3237
|
+
/* @__PURE__ */ jsx28("legend", { className: "text-sm font-medium text-foreground", children: "Events" }),
|
|
3238
|
+
/* @__PURE__ */ jsx28("div", { className: "flex flex-wrap gap-3", children: EVENT_TYPES.map((evt) => {
|
|
3131
3239
|
const id = `webhook-event-${evt}`;
|
|
3132
|
-
return /* @__PURE__ */
|
|
3240
|
+
return /* @__PURE__ */ jsxs25(
|
|
3133
3241
|
"label",
|
|
3134
3242
|
{
|
|
3135
3243
|
htmlFor: id,
|
|
3136
3244
|
className: "flex items-center gap-2 text-sm text-foreground",
|
|
3137
3245
|
children: [
|
|
3138
|
-
/* @__PURE__ */
|
|
3246
|
+
/* @__PURE__ */ jsx28(
|
|
3139
3247
|
"input",
|
|
3140
3248
|
{
|
|
3141
3249
|
id,
|
|
@@ -3152,8 +3260,8 @@ function WebhookEndpointManager({
|
|
|
3152
3260
|
);
|
|
3153
3261
|
}) })
|
|
3154
3262
|
] }),
|
|
3155
|
-
/* @__PURE__ */
|
|
3156
|
-
/* @__PURE__ */
|
|
3263
|
+
/* @__PURE__ */ jsxs25("label", { htmlFor: "webhook-active", className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
3264
|
+
/* @__PURE__ */ jsx28(
|
|
3157
3265
|
"input",
|
|
3158
3266
|
{
|
|
3159
3267
|
id: "webhook-active",
|
|
@@ -3165,7 +3273,7 @@ function WebhookEndpointManager({
|
|
|
3165
3273
|
),
|
|
3166
3274
|
"Active"
|
|
3167
3275
|
] }),
|
|
3168
|
-
/* @__PURE__ */
|
|
3276
|
+
/* @__PURE__ */ jsx28("div", { children: /* @__PURE__ */ jsx28(
|
|
3169
3277
|
"button",
|
|
3170
3278
|
{
|
|
3171
3279
|
type: "submit",
|
|
@@ -3177,14 +3285,14 @@ function WebhookEndpointManager({
|
|
|
3177
3285
|
] });
|
|
3178
3286
|
let body;
|
|
3179
3287
|
if (isLoading) {
|
|
3180
|
-
body = /* @__PURE__ */
|
|
3181
|
-
/* @__PURE__ */
|
|
3182
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3288
|
+
body = /* @__PURE__ */ jsxs25("div", { role: "status", "aria-label": "Loading webhook endpoints", className: "flex flex-col gap-2 p-4", children: [
|
|
3289
|
+
/* @__PURE__ */ jsx28("span", { className: "sr-only", children: "Loading webhook endpoints" }),
|
|
3290
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx28("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3183
3291
|
] });
|
|
3184
3292
|
} else if (isError) {
|
|
3185
|
-
body = /* @__PURE__ */
|
|
3186
|
-
/* @__PURE__ */
|
|
3187
|
-
/* @__PURE__ */
|
|
3293
|
+
body = /* @__PURE__ */ jsxs25("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
3294
|
+
/* @__PURE__ */ jsx28("p", { className: "text-sm text-foreground", children: "Failed to load webhook endpoints" }),
|
|
3295
|
+
/* @__PURE__ */ jsx28(
|
|
3188
3296
|
"button",
|
|
3189
3297
|
{
|
|
3190
3298
|
type: "button",
|
|
@@ -3197,26 +3305,26 @@ function WebhookEndpointManager({
|
|
|
3197
3305
|
} else {
|
|
3198
3306
|
const rows = normalizeEndpoints(data);
|
|
3199
3307
|
if (rows.length === 0) {
|
|
3200
|
-
body = /* @__PURE__ */
|
|
3308
|
+
body = /* @__PURE__ */ jsx28("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No webhook endpoints" });
|
|
3201
3309
|
} else {
|
|
3202
|
-
body = /* @__PURE__ */
|
|
3203
|
-
/* @__PURE__ */
|
|
3204
|
-
/* @__PURE__ */
|
|
3205
|
-
/* @__PURE__ */
|
|
3206
|
-
/* @__PURE__ */
|
|
3207
|
-
/* @__PURE__ */
|
|
3208
|
-
/* @__PURE__ */
|
|
3310
|
+
body = /* @__PURE__ */ jsxs25("table", { className: "w-full text-sm", children: [
|
|
3311
|
+
/* @__PURE__ */ jsx28("thead", { children: /* @__PURE__ */ jsxs25("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3312
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "URL" }),
|
|
3313
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Events" }),
|
|
3314
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Active" }),
|
|
3315
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
3316
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx28("span", { className: "sr-only", children: "Actions" }) })
|
|
3209
3317
|
] }) }),
|
|
3210
|
-
/* @__PURE__ */
|
|
3318
|
+
/* @__PURE__ */ jsx28("tbody", { children: rows.map((row) => {
|
|
3211
3319
|
const isExpanded = expandedId === row.id;
|
|
3212
|
-
return /* @__PURE__ */
|
|
3213
|
-
/* @__PURE__ */
|
|
3214
|
-
/* @__PURE__ */
|
|
3215
|
-
/* @__PURE__ */
|
|
3216
|
-
/* @__PURE__ */
|
|
3217
|
-
/* @__PURE__ */
|
|
3218
|
-
/* @__PURE__ */
|
|
3219
|
-
/* @__PURE__ */
|
|
3320
|
+
return /* @__PURE__ */ jsxs25(Fragment6, { children: [
|
|
3321
|
+
/* @__PURE__ */ jsxs25("tr", { className: "border-b border-border", children: [
|
|
3322
|
+
/* @__PURE__ */ jsx28("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.url }),
|
|
3323
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3 text-muted-foreground", children: row.events.length > 0 ? row.events.join(", ") : "\u2014" }),
|
|
3324
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx28(StatusBadge5, { variant: row.active ? "success" : "neutral", appearance: "dot", children: row.active ? "active" : "inactive" }) }),
|
|
3325
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime6(row.createdAt) }),
|
|
3326
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
|
|
3327
|
+
/* @__PURE__ */ jsx28(
|
|
3220
3328
|
"button",
|
|
3221
3329
|
{
|
|
3222
3330
|
type: "button",
|
|
@@ -3226,7 +3334,7 @@ function WebhookEndpointManager({
|
|
|
3226
3334
|
children: row.active ? "Disable" : "Enable"
|
|
3227
3335
|
}
|
|
3228
3336
|
),
|
|
3229
|
-
/* @__PURE__ */
|
|
3337
|
+
/* @__PURE__ */ jsx28(
|
|
3230
3338
|
"button",
|
|
3231
3339
|
{
|
|
3232
3340
|
type: "button",
|
|
@@ -3236,7 +3344,7 @@ function WebhookEndpointManager({
|
|
|
3236
3344
|
children: "Deliveries"
|
|
3237
3345
|
}
|
|
3238
3346
|
),
|
|
3239
|
-
/* @__PURE__ */
|
|
3347
|
+
/* @__PURE__ */ jsx28(
|
|
3240
3348
|
"button",
|
|
3241
3349
|
{
|
|
3242
3350
|
type: "button",
|
|
@@ -3248,45 +3356,45 @@ function WebhookEndpointManager({
|
|
|
3248
3356
|
)
|
|
3249
3357
|
] }) })
|
|
3250
3358
|
] }),
|
|
3251
|
-
isExpanded && /* @__PURE__ */
|
|
3359
|
+
isExpanded && /* @__PURE__ */ jsx28("tr", { className: "border-b border-border", children: /* @__PURE__ */ jsx28("td", { colSpan: 5, className: "bg-muted px-4 py-3", children: /* @__PURE__ */ jsx28(WebhookDeliveries, { endpointId: row.id, basePath }) }) })
|
|
3252
3360
|
] }, row.id);
|
|
3253
3361
|
}) })
|
|
3254
3362
|
] });
|
|
3255
3363
|
}
|
|
3256
3364
|
}
|
|
3257
|
-
return /* @__PURE__ */
|
|
3365
|
+
return /* @__PURE__ */ jsxs25("section", { "aria-label": "Webhook endpoints", className: cn26("flex flex-col gap-4", className), children: [
|
|
3258
3366
|
createForm,
|
|
3259
3367
|
body
|
|
3260
3368
|
] });
|
|
3261
3369
|
}
|
|
3262
3370
|
|
|
3263
3371
|
// src/operations-overview.tsx
|
|
3264
|
-
import { cn as
|
|
3372
|
+
import { cn as cn27, formatDateTime as formatDateTime7, StatusBadge as StatusBadge6 } from "@quanticjs/react-ui";
|
|
3265
3373
|
import { useApiQuery as useApiQuery21 } from "@quanticjs/react-query";
|
|
3266
|
-
import { jsx as
|
|
3374
|
+
import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3267
3375
|
function OperationsOverview({ basePath = "/api", className }) {
|
|
3268
3376
|
const { data, isLoading, isError, refetch } = useApiQuery21(
|
|
3269
3377
|
["operations-overview"],
|
|
3270
3378
|
(client) => client.get(`${basePath}/v1/admin/overview`)
|
|
3271
3379
|
);
|
|
3272
3380
|
if (isLoading) {
|
|
3273
|
-
return /* @__PURE__ */
|
|
3381
|
+
return /* @__PURE__ */ jsxs26(
|
|
3274
3382
|
"div",
|
|
3275
3383
|
{
|
|
3276
3384
|
role: "status",
|
|
3277
3385
|
"aria-label": "Loading operations overview",
|
|
3278
|
-
className:
|
|
3386
|
+
className: cn27("flex flex-col gap-2 p-4", className),
|
|
3279
3387
|
children: [
|
|
3280
|
-
/* @__PURE__ */
|
|
3281
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3388
|
+
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Loading operations overview" }),
|
|
3389
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx29("div", { "aria-hidden": "true", className: "h-20 animate-pulse rounded bg-muted" }, i))
|
|
3282
3390
|
]
|
|
3283
3391
|
}
|
|
3284
3392
|
);
|
|
3285
3393
|
}
|
|
3286
3394
|
if (isError) {
|
|
3287
|
-
return /* @__PURE__ */
|
|
3288
|
-
/* @__PURE__ */
|
|
3289
|
-
/* @__PURE__ */
|
|
3395
|
+
return /* @__PURE__ */ jsxs26("div", { className: cn27("flex flex-col items-start gap-3 p-4", className), children: [
|
|
3396
|
+
/* @__PURE__ */ jsx29("p", { className: "text-sm text-foreground", children: "Failed to load operations overview" }),
|
|
3397
|
+
/* @__PURE__ */ jsx29(
|
|
3290
3398
|
"button",
|
|
3291
3399
|
{
|
|
3292
3400
|
type: "button",
|
|
@@ -3298,7 +3406,7 @@ function OperationsOverview({ basePath = "/api", className }) {
|
|
|
3298
3406
|
] });
|
|
3299
3407
|
}
|
|
3300
3408
|
if (!data) {
|
|
3301
|
-
return /* @__PURE__ */
|
|
3409
|
+
return /* @__PURE__ */ jsx29("div", { className: cn27("p-6 text-center text-sm text-muted-foreground", className), children: "No overview data" });
|
|
3302
3410
|
}
|
|
3303
3411
|
const windowHours = data.windowHours;
|
|
3304
3412
|
const channels = data.channels ?? [];
|
|
@@ -3308,40 +3416,40 @@ function OperationsOverview({ basePath = "/api", className }) {
|
|
|
3308
3416
|
{ label: `Delivered (${windowHours}h)`, value: data.totalDelivered },
|
|
3309
3417
|
{ label: `Failed (${windowHours}h)`, value: data.totalFailed }
|
|
3310
3418
|
];
|
|
3311
|
-
return /* @__PURE__ */
|
|
3312
|
-
/* @__PURE__ */
|
|
3313
|
-
/* @__PURE__ */
|
|
3314
|
-
/* @__PURE__ */
|
|
3419
|
+
return /* @__PURE__ */ jsxs26("section", { "aria-label": "Operations overview", className: cn27("flex flex-col gap-4", className), children: [
|
|
3420
|
+
/* @__PURE__ */ jsx29("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", children: cards.map((card) => /* @__PURE__ */ jsxs26("div", { className: "rounded-md border border-border bg-card p-4", children: [
|
|
3421
|
+
/* @__PURE__ */ jsx29("p", { className: "text-xs font-medium text-muted-foreground", children: card.label }),
|
|
3422
|
+
/* @__PURE__ */ jsx29("p", { className: "mt-1 text-2xl font-semibold text-foreground", children: card.value })
|
|
3315
3423
|
] }, card.label)) }),
|
|
3316
|
-
/* @__PURE__ */
|
|
3317
|
-
/* @__PURE__ */
|
|
3318
|
-
/* @__PURE__ */
|
|
3319
|
-
/* @__PURE__ */
|
|
3424
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex flex-wrap items-center gap-4", children: [
|
|
3425
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
3426
|
+
/* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: "DLQ pending" }),
|
|
3427
|
+
/* @__PURE__ */ jsx29(StatusBadge6, { variant: dlqPending > 0 ? "destructive" : "success", children: dlqPending })
|
|
3320
3428
|
] }),
|
|
3321
|
-
/* @__PURE__ */
|
|
3322
|
-
/* @__PURE__ */
|
|
3323
|
-
/* @__PURE__ */
|
|
3429
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
3430
|
+
/* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: "Broadcasts in flight" }),
|
|
3431
|
+
/* @__PURE__ */ jsx29("span", { className: "text-sm font-medium text-foreground", children: data.broadcastsInFlight })
|
|
3324
3432
|
] }),
|
|
3325
|
-
/* @__PURE__ */
|
|
3326
|
-
/* @__PURE__ */
|
|
3327
|
-
/* @__PURE__ */
|
|
3433
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
3434
|
+
/* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: "Queue" }),
|
|
3435
|
+
/* @__PURE__ */ jsx29(StatusBadge6, { variant: data.queueHealthy ? "success" : "destructive", children: data.queueHealthy ? "Healthy" : "Unhealthy" })
|
|
3328
3436
|
] })
|
|
3329
3437
|
] }),
|
|
3330
|
-
/* @__PURE__ */
|
|
3331
|
-
/* @__PURE__ */
|
|
3332
|
-
/* @__PURE__ */
|
|
3333
|
-
/* @__PURE__ */
|
|
3334
|
-
/* @__PURE__ */
|
|
3335
|
-
/* @__PURE__ */
|
|
3438
|
+
/* @__PURE__ */ jsxs26("table", { className: "w-full text-sm", children: [
|
|
3439
|
+
/* @__PURE__ */ jsx29("thead", { children: /* @__PURE__ */ jsxs26("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3440
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
|
|
3441
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Sends" }),
|
|
3442
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Delivered" }),
|
|
3443
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Failed" })
|
|
3336
3444
|
] }) }),
|
|
3337
|
-
/* @__PURE__ */
|
|
3338
|
-
/* @__PURE__ */
|
|
3339
|
-
/* @__PURE__ */
|
|
3340
|
-
/* @__PURE__ */
|
|
3341
|
-
/* @__PURE__ */
|
|
3445
|
+
/* @__PURE__ */ jsx29("tbody", { children: channels.length === 0 ? /* @__PURE__ */ jsx29("tr", { className: "border-b border-border", children: /* @__PURE__ */ jsx29("td", { colSpan: 4, className: "py-3 text-center text-muted-foreground", children: "No channel activity" }) }) : channels.map((row) => /* @__PURE__ */ jsxs26("tr", { className: "border-b border-border", children: [
|
|
3446
|
+
/* @__PURE__ */ jsx29("td", { className: "py-3 pe-4 text-foreground", children: row.channel }),
|
|
3447
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3 text-muted-foreground", children: row.sends }),
|
|
3448
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3 text-muted-foreground", children: row.delivered }),
|
|
3449
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3 text-muted-foreground", children: row.failed })
|
|
3342
3450
|
] }, row.channel)) })
|
|
3343
3451
|
] }),
|
|
3344
|
-
/* @__PURE__ */
|
|
3452
|
+
/* @__PURE__ */ jsxs26("p", { className: "text-xs text-muted-foreground", children: [
|
|
3345
3453
|
"Generated ",
|
|
3346
3454
|
formatDateTime7(data.generatedAt)
|
|
3347
3455
|
] })
|
|
@@ -3349,10 +3457,10 @@ function OperationsOverview({ basePath = "/api", className }) {
|
|
|
3349
3457
|
}
|
|
3350
3458
|
|
|
3351
3459
|
// src/delivery-log-explorer.tsx
|
|
3352
|
-
import { useState as
|
|
3353
|
-
import { cn as
|
|
3460
|
+
import { useState as useState15 } from "react";
|
|
3461
|
+
import { cn as cn28, formatDateTime as formatDateTime8, StatusBadge as StatusBadge7 } from "@quanticjs/react-ui";
|
|
3354
3462
|
import { useApiQuery as useApiQuery22 } from "@quanticjs/react-query";
|
|
3355
|
-
import { Fragment as Fragment7, jsx as
|
|
3463
|
+
import { Fragment as Fragment7, jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3356
3464
|
var LIMIT6 = 20;
|
|
3357
3465
|
var EMPTY_FILTERS = {
|
|
3358
3466
|
channel: "",
|
|
@@ -3373,9 +3481,9 @@ function channelVariant(channel) {
|
|
|
3373
3481
|
}
|
|
3374
3482
|
}
|
|
3375
3483
|
function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
3376
|
-
const [page, setPage] =
|
|
3377
|
-
const [draft, setDraft] =
|
|
3378
|
-
const [applied, setApplied] =
|
|
3484
|
+
const [page, setPage] = useState15(1);
|
|
3485
|
+
const [draft, setDraft] = useState15(EMPTY_FILTERS);
|
|
3486
|
+
const [applied, setApplied] = useState15(EMPTY_FILTERS);
|
|
3379
3487
|
const queryString = (() => {
|
|
3380
3488
|
const params = new URLSearchParams();
|
|
3381
3489
|
params.set("page", String(page));
|
|
@@ -3405,10 +3513,10 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3405
3513
|
});
|
|
3406
3514
|
};
|
|
3407
3515
|
const setField = (key, value) => setDraft((prev) => ({ ...prev, [key]: value }));
|
|
3408
|
-
const filterForm = /* @__PURE__ */
|
|
3409
|
-
/* @__PURE__ */
|
|
3410
|
-
/* @__PURE__ */
|
|
3411
|
-
/* @__PURE__ */
|
|
3516
|
+
const filterForm = /* @__PURE__ */ jsxs27("form", { onSubmit: onApply, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
3517
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3518
|
+
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-channel", className: "text-sm font-medium text-foreground", children: "Channel" }),
|
|
3519
|
+
/* @__PURE__ */ jsxs27(
|
|
3412
3520
|
"select",
|
|
3413
3521
|
{
|
|
3414
3522
|
id: "dle-channel",
|
|
@@ -3416,16 +3524,16 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3416
3524
|
onChange: (e) => setField("channel", e.target.value),
|
|
3417
3525
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
3418
3526
|
children: [
|
|
3419
|
-
/* @__PURE__ */
|
|
3420
|
-
/* @__PURE__ */
|
|
3421
|
-
/* @__PURE__ */
|
|
3527
|
+
/* @__PURE__ */ jsx30("option", { value: "", children: "All" }),
|
|
3528
|
+
/* @__PURE__ */ jsx30("option", { value: "email", children: "Email" }),
|
|
3529
|
+
/* @__PURE__ */ jsx30("option", { value: "sms", children: "SMS" })
|
|
3422
3530
|
]
|
|
3423
3531
|
}
|
|
3424
3532
|
)
|
|
3425
3533
|
] }),
|
|
3426
|
-
/* @__PURE__ */
|
|
3427
|
-
/* @__PURE__ */
|
|
3428
|
-
/* @__PURE__ */
|
|
3534
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3535
|
+
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-status", className: "text-sm font-medium text-foreground", children: "Status" }),
|
|
3536
|
+
/* @__PURE__ */ jsx30(
|
|
3429
3537
|
"input",
|
|
3430
3538
|
{
|
|
3431
3539
|
id: "dle-status",
|
|
@@ -3436,9 +3544,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3436
3544
|
}
|
|
3437
3545
|
)
|
|
3438
3546
|
] }),
|
|
3439
|
-
/* @__PURE__ */
|
|
3440
|
-
/* @__PURE__ */
|
|
3441
|
-
/* @__PURE__ */
|
|
3547
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3548
|
+
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-recipient", className: "text-sm font-medium text-foreground", children: "Recipient" }),
|
|
3549
|
+
/* @__PURE__ */ jsx30(
|
|
3442
3550
|
"input",
|
|
3443
3551
|
{
|
|
3444
3552
|
id: "dle-recipient",
|
|
@@ -3449,9 +3557,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3449
3557
|
}
|
|
3450
3558
|
)
|
|
3451
3559
|
] }),
|
|
3452
|
-
/* @__PURE__ */
|
|
3453
|
-
/* @__PURE__ */
|
|
3454
|
-
/* @__PURE__ */
|
|
3560
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3561
|
+
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-user", className: "text-sm font-medium text-foreground", children: "User ID" }),
|
|
3562
|
+
/* @__PURE__ */ jsx30(
|
|
3455
3563
|
"input",
|
|
3456
3564
|
{
|
|
3457
3565
|
id: "dle-user",
|
|
@@ -3462,9 +3570,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3462
3570
|
}
|
|
3463
3571
|
)
|
|
3464
3572
|
] }),
|
|
3465
|
-
/* @__PURE__ */
|
|
3466
|
-
/* @__PURE__ */
|
|
3467
|
-
/* @__PURE__ */
|
|
3573
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3574
|
+
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-from", className: "text-sm font-medium text-foreground", children: "From" }),
|
|
3575
|
+
/* @__PURE__ */ jsx30(
|
|
3468
3576
|
"input",
|
|
3469
3577
|
{
|
|
3470
3578
|
id: "dle-from",
|
|
@@ -3475,9 +3583,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3475
3583
|
}
|
|
3476
3584
|
)
|
|
3477
3585
|
] }),
|
|
3478
|
-
/* @__PURE__ */
|
|
3479
|
-
/* @__PURE__ */
|
|
3480
|
-
/* @__PURE__ */
|
|
3586
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3587
|
+
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-to", className: "text-sm font-medium text-foreground", children: "To" }),
|
|
3588
|
+
/* @__PURE__ */ jsx30(
|
|
3481
3589
|
"input",
|
|
3482
3590
|
{
|
|
3483
3591
|
id: "dle-to",
|
|
@@ -3488,7 +3596,7 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3488
3596
|
}
|
|
3489
3597
|
)
|
|
3490
3598
|
] }),
|
|
3491
|
-
/* @__PURE__ */
|
|
3599
|
+
/* @__PURE__ */ jsx30(
|
|
3492
3600
|
"button",
|
|
3493
3601
|
{
|
|
3494
3602
|
type: "submit",
|
|
@@ -3499,14 +3607,14 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3499
3607
|
] });
|
|
3500
3608
|
let body;
|
|
3501
3609
|
if (isLoading) {
|
|
3502
|
-
body = /* @__PURE__ */
|
|
3503
|
-
/* @__PURE__ */
|
|
3504
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3610
|
+
body = /* @__PURE__ */ jsxs27("div", { role: "status", "aria-label": "Loading delivery logs", className: "flex flex-col gap-2 p-4", children: [
|
|
3611
|
+
/* @__PURE__ */ jsx30("span", { className: "sr-only", children: "Loading delivery logs" }),
|
|
3612
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx30("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3505
3613
|
] });
|
|
3506
3614
|
} else if (isError) {
|
|
3507
|
-
body = /* @__PURE__ */
|
|
3508
|
-
/* @__PURE__ */
|
|
3509
|
-
/* @__PURE__ */
|
|
3615
|
+
body = /* @__PURE__ */ jsxs27("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
3616
|
+
/* @__PURE__ */ jsx30("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
|
|
3617
|
+
/* @__PURE__ */ jsx30(
|
|
3510
3618
|
"button",
|
|
3511
3619
|
{
|
|
3512
3620
|
type: "button",
|
|
@@ -3520,31 +3628,31 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3520
3628
|
const rows = data?.items ?? [];
|
|
3521
3629
|
const totalPages = data?.totalPages ?? 1;
|
|
3522
3630
|
if (rows.length === 0) {
|
|
3523
|
-
body = /* @__PURE__ */
|
|
3631
|
+
body = /* @__PURE__ */ jsx30("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No delivery logs" });
|
|
3524
3632
|
} else {
|
|
3525
|
-
body = /* @__PURE__ */
|
|
3526
|
-
/* @__PURE__ */
|
|
3527
|
-
/* @__PURE__ */
|
|
3528
|
-
/* @__PURE__ */
|
|
3529
|
-
/* @__PURE__ */
|
|
3530
|
-
/* @__PURE__ */
|
|
3531
|
-
/* @__PURE__ */
|
|
3532
|
-
/* @__PURE__ */
|
|
3533
|
-
/* @__PURE__ */
|
|
3534
|
-
/* @__PURE__ */
|
|
3633
|
+
body = /* @__PURE__ */ jsxs27(Fragment7, { children: [
|
|
3634
|
+
/* @__PURE__ */ jsxs27("table", { className: "w-full text-sm", children: [
|
|
3635
|
+
/* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsxs27("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3636
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
|
|
3637
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipient" }),
|
|
3638
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "User" }),
|
|
3639
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
3640
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Provider" }),
|
|
3641
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
|
|
3642
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
3535
3643
|
] }) }),
|
|
3536
|
-
/* @__PURE__ */
|
|
3537
|
-
/* @__PURE__ */
|
|
3538
|
-
/* @__PURE__ */
|
|
3539
|
-
/* @__PURE__ */
|
|
3540
|
-
/* @__PURE__ */
|
|
3541
|
-
/* @__PURE__ */
|
|
3542
|
-
/* @__PURE__ */
|
|
3543
|
-
/* @__PURE__ */
|
|
3644
|
+
/* @__PURE__ */ jsx30("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs27("tr", { className: "border-b border-border", children: [
|
|
3645
|
+
/* @__PURE__ */ jsx30("td", { className: "py-3 pe-4", children: /* @__PURE__ */ jsx30(StatusBadge7, { variant: channelVariant(row.channel), appearance: "dot", children: row.channel }) }),
|
|
3646
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-foreground", children: row.recipient ?? "\u2014" }),
|
|
3647
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 font-mono text-foreground", children: row.userId }),
|
|
3648
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-foreground", children: row.status }),
|
|
3649
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-muted-foreground", children: row.provider ?? "\u2014" }),
|
|
3650
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-muted-foreground", children: row.attempts }),
|
|
3651
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime8(row.createdAt) })
|
|
3544
3652
|
] }, row.id)) })
|
|
3545
3653
|
] }),
|
|
3546
|
-
/* @__PURE__ */
|
|
3547
|
-
/* @__PURE__ */
|
|
3654
|
+
/* @__PURE__ */ jsxs27("nav", { "aria-label": "Delivery log pagination", className: "flex items-center justify-between", children: [
|
|
3655
|
+
/* @__PURE__ */ jsx30(
|
|
3548
3656
|
"button",
|
|
3549
3657
|
{
|
|
3550
3658
|
type: "button",
|
|
@@ -3554,13 +3662,13 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3554
3662
|
children: "Previous"
|
|
3555
3663
|
}
|
|
3556
3664
|
),
|
|
3557
|
-
/* @__PURE__ */
|
|
3665
|
+
/* @__PURE__ */ jsxs27("span", { className: "text-xs text-muted-foreground", children: [
|
|
3558
3666
|
"Page ",
|
|
3559
3667
|
page,
|
|
3560
3668
|
" of ",
|
|
3561
3669
|
totalPages
|
|
3562
3670
|
] }),
|
|
3563
|
-
/* @__PURE__ */
|
|
3671
|
+
/* @__PURE__ */ jsx30(
|
|
3564
3672
|
"button",
|
|
3565
3673
|
{
|
|
3566
3674
|
type: "button",
|
|
@@ -3574,17 +3682,17 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3574
3682
|
] });
|
|
3575
3683
|
}
|
|
3576
3684
|
}
|
|
3577
|
-
return /* @__PURE__ */
|
|
3685
|
+
return /* @__PURE__ */ jsxs27("section", { "aria-label": "Delivery log explorer", className: cn28("flex flex-col gap-4", className), children: [
|
|
3578
3686
|
filterForm,
|
|
3579
3687
|
body
|
|
3580
3688
|
] });
|
|
3581
3689
|
}
|
|
3582
3690
|
|
|
3583
3691
|
// src/quiet-hours-form.tsx
|
|
3584
|
-
import { useEffect as
|
|
3585
|
-
import { cn as
|
|
3692
|
+
import { useEffect as useEffect6, useState as useState16 } from "react";
|
|
3693
|
+
import { cn as cn29, useToast as useToast13 } from "@quanticjs/react-ui";
|
|
3586
3694
|
import { useApiMutation as useApiMutation14, useApiQuery as useApiQuery23 } from "@quanticjs/react-query";
|
|
3587
|
-
import { jsx as
|
|
3695
|
+
import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3588
3696
|
var DEFAULTS = {
|
|
3589
3697
|
enabled: false,
|
|
3590
3698
|
start: "22:00",
|
|
@@ -3607,8 +3715,8 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3607
3715
|
["quiet-hours"],
|
|
3608
3716
|
(client) => client.get(url)
|
|
3609
3717
|
);
|
|
3610
|
-
const [form, setForm] =
|
|
3611
|
-
|
|
3718
|
+
const [form, setForm] = useState16(DEFAULTS);
|
|
3719
|
+
useEffect6(() => {
|
|
3612
3720
|
if (data !== void 0) {
|
|
3613
3721
|
setForm(normalize5(data));
|
|
3614
3722
|
}
|
|
@@ -3625,23 +3733,23 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3625
3733
|
save.mutate(form);
|
|
3626
3734
|
};
|
|
3627
3735
|
if (isLoading) {
|
|
3628
|
-
return /* @__PURE__ */
|
|
3736
|
+
return /* @__PURE__ */ jsxs28(
|
|
3629
3737
|
"div",
|
|
3630
3738
|
{
|
|
3631
3739
|
role: "status",
|
|
3632
3740
|
"aria-label": "Loading quiet hours",
|
|
3633
|
-
className:
|
|
3741
|
+
className: cn29("flex flex-col gap-2 p-4", className),
|
|
3634
3742
|
children: [
|
|
3635
|
-
/* @__PURE__ */
|
|
3636
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3743
|
+
/* @__PURE__ */ jsx31("span", { className: "sr-only", children: "Loading quiet hours" }),
|
|
3744
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx31("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3637
3745
|
]
|
|
3638
3746
|
}
|
|
3639
3747
|
);
|
|
3640
3748
|
}
|
|
3641
3749
|
if (isError) {
|
|
3642
|
-
return /* @__PURE__ */
|
|
3643
|
-
/* @__PURE__ */
|
|
3644
|
-
/* @__PURE__ */
|
|
3750
|
+
return /* @__PURE__ */ jsxs28("div", { className: cn29("flex flex-col items-start gap-3 p-4", className), children: [
|
|
3751
|
+
/* @__PURE__ */ jsx31("p", { className: "text-sm text-foreground", children: "Failed to load quiet hours" }),
|
|
3752
|
+
/* @__PURE__ */ jsx31(
|
|
3645
3753
|
"button",
|
|
3646
3754
|
{
|
|
3647
3755
|
type: "button",
|
|
@@ -3652,10 +3760,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3652
3760
|
)
|
|
3653
3761
|
] });
|
|
3654
3762
|
}
|
|
3655
|
-
return /* @__PURE__ */
|
|
3656
|
-
/* @__PURE__ */
|
|
3657
|
-
/* @__PURE__ */
|
|
3658
|
-
/* @__PURE__ */
|
|
3763
|
+
return /* @__PURE__ */ jsxs28("form", { onSubmit, className: cn29("flex flex-col gap-4", className), noValidate: true, children: [
|
|
3764
|
+
/* @__PURE__ */ jsx31("h2", { className: "text-sm font-semibold text-foreground", children: "Quiet hours" }),
|
|
3765
|
+
/* @__PURE__ */ jsxs28("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
3766
|
+
/* @__PURE__ */ jsx31(
|
|
3659
3767
|
"input",
|
|
3660
3768
|
{
|
|
3661
3769
|
type: "checkbox",
|
|
@@ -3666,10 +3774,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3666
3774
|
),
|
|
3667
3775
|
"Enable quiet hours"
|
|
3668
3776
|
] }),
|
|
3669
|
-
/* @__PURE__ */
|
|
3670
|
-
/* @__PURE__ */
|
|
3671
|
-
/* @__PURE__ */
|
|
3672
|
-
/* @__PURE__ */
|
|
3777
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex flex-wrap gap-4", children: [
|
|
3778
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-1", children: [
|
|
3779
|
+
/* @__PURE__ */ jsx31("label", { htmlFor: "qh-start", className: "text-sm font-medium text-foreground", children: "Start" }),
|
|
3780
|
+
/* @__PURE__ */ jsx31(
|
|
3673
3781
|
"input",
|
|
3674
3782
|
{
|
|
3675
3783
|
id: "qh-start",
|
|
@@ -3680,9 +3788,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3680
3788
|
}
|
|
3681
3789
|
)
|
|
3682
3790
|
] }),
|
|
3683
|
-
/* @__PURE__ */
|
|
3684
|
-
/* @__PURE__ */
|
|
3685
|
-
/* @__PURE__ */
|
|
3791
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-1", children: [
|
|
3792
|
+
/* @__PURE__ */ jsx31("label", { htmlFor: "qh-end", className: "text-sm font-medium text-foreground", children: "End" }),
|
|
3793
|
+
/* @__PURE__ */ jsx31(
|
|
3686
3794
|
"input",
|
|
3687
3795
|
{
|
|
3688
3796
|
id: "qh-end",
|
|
@@ -3693,9 +3801,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3693
3801
|
}
|
|
3694
3802
|
)
|
|
3695
3803
|
] }),
|
|
3696
|
-
/* @__PURE__ */
|
|
3697
|
-
/* @__PURE__ */
|
|
3698
|
-
/* @__PURE__ */
|
|
3804
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-1", children: [
|
|
3805
|
+
/* @__PURE__ */ jsx31("label", { htmlFor: "qh-tz", className: "text-sm font-medium text-foreground", children: "Timezone" }),
|
|
3806
|
+
/* @__PURE__ */ jsx31(
|
|
3699
3807
|
"input",
|
|
3700
3808
|
{
|
|
3701
3809
|
id: "qh-tz",
|
|
@@ -3707,7 +3815,7 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3707
3815
|
)
|
|
3708
3816
|
] })
|
|
3709
3817
|
] }),
|
|
3710
|
-
/* @__PURE__ */
|
|
3818
|
+
/* @__PURE__ */ jsx31("div", { children: /* @__PURE__ */ jsx31(
|
|
3711
3819
|
"button",
|
|
3712
3820
|
{
|
|
3713
3821
|
type: "submit",
|
|
@@ -3720,10 +3828,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3720
3828
|
}
|
|
3721
3829
|
|
|
3722
3830
|
// src/frequency-cap-table.tsx
|
|
3723
|
-
import { useEffect as
|
|
3724
|
-
import { cn as
|
|
3831
|
+
import { useEffect as useEffect7, useState as useState17 } from "react";
|
|
3832
|
+
import { cn as cn30, useToast as useToast14 } from "@quanticjs/react-ui";
|
|
3725
3833
|
import { useApiMutation as useApiMutation15, useApiQuery as useApiQuery24 } from "@quanticjs/react-query";
|
|
3726
|
-
import { jsx as
|
|
3834
|
+
import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3727
3835
|
function normalize6(raw) {
|
|
3728
3836
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.caps) ? raw.caps : [];
|
|
3729
3837
|
return list.map((entry) => {
|
|
@@ -3739,10 +3847,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3739
3847
|
["frequency-cap"],
|
|
3740
3848
|
(client) => client.get(url)
|
|
3741
3849
|
);
|
|
3742
|
-
const [caps, setCaps] =
|
|
3743
|
-
const [newType, setNewType] =
|
|
3744
|
-
const [newMax, setNewMax] =
|
|
3745
|
-
|
|
3850
|
+
const [caps, setCaps] = useState17([]);
|
|
3851
|
+
const [newType, setNewType] = useState17("");
|
|
3852
|
+
const [newMax, setNewMax] = useState17(0);
|
|
3853
|
+
useEffect7(() => {
|
|
3746
3854
|
if (data !== void 0) {
|
|
3747
3855
|
setCaps(normalize6(data));
|
|
3748
3856
|
}
|
|
@@ -3768,23 +3876,23 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3768
3876
|
setNewMax(0);
|
|
3769
3877
|
};
|
|
3770
3878
|
if (isLoading) {
|
|
3771
|
-
return /* @__PURE__ */
|
|
3879
|
+
return /* @__PURE__ */ jsxs29(
|
|
3772
3880
|
"div",
|
|
3773
3881
|
{
|
|
3774
3882
|
role: "status",
|
|
3775
3883
|
"aria-label": "Loading frequency caps",
|
|
3776
|
-
className:
|
|
3884
|
+
className: cn30("flex flex-col gap-2 p-4", className),
|
|
3777
3885
|
children: [
|
|
3778
|
-
/* @__PURE__ */
|
|
3779
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3886
|
+
/* @__PURE__ */ jsx32("span", { className: "sr-only", children: "Loading frequency caps" }),
|
|
3887
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx32("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3780
3888
|
]
|
|
3781
3889
|
}
|
|
3782
3890
|
);
|
|
3783
3891
|
}
|
|
3784
3892
|
if (isError) {
|
|
3785
|
-
return /* @__PURE__ */
|
|
3786
|
-
/* @__PURE__ */
|
|
3787
|
-
/* @__PURE__ */
|
|
3893
|
+
return /* @__PURE__ */ jsxs29("div", { className: cn30("flex flex-col items-start gap-3 p-4", className), children: [
|
|
3894
|
+
/* @__PURE__ */ jsx32("p", { className: "text-sm text-foreground", children: "Failed to load frequency caps" }),
|
|
3895
|
+
/* @__PURE__ */ jsx32(
|
|
3788
3896
|
"button",
|
|
3789
3897
|
{
|
|
3790
3898
|
type: "button",
|
|
@@ -3795,24 +3903,24 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3795
3903
|
)
|
|
3796
3904
|
] });
|
|
3797
3905
|
}
|
|
3798
|
-
return /* @__PURE__ */
|
|
3799
|
-
/* @__PURE__ */
|
|
3800
|
-
/* @__PURE__ */
|
|
3801
|
-
/* @__PURE__ */
|
|
3802
|
-
/* @__PURE__ */
|
|
3803
|
-
/* @__PURE__ */
|
|
3804
|
-
/* @__PURE__ */
|
|
3906
|
+
return /* @__PURE__ */ jsxs29("section", { "aria-label": "Frequency caps", className: cn30("flex flex-col gap-4", className), children: [
|
|
3907
|
+
/* @__PURE__ */ jsx32("h2", { className: "text-sm font-semibold text-foreground", children: "Frequency caps" }),
|
|
3908
|
+
/* @__PURE__ */ jsxs29("table", { className: "w-full text-sm", children: [
|
|
3909
|
+
/* @__PURE__ */ jsx32("thead", { children: /* @__PURE__ */ jsxs29("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3910
|
+
/* @__PURE__ */ jsx32("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
|
|
3911
|
+
/* @__PURE__ */ jsx32("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Max per day" }),
|
|
3912
|
+
/* @__PURE__ */ jsx32("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx32("span", { className: "sr-only", children: "Actions" }) })
|
|
3805
3913
|
] }) }),
|
|
3806
|
-
/* @__PURE__ */
|
|
3914
|
+
/* @__PURE__ */ jsx32("tbody", { children: caps.map((cap, index) => {
|
|
3807
3915
|
const inputId = `cap-${index}`;
|
|
3808
|
-
return /* @__PURE__ */
|
|
3809
|
-
/* @__PURE__ */
|
|
3810
|
-
/* @__PURE__ */
|
|
3811
|
-
/* @__PURE__ */
|
|
3916
|
+
return /* @__PURE__ */ jsxs29("tr", { className: "border-b border-border", children: [
|
|
3917
|
+
/* @__PURE__ */ jsx32("td", { className: "py-3 pe-4 text-foreground", children: cap.type }),
|
|
3918
|
+
/* @__PURE__ */ jsxs29("td", { className: "px-4 py-3", children: [
|
|
3919
|
+
/* @__PURE__ */ jsxs29("label", { htmlFor: inputId, className: "sr-only", children: [
|
|
3812
3920
|
"Max per day for ",
|
|
3813
3921
|
cap.type
|
|
3814
3922
|
] }),
|
|
3815
|
-
/* @__PURE__ */
|
|
3923
|
+
/* @__PURE__ */ jsx32(
|
|
3816
3924
|
"input",
|
|
3817
3925
|
{
|
|
3818
3926
|
id: inputId,
|
|
@@ -3824,7 +3932,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3824
3932
|
}
|
|
3825
3933
|
)
|
|
3826
3934
|
] }),
|
|
3827
|
-
/* @__PURE__ */
|
|
3935
|
+
/* @__PURE__ */ jsx32("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx32(
|
|
3828
3936
|
"button",
|
|
3829
3937
|
{
|
|
3830
3938
|
type: "button",
|
|
@@ -3836,10 +3944,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3836
3944
|
] }, `${cap.type}-${index}`);
|
|
3837
3945
|
}) })
|
|
3838
3946
|
] }),
|
|
3839
|
-
/* @__PURE__ */
|
|
3840
|
-
/* @__PURE__ */
|
|
3841
|
-
/* @__PURE__ */
|
|
3842
|
-
/* @__PURE__ */
|
|
3947
|
+
/* @__PURE__ */ jsxs29("form", { onSubmit: addRow, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
3948
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3949
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "cap-new-type", className: "text-sm font-medium text-foreground", children: "New type" }),
|
|
3950
|
+
/* @__PURE__ */ jsx32(
|
|
3843
3951
|
"input",
|
|
3844
3952
|
{
|
|
3845
3953
|
id: "cap-new-type",
|
|
@@ -3850,9 +3958,9 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3850
3958
|
}
|
|
3851
3959
|
)
|
|
3852
3960
|
] }),
|
|
3853
|
-
/* @__PURE__ */
|
|
3854
|
-
/* @__PURE__ */
|
|
3855
|
-
/* @__PURE__ */
|
|
3961
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3962
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "cap-new-max", className: "text-sm font-medium text-foreground", children: "Max per day" }),
|
|
3963
|
+
/* @__PURE__ */ jsx32(
|
|
3856
3964
|
"input",
|
|
3857
3965
|
{
|
|
3858
3966
|
id: "cap-new-max",
|
|
@@ -3864,7 +3972,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3864
3972
|
}
|
|
3865
3973
|
)
|
|
3866
3974
|
] }),
|
|
3867
|
-
/* @__PURE__ */
|
|
3975
|
+
/* @__PURE__ */ jsx32(
|
|
3868
3976
|
"button",
|
|
3869
3977
|
{
|
|
3870
3978
|
type: "submit",
|
|
@@ -3873,7 +3981,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3873
3981
|
}
|
|
3874
3982
|
)
|
|
3875
3983
|
] }),
|
|
3876
|
-
/* @__PURE__ */
|
|
3984
|
+
/* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(
|
|
3877
3985
|
"button",
|
|
3878
3986
|
{
|
|
3879
3987
|
type: "button",
|
|
@@ -3887,10 +3995,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3887
3995
|
}
|
|
3888
3996
|
|
|
3889
3997
|
// src/tenant-config-form.tsx
|
|
3890
|
-
import { useEffect as
|
|
3891
|
-
import { cn as
|
|
3998
|
+
import { useEffect as useEffect8, useState as useState18 } from "react";
|
|
3999
|
+
import { cn as cn31, useToast as useToast15 } from "@quanticjs/react-ui";
|
|
3892
4000
|
import { useApiMutation as useApiMutation16, useApiQuery as useApiQuery25 } from "@quanticjs/react-query";
|
|
3893
|
-
import { jsx as
|
|
4001
|
+
import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3894
4002
|
function normalize7(raw) {
|
|
3895
4003
|
const obj = raw ?? {};
|
|
3896
4004
|
const toList = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
@@ -3900,7 +4008,7 @@ function normalize7(raw) {
|
|
|
3900
4008
|
};
|
|
3901
4009
|
}
|
|
3902
4010
|
function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
3903
|
-
const [draft, setDraft] =
|
|
4011
|
+
const [draft, setDraft] = useState18("");
|
|
3904
4012
|
const add = (event) => {
|
|
3905
4013
|
event.preventDefault();
|
|
3906
4014
|
const value = draft.trim();
|
|
@@ -3908,15 +4016,15 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
3908
4016
|
onAdd(value);
|
|
3909
4017
|
setDraft("");
|
|
3910
4018
|
};
|
|
3911
|
-
return /* @__PURE__ */
|
|
3912
|
-
/* @__PURE__ */
|
|
3913
|
-
/* @__PURE__ */
|
|
4019
|
+
return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-2", children: [
|
|
4020
|
+
/* @__PURE__ */ jsx33("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
4021
|
+
/* @__PURE__ */ jsx33("ul", { className: "flex flex-wrap gap-2", children: values.length === 0 ? /* @__PURE__ */ jsx33("li", { className: "text-sm text-muted-foreground", children: "None" }) : values.map((value) => /* @__PURE__ */ jsxs30(
|
|
3914
4022
|
"li",
|
|
3915
4023
|
{
|
|
3916
4024
|
className: "flex items-center gap-1 rounded-md border border-border bg-card px-2 py-1 text-sm text-foreground",
|
|
3917
4025
|
children: [
|
|
3918
4026
|
value,
|
|
3919
|
-
/* @__PURE__ */
|
|
4027
|
+
/* @__PURE__ */ jsx33(
|
|
3920
4028
|
"button",
|
|
3921
4029
|
{
|
|
3922
4030
|
type: "button",
|
|
@@ -3930,13 +4038,13 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
3930
4038
|
},
|
|
3931
4039
|
value
|
|
3932
4040
|
)) }),
|
|
3933
|
-
/* @__PURE__ */
|
|
3934
|
-
/* @__PURE__ */
|
|
3935
|
-
/* @__PURE__ */
|
|
4041
|
+
/* @__PURE__ */ jsxs30("form", { onSubmit: add, className: "flex items-end gap-2", noValidate: true, children: [
|
|
4042
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
4043
|
+
/* @__PURE__ */ jsxs30("label", { htmlFor: id, className: "sr-only", children: [
|
|
3936
4044
|
"Add to ",
|
|
3937
4045
|
label
|
|
3938
4046
|
] }),
|
|
3939
|
-
/* @__PURE__ */
|
|
4047
|
+
/* @__PURE__ */ jsx33(
|
|
3940
4048
|
"input",
|
|
3941
4049
|
{
|
|
3942
4050
|
id,
|
|
@@ -3947,7 +4055,7 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
3947
4055
|
}
|
|
3948
4056
|
)
|
|
3949
4057
|
] }),
|
|
3950
|
-
/* @__PURE__ */
|
|
4058
|
+
/* @__PURE__ */ jsx33(
|
|
3951
4059
|
"button",
|
|
3952
4060
|
{
|
|
3953
4061
|
type: "submit",
|
|
@@ -3965,12 +4073,12 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
3965
4073
|
["tenant-config"],
|
|
3966
4074
|
(client) => client.get(url)
|
|
3967
4075
|
);
|
|
3968
|
-
const [config, setConfig] =
|
|
4076
|
+
const [config, setConfig] = useState18({
|
|
3969
4077
|
notificationTypes: [],
|
|
3970
4078
|
immediateEmailTypes: []
|
|
3971
4079
|
});
|
|
3972
|
-
const [subsetError, setSubsetError] =
|
|
3973
|
-
|
|
4080
|
+
const [subsetError, setSubsetError] = useState18(void 0);
|
|
4081
|
+
useEffect8(() => {
|
|
3974
4082
|
if (data !== void 0) {
|
|
3975
4083
|
setConfig(normalize7(data));
|
|
3976
4084
|
}
|
|
@@ -4012,23 +4120,23 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4012
4120
|
save.mutate(config);
|
|
4013
4121
|
};
|
|
4014
4122
|
if (isLoading) {
|
|
4015
|
-
return /* @__PURE__ */
|
|
4123
|
+
return /* @__PURE__ */ jsxs30(
|
|
4016
4124
|
"div",
|
|
4017
4125
|
{
|
|
4018
4126
|
role: "status",
|
|
4019
4127
|
"aria-label": "Loading tenant configuration",
|
|
4020
|
-
className:
|
|
4128
|
+
className: cn31("flex flex-col gap-2 p-4", className),
|
|
4021
4129
|
children: [
|
|
4022
|
-
/* @__PURE__ */
|
|
4023
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4130
|
+
/* @__PURE__ */ jsx33("span", { className: "sr-only", children: "Loading tenant configuration" }),
|
|
4131
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx33("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4024
4132
|
]
|
|
4025
4133
|
}
|
|
4026
4134
|
);
|
|
4027
4135
|
}
|
|
4028
4136
|
if (isError) {
|
|
4029
|
-
return /* @__PURE__ */
|
|
4030
|
-
/* @__PURE__ */
|
|
4031
|
-
/* @__PURE__ */
|
|
4137
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn31("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4138
|
+
/* @__PURE__ */ jsx33("p", { className: "text-sm text-foreground", children: "Failed to load tenant configuration" }),
|
|
4139
|
+
/* @__PURE__ */ jsx33(
|
|
4032
4140
|
"button",
|
|
4033
4141
|
{
|
|
4034
4142
|
type: "button",
|
|
@@ -4040,17 +4148,17 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4040
4148
|
] });
|
|
4041
4149
|
}
|
|
4042
4150
|
const errorId = "tenant-config-subset-error";
|
|
4043
|
-
return /* @__PURE__ */
|
|
4151
|
+
return /* @__PURE__ */ jsxs30(
|
|
4044
4152
|
"form",
|
|
4045
4153
|
{
|
|
4046
4154
|
onSubmit,
|
|
4047
|
-
className:
|
|
4155
|
+
className: cn31("flex flex-col gap-5", className),
|
|
4048
4156
|
noValidate: true,
|
|
4049
4157
|
"aria-invalid": subsetError ? "true" : void 0,
|
|
4050
4158
|
"aria-describedby": subsetError ? errorId : void 0,
|
|
4051
4159
|
children: [
|
|
4052
|
-
/* @__PURE__ */
|
|
4053
|
-
/* @__PURE__ */
|
|
4160
|
+
/* @__PURE__ */ jsx33("h2", { className: "text-sm font-semibold text-foreground", children: "Notification configuration" }),
|
|
4161
|
+
/* @__PURE__ */ jsx33(
|
|
4054
4162
|
TagEditor,
|
|
4055
4163
|
{
|
|
4056
4164
|
id: "tc-notification-types",
|
|
@@ -4060,7 +4168,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4060
4168
|
onRemove: removeType
|
|
4061
4169
|
}
|
|
4062
4170
|
),
|
|
4063
|
-
/* @__PURE__ */
|
|
4171
|
+
/* @__PURE__ */ jsx33(
|
|
4064
4172
|
TagEditor,
|
|
4065
4173
|
{
|
|
4066
4174
|
id: "tc-immediate-email-types",
|
|
@@ -4070,8 +4178,8 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4070
4178
|
onRemove: removeImmediate
|
|
4071
4179
|
}
|
|
4072
4180
|
),
|
|
4073
|
-
subsetError && /* @__PURE__ */
|
|
4074
|
-
/* @__PURE__ */
|
|
4181
|
+
subsetError && /* @__PURE__ */ jsx33("p", { id: errorId, className: "text-xs text-destructive", children: subsetError }),
|
|
4182
|
+
/* @__PURE__ */ jsx33("div", { children: /* @__PURE__ */ jsx33(
|
|
4075
4183
|
"button",
|
|
4076
4184
|
{
|
|
4077
4185
|
type: "submit",
|
|
@@ -4086,10 +4194,10 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4086
4194
|
}
|
|
4087
4195
|
|
|
4088
4196
|
// src/tracking-config-form.tsx
|
|
4089
|
-
import { useEffect as
|
|
4090
|
-
import { cn as
|
|
4197
|
+
import { useEffect as useEffect9, useState as useState19 } from "react";
|
|
4198
|
+
import { cn as cn32, useToast as useToast16 } from "@quanticjs/react-ui";
|
|
4091
4199
|
import { useApiMutation as useApiMutation17, useApiQuery as useApiQuery26 } from "@quanticjs/react-query";
|
|
4092
|
-
import { jsx as
|
|
4200
|
+
import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
4093
4201
|
function normalize8(raw) {
|
|
4094
4202
|
const obj = raw ?? {};
|
|
4095
4203
|
const bool = (...keys) => {
|
|
@@ -4110,11 +4218,11 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4110
4218
|
["tracking-config"],
|
|
4111
4219
|
(client) => client.get(url)
|
|
4112
4220
|
);
|
|
4113
|
-
const [form, setForm] =
|
|
4221
|
+
const [form, setForm] = useState19({
|
|
4114
4222
|
openTrackingEnabled: false,
|
|
4115
4223
|
clickTrackingEnabled: false
|
|
4116
4224
|
});
|
|
4117
|
-
|
|
4225
|
+
useEffect9(() => {
|
|
4118
4226
|
if (data !== void 0) {
|
|
4119
4227
|
setForm(normalize8(data));
|
|
4120
4228
|
}
|
|
@@ -4134,23 +4242,23 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4134
4242
|
save.mutate(form);
|
|
4135
4243
|
};
|
|
4136
4244
|
if (isLoading) {
|
|
4137
|
-
return /* @__PURE__ */
|
|
4245
|
+
return /* @__PURE__ */ jsxs31(
|
|
4138
4246
|
"div",
|
|
4139
4247
|
{
|
|
4140
4248
|
role: "status",
|
|
4141
4249
|
"aria-label": "Loading tracking configuration",
|
|
4142
|
-
className:
|
|
4250
|
+
className: cn32("flex flex-col gap-2 p-4", className),
|
|
4143
4251
|
children: [
|
|
4144
|
-
/* @__PURE__ */
|
|
4145
|
-
[0, 1].map((i) => /* @__PURE__ */
|
|
4252
|
+
/* @__PURE__ */ jsx34("span", { className: "sr-only", children: "Loading tracking configuration" }),
|
|
4253
|
+
[0, 1].map((i) => /* @__PURE__ */ jsx34("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4146
4254
|
]
|
|
4147
4255
|
}
|
|
4148
4256
|
);
|
|
4149
4257
|
}
|
|
4150
4258
|
if (isError) {
|
|
4151
|
-
return /* @__PURE__ */
|
|
4152
|
-
/* @__PURE__ */
|
|
4153
|
-
/* @__PURE__ */
|
|
4259
|
+
return /* @__PURE__ */ jsxs31("div", { className: cn32("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4260
|
+
/* @__PURE__ */ jsx34("p", { className: "text-sm text-foreground", children: "Failed to load tracking configuration" }),
|
|
4261
|
+
/* @__PURE__ */ jsx34(
|
|
4154
4262
|
"button",
|
|
4155
4263
|
{
|
|
4156
4264
|
type: "button",
|
|
@@ -4161,10 +4269,10 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4161
4269
|
)
|
|
4162
4270
|
] });
|
|
4163
4271
|
}
|
|
4164
|
-
return /* @__PURE__ */
|
|
4165
|
-
/* @__PURE__ */
|
|
4166
|
-
/* @__PURE__ */
|
|
4167
|
-
/* @__PURE__ */
|
|
4272
|
+
return /* @__PURE__ */ jsxs31("form", { onSubmit, className: cn32("flex flex-col gap-4", className), noValidate: true, children: [
|
|
4273
|
+
/* @__PURE__ */ jsx34("h2", { className: "text-sm font-semibold text-foreground", children: "Tracking configuration" }),
|
|
4274
|
+
/* @__PURE__ */ jsxs31("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
4275
|
+
/* @__PURE__ */ jsx34(
|
|
4168
4276
|
"input",
|
|
4169
4277
|
{
|
|
4170
4278
|
type: "checkbox",
|
|
@@ -4175,8 +4283,8 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4175
4283
|
),
|
|
4176
4284
|
"Open tracking"
|
|
4177
4285
|
] }),
|
|
4178
|
-
/* @__PURE__ */
|
|
4179
|
-
/* @__PURE__ */
|
|
4286
|
+
/* @__PURE__ */ jsxs31("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
4287
|
+
/* @__PURE__ */ jsx34(
|
|
4180
4288
|
"input",
|
|
4181
4289
|
{
|
|
4182
4290
|
type: "checkbox",
|
|
@@ -4187,7 +4295,7 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4187
4295
|
),
|
|
4188
4296
|
"Click tracking"
|
|
4189
4297
|
] }),
|
|
4190
|
-
/* @__PURE__ */
|
|
4298
|
+
/* @__PURE__ */ jsx34("div", { children: /* @__PURE__ */ jsx34(
|
|
4191
4299
|
"button",
|
|
4192
4300
|
{
|
|
4193
4301
|
type: "submit",
|
|
@@ -4200,10 +4308,10 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4200
4308
|
}
|
|
4201
4309
|
|
|
4202
4310
|
// src/api-key-manager.tsx
|
|
4203
|
-
import { useState as
|
|
4204
|
-
import { cn as
|
|
4311
|
+
import { useState as useState20 } from "react";
|
|
4312
|
+
import { cn as cn33, formatDateTime as formatDateTime9, StatusBadge as StatusBadge8, useToast as useToast17 } from "@quanticjs/react-ui";
|
|
4205
4313
|
import { useApiMutation as useApiMutation18, useApiQuery as useApiQuery27 } from "@quanticjs/react-query";
|
|
4206
|
-
import { jsx as
|
|
4314
|
+
import { jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
4207
4315
|
function normalize9(raw) {
|
|
4208
4316
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
|
|
4209
4317
|
return list;
|
|
@@ -4215,8 +4323,8 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4215
4323
|
["api-keys"],
|
|
4216
4324
|
(client) => client.get(url)
|
|
4217
4325
|
);
|
|
4218
|
-
const [name, setName] =
|
|
4219
|
-
const [applicationKey, setApplicationKey] =
|
|
4326
|
+
const [name, setName] = useState20("");
|
|
4327
|
+
const [applicationKey, setApplicationKey] = useState20("");
|
|
4220
4328
|
const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
|
|
4221
4329
|
description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
|
|
4222
4330
|
});
|
|
@@ -4261,10 +4369,10 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4261
4369
|
revoke.mutate(id);
|
|
4262
4370
|
}
|
|
4263
4371
|
};
|
|
4264
|
-
const createForm = /* @__PURE__ */
|
|
4265
|
-
/* @__PURE__ */
|
|
4266
|
-
/* @__PURE__ */
|
|
4267
|
-
/* @__PURE__ */
|
|
4372
|
+
const createForm = /* @__PURE__ */ jsxs32("form", { onSubmit: onCreate, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
4373
|
+
/* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1", children: [
|
|
4374
|
+
/* @__PURE__ */ jsx35("label", { htmlFor: "api-key-name", className: "text-sm font-medium text-foreground", children: "New key name" }),
|
|
4375
|
+
/* @__PURE__ */ jsx35(
|
|
4268
4376
|
"input",
|
|
4269
4377
|
{
|
|
4270
4378
|
id: "api-key-name",
|
|
@@ -4275,9 +4383,9 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4275
4383
|
}
|
|
4276
4384
|
)
|
|
4277
4385
|
] }),
|
|
4278
|
-
/* @__PURE__ */
|
|
4279
|
-
/* @__PURE__ */
|
|
4280
|
-
/* @__PURE__ */
|
|
4386
|
+
/* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1", children: [
|
|
4387
|
+
/* @__PURE__ */ jsx35("label", { htmlFor: "api-key-app", className: "text-sm font-medium text-foreground", children: "Application (optional)" }),
|
|
4388
|
+
/* @__PURE__ */ jsx35(
|
|
4281
4389
|
"input",
|
|
4282
4390
|
{
|
|
4283
4391
|
id: "api-key-app",
|
|
@@ -4289,7 +4397,7 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4289
4397
|
}
|
|
4290
4398
|
)
|
|
4291
4399
|
] }),
|
|
4292
|
-
/* @__PURE__ */
|
|
4400
|
+
/* @__PURE__ */ jsx35(
|
|
4293
4401
|
"button",
|
|
4294
4402
|
{
|
|
4295
4403
|
type: "submit",
|
|
@@ -4301,14 +4409,14 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4301
4409
|
] });
|
|
4302
4410
|
let body;
|
|
4303
4411
|
if (isLoading) {
|
|
4304
|
-
body = /* @__PURE__ */
|
|
4305
|
-
/* @__PURE__ */
|
|
4306
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4412
|
+
body = /* @__PURE__ */ jsxs32("div", { role: "status", "aria-label": "Loading API keys", className: "flex flex-col gap-2 p-4", children: [
|
|
4413
|
+
/* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Loading API keys" }),
|
|
4414
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx35("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4307
4415
|
] });
|
|
4308
4416
|
} else if (isError) {
|
|
4309
|
-
body = /* @__PURE__ */
|
|
4310
|
-
/* @__PURE__ */
|
|
4311
|
-
/* @__PURE__ */
|
|
4417
|
+
body = /* @__PURE__ */ jsxs32("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
4418
|
+
/* @__PURE__ */ jsx35("p", { className: "text-sm text-foreground", children: "Failed to load API keys" }),
|
|
4419
|
+
/* @__PURE__ */ jsx35(
|
|
4312
4420
|
"button",
|
|
4313
4421
|
{
|
|
4314
4422
|
type: "button",
|
|
@@ -4321,26 +4429,26 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4321
4429
|
} else {
|
|
4322
4430
|
const rows = normalize9(data);
|
|
4323
4431
|
if (rows.length === 0) {
|
|
4324
|
-
body = /* @__PURE__ */
|
|
4432
|
+
body = /* @__PURE__ */ jsx35("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No API keys" });
|
|
4325
4433
|
} else {
|
|
4326
|
-
body = /* @__PURE__ */
|
|
4327
|
-
/* @__PURE__ */
|
|
4328
|
-
/* @__PURE__ */
|
|
4329
|
-
/* @__PURE__ */
|
|
4330
|
-
/* @__PURE__ */
|
|
4331
|
-
/* @__PURE__ */
|
|
4332
|
-
/* @__PURE__ */
|
|
4333
|
-
/* @__PURE__ */
|
|
4334
|
-
/* @__PURE__ */
|
|
4434
|
+
body = /* @__PURE__ */ jsxs32("table", { className: "w-full text-sm", children: [
|
|
4435
|
+
/* @__PURE__ */ jsx35("thead", { children: /* @__PURE__ */ jsxs32("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4436
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
|
|
4437
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Prefix" }),
|
|
4438
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Application" }),
|
|
4439
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
4440
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
4441
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last used" }),
|
|
4442
|
+
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Actions" }) })
|
|
4335
4443
|
] }) }),
|
|
4336
|
-
/* @__PURE__ */
|
|
4337
|
-
/* @__PURE__ */
|
|
4338
|
-
/* @__PURE__ */
|
|
4339
|
-
/* @__PURE__ */
|
|
4340
|
-
/* @__PURE__ */
|
|
4341
|
-
/* @__PURE__ */
|
|
4342
|
-
/* @__PURE__ */
|
|
4343
|
-
/* @__PURE__ */
|
|
4444
|
+
/* @__PURE__ */ jsx35("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs32("tr", { className: "border-b border-border", children: [
|
|
4445
|
+
/* @__PURE__ */ jsx35("td", { className: "py-3 pe-4 text-foreground", children: row.name }),
|
|
4446
|
+
/* @__PURE__ */ jsx35("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.prefix ?? "\u2014" }),
|
|
4447
|
+
/* @__PURE__ */ jsx35("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.applicationKey ?? "\u2014" }),
|
|
4448
|
+
/* @__PURE__ */ jsx35("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx35(StatusBadge8, { variant: row.revoked ? "destructive" : "success", children: row.revoked ? "Revoked" : "Active" }) }),
|
|
4449
|
+
/* @__PURE__ */ jsx35("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime9(row.createdAt) }),
|
|
4450
|
+
/* @__PURE__ */ jsx35("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastUsedAt ? formatDateTime9(row.lastUsedAt) : "\u2014" }),
|
|
4451
|
+
/* @__PURE__ */ jsx35("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx35(
|
|
4344
4452
|
"button",
|
|
4345
4453
|
{
|
|
4346
4454
|
type: "button",
|
|
@@ -4354,17 +4462,17 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4354
4462
|
] });
|
|
4355
4463
|
}
|
|
4356
4464
|
}
|
|
4357
|
-
return /* @__PURE__ */
|
|
4465
|
+
return /* @__PURE__ */ jsxs32("section", { "aria-label": "API key management", className: cn33("flex flex-col gap-4", className), children: [
|
|
4358
4466
|
createForm,
|
|
4359
4467
|
body
|
|
4360
4468
|
] });
|
|
4361
4469
|
}
|
|
4362
4470
|
|
|
4363
4471
|
// src/application-registry-panel.tsx
|
|
4364
|
-
import { useState as
|
|
4365
|
-
import { cn as
|
|
4472
|
+
import { useState as useState21 } from "react";
|
|
4473
|
+
import { cn as cn34, formatDateTime as formatDateTime10, StatusBadge as StatusBadge9, useToast as useToast18 } from "@quanticjs/react-ui";
|
|
4366
4474
|
import { useApiMutation as useApiMutation19, useApiQuery as useApiQuery28 } from "@quanticjs/react-query";
|
|
4367
|
-
import { jsx as
|
|
4475
|
+
import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
4368
4476
|
function normalize10(raw) {
|
|
4369
4477
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
|
|
4370
4478
|
return list;
|
|
@@ -4379,9 +4487,9 @@ function ApplicationRegistryPanel({
|
|
|
4379
4487
|
["applications"],
|
|
4380
4488
|
(client) => client.get(url)
|
|
4381
4489
|
);
|
|
4382
|
-
const [key, setKey] =
|
|
4383
|
-
const [displayName, setDisplayName] =
|
|
4384
|
-
const [description, setDescription] =
|
|
4490
|
+
const [key, setKey] = useState21("");
|
|
4491
|
+
const [displayName, setDisplayName] = useState21("");
|
|
4492
|
+
const [description, setDescription] = useState21("");
|
|
4385
4493
|
const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
|
|
4386
4494
|
description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
|
|
4387
4495
|
});
|
|
@@ -4410,10 +4518,10 @@ function ApplicationRegistryPanel({
|
|
|
4410
4518
|
if (!k || !name) return;
|
|
4411
4519
|
register.mutate({ key: k, displayName: name, description: description.trim() || void 0 });
|
|
4412
4520
|
};
|
|
4413
|
-
const registerForm = /* @__PURE__ */
|
|
4414
|
-
/* @__PURE__ */
|
|
4415
|
-
/* @__PURE__ */
|
|
4416
|
-
/* @__PURE__ */
|
|
4521
|
+
const registerForm = /* @__PURE__ */ jsxs33("form", { onSubmit: onRegister, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
4522
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
|
|
4523
|
+
/* @__PURE__ */ jsx36("label", { htmlFor: "application-key", className: "text-sm font-medium text-foreground", children: "Key (slug)" }),
|
|
4524
|
+
/* @__PURE__ */ jsx36(
|
|
4417
4525
|
"input",
|
|
4418
4526
|
{
|
|
4419
4527
|
id: "application-key",
|
|
@@ -4425,9 +4533,9 @@ function ApplicationRegistryPanel({
|
|
|
4425
4533
|
}
|
|
4426
4534
|
)
|
|
4427
4535
|
] }),
|
|
4428
|
-
/* @__PURE__ */
|
|
4429
|
-
/* @__PURE__ */
|
|
4430
|
-
/* @__PURE__ */
|
|
4536
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
|
|
4537
|
+
/* @__PURE__ */ jsx36("label", { htmlFor: "application-name", className: "text-sm font-medium text-foreground", children: "Display name" }),
|
|
4538
|
+
/* @__PURE__ */ jsx36(
|
|
4431
4539
|
"input",
|
|
4432
4540
|
{
|
|
4433
4541
|
id: "application-name",
|
|
@@ -4439,9 +4547,9 @@ function ApplicationRegistryPanel({
|
|
|
4439
4547
|
}
|
|
4440
4548
|
)
|
|
4441
4549
|
] }),
|
|
4442
|
-
/* @__PURE__ */
|
|
4443
|
-
/* @__PURE__ */
|
|
4444
|
-
/* @__PURE__ */
|
|
4550
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
|
|
4551
|
+
/* @__PURE__ */ jsx36("label", { htmlFor: "application-description", className: "text-sm font-medium text-foreground", children: "Description (optional)" }),
|
|
4552
|
+
/* @__PURE__ */ jsx36(
|
|
4445
4553
|
"input",
|
|
4446
4554
|
{
|
|
4447
4555
|
id: "application-description",
|
|
@@ -4452,7 +4560,7 @@ function ApplicationRegistryPanel({
|
|
|
4452
4560
|
}
|
|
4453
4561
|
)
|
|
4454
4562
|
] }),
|
|
4455
|
-
/* @__PURE__ */
|
|
4563
|
+
/* @__PURE__ */ jsx36(
|
|
4456
4564
|
"button",
|
|
4457
4565
|
{
|
|
4458
4566
|
type: "submit",
|
|
@@ -4463,23 +4571,23 @@ function ApplicationRegistryPanel({
|
|
|
4463
4571
|
)
|
|
4464
4572
|
] });
|
|
4465
4573
|
if (isLoading) {
|
|
4466
|
-
return /* @__PURE__ */
|
|
4574
|
+
return /* @__PURE__ */ jsxs33(
|
|
4467
4575
|
"div",
|
|
4468
4576
|
{
|
|
4469
4577
|
role: "status",
|
|
4470
4578
|
"aria-label": "Loading applications",
|
|
4471
|
-
className:
|
|
4579
|
+
className: cn34("flex flex-col gap-2 p-4", className),
|
|
4472
4580
|
children: [
|
|
4473
|
-
/* @__PURE__ */
|
|
4474
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4581
|
+
/* @__PURE__ */ jsx36("span", { className: "sr-only", children: "Loading applications" }),
|
|
4582
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx36("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4475
4583
|
]
|
|
4476
4584
|
}
|
|
4477
4585
|
);
|
|
4478
4586
|
}
|
|
4479
4587
|
if (isError) {
|
|
4480
|
-
return /* @__PURE__ */
|
|
4481
|
-
/* @__PURE__ */
|
|
4482
|
-
/* @__PURE__ */
|
|
4588
|
+
return /* @__PURE__ */ jsxs33("div", { className: cn34("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4589
|
+
/* @__PURE__ */ jsx36("p", { className: "text-sm text-foreground", children: "Failed to load applications" }),
|
|
4590
|
+
/* @__PURE__ */ jsx36(
|
|
4483
4591
|
"button",
|
|
4484
4592
|
{
|
|
4485
4593
|
type: "button",
|
|
@@ -4491,22 +4599,22 @@ function ApplicationRegistryPanel({
|
|
|
4491
4599
|
] });
|
|
4492
4600
|
}
|
|
4493
4601
|
const apps = normalize10(data);
|
|
4494
|
-
return /* @__PURE__ */
|
|
4602
|
+
return /* @__PURE__ */ jsxs33("section", { "aria-label": "Applications", className: cn34("flex flex-col gap-4 p-4", className), children: [
|
|
4495
4603
|
registerForm,
|
|
4496
|
-
apps.length === 0 ? /* @__PURE__ */
|
|
4497
|
-
/* @__PURE__ */
|
|
4498
|
-
/* @__PURE__ */
|
|
4499
|
-
/* @__PURE__ */
|
|
4500
|
-
/* @__PURE__ */
|
|
4501
|
-
/* @__PURE__ */
|
|
4502
|
-
/* @__PURE__ */
|
|
4604
|
+
apps.length === 0 ? /* @__PURE__ */ jsx36("p", { className: "p-6 text-center text-sm text-muted-foreground", children: "No applications registered" }) : /* @__PURE__ */ jsxs33("table", { className: "w-full text-sm", children: [
|
|
4605
|
+
/* @__PURE__ */ jsx36("thead", { children: /* @__PURE__ */ jsxs33("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4606
|
+
/* @__PURE__ */ jsx36("th", { className: "py-2 font-medium", children: "Key" }),
|
|
4607
|
+
/* @__PURE__ */ jsx36("th", { className: "py-2 font-medium", children: "Name" }),
|
|
4608
|
+
/* @__PURE__ */ jsx36("th", { className: "py-2 font-medium", children: "Status" }),
|
|
4609
|
+
/* @__PURE__ */ jsx36("th", { className: "py-2 font-medium", children: "Created" }),
|
|
4610
|
+
/* @__PURE__ */ jsx36("th", { className: "py-2 font-medium", children: "Actions" })
|
|
4503
4611
|
] }) }),
|
|
4504
|
-
/* @__PURE__ */
|
|
4505
|
-
/* @__PURE__ */
|
|
4506
|
-
/* @__PURE__ */
|
|
4507
|
-
/* @__PURE__ */
|
|
4508
|
-
/* @__PURE__ */
|
|
4509
|
-
/* @__PURE__ */
|
|
4612
|
+
/* @__PURE__ */ jsx36("tbody", { children: apps.map((app) => /* @__PURE__ */ jsxs33("tr", { className: "border-b border-border", children: [
|
|
4613
|
+
/* @__PURE__ */ jsx36("td", { className: "py-2 font-mono text-foreground", children: app.key }),
|
|
4614
|
+
/* @__PURE__ */ jsx36("td", { className: "py-2 text-foreground", children: app.displayName }),
|
|
4615
|
+
/* @__PURE__ */ jsx36("td", { className: "py-2", children: /* @__PURE__ */ jsx36(StatusBadge9, { variant: app.status === "active" ? "success" : "neutral", children: app.status }) }),
|
|
4616
|
+
/* @__PURE__ */ jsx36("td", { className: "py-2 text-muted-foreground", children: formatDateTime10(app.createdAt) }),
|
|
4617
|
+
/* @__PURE__ */ jsx36("td", { className: "py-2", children: /* @__PURE__ */ jsx36(
|
|
4510
4618
|
"button",
|
|
4511
4619
|
{
|
|
4512
4620
|
type: "button",
|
|
@@ -4539,6 +4647,7 @@ export {
|
|
|
4539
4647
|
FunnelStats,
|
|
4540
4648
|
MissingTranslationsPanel,
|
|
4541
4649
|
NotificationBell,
|
|
4650
|
+
NotificationCenter,
|
|
4542
4651
|
NotificationInbox,
|
|
4543
4652
|
NotificationPreferences,
|
|
4544
4653
|
NotificationProvider,
|