@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/dist/index.cjs CHANGED
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  FunnelStats: () => FunnelStats,
36
36
  MissingTranslationsPanel: () => MissingTranslationsPanel,
37
37
  NotificationBell: () => NotificationBell,
38
+ NotificationCenter: () => NotificationCenter,
38
39
  NotificationInbox: () => NotificationInbox,
39
40
  NotificationPreferences: () => NotificationPreferences,
40
41
  NotificationProvider: () => NotificationProvider,
@@ -431,7 +432,7 @@ function NotificationBell({
431
432
  "span",
432
433
  {
433
434
  "aria-hidden": "true",
434
- className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-destructive px-1.5 text-xs font-semibold text-destructive-foreground",
435
+ 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",
435
436
  children: count > 99 ? "99+" : count
436
437
  }
437
438
  )
@@ -519,7 +520,7 @@ function InboxRow({
519
520
  ),
520
521
  children: [
521
522
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "flex items-center gap-2 text-sm font-medium", children: [
522
- !item.isRead && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": "true", className: "h-2 w-2 rounded-full bg-primary" }),
523
+ !item.isRead && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": "true", className: "h-2 w-2 rounded-full bg-coral" }),
523
524
  item.title
524
525
  ] }),
525
526
  item.body && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs text-muted-foreground", children: item.body })
@@ -528,9 +529,117 @@ function InboxRow({
528
529
  ) });
529
530
  }
530
531
 
531
- // src/delivery-analytics-page.tsx
532
+ // src/notification-center.tsx
532
533
  var import_react5 = require("react");
533
- var import_react_ui8 = require("@quanticjs/react-ui");
534
+ var import_react_ui5 = require("@quanticjs/react-ui");
535
+ var import_jsx_runtime6 = require("react/jsx-runtime");
536
+ function BellIcon() {
537
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
538
+ "svg",
539
+ {
540
+ "aria-hidden": true,
541
+ viewBox: "0 0 24 24",
542
+ fill: "none",
543
+ stroke: "currentColor",
544
+ strokeWidth: "2",
545
+ strokeLinecap: "round",
546
+ strokeLinejoin: "round",
547
+ className: "h-5 w-5",
548
+ children: [
549
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
550
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
551
+ ]
552
+ }
553
+ );
554
+ }
555
+ function NotificationCenter({
556
+ appId,
557
+ basePath,
558
+ pollIntervalMs,
559
+ className,
560
+ panelClassName
561
+ }) {
562
+ const [open, setOpen] = (0, import_react5.useState)(false);
563
+ const containerRef = (0, import_react5.useRef)(null);
564
+ const panelRef = (0, import_react5.useRef)(null);
565
+ const { data } = useUnreadCount({ appId, basePath, pollIntervalMs });
566
+ const unreadCount = data?.count ?? 0;
567
+ const badge = unreadCount > 99 ? "99+" : String(unreadCount);
568
+ const label = unreadCount === 0 ? "No unread notifications" : `${unreadCount} unread notifications`;
569
+ const close = (0, import_react5.useCallback)(() => setOpen(false), []);
570
+ (0, import_react5.useEffect)(() => {
571
+ if (!open) return;
572
+ const onKey = (e) => {
573
+ if (e.key === "Escape") close();
574
+ };
575
+ const onPointer = (e) => {
576
+ const c = containerRef.current;
577
+ if (c && e.target instanceof Node && !c.contains(e.target)) close();
578
+ };
579
+ document.addEventListener("keydown", onKey);
580
+ document.addEventListener("mousedown", onPointer);
581
+ return () => {
582
+ document.removeEventListener("keydown", onKey);
583
+ document.removeEventListener("mousedown", onPointer);
584
+ };
585
+ }, [open, close]);
586
+ (0, import_react_ui5.useFocusTrap)(panelRef, open);
587
+ const panelExit = (0, import_react_ui5.useExitAnimation)(open);
588
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: containerRef, className: (0, import_react_ui5.cn)("relative inline-block", className), children: [
589
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
590
+ "button",
591
+ {
592
+ type: "button",
593
+ "aria-label": label,
594
+ "aria-haspopup": "dialog",
595
+ "aria-expanded": open,
596
+ onClick: () => setOpen((p) => !p),
597
+ 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",
598
+ children: [
599
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BellIcon, {}),
600
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { role: "status", className: "sr-only", children: label }),
601
+ unreadCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
602
+ "span",
603
+ {
604
+ "aria-hidden": true,
605
+ 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",
606
+ children: badge
607
+ }
608
+ )
609
+ ]
610
+ }
611
+ ),
612
+ panelExit.mounted && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
613
+ "div",
614
+ {
615
+ ref: panelRef,
616
+ role: "dialog",
617
+ "aria-label": "Notifications",
618
+ tabIndex: -1,
619
+ "data-state": panelExit.state,
620
+ onAnimationEnd: panelExit.onAnimationEnd,
621
+ className: (0, import_react_ui5.cn)(
622
+ "absolute end-0 z-(--z-popover) mt-2 w-96 overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-raised",
623
+ panelExit.state === "open" ? "animate-pop-in" : "animate-pop-out [animation-fill-mode:forwards]",
624
+ panelClassName
625
+ ),
626
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
627
+ NotificationInbox,
628
+ {
629
+ appId,
630
+ basePath,
631
+ pollIntervalMs,
632
+ className: "max-h-[28rem] overflow-y-auto"
633
+ }
634
+ )
635
+ }
636
+ )
637
+ ] });
638
+ }
639
+
640
+ // src/delivery-analytics-page.tsx
641
+ var import_react6 = require("react");
642
+ var import_react_ui9 = require("@quanticjs/react-ui");
534
643
 
535
644
  // src/use-delivery-analytics.ts
536
645
  var import_react_query5 = require("@quanticjs/react-query");
@@ -582,8 +691,8 @@ function useDeliveryTypes({
582
691
  }
583
692
 
584
693
  // src/funnel-stats.tsx
585
- var import_react_ui5 = require("@quanticjs/react-ui");
586
- var import_jsx_runtime6 = require("react/jsx-runtime");
694
+ var import_react_ui6 = require("@quanticjs/react-ui");
695
+ var import_jsx_runtime7 = require("react/jsx-runtime");
587
696
  var pct = (n) => `${(n * 100).toFixed(1)}%`;
588
697
  function FunnelStats({ funnel, className }) {
589
698
  const cards = [
@@ -596,13 +705,13 @@ function FunnelStats({ funnel, className }) {
596
705
  { label: "Bounce rate", value: pct(funnel.bounceRate) },
597
706
  { label: "Delivery rate", value: pct(funnel.deliveryRate) }
598
707
  ];
599
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: (0, import_react_ui5.cn)("grid grid-cols-2 gap-3 sm:grid-cols-4", className), "aria-label": "Delivery funnel", children: cards.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
708
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: (0, import_react_ui6.cn)("grid grid-cols-2 gap-3 sm:grid-cols-4", className), "aria-label": "Delivery funnel", children: cards.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
600
709
  "li",
601
710
  {
602
711
  className: "flex flex-col gap-1 rounded-lg border border-border bg-card p-4",
603
712
  children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: c.label }),
605
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: c.value })
713
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: c.label }),
714
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: c.value })
606
715
  ]
607
716
  },
608
717
  c.label
@@ -610,48 +719,48 @@ function FunnelStats({ funnel, className }) {
610
719
  }
611
720
 
612
721
  // src/trend-chart.tsx
613
- var import_react_ui6 = require("@quanticjs/react-ui");
722
+ var import_react_ui7 = require("@quanticjs/react-ui");
614
723
  var import_recharts = require("recharts");
615
- var import_jsx_runtime7 = require("react/jsx-runtime");
724
+ var import_jsx_runtime8 = require("react/jsx-runtime");
616
725
  function TrendChart({ data, className }) {
617
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: (0, import_react_ui6.cn)("h-72 w-full", className), role: "img", "aria-label": "Delivery trend over time", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts.LineChart, { data, margin: { top: 8, right: 16, bottom: 8, left: 0 }, children: [
618
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: "hsl(var(--border))" }),
619
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.XAxis, { dataKey: "day", stroke: "hsl(var(--muted-foreground))", fontSize: 12 }),
620
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.YAxis, { stroke: "hsl(var(--muted-foreground))", fontSize: 12, allowDecimals: false }),
621
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.Tooltip, {}),
622
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.Line, { type: "monotone", dataKey: "sends", stroke: "hsl(var(--primary))", dot: false }),
623
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.Line, { type: "monotone", dataKey: "delivered", stroke: "hsl(var(--chart-2, var(--primary)))", dot: false }),
624
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.Line, { type: "monotone", dataKey: "opened", stroke: "hsl(var(--chart-3, var(--primary)))", dot: false }),
625
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts.Line, { type: "monotone", dataKey: "clicked", stroke: "hsl(var(--chart-4, var(--primary)))", dot: false })
726
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: (0, import_react_ui7.cn)("h-72 w-full", className), role: "img", "aria-label": "Delivery trend over time", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_recharts.LineChart, { data, margin: { top: 8, right: 16, bottom: 8, left: 0 }, children: [
727
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--border)" }),
728
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.XAxis, { dataKey: "day", stroke: "var(--muted-foreground)", fontSize: 12 }),
729
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.YAxis, { stroke: "var(--muted-foreground)", fontSize: 12, allowDecimals: false }),
730
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.Tooltip, {}),
731
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.Line, { type: "monotone", dataKey: "sends", stroke: "var(--primary)", dot: false }),
732
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.Line, { type: "monotone", dataKey: "delivered", stroke: "var(--chart-2, var(--primary))", dot: false }),
733
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.Line, { type: "monotone", dataKey: "opened", stroke: "var(--chart-3, var(--primary))", dot: false }),
734
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_recharts.Line, { type: "monotone", dataKey: "clicked", stroke: "var(--chart-4, var(--primary))", dot: false })
626
735
  ] }) }) });
627
736
  }
628
737
 
629
738
  // src/type-table.tsx
630
- var import_react_ui7 = require("@quanticjs/react-ui");
631
- var import_jsx_runtime8 = require("react/jsx-runtime");
739
+ var import_react_ui8 = require("@quanticjs/react-ui");
740
+ var import_jsx_runtime9 = require("react/jsx-runtime");
632
741
  var pct2 = (n) => `${(n * 100).toFixed(1)}%`;
633
742
  function TypeTable({ rows, className }) {
634
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { className: (0, import_react_ui7.cn)("w-full border-collapse text-sm", className), children: [
635
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("caption", { className: "sr-only", children: "Delivery breakdown by notification type" }),
636
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
637
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
638
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Sends" }),
639
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivered" }),
640
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Open rate" }),
641
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { scope: "col", className: "py-2 font-medium", children: "Click rate" })
743
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { className: (0, import_react_ui8.cn)("w-full border-collapse text-sm", className), children: [
744
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("caption", { className: "sr-only", children: "Delivery breakdown by notification type" }),
745
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
746
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
747
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Sends" }),
748
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivered" }),
749
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Open rate" }),
750
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { scope: "col", className: "py-2 font-medium", children: "Click rate" })
642
751
  ] }) }),
643
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { className: "border-b border-border/50", children: [
644
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "py-2 pe-4 font-medium text-foreground", children: r.type }),
645
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "py-2 pe-4 text-foreground", children: r.sends }),
646
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "py-2 pe-4 text-foreground", children: r.delivered }),
647
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "py-2 pe-4 text-foreground", children: pct2(r.openRate) }),
648
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "py-2 text-foreground", children: pct2(r.clickRate) })
752
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { className: "border-b border-border/50", children: [
753
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "py-2 pe-4 font-medium text-foreground", children: r.type }),
754
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "py-2 pe-4 text-foreground", children: r.sends }),
755
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "py-2 pe-4 text-foreground", children: r.delivered }),
756
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "py-2 pe-4 text-foreground", children: pct2(r.openRate) }),
757
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "py-2 text-foreground", children: pct2(r.clickRate) })
649
758
  ] }, r.type)) })
650
759
  ] });
651
760
  }
652
761
 
653
762
  // src/delivery-analytics-page.tsx
654
- var import_jsx_runtime9 = require("react/jsx-runtime");
763
+ var import_jsx_runtime10 = require("react/jsx-runtime");
655
764
  var DEFAULT_FROM = "2026-06-01";
656
765
  var DEFAULT_TO = "2026-06-30";
657
766
  var CHANNELS = ["", "email", "inapp", "push", "sms"];
@@ -660,36 +769,36 @@ function DeliveryAnalyticsPage({
660
769
  organizationId,
661
770
  className
662
771
  }) {
663
- const [channel, setChannel] = (0, import_react5.useState)("");
664
- const [from, setFrom] = (0, import_react5.useState)(DEFAULT_FROM);
665
- const [to, setTo] = (0, import_react5.useState)(DEFAULT_TO);
772
+ const [channel, setChannel] = (0, import_react6.useState)("");
773
+ const [from, setFrom] = (0, import_react6.useState)(DEFAULT_FROM);
774
+ const [to, setTo] = (0, import_react6.useState)(DEFAULT_TO);
666
775
  const filters = { from, to, channel: channel || void 0, organizationId, basePath };
667
776
  const summary = useDeliveryAnalytics(filters);
668
777
  const funnel = useFunnelStats(filters);
669
778
  const types = useDeliveryTypes({ from, to, organizationId, basePath });
670
779
  const isLoading = summary.isLoading || funnel.isLoading || types.isLoading;
671
780
  const isError = summary.isError || funnel.isError || types.isError;
672
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("main", { className: (0, import_react_ui8.cn)("flex flex-col gap-6 p-4 sm:p-6", className), children: [
673
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { className: "flex flex-col gap-1", children: [
674
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { className: "text-xl font-semibold text-foreground", children: "Delivery Analytics" }),
675
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-muted-foreground", children: "Cross-channel send, open, and click performance." })
781
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("main", { className: (0, import_react_ui9.cn)("flex flex-col gap-6 p-4 sm:p-6", className), children: [
782
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("header", { className: "flex flex-col gap-1", children: [
783
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { className: "text-xl font-semibold text-foreground", children: "Delivery Analytics" }),
784
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-muted-foreground", children: "Cross-channel send, open, and click performance." })
676
785
  ] }),
677
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap items-end gap-3", children: [
678
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1 text-sm", children: [
679
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-medium text-foreground", children: "Channel" }),
680
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
786
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-wrap items-end gap-3", children: [
787
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex flex-col gap-1 text-sm", children: [
788
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium text-foreground", children: "Channel" }),
789
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
681
790
  "select",
682
791
  {
683
792
  value: channel,
684
793
  onChange: (e) => setChannel(e.target.value),
685
794
  className: "rounded border border-border bg-background px-2 py-1.5 text-foreground",
686
- children: CHANNELS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: c, children: c === "" ? "All channels" : c }, c || "all"))
795
+ children: CHANNELS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: c, children: c === "" ? "All channels" : c }, c || "all"))
687
796
  }
688
797
  )
689
798
  ] }),
690
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1 text-sm", children: [
691
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-medium text-foreground", children: "From" }),
692
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
799
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex flex-col gap-1 text-sm", children: [
800
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium text-foreground", children: "From" }),
801
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
693
802
  "input",
694
803
  {
695
804
  type: "date",
@@ -699,9 +808,9 @@ function DeliveryAnalyticsPage({
699
808
  }
700
809
  )
701
810
  ] }),
702
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1 text-sm", children: [
703
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-medium text-foreground", children: "To" }),
704
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
811
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex flex-col gap-1 text-sm", children: [
812
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium text-foreground", children: "To" }),
813
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
705
814
  "input",
706
815
  {
707
816
  type: "date",
@@ -712,13 +821,13 @@ function DeliveryAnalyticsPage({
712
821
  )
713
822
  ] })
714
823
  ] }),
715
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { role: "status", "aria-label": "Loading delivery analytics", className: "flex flex-col gap-3", children: [
716
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "sr-only", children: "Loading delivery analytics" }),
717
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { "aria-hidden": "true", className: "h-24 animate-pulse rounded bg-muted" }),
718
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { "aria-hidden": "true", className: "h-72 animate-pulse rounded bg-muted" })
719
- ] }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col items-start gap-3", children: [
720
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load delivery analytics" }),
721
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
824
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { role: "status", "aria-label": "Loading delivery analytics", className: "flex flex-col gap-3", children: [
825
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "sr-only", children: "Loading delivery analytics" }),
826
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "aria-hidden": "true", className: "h-24 animate-pulse rounded bg-muted" }),
827
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "aria-hidden": "true", className: "h-72 animate-pulse rounded bg-muted" })
828
+ ] }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-start gap-3", children: [
829
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load delivery analytics" }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
722
831
  "button",
723
832
  {
724
833
  type: "button",
@@ -731,23 +840,23 @@ function DeliveryAnalyticsPage({
731
840
  children: "Try again"
732
841
  }
733
842
  )
734
- ] }) : (summary.data?.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "rounded border border-border p-6 text-center text-sm text-muted-foreground", children: "No delivery data for the selected range" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-6", children: [
735
- funnel.data ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FunnelStats, { funnel: funnel.data }) : null,
736
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { "aria-label": "Delivery trend", className: "rounded-lg border border-border p-4", children: [
737
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: "Trend" }),
738
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TrendChart, { data: summary.data ?? [] })
843
+ ] }) : (summary.data?.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "rounded border border-border p-6 text-center text-sm text-muted-foreground", children: "No delivery data for the selected range" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-6", children: [
844
+ funnel.data ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FunnelStats, { funnel: funnel.data }) : null,
845
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { "aria-label": "Delivery trend", className: "rounded-lg border border-border p-4", children: [
846
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: "Trend" }),
847
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TrendChart, { data: summary.data ?? [] })
739
848
  ] }),
740
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { "aria-label": "Delivery by type", className: "rounded-lg border border-border p-4", children: [
741
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: "By type" }),
742
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TypeTable, { rows: types.data ?? [] })
849
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { "aria-label": "Delivery by type", className: "rounded-lg border border-border p-4", children: [
850
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: "By type" }),
851
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TypeTable, { rows: types.data ?? [] })
743
852
  ] })
744
853
  ] })
745
854
  ] });
746
855
  }
747
856
 
748
857
  // src/template-status-badge.tsx
749
- var import_react_ui9 = require("@quanticjs/react-ui");
750
- var import_jsx_runtime10 = require("react/jsx-runtime");
858
+ var import_react_ui10 = require("@quanticjs/react-ui");
859
+ var import_jsx_runtime11 = require("react/jsx-runtime");
751
860
  var STATUS_STYLES = {
752
861
  draft: "bg-muted text-muted-foreground",
753
862
  published: "bg-primary text-primary-foreground",
@@ -758,10 +867,10 @@ function TemplateStatusBadge({
758
867
  className
759
868
  }) {
760
869
  const style = STATUS_STYLES[status] ?? "bg-muted text-muted-foreground";
761
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
870
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
762
871
  "span",
763
872
  {
764
- className: (0, import_react_ui9.cn)(
873
+ className: (0, import_react_ui10.cn)(
765
874
  "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize",
766
875
  style,
767
876
  className
@@ -772,32 +881,32 @@ function TemplateStatusBadge({
772
881
  }
773
882
 
774
883
  // src/template-list.tsx
775
- var import_react_ui10 = require("@quanticjs/react-ui");
884
+ var import_react_ui11 = require("@quanticjs/react-ui");
776
885
  var import_react_query8 = require("@quanticjs/react-query");
777
- var import_jsx_runtime11 = require("react/jsx-runtime");
886
+ var import_jsx_runtime12 = require("react/jsx-runtime");
778
887
  function TemplateList({ basePath = "/api/templates", className }) {
779
888
  const { data, isLoading, isError, refetch } = (0, import_react_query8.useApiQuery)(
780
889
  ["templates", basePath],
781
890
  (client) => client.get(basePath)
782
891
  );
783
892
  if (isLoading) {
784
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
893
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
785
894
  "div",
786
895
  {
787
896
  role: "status",
788
897
  "aria-label": "Loading templates",
789
- className: (0, import_react_ui10.cn)("flex flex-col gap-2 p-4", className),
898
+ className: (0, import_react_ui11.cn)("flex flex-col gap-2 p-4", className),
790
899
  children: [
791
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sr-only", children: "Loading templates" }),
792
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "aria-hidden": "true", className: "h-12 animate-pulse rounded bg-muted" }, i))
900
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "sr-only", children: "Loading templates" }),
901
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { "aria-hidden": "true", className: "h-12 animate-pulse rounded bg-muted" }, i))
793
902
  ]
794
903
  }
795
904
  );
796
905
  }
797
906
  if (isError) {
798
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: (0, import_react_ui10.cn)("flex flex-col items-start gap-3 p-4", className), children: [
799
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load templates" }),
800
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
907
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: (0, import_react_ui11.cn)("flex flex-col items-start gap-3 p-4", className), children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load templates" }),
909
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
801
910
  "button",
802
911
  {
803
912
  type: "button",
@@ -810,29 +919,29 @@ function TemplateList({ basePath = "/api/templates", className }) {
810
919
  }
811
920
  const items = data ?? [];
812
921
  if (items.length === 0) {
813
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: (0, import_react_ui10.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No templates found" });
922
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: (0, import_react_ui11.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No templates found" });
814
923
  }
815
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("section", { "aria-label": "Templates", className: (0, import_react_ui10.cn)("flex flex-col", className), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { className: "w-full text-sm", children: [
816
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
817
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Template" }),
818
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
819
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locales" }),
820
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Versions" })
924
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("section", { "aria-label": "Templates", className: (0, import_react_ui11.cn)("flex flex-col", className), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { className: "w-full text-sm", children: [
925
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Template" }),
927
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
928
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locales" }),
929
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Versions" })
821
930
  ] }) }),
822
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { className: "border-b border-border", children: [
823
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "py-3 pe-4 font-medium text-foreground", children: item.templateId }),
824
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TemplateStatusBadge, { status: item.latestStatus }) }),
825
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: item.locales.join(", ") }),
826
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: item.versionCount })
931
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: "border-b border-border", children: [
932
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-3 pe-4 font-medium text-foreground", children: item.templateId }),
933
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TemplateStatusBadge, { status: item.latestStatus }) }),
934
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: item.locales.join(", ") }),
935
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: item.versionCount })
827
936
  ] }, item.templateId)) })
828
937
  ] }) });
829
938
  }
830
939
 
831
940
  // src/template-editor.tsx
832
- var import_react6 = require("react");
833
- var import_react_ui11 = require("@quanticjs/react-ui");
941
+ var import_react7 = require("react");
942
+ var import_react_ui12 = require("@quanticjs/react-ui");
834
943
  var import_react_query9 = require("@quanticjs/react-query");
835
- var import_jsx_runtime12 = require("react/jsx-runtime");
944
+ var import_jsx_runtime13 = require("react/jsx-runtime");
836
945
  var FIELD_DEFS = [
837
946
  { key: "subject", label: "Subject", multiline: false },
838
947
  { key: "heading", label: "Heading", multiline: false },
@@ -853,17 +962,17 @@ function TemplateEditor({
853
962
  basePath = "/api/templates",
854
963
  className
855
964
  }) {
856
- const toast = (0, import_react_ui11.useToast)();
857
- const [fields, setFields] = (0, import_react6.useState)({
965
+ const toast = (0, import_react_ui12.useToast)();
966
+ const [fields, setFields] = (0, import_react7.useState)({
858
967
  subject: initialFields?.subject ?? "",
859
968
  heading: initialFields?.heading ?? "",
860
969
  body: initialFields?.body ?? "",
861
970
  cta: initialFields?.cta ?? "",
862
971
  html: initialFields?.html ?? ""
863
972
  });
864
- const [errors, setErrors] = (0, import_react6.useState)({});
865
- const [status, setStatus] = (0, import_react6.useState)(initialStatus);
866
- const [activeVersionId, setActiveVersionId] = (0, import_react6.useState)(versionId);
973
+ const [errors, setErrors] = (0, import_react7.useState)({});
974
+ const [status, setStatus] = (0, import_react7.useState)(initialStatus);
975
+ const [activeVersionId, setActiveVersionId] = (0, import_react7.useState)(versionId);
867
976
  const save = (0, import_react_query9.useApiMutation)(
868
977
  (client, payload) => client.put(`${basePath}/${templateId}`, payload),
869
978
  {
@@ -907,21 +1016,21 @@ function TemplateEditor({
907
1016
  if (!validate()) return;
908
1017
  save.mutate(fields);
909
1018
  };
910
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("form", { onSubmit, className: (0, import_react_ui11.cn)("flex flex-col gap-4", className), noValidate: true, children: [
911
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "flex items-center justify-between", children: [
912
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("h2", { className: "text-sm font-semibold text-foreground", children: [
1019
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("form", { onSubmit, className: (0, import_react_ui12.cn)("flex flex-col gap-4", className), noValidate: true, children: [
1020
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("header", { className: "flex items-center justify-between", children: [
1021
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("h2", { className: "text-sm font-semibold text-foreground", children: [
913
1022
  "Edit template: ",
914
1023
  templateId
915
1024
  ] }),
916
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TemplateStatusBadge, { status })
1025
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TemplateStatusBadge, { status })
917
1026
  ] }),
918
1027
  FIELD_DEFS.map(({ key, label, multiline }) => {
919
1028
  const fieldId = `template-${key}`;
920
1029
  const errorId = `${fieldId}-error`;
921
1030
  const error = errors[key];
922
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1", children: [
923
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { htmlFor: fieldId, className: "text-sm font-medium text-foreground", children: label }),
924
- multiline ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1031
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-1", children: [
1032
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: fieldId, className: "text-sm font-medium text-foreground", children: label }),
1033
+ multiline ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
925
1034
  "textarea",
926
1035
  {
927
1036
  id: fieldId,
@@ -932,7 +1041,7 @@ function TemplateEditor({
932
1041
  onChange: (e) => setFields((prev) => ({ ...prev, [key]: e.target.value })),
933
1042
  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"
934
1043
  }
935
- ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1044
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
936
1045
  "input",
937
1046
  {
938
1047
  id: fieldId,
@@ -944,11 +1053,11 @@ function TemplateEditor({
944
1053
  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"
945
1054
  }
946
1055
  ),
947
- error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { id: errorId, className: "text-xs text-destructive", children: error })
1056
+ error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { id: errorId, className: "text-xs text-destructive", children: error })
948
1057
  ] }, key);
949
1058
  }),
950
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-3", children: [
951
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1059
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
1060
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
952
1061
  "button",
953
1062
  {
954
1063
  type: "submit",
@@ -957,7 +1066,7 @@ function TemplateEditor({
957
1066
  children: save.isPending ? "Saving\u2026" : "Save draft"
958
1067
  }
959
1068
  ),
960
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1069
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
961
1070
  "button",
962
1071
  {
963
1072
  type: "button",
@@ -972,10 +1081,10 @@ function TemplateEditor({
972
1081
  }
973
1082
 
974
1083
  // src/template-preview-pane.tsx
975
- var import_react7 = require("react");
976
- var import_react_ui12 = require("@quanticjs/react-ui");
1084
+ var import_react8 = require("react");
1085
+ var import_react_ui13 = require("@quanticjs/react-ui");
977
1086
  var import_react_query10 = require("@quanticjs/react-query");
978
- var import_jsx_runtime13 = require("react/jsx-runtime");
1087
+ var import_jsx_runtime14 = require("react/jsx-runtime");
979
1088
  function TemplatePreviewPane({
980
1089
  templateId,
981
1090
  versionId,
@@ -987,28 +1096,28 @@ function TemplatePreviewPane({
987
1096
  (client, payload) => client.post(`${basePath}/${templateId}/preview`, payload)
988
1097
  );
989
1098
  const { mutate, data, isPending, isError } = preview;
990
- (0, import_react7.useEffect)(() => {
1099
+ (0, import_react8.useEffect)(() => {
991
1100
  mutate({ versionId, vars });
992
1101
  }, [templateId, versionId]);
993
1102
  if (isPending) {
994
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1103
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
995
1104
  "div",
996
1105
  {
997
1106
  role: "status",
998
1107
  "aria-label": "Loading preview",
999
- className: (0, import_react_ui12.cn)("flex flex-col gap-2 p-4", className),
1108
+ className: (0, import_react_ui13.cn)("flex flex-col gap-2 p-4", className),
1000
1109
  children: [
1001
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "sr-only", children: "Loading preview" }),
1002
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { "aria-hidden": "true", className: "h-6 w-1/2 animate-pulse rounded bg-muted" }),
1003
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { "aria-hidden": "true", className: "h-40 animate-pulse rounded bg-muted" })
1110
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "sr-only", children: "Loading preview" }),
1111
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { "aria-hidden": "true", className: "h-6 w-1/2 animate-pulse rounded bg-muted" }),
1112
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { "aria-hidden": "true", className: "h-40 animate-pulse rounded bg-muted" })
1004
1113
  ]
1005
1114
  }
1006
1115
  );
1007
1116
  }
1008
1117
  if (isError || !data) {
1009
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: (0, import_react_ui12.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1010
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load preview" }),
1011
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1118
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: (0, import_react_ui13.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1119
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load preview" }),
1120
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1012
1121
  "button",
1013
1122
  {
1014
1123
  type: "button",
@@ -1019,9 +1128,9 @@ function TemplatePreviewPane({
1019
1128
  )
1020
1129
  ] });
1021
1130
  }
1022
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("section", { "aria-label": "Template preview", className: (0, import_react_ui12.cn)("flex flex-col gap-4", className), children: [
1023
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: data.subject }),
1024
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1131
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { "aria-label": "Template preview", className: (0, import_react_ui13.cn)("flex flex-col gap-4", className), children: [
1132
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: data.subject }),
1133
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1025
1134
  "iframe",
1026
1135
  {
1027
1136
  title: "Email preview",
@@ -1030,24 +1139,24 @@ function TemplatePreviewPane({
1030
1139
  className: "h-96 w-full rounded-md border border-border bg-background"
1031
1140
  }
1032
1141
  ),
1033
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-1", children: [
1034
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: "text-xs font-medium text-muted-foreground", children: "Plain text" }),
1035
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "overflow-auto whitespace-pre-wrap rounded-md border border-border bg-muted p-3 text-xs text-foreground", children: data.text })
1142
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
1143
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-xs font-medium text-muted-foreground", children: "Plain text" }),
1144
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { className: "overflow-auto whitespace-pre-wrap rounded-md border border-border bg-muted p-3 text-xs text-foreground", children: data.text })
1036
1145
  ] })
1037
1146
  ] });
1038
1147
  }
1039
1148
 
1040
1149
  // src/template-version-history.tsx
1041
- var import_react_ui13 = require("@quanticjs/react-ui");
1150
+ var import_react_ui14 = require("@quanticjs/react-ui");
1042
1151
  var import_react_query11 = require("@quanticjs/react-query");
1043
- var import_jsx_runtime14 = require("react/jsx-runtime");
1152
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1044
1153
  function TemplateVersionHistory({
1045
1154
  templateId,
1046
1155
  basePath = "/api/templates",
1047
1156
  className,
1048
1157
  canRollback = true
1049
1158
  }) {
1050
- const toast = (0, import_react_ui13.useToast)();
1159
+ const toast = (0, import_react_ui14.useToast)();
1051
1160
  const versionsKey = ["templates", templateId, "versions"];
1052
1161
  const { data, isLoading, isError, refetch } = (0, import_react_query11.useApiQuery)(
1053
1162
  versionsKey,
@@ -1065,23 +1174,23 @@ function TemplateVersionHistory({
1065
1174
  }
1066
1175
  );
1067
1176
  if (isLoading) {
1068
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1177
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1069
1178
  "div",
1070
1179
  {
1071
1180
  role: "status",
1072
1181
  "aria-label": "Loading versions",
1073
- className: (0, import_react_ui13.cn)("flex flex-col gap-2 p-4", className),
1182
+ className: (0, import_react_ui14.cn)("flex flex-col gap-2 p-4", className),
1074
1183
  children: [
1075
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "sr-only", children: "Loading versions" }),
1076
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1184
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sr-only", children: "Loading versions" }),
1185
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1077
1186
  ]
1078
1187
  }
1079
1188
  );
1080
1189
  }
1081
1190
  if (isError) {
1082
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: (0, import_react_ui13.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1083
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load versions" }),
1084
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1191
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: (0, import_react_ui14.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1192
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load versions" }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1085
1194
  "button",
1086
1195
  {
1087
1196
  type: "button",
@@ -1094,25 +1203,25 @@ function TemplateVersionHistory({
1094
1203
  }
1095
1204
  const versions = data ?? [];
1096
1205
  if (versions.length === 0) {
1097
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: (0, import_react_ui13.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No versions" });
1206
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: (0, import_react_ui14.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No versions" });
1098
1207
  }
1099
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("section", { "aria-label": "Version history", className: (0, import_react_ui13.cn)("flex flex-col", className), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("table", { className: "w-full text-sm", children: [
1100
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1101
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Version" }),
1102
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
1103
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Author" }),
1104
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Date" }),
1105
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "sr-only", children: "Actions" }) })
1208
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("section", { "aria-label": "Version history", className: (0, import_react_ui14.cn)("flex flex-col", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("table", { className: "w-full text-sm", children: [
1209
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1210
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Version" }),
1211
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
1212
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Author" }),
1213
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Date" }),
1214
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sr-only", children: "Actions" }) })
1106
1215
  ] }) }),
1107
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tbody", { children: versions.map((version) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b border-border", children: [
1108
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("td", { className: "py-3 pe-4 font-medium text-foreground", children: [
1216
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tbody", { children: versions.map((version) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("tr", { className: "border-b border-border", children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("td", { className: "py-3 pe-4 font-medium text-foreground", children: [
1109
1218
  "v",
1110
1219
  version.versionNumber
1111
1220
  ] }),
1112
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TemplateStatusBadge, { status: version.status }) }),
1113
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: version.createdBy }),
1114
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: version.createdAt }),
1115
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "px-4 py-3 text-end", children: canRollback && version.status === "archived" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1221
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TemplateStatusBadge, { status: version.status }) }),
1222
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: version.createdBy }),
1223
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: version.createdAt }),
1224
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3 text-end", children: canRollback && version.status === "archived" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1116
1225
  "button",
1117
1226
  {
1118
1227
  type: "button",
@@ -1127,39 +1236,39 @@ function TemplateVersionHistory({
1127
1236
  }
1128
1237
 
1129
1238
  // src/delivery-log-viewer.tsx
1130
- var import_react8 = require("react");
1131
- var import_react_ui14 = require("@quanticjs/react-ui");
1239
+ var import_react9 = require("react");
1240
+ var import_react_ui15 = require("@quanticjs/react-ui");
1132
1241
  var import_react_query12 = require("@quanticjs/react-query");
1133
- var import_jsx_runtime15 = require("react/jsx-runtime");
1242
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1134
1243
  var LIMIT = 20;
1135
1244
  function DeliveryLogViewer({
1136
1245
  templateId,
1137
1246
  basePath = "/api/templates",
1138
1247
  className
1139
1248
  }) {
1140
- const [page, setPage] = (0, import_react8.useState)(1);
1249
+ const [page, setPage] = (0, import_react9.useState)(1);
1141
1250
  const { data, isLoading, isError, refetch } = (0, import_react_query12.useApiQuery)(
1142
1251
  ["templates", templateId, "delivery-logs", page],
1143
1252
  (client) => client.get(`${basePath}/${templateId}/delivery-logs?page=${page}&limit=${LIMIT}`)
1144
1253
  );
1145
1254
  if (isLoading) {
1146
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1255
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1147
1256
  "div",
1148
1257
  {
1149
1258
  role: "status",
1150
1259
  "aria-label": "Loading delivery logs",
1151
- className: (0, import_react_ui14.cn)("flex flex-col gap-2 p-4", className),
1260
+ className: (0, import_react_ui15.cn)("flex flex-col gap-2 p-4", className),
1152
1261
  children: [
1153
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sr-only", children: "Loading delivery logs" }),
1154
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1262
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "sr-only", children: "Loading delivery logs" }),
1263
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1155
1264
  ]
1156
1265
  }
1157
1266
  );
1158
1267
  }
1159
1268
  if (isError) {
1160
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: (0, import_react_ui14.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1161
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
1162
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1269
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: (0, import_react_ui15.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1270
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
1271
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1163
1272
  "button",
1164
1273
  {
1165
1274
  type: "button",
@@ -1173,25 +1282,25 @@ function DeliveryLogViewer({
1173
1282
  const rows = data?.items ?? [];
1174
1283
  const totalPages = data?.totalPages ?? 1;
1175
1284
  if (rows.length === 0) {
1176
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: (0, import_react_ui14.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No delivery logs" });
1285
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: (0, import_react_ui15.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No delivery logs" });
1177
1286
  }
1178
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { "aria-label": "Delivery logs", className: (0, import_react_ui14.cn)("flex flex-col gap-3", className), children: [
1179
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("table", { className: "w-full text-sm", children: [
1180
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Recipient" }),
1182
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
1183
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
1184
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last error" })
1287
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("section", { "aria-label": "Delivery logs", className: (0, import_react_ui15.cn)("flex flex-col gap-3", className), children: [
1288
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("table", { className: "w-full text-sm", children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Recipient" }),
1291
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
1292
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
1293
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last error" })
1185
1294
  ] }) }),
1186
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("tr", { className: "border-b border-border", children: [
1187
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.recipientEmail }),
1188
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TemplateStatusBadge, { status: row.status }) }),
1189
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.attempts }),
1190
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastError ?? "\u2014" })
1295
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("tr", { className: "border-b border-border", children: [
1296
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.recipientEmail }),
1297
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TemplateStatusBadge, { status: row.status }) }),
1298
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.attempts }),
1299
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastError ?? "\u2014" })
1191
1300
  ] }, row.id)) })
1192
1301
  ] }),
1193
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("nav", { "aria-label": "Delivery log pagination", className: "flex items-center justify-between", children: [
1194
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1302
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("nav", { "aria-label": "Delivery log pagination", className: "flex items-center justify-between", children: [
1303
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1195
1304
  "button",
1196
1305
  {
1197
1306
  type: "button",
@@ -1201,13 +1310,13 @@ function DeliveryLogViewer({
1201
1310
  children: "Previous"
1202
1311
  }
1203
1312
  ),
1204
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
1313
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
1205
1314
  "Page ",
1206
1315
  page,
1207
1316
  " of ",
1208
1317
  totalPages
1209
1318
  ] }),
1210
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1319
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1211
1320
  "button",
1212
1321
  {
1213
1322
  type: "button",
@@ -1233,9 +1342,9 @@ function useBroadcasts({ page = 1, status, basePath = "/api" } = {}) {
1233
1342
  }
1234
1343
 
1235
1344
  // src/broadcast-list.tsx
1236
- var import_react9 = require("react");
1237
- var import_react_ui15 = require("@quanticjs/react-ui");
1238
- var import_jsx_runtime16 = require("react/jsx-runtime");
1345
+ var import_react10 = require("react");
1346
+ var import_react_ui16 = require("@quanticjs/react-ui");
1347
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1239
1348
  function statusVariant(status) {
1240
1349
  switch (status) {
1241
1350
  case "completed":
@@ -1260,26 +1369,26 @@ function BroadcastList({
1260
1369
  onSelect,
1261
1370
  className
1262
1371
  }) {
1263
- const [page, setPage] = (0, import_react9.useState)(1);
1372
+ const [page, setPage] = (0, import_react10.useState)(1);
1264
1373
  const { data, isLoading, isError, refetch } = useBroadcasts({ page, status, basePath });
1265
1374
  if (isLoading) {
1266
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1375
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1267
1376
  "div",
1268
1377
  {
1269
1378
  role: "status",
1270
1379
  "aria-label": "Loading broadcasts",
1271
- className: (0, import_react_ui15.cn)("flex flex-col gap-2 p-4", className),
1380
+ className: (0, import_react_ui16.cn)("flex flex-col gap-2 p-4", className),
1272
1381
  children: [
1273
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "sr-only", children: "Loading broadcasts" }),
1274
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1382
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "sr-only", children: "Loading broadcasts" }),
1383
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1275
1384
  ]
1276
1385
  }
1277
1386
  );
1278
1387
  }
1279
1388
  if (isError) {
1280
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: (0, import_react_ui15.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1281
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load broadcasts" }),
1282
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1389
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: (0, import_react_ui16.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1390
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load broadcasts" }),
1391
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1283
1392
  "button",
1284
1393
  {
1285
1394
  type: "button",
@@ -1293,9 +1402,9 @@ function BroadcastList({
1293
1402
  const rows = data?.items ?? [];
1294
1403
  const totalPages = data?.totalPages ?? 1;
1295
1404
  if (rows.length === 0) {
1296
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: (0, import_react_ui15.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No broadcasts" });
1405
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: (0, import_react_ui16.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No broadcasts" });
1297
1406
  }
1298
- const renderTemplateCell = (row) => onSelect ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1407
+ const renderTemplateCell = (row) => onSelect ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1299
1408
  "button",
1300
1409
  {
1301
1410
  type: "button",
@@ -1303,34 +1412,34 @@ function BroadcastList({
1303
1412
  className: "rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
1304
1413
  children: row.templateId
1305
1414
  }
1306
- ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-foreground", children: row.templateId });
1307
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("section", { "aria-label": "Broadcasts", className: (0, import_react_ui15.cn)("flex flex-col gap-3", className), children: [
1308
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("table", { className: "w-full text-sm", children: [
1309
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1310
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Template" }),
1311
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
1312
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Channels" }),
1313
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Sent / Failed / Skipped" }),
1314
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created by" }),
1315
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
1415
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-foreground", children: row.templateId });
1416
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { "aria-label": "Broadcasts", className: (0, import_react_ui16.cn)("flex flex-col gap-3", className), children: [
1417
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("table", { className: "w-full text-sm", children: [
1418
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1419
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Template" }),
1420
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
1421
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Channels" }),
1422
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Sent / Failed / Skipped" }),
1423
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created by" }),
1424
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
1316
1425
  ] }) }),
1317
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("tr", { className: "border-b border-border", children: [
1318
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "py-3 pe-4", children: renderTemplateCell(row) }),
1319
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_ui15.StatusBadge, { variant: statusVariant(row.status), children: row.status }) }),
1320
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.channels.length > 0 ? row.channels.join(", ") : "\u2014" }),
1321
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("td", { className: "px-4 py-3 text-muted-foreground", children: [
1426
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("tr", { className: "border-b border-border", children: [
1427
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "py-3 pe-4", children: renderTemplateCell(row) }),
1428
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_ui16.StatusBadge, { variant: statusVariant(row.status), children: row.status }) }),
1429
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.channels.length > 0 ? row.channels.join(", ") : "\u2014" }),
1430
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("td", { className: "px-4 py-3 text-muted-foreground", children: [
1322
1431
  row.sentCount,
1323
1432
  " / ",
1324
1433
  row.failedCount,
1325
1434
  " / ",
1326
1435
  row.skippedCount
1327
1436
  ] }),
1328
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.createdBy }),
1329
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui15.formatDateTime)(row.createdAt) })
1437
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.createdBy }),
1438
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui16.formatDateTime)(row.createdAt) })
1330
1439
  ] }, row.id)) })
1331
1440
  ] }),
1332
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("nav", { "aria-label": "Broadcast pagination", className: "flex items-center justify-between", children: [
1333
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1441
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("nav", { "aria-label": "Broadcast pagination", className: "flex items-center justify-between", children: [
1442
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1334
1443
  "button",
1335
1444
  {
1336
1445
  type: "button",
@@ -1340,13 +1449,13 @@ function BroadcastList({
1340
1449
  children: "Previous"
1341
1450
  }
1342
1451
  ),
1343
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
1344
1453
  "Page ",
1345
1454
  page,
1346
1455
  " of ",
1347
1456
  totalPages
1348
1457
  ] }),
1349
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1458
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1350
1459
  "button",
1351
1460
  {
1352
1461
  type: "button",
@@ -1361,9 +1470,9 @@ function BroadcastList({
1361
1470
  }
1362
1471
 
1363
1472
  // src/broadcast-progress.tsx
1364
- var import_react_ui16 = require("@quanticjs/react-ui");
1473
+ var import_react_ui17 = require("@quanticjs/react-ui");
1365
1474
  var import_react_query14 = require("@quanticjs/react-query");
1366
- var import_jsx_runtime17 = require("react/jsx-runtime");
1475
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1367
1476
  var TERMINAL_STATUSES = ["completed", "completed_with_errors", "failed", "cancelled"];
1368
1477
  function isTerminalStatus(status) {
1369
1478
  return status !== void 0 && TERMINAL_STATUSES.includes(status);
@@ -1388,7 +1497,7 @@ function BroadcastProgress({
1388
1497
  onCancelled,
1389
1498
  className
1390
1499
  }) {
1391
- const toast = (0, import_react_ui16.useToast)();
1500
+ const toast = (0, import_react_ui17.useToast)();
1392
1501
  const { data, isLoading, isError, refetch } = (0, import_react_query14.useApiQuery)(
1393
1502
  ["broadcasts", broadcastId],
1394
1503
  (client) => client.get(`${basePath}/v1/broadcasts/${broadcastId}`),
@@ -1410,23 +1519,23 @@ function BroadcastProgress({
1410
1519
  }
1411
1520
  );
1412
1521
  if (isLoading) {
1413
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1522
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1414
1523
  "div",
1415
1524
  {
1416
1525
  role: "status",
1417
1526
  "aria-label": "Loading broadcast",
1418
- className: (0, import_react_ui16.cn)("flex flex-col gap-2 p-4", className),
1527
+ className: (0, import_react_ui17.cn)("flex flex-col gap-2 p-4", className),
1419
1528
  children: [
1420
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "sr-only", children: "Loading broadcast" }),
1421
- [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1529
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sr-only", children: "Loading broadcast" }),
1530
+ [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1422
1531
  ]
1423
1532
  }
1424
1533
  );
1425
1534
  }
1426
1535
  if (isError) {
1427
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: (0, import_react_ui16.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1428
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load broadcast" }),
1429
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1536
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: (0, import_react_ui17.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1537
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load broadcast" }),
1538
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1430
1539
  "button",
1431
1540
  {
1432
1541
  type: "button",
@@ -1438,21 +1547,21 @@ function BroadcastProgress({
1438
1547
  ] });
1439
1548
  }
1440
1549
  if (!data) {
1441
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: (0, import_react_ui16.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No broadcast" });
1550
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: (0, import_react_ui17.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No broadcast" });
1442
1551
  }
1443
1552
  const total = data.totalRecipients;
1444
1553
  const processed = data.sentCount + data.failedCount + data.skippedCount;
1445
1554
  const pct3 = total > 0 ? Math.min(100, Math.round(processed / total * 100)) : 0;
1446
1555
  const terminal = isTerminalStatus(data.status);
1447
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { "aria-label": "Broadcast progress", className: (0, import_react_ui16.cn)("flex flex-col gap-4 p-4", className), children: [
1448
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("header", { className: "flex items-center justify-between", children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("h2", { className: "text-sm font-semibold text-foreground", children: [
1556
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { "aria-label": "Broadcast progress", className: (0, import_react_ui17.cn)("flex flex-col gap-4 p-4", className), children: [
1557
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("header", { className: "flex items-center justify-between", children: [
1558
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("h2", { className: "text-sm font-semibold text-foreground", children: [
1450
1559
  "Broadcast ",
1451
1560
  data.templateId
1452
1561
  ] }),
1453
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_ui16.StatusBadge, { variant: statusVariant2(data.status), appearance: "solid", children: data.status })
1562
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_ui17.StatusBadge, { variant: statusVariant2(data.status), appearance: "solid", children: data.status })
1454
1563
  ] }),
1455
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1564
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1456
1565
  "div",
1457
1566
  {
1458
1567
  role: "progressbar",
@@ -1461,10 +1570,10 @@ function BroadcastProgress({
1461
1570
  "aria-valuemax": 100,
1462
1571
  "aria-label": "Broadcast completion",
1463
1572
  className: "h-2 w-full overflow-hidden rounded-full bg-muted",
1464
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "h-full rounded-full bg-primary", style: { width: `${pct3}%` } })
1573
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "h-full rounded-full bg-primary", style: { width: `${pct3}%` } })
1465
1574
  }
1466
1575
  ),
1467
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
1576
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
1468
1577
  processed,
1469
1578
  " of ",
1470
1579
  total,
@@ -1472,25 +1581,25 @@ function BroadcastProgress({
1472
1581
  pct3,
1473
1582
  "%)"
1474
1583
  ] }),
1475
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("dl", { className: "grid grid-cols-2 gap-3 text-sm sm:grid-cols-4", children: [
1476
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1477
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Sent" }),
1478
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { className: "text-foreground", children: data.sentCount })
1584
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("dl", { className: "grid grid-cols-2 gap-3 text-sm sm:grid-cols-4", children: [
1585
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1586
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Sent" }),
1587
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: "text-foreground", children: data.sentCount })
1479
1588
  ] }),
1480
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1481
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Failed" }),
1482
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { className: "text-foreground", children: data.failedCount })
1589
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1590
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Failed" }),
1591
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: "text-foreground", children: data.failedCount })
1483
1592
  ] }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1485
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Skipped" }),
1486
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { className: "text-foreground", children: data.skippedCount })
1593
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1594
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Skipped" }),
1595
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: "text-foreground", children: data.skippedCount })
1487
1596
  ] }),
1488
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1489
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Total" }),
1490
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { className: "text-foreground", children: total })
1597
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col rounded-md border border-border bg-card p-3", children: [
1598
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { className: "text-xs text-muted-foreground", children: "Total" }),
1599
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: "text-foreground", children: total })
1491
1600
  ] })
1492
1601
  ] }),
1493
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1602
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1494
1603
  "button",
1495
1604
  {
1496
1605
  type: "button",
@@ -1504,10 +1613,10 @@ function BroadcastProgress({
1504
1613
  }
1505
1614
 
1506
1615
  // src/broadcast-composer.tsx
1507
- var import_react10 = require("react");
1508
- var import_react_ui17 = require("@quanticjs/react-ui");
1616
+ var import_react11 = require("react");
1617
+ var import_react_ui18 = require("@quanticjs/react-ui");
1509
1618
  var import_react_query15 = require("@quanticjs/react-query");
1510
- var import_jsx_runtime18 = require("react/jsx-runtime");
1619
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1511
1620
  var CHANNELS2 = ["inapp", "email", "push", "sms", "webhook", "slack", "teams"];
1512
1621
  function normalizeList(data) {
1513
1622
  if (!data) return [];
@@ -1522,15 +1631,15 @@ function BroadcastComposer({
1522
1631
  onCreated,
1523
1632
  className
1524
1633
  }) {
1525
- const toast = (0, import_react_ui17.useToast)();
1526
- const [idempotencyKey] = (0, import_react10.useState)(() => crypto.randomUUID());
1527
- const [templateId, setTemplateId] = (0, import_react10.useState)("");
1528
- const [channels, setChannels] = (0, import_react10.useState)([]);
1529
- const [audienceMode, setAudienceMode] = (0, import_react10.useState)("segment");
1530
- const [segmentId, setSegmentId] = (0, import_react10.useState)("");
1531
- const [recipientsRaw, setRecipientsRaw] = (0, import_react10.useState)("");
1532
- const [type, setType] = (0, import_react10.useState)("");
1533
- const [errors, setErrors] = (0, import_react10.useState)({});
1634
+ const toast = (0, import_react_ui18.useToast)();
1635
+ const [idempotencyKey] = (0, import_react11.useState)(() => crypto.randomUUID());
1636
+ const [templateId, setTemplateId] = (0, import_react11.useState)("");
1637
+ const [channels, setChannels] = (0, import_react11.useState)([]);
1638
+ const [audienceMode, setAudienceMode] = (0, import_react11.useState)("segment");
1639
+ const [segmentId, setSegmentId] = (0, import_react11.useState)("");
1640
+ const [recipientsRaw, setRecipientsRaw] = (0, import_react11.useState)("");
1641
+ const [type, setType] = (0, import_react11.useState)("");
1642
+ const [errors, setErrors] = (0, import_react11.useState)({});
1534
1643
  const templatesQuery = (0, import_react_query15.useApiQuery)(
1535
1644
  ["templates"],
1536
1645
  (client) => client.get(`${basePath}/templates`)
@@ -1555,23 +1664,23 @@ function BroadcastComposer({
1555
1664
  const isLoading = templatesQuery.isLoading || segmentsQuery.isLoading;
1556
1665
  const isError = templatesQuery.isError || segmentsQuery.isError;
1557
1666
  if (isLoading) {
1558
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1667
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1559
1668
  "div",
1560
1669
  {
1561
1670
  role: "status",
1562
1671
  "aria-label": "Loading broadcast composer",
1563
- className: (0, import_react_ui17.cn)("flex flex-col gap-2 p-4", className),
1672
+ className: (0, import_react_ui18.cn)("flex flex-col gap-2 p-4", className),
1564
1673
  children: [
1565
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sr-only", children: "Loading broadcast composer" }),
1566
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1674
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "sr-only", children: "Loading broadcast composer" }),
1675
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1567
1676
  ]
1568
1677
  }
1569
1678
  );
1570
1679
  }
1571
1680
  if (isError) {
1572
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: (0, import_react_ui17.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1573
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load broadcast composer" }),
1574
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1681
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: (0, import_react_ui18.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1682
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load broadcast composer" }),
1683
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1575
1684
  "button",
1576
1685
  {
1577
1686
  type: "button",
@@ -1618,11 +1727,11 @@ function BroadcastComposer({
1618
1727
  idempotencyKey
1619
1728
  });
1620
1729
  };
1621
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("form", { onSubmit, className: (0, import_react_ui17.cn)("flex flex-col gap-4 p-4", className), noValidate: true, children: [
1622
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "New broadcast" }),
1623
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col gap-1", children: [
1624
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { htmlFor: "composer-template", className: "text-sm font-medium text-foreground", children: "Template" }),
1625
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1730
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("form", { onSubmit, className: (0, import_react_ui18.cn)("flex flex-col gap-4 p-4", className), noValidate: true, children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "New broadcast" }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-1", children: [
1733
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { htmlFor: "composer-template", className: "text-sm font-medium text-foreground", children: "Template" }),
1734
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1626
1735
  "select",
1627
1736
  {
1628
1737
  id: "composer-template",
@@ -1632,30 +1741,30 @@ function BroadcastComposer({
1632
1741
  onChange: (e) => setTemplateId(e.target.value),
1633
1742
  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",
1634
1743
  children: [
1635
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "Select a template\u2026" }),
1636
- templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: t.id, children: t.name ?? t.id }, t.id))
1744
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Select a template\u2026" }),
1745
+ templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: t.id, children: t.name ?? t.id }, t.id))
1637
1746
  ]
1638
1747
  }
1639
1748
  ),
1640
- errors.templateId && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { id: "composer-template-error", className: "text-xs text-destructive", children: errors.templateId })
1749
+ errors.templateId && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { id: "composer-template-error", className: "text-xs text-destructive", children: errors.templateId })
1641
1750
  ] }),
1642
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1751
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1643
1752
  "fieldset",
1644
1753
  {
1645
1754
  className: "flex flex-col gap-2",
1646
1755
  "aria-invalid": errors.channels ? "true" : void 0,
1647
1756
  "aria-describedby": errors.channels ? "composer-channels-error" : void 0,
1648
1757
  children: [
1649
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("legend", { className: "text-sm font-medium text-foreground", children: "Channels" }),
1650
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex flex-wrap gap-3", children: CHANNELS2.map((channel) => {
1758
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("legend", { className: "text-sm font-medium text-foreground", children: "Channels" }),
1759
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-wrap gap-3", children: CHANNELS2.map((channel) => {
1651
1760
  const checkboxId = `composer-channel-${channel}`;
1652
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1761
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1653
1762
  "label",
1654
1763
  {
1655
1764
  htmlFor: checkboxId,
1656
1765
  className: "flex items-center gap-2 text-sm text-foreground",
1657
1766
  children: [
1658
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1767
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1659
1768
  "input",
1660
1769
  {
1661
1770
  id: checkboxId,
@@ -1671,20 +1780,20 @@ function BroadcastComposer({
1671
1780
  channel
1672
1781
  );
1673
1782
  }) }),
1674
- errors.channels && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { id: "composer-channels-error", className: "text-xs text-destructive", children: errors.channels })
1783
+ errors.channels && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { id: "composer-channels-error", className: "text-xs text-destructive", children: errors.channels })
1675
1784
  ]
1676
1785
  }
1677
1786
  ),
1678
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("fieldset", { className: "flex flex-col gap-2", children: [
1679
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("legend", { className: "text-sm font-medium text-foreground", children: "Audience" }),
1680
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex gap-4", children: [
1681
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1787
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("fieldset", { className: "flex flex-col gap-2", children: [
1788
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("legend", { className: "text-sm font-medium text-foreground", children: "Audience" }),
1789
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-4", children: [
1790
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1682
1791
  "label",
1683
1792
  {
1684
1793
  htmlFor: "composer-audience-segment",
1685
1794
  className: "flex items-center gap-2 text-sm text-foreground",
1686
1795
  children: [
1687
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1796
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1688
1797
  "input",
1689
1798
  {
1690
1799
  id: "composer-audience-segment",
@@ -1699,13 +1808,13 @@ function BroadcastComposer({
1699
1808
  ]
1700
1809
  }
1701
1810
  ),
1702
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1811
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1703
1812
  "label",
1704
1813
  {
1705
1814
  htmlFor: "composer-audience-recipients",
1706
1815
  className: "flex items-center gap-2 text-sm text-foreground",
1707
1816
  children: [
1708
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1817
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1709
1818
  "input",
1710
1819
  {
1711
1820
  id: "composer-audience-recipients",
@@ -1721,7 +1830,7 @@ function BroadcastComposer({
1721
1830
  }
1722
1831
  )
1723
1832
  ] }),
1724
- audienceMode === "segment" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1833
+ audienceMode === "segment" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1725
1834
  "select",
1726
1835
  {
1727
1836
  id: "composer-segment",
@@ -1732,11 +1841,11 @@ function BroadcastComposer({
1732
1841
  onChange: (e) => setSegmentId(e.target.value),
1733
1842
  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",
1734
1843
  children: [
1735
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "Select a segment\u2026" }),
1736
- segments.map((s) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: s.id, children: s.name }, s.id))
1844
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Select a segment\u2026" }),
1845
+ segments.map((s) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: s.id, children: s.name }, s.id))
1737
1846
  ]
1738
1847
  }
1739
- ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1848
+ ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1740
1849
  "textarea",
1741
1850
  {
1742
1851
  id: "composer-recipients",
@@ -1750,11 +1859,11 @@ function BroadcastComposer({
1750
1859
  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"
1751
1860
  }
1752
1861
  ),
1753
- errors.audience && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { id: "composer-audience-error", className: "text-xs text-destructive", children: errors.audience })
1862
+ errors.audience && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { id: "composer-audience-error", className: "text-xs text-destructive", children: errors.audience })
1754
1863
  ] }),
1755
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col gap-1", children: [
1756
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { htmlFor: "composer-type", className: "text-sm font-medium text-foreground", children: "Type (optional)" }),
1757
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1864
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-1", children: [
1865
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { htmlFor: "composer-type", className: "text-sm font-medium text-foreground", children: "Type (optional)" }),
1866
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1758
1867
  "input",
1759
1868
  {
1760
1869
  id: "composer-type",
@@ -1765,7 +1874,7 @@ function BroadcastComposer({
1765
1874
  }
1766
1875
  )
1767
1876
  ] }),
1768
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1877
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1769
1878
  "button",
1770
1879
  {
1771
1880
  type: "submit",
@@ -1778,9 +1887,9 @@ function BroadcastComposer({
1778
1887
  }
1779
1888
 
1780
1889
  // src/segment-list.tsx
1781
- var import_react_ui18 = require("@quanticjs/react-ui");
1890
+ var import_react_ui19 = require("@quanticjs/react-ui");
1782
1891
  var import_react_query16 = require("@quanticjs/react-query");
1783
- var import_jsx_runtime19 = require("react/jsx-runtime");
1892
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1784
1893
  function normalize(data) {
1785
1894
  if (Array.isArray(data)) return data;
1786
1895
  return data?.items ?? [];
@@ -1806,23 +1915,23 @@ function SegmentList({
1806
1915
  (client) => client.get(`${basePath}/v1/segments`)
1807
1916
  );
1808
1917
  if (isLoading) {
1809
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1918
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1810
1919
  "div",
1811
1920
  {
1812
1921
  role: "status",
1813
1922
  "aria-label": "Loading segments",
1814
- className: (0, import_react_ui18.cn)("flex flex-col gap-2 p-4", className),
1923
+ className: (0, import_react_ui19.cn)("flex flex-col gap-2 p-4", className),
1815
1924
  children: [
1816
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "sr-only", children: "Loading segments" }),
1817
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1925
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "sr-only", children: "Loading segments" }),
1926
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
1818
1927
  ]
1819
1928
  }
1820
1929
  );
1821
1930
  }
1822
1931
  if (isError) {
1823
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: (0, import_react_ui18.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1824
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load segments" }),
1825
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1932
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: (0, import_react_ui19.cn)("flex flex-col items-start gap-3 p-4", className), children: [
1933
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load segments" }),
1934
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1826
1935
  "button",
1827
1936
  {
1828
1937
  type: "button",
@@ -1834,7 +1943,7 @@ function SegmentList({
1834
1943
  ] });
1835
1944
  }
1836
1945
  const rows = normalize(data);
1837
- const header = onCreate ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("header", { className: "flex items-center justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1946
+ const header = onCreate ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("header", { className: "flex items-center justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1838
1947
  "button",
1839
1948
  {
1840
1949
  type: "button",
@@ -1844,12 +1953,12 @@ function SegmentList({
1844
1953
  }
1845
1954
  ) }) : null;
1846
1955
  if (rows.length === 0) {
1847
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "aria-label": "Segments", className: (0, import_react_ui18.cn)("flex flex-col gap-3", className), children: [
1956
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "aria-label": "Segments", className: (0, import_react_ui19.cn)("flex flex-col gap-3", className), children: [
1848
1957
  header,
1849
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No segments" })
1958
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No segments" })
1850
1959
  ] });
1851
1960
  }
1852
- const renderNameCell = (row) => onSelect ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1961
+ const renderNameCell = (row) => onSelect ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1853
1962
  "button",
1854
1963
  {
1855
1964
  type: "button",
@@ -1857,33 +1966,33 @@ function SegmentList({
1857
1966
  className: "rounded text-start font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
1858
1967
  children: row.name
1859
1968
  }
1860
- ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-foreground", children: row.name });
1861
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "aria-label": "Segments", className: (0, import_react_ui18.cn)("flex flex-col gap-3", className), children: [
1969
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-foreground", children: row.name });
1970
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "aria-label": "Segments", className: (0, import_react_ui19.cn)("flex flex-col gap-3", className), children: [
1862
1971
  header,
1863
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("table", { className: "w-full text-sm", children: [
1864
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1865
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
1866
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" }),
1867
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Description" }),
1868
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipients" }),
1869
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
1972
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("table", { className: "w-full text-sm", children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
1974
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
1975
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" }),
1976
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Description" }),
1977
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipients" }),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
1870
1979
  ] }) }),
1871
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("tr", { className: "border-b border-border", children: [
1872
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "py-3 pe-4", children: renderNameCell(row) }),
1873
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_ui18.StatusBadge, { variant: typeVariant(row.type), appearance: "dot", children: row.type }) }),
1874
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.description ?? "\u2014" }),
1875
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.recipientIds?.length ?? "\u2014" }),
1876
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui18.formatDateTime)(row.createdAt) })
1980
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("tr", { className: "border-b border-border", children: [
1981
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { className: "py-3 pe-4", children: renderNameCell(row) }),
1982
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_ui19.StatusBadge, { variant: typeVariant(row.type), appearance: "dot", children: row.type }) }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.description ?? "\u2014" }),
1984
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.recipientIds?.length ?? "\u2014" }),
1985
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui19.formatDateTime)(row.createdAt) })
1877
1986
  ] }, row.id)) })
1878
1987
  ] })
1879
1988
  ] });
1880
1989
  }
1881
1990
 
1882
1991
  // src/segment-builder.tsx
1883
- var import_react11 = require("react");
1884
- var import_react_ui19 = require("@quanticjs/react-ui");
1992
+ var import_react12 = require("react");
1993
+ var import_react_ui20 = require("@quanticjs/react-ui");
1885
1994
  var import_react_query17 = require("@quanticjs/react-query");
1886
- var import_jsx_runtime20 = require("react/jsx-runtime");
1995
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1887
1996
  function parseRecipientIds(value) {
1888
1997
  return value.split(/[\n,]/).map((id) => id.trim()).filter((id) => id.length > 0);
1889
1998
  }
@@ -1895,12 +2004,12 @@ function SegmentBuilder({
1895
2004
  onDeleted,
1896
2005
  className
1897
2006
  }) {
1898
- const toast = (0, import_react_ui19.useToast)();
1899
- const [name, setName] = (0, import_react11.useState)(initial?.name ?? "");
1900
- const [type, setType] = (0, import_react11.useState)(initial?.type ?? "static");
1901
- const [description, setDescription] = (0, import_react11.useState)(initial?.description ?? "");
1902
- const [recipientText, setRecipientText] = (0, import_react11.useState)((initial?.recipientIds ?? []).join("\n"));
1903
- const [errors, setErrors] = (0, import_react11.useState)({});
2007
+ const toast = (0, import_react_ui20.useToast)();
2008
+ const [name, setName] = (0, import_react12.useState)(initial?.name ?? "");
2009
+ const [type, setType] = (0, import_react12.useState)(initial?.type ?? "static");
2010
+ const [description, setDescription] = (0, import_react12.useState)(initial?.description ?? "");
2011
+ const [recipientText, setRecipientText] = (0, import_react12.useState)((initial?.recipientIds ?? []).join("\n"));
2012
+ const [errors, setErrors] = (0, import_react12.useState)({});
1904
2013
  const isEdit = Boolean(segmentId);
1905
2014
  const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
1906
2015
  description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
@@ -1949,11 +2058,11 @@ function SegmentBuilder({
1949
2058
  if (!window.confirm("Delete this segment? This cannot be undone.")) return;
1950
2059
  remove.mutate();
1951
2060
  };
1952
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("form", { onSubmit, className: (0, import_react_ui19.cn)("flex flex-col gap-4", className), noValidate: true, children: [
1953
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("header", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: isEdit ? `Edit segment: ${segmentId}` : "New segment" }) }),
1954
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-1", children: [
1955
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "segment-name", className: "text-sm font-medium text-foreground", children: "Name" }),
1956
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2061
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("form", { onSubmit, className: (0, import_react_ui20.cn)("flex flex-col gap-4", className), noValidate: true, children: [
2062
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("header", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: isEdit ? `Edit segment: ${segmentId}` : "New segment" }) }),
2063
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2064
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "segment-name", className: "text-sm font-medium text-foreground", children: "Name" }),
2065
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1957
2066
  "input",
1958
2067
  {
1959
2068
  id: "segment-name",
@@ -1965,11 +2074,11 @@ function SegmentBuilder({
1965
2074
  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"
1966
2075
  }
1967
2076
  ),
1968
- errors.name && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { id: "segment-name-error", className: "text-xs text-destructive", children: errors.name })
2077
+ errors.name && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { id: "segment-name-error", className: "text-xs text-destructive", children: errors.name })
1969
2078
  ] }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-1", children: [
1971
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "segment-type", className: "text-sm font-medium text-foreground", children: "Type" }),
1972
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2079
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2080
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "segment-type", className: "text-sm font-medium text-foreground", children: "Type" }),
2081
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1973
2082
  "select",
1974
2083
  {
1975
2084
  id: "segment-type",
@@ -1977,15 +2086,15 @@ function SegmentBuilder({
1977
2086
  onChange: (e) => setType(e.target.value),
1978
2087
  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",
1979
2088
  children: [
1980
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "static", children: "static" }),
1981
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "dynamic", children: "dynamic" })
2089
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "static", children: "static" }),
2090
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "dynamic", children: "dynamic" })
1982
2091
  ]
1983
2092
  }
1984
2093
  )
1985
2094
  ] }),
1986
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-1", children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "segment-description", className: "text-sm font-medium text-foreground", children: "Description" }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2095
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2096
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "segment-description", className: "text-sm font-medium text-foreground", children: "Description" }),
2097
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1989
2098
  "textarea",
1990
2099
  {
1991
2100
  id: "segment-description",
@@ -1996,9 +2105,9 @@ function SegmentBuilder({
1996
2105
  }
1997
2106
  )
1998
2107
  ] }),
1999
- type === "static" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-1", children: [
2000
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "segment-recipients", className: "text-sm font-medium text-foreground", children: "Recipient ids" }),
2001
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2108
+ type === "static" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2109
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "segment-recipients", className: "text-sm font-medium text-foreground", children: "Recipient ids" }),
2110
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2002
2111
  "textarea",
2003
2112
  {
2004
2113
  id: "segment-recipients",
@@ -2011,10 +2120,10 @@ function SegmentBuilder({
2011
2120
  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"
2012
2121
  }
2013
2122
  ),
2014
- errors.recipientIds && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { id: "segment-recipients-error", className: "text-xs text-destructive", children: errors.recipientIds })
2123
+ errors.recipientIds && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { id: "segment-recipients-error", className: "text-xs text-destructive", children: errors.recipientIds })
2015
2124
  ] }),
2016
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-3", children: [
2017
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2125
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-3", children: [
2126
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2018
2127
  "button",
2019
2128
  {
2020
2129
  type: "submit",
@@ -2023,7 +2132,7 @@ function SegmentBuilder({
2023
2132
  children: save.isPending ? "Saving\u2026" : isEdit ? "Save changes" : "Create segment"
2024
2133
  }
2025
2134
  ),
2026
- isEdit && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2135
+ isEdit && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2027
2136
  "button",
2028
2137
  {
2029
2138
  type: "button",
@@ -2038,18 +2147,18 @@ function SegmentBuilder({
2038
2147
  }
2039
2148
 
2040
2149
  // src/suppression-manager.tsx
2041
- var import_react12 = require("react");
2042
- var import_react_ui20 = require("@quanticjs/react-ui");
2150
+ var import_react13 = require("react");
2151
+ var import_react_ui21 = require("@quanticjs/react-ui");
2043
2152
  var import_react_query18 = require("@quanticjs/react-query");
2044
- var import_jsx_runtime21 = require("react/jsx-runtime");
2153
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2045
2154
  var LIMIT3 = 20;
2046
2155
  var CHANNELS3 = ["inapp", "email", "push", "sms"];
2047
2156
  function SuppressionManager({ basePath = "/api", className }) {
2048
- const toast = (0, import_react_ui20.useToast)();
2049
- const [page, setPage] = (0, import_react12.useState)(1);
2050
- const [channel, setChannel] = (0, import_react12.useState)("email");
2051
- const [address, setAddress] = (0, import_react12.useState)("");
2052
- const [reason, setReason] = (0, import_react12.useState)("");
2157
+ const toast = (0, import_react_ui21.useToast)();
2158
+ const [page, setPage] = (0, import_react13.useState)(1);
2159
+ const [channel, setChannel] = (0, import_react13.useState)("email");
2160
+ const [address, setAddress] = (0, import_react13.useState)("");
2161
+ const [reason, setReason] = (0, import_react13.useState)("");
2053
2162
  const { data, isLoading, isError, refetch } = (0, import_react_query18.useApiQuery)(
2054
2163
  ["suppression", page],
2055
2164
  (client) => client.get(`${basePath}/v1/admin/suppression?page=${page}&limit=${LIMIT3}`)
@@ -2085,23 +2194,23 @@ function SuppressionManager({ basePath = "/api", className }) {
2085
2194
  event.preventDefault();
2086
2195
  add.mutate({ channel, address: address.trim(), reason: reason.trim() });
2087
2196
  };
2088
- const addForm = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
2089
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2090
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "suppression-channel", className: "text-sm font-medium text-foreground", children: "Channel" }),
2091
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2197
+ const addForm = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
2198
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-1", children: [
2199
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: "suppression-channel", className: "text-sm font-medium text-foreground", children: "Channel" }),
2200
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2092
2201
  "select",
2093
2202
  {
2094
2203
  id: "suppression-channel",
2095
2204
  value: channel,
2096
2205
  onChange: (e) => setChannel(e.target.value),
2097
2206
  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",
2098
- children: CHANNELS3.map((c) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: c, children: c }, c))
2207
+ children: CHANNELS3.map((c) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: c, children: c }, c))
2099
2208
  }
2100
2209
  )
2101
2210
  ] }),
2102
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2103
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "suppression-address", className: "text-sm font-medium text-foreground", children: "Address" }),
2104
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2211
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-1", children: [
2212
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: "suppression-address", className: "text-sm font-medium text-foreground", children: "Address" }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2105
2214
  "input",
2106
2215
  {
2107
2216
  id: "suppression-address",
@@ -2112,9 +2221,9 @@ function SuppressionManager({ basePath = "/api", className }) {
2112
2221
  }
2113
2222
  )
2114
2223
  ] }),
2115
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
2116
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "suppression-reason", className: "text-sm font-medium text-foreground", children: "Reason" }),
2117
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2224
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-1", children: [
2225
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: "suppression-reason", className: "text-sm font-medium text-foreground", children: "Reason" }),
2226
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2118
2227
  "input",
2119
2228
  {
2120
2229
  id: "suppression-reason",
@@ -2125,7 +2234,7 @@ function SuppressionManager({ basePath = "/api", className }) {
2125
2234
  }
2126
2235
  )
2127
2236
  ] }),
2128
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2237
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2129
2238
  "button",
2130
2239
  {
2131
2240
  type: "submit",
@@ -2137,14 +2246,14 @@ function SuppressionManager({ basePath = "/api", className }) {
2137
2246
  ] });
2138
2247
  let body;
2139
2248
  if (isLoading) {
2140
- body = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { role: "status", "aria-label": "Loading suppressions", className: "flex flex-col gap-2 p-4", children: [
2141
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "sr-only", children: "Loading suppressions" }),
2142
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2249
+ body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { role: "status", "aria-label": "Loading suppressions", className: "flex flex-col gap-2 p-4", children: [
2250
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Loading suppressions" }),
2251
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2143
2252
  ] });
2144
2253
  } else if (isError) {
2145
- body = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2146
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load suppressions" }),
2147
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2254
+ body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2255
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load suppressions" }),
2256
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2148
2257
  "button",
2149
2258
  {
2150
2259
  type: "button",
@@ -2158,23 +2267,23 @@ function SuppressionManager({ basePath = "/api", className }) {
2158
2267
  const rows = data?.items ?? [];
2159
2268
  const totalPages = data?.totalPages ?? 1;
2160
2269
  if (rows.length === 0) {
2161
- body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No suppressions" });
2270
+ body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No suppressions" });
2162
2271
  } else {
2163
- body = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2164
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("table", { className: "w-full text-sm", children: [
2165
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2166
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
2167
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Address" }),
2168
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Reason" }),
2169
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
2170
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "sr-only", children: "Actions" }) })
2272
+ body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2273
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("table", { className: "w-full text-sm", children: [
2274
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2275
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
2276
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Address" }),
2277
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Reason" }),
2278
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
2279
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Actions" }) })
2171
2280
  ] }) }),
2172
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("tr", { className: "border-b border-border", children: [
2173
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.channel }),
2174
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.address }),
2175
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.reason }),
2176
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui20.formatDateTime)(row.createdAt) }),
2177
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2281
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("tr", { className: "border-b border-border", children: [
2282
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.channel }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.address }),
2284
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.reason }),
2285
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui21.formatDateTime)(row.createdAt) }),
2286
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2178
2287
  "button",
2179
2288
  {
2180
2289
  type: "button",
@@ -2186,8 +2295,8 @@ function SuppressionManager({ basePath = "/api", className }) {
2186
2295
  ) })
2187
2296
  ] }, row.id)) })
2188
2297
  ] }),
2189
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("nav", { "aria-label": "Suppression pagination", className: "flex items-center justify-between", children: [
2190
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2298
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("nav", { "aria-label": "Suppression pagination", className: "flex items-center justify-between", children: [
2299
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2191
2300
  "button",
2192
2301
  {
2193
2302
  type: "button",
@@ -2197,13 +2306,13 @@ function SuppressionManager({ basePath = "/api", className }) {
2197
2306
  children: "Previous"
2198
2307
  }
2199
2308
  ),
2200
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
2309
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
2201
2310
  "Page ",
2202
2311
  page,
2203
2312
  " of ",
2204
2313
  totalPages
2205
2314
  ] }),
2206
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2315
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2207
2316
  "button",
2208
2317
  {
2209
2318
  type: "button",
@@ -2217,17 +2326,17 @@ function SuppressionManager({ basePath = "/api", className }) {
2217
2326
  ] });
2218
2327
  }
2219
2328
  }
2220
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { "aria-label": "Suppression list", className: (0, import_react_ui20.cn)("flex flex-col gap-4", className), children: [
2329
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("section", { "aria-label": "Suppression list", className: (0, import_react_ui21.cn)("flex flex-col gap-4", className), children: [
2221
2330
  addForm,
2222
2331
  body
2223
2332
  ] });
2224
2333
  }
2225
2334
 
2226
2335
  // src/dlq-console.tsx
2227
- var import_react13 = require("react");
2228
- var import_react_ui21 = require("@quanticjs/react-ui");
2336
+ var import_react14 = require("react");
2337
+ var import_react_ui22 = require("@quanticjs/react-ui");
2229
2338
  var import_react_query19 = require("@quanticjs/react-query");
2230
- var import_jsx_runtime22 = require("react/jsx-runtime");
2339
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2231
2340
  var LIMIT4 = 20;
2232
2341
  var STATUS_FILTERS = ["queued", "replayed", "discarded"];
2233
2342
  function buildErrorDescription(error) {
@@ -2251,15 +2360,15 @@ function DlqMessageDetailRow({ id, basePath }) {
2251
2360
  (client) => client.get(`${basePath}/admin/dlq/${id}`)
2252
2361
  );
2253
2362
  if (isLoading) {
2254
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { role: "status", "aria-label": "Loading message detail", className: "flex flex-col gap-2 p-3", children: [
2255
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Loading message detail" }),
2256
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "aria-hidden": "true", className: "h-16 animate-pulse rounded bg-muted" })
2363
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "status", "aria-label": "Loading message detail", className: "flex flex-col gap-2 p-3", children: [
2364
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: "Loading message detail" }),
2365
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "aria-hidden": "true", className: "h-16 animate-pulse rounded bg-muted" })
2257
2366
  ] });
2258
2367
  }
2259
2368
  if (isError) {
2260
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col items-start gap-3 p-3", children: [
2261
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load message detail" }),
2262
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2369
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col items-start gap-3 p-3", children: [
2370
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load message detail" }),
2371
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2263
2372
  "button",
2264
2373
  {
2265
2374
  type: "button",
@@ -2270,19 +2379,19 @@ function DlqMessageDetailRow({ id, basePath }) {
2270
2379
  )
2271
2380
  ] });
2272
2381
  }
2273
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-2 p-3 text-sm", children: [
2274
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { className: "text-muted-foreground", children: [
2382
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-2 p-3 text-sm", children: [
2383
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { className: "text-muted-foreground", children: [
2275
2384
  "Error: ",
2276
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-foreground", children: data?.errorMessage ?? "\u2014" })
2385
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-foreground", children: data?.errorMessage ?? "\u2014" })
2277
2386
  ] }),
2278
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("pre", { className: "max-h-64 overflow-auto rounded bg-muted p-3 text-xs text-foreground", children: JSON.stringify(data?.payload ?? {}, null, 2) })
2387
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "max-h-64 overflow-auto rounded bg-muted p-3 text-xs text-foreground", children: JSON.stringify(data?.payload ?? {}, null, 2) })
2279
2388
  ] });
2280
2389
  }
2281
2390
  function DlqConsole({ basePath = "/api", className }) {
2282
- const toast = (0, import_react_ui21.useToast)();
2283
- const [page, setPage] = (0, import_react13.useState)(1);
2284
- const [statusFilter, setStatusFilter] = (0, import_react13.useState)("");
2285
- const [expandedId, setExpandedId] = (0, import_react13.useState)(null);
2391
+ const toast = (0, import_react_ui22.useToast)();
2392
+ const [page, setPage] = (0, import_react14.useState)(1);
2393
+ const [statusFilter, setStatusFilter] = (0, import_react14.useState)("");
2394
+ const [expandedId, setExpandedId] = (0, import_react14.useState)(null);
2286
2395
  const statusQuery = statusFilter ? `&status=${statusFilter}` : "";
2287
2396
  const { data, isLoading, isError, refetch } = (0, import_react_query19.useApiQuery)(
2288
2397
  ["dlq", page, statusFilter],
@@ -2323,9 +2432,9 @@ function DlqConsole({ basePath = "/api", className }) {
2323
2432
  })
2324
2433
  }
2325
2434
  );
2326
- const filterControl = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
2327
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: "dlq-status", className: "text-sm font-medium text-foreground", children: "Status" }),
2328
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2435
+ const filterControl = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
2436
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: "dlq-status", className: "text-sm font-medium text-foreground", children: "Status" }),
2437
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2329
2438
  "select",
2330
2439
  {
2331
2440
  id: "dlq-status",
@@ -2336,30 +2445,30 @@ function DlqConsole({ basePath = "/api", className }) {
2336
2445
  },
2337
2446
  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",
2338
2447
  children: [
2339
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "", children: "All" }),
2340
- STATUS_FILTERS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: s, children: s }, s))
2448
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "", children: "All" }),
2449
+ STATUS_FILTERS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: s, children: s }, s))
2341
2450
  ]
2342
2451
  }
2343
2452
  )
2344
2453
  ] });
2345
2454
  let body;
2346
2455
  if (isLoading) {
2347
- body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2456
+ body = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2348
2457
  "div",
2349
2458
  {
2350
2459
  role: "status",
2351
2460
  "aria-label": "Loading dead-letter messages",
2352
2461
  className: "flex flex-col gap-2 p-4",
2353
2462
  children: [
2354
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Loading dead-letter messages" }),
2355
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2463
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: "Loading dead-letter messages" }),
2464
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2356
2465
  ]
2357
2466
  }
2358
2467
  );
2359
2468
  } else if (isError) {
2360
- body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2361
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load dead-letter messages" }),
2362
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2469
+ body = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2470
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load dead-letter messages" }),
2471
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2363
2472
  "button",
2364
2473
  {
2365
2474
  type: "button",
@@ -2373,23 +2482,23 @@ function DlqConsole({ basePath = "/api", className }) {
2373
2482
  const rows = data?.items ?? [];
2374
2483
  const totalPages = data?.totalPages ?? 1;
2375
2484
  if (rows.length === 0) {
2376
- body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No dead-letter messages" });
2485
+ body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No dead-letter messages" });
2377
2486
  } else {
2378
- body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2379
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("table", { className: "w-full text-sm", children: [
2380
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2381
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Request" }),
2382
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Failure reason" }),
2383
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
2384
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
2385
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "First seen" }),
2386
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "sr-only", children: "Actions" }) })
2487
+ body = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
2488
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("table", { className: "w-full text-sm", children: [
2489
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2490
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Request" }),
2491
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Failure reason" }),
2492
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
2493
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
2494
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "First seen" }),
2495
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: "Actions" }) })
2387
2496
  ] }) }),
2388
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tbody", { children: rows.map((row) => {
2497
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tbody", { children: rows.map((row) => {
2389
2498
  const isExpanded = expandedId === row.id;
2390
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react13.Fragment, { children: [
2391
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("tr", { className: "border-b border-border", children: [
2392
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "py-3 pe-4", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2499
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react14.Fragment, { children: [
2500
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("tr", { className: "border-b border-border", children: [
2501
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "py-3 pe-4", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2393
2502
  "button",
2394
2503
  {
2395
2504
  type: "button",
@@ -2399,12 +2508,12 @@ function DlqConsole({ basePath = "/api", className }) {
2399
2508
  children: row.requestId ?? row.id
2400
2509
  }
2401
2510
  ) }),
2402
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.failureReason }),
2403
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_ui21.StatusBadge, { variant: statusVariant3(row.status), appearance: "dot", children: row.status }) }),
2404
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.attemptCount }),
2405
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui21.formatDateTime)(row.firstSeenAt) }),
2406
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
2407
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2511
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.failureReason }),
2512
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_ui22.StatusBadge, { variant: statusVariant3(row.status), appearance: "dot", children: row.status }) }),
2513
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.attemptCount }),
2514
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui22.formatDateTime)(row.firstSeenAt) }),
2515
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
2516
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2408
2517
  "button",
2409
2518
  {
2410
2519
  type: "button",
@@ -2414,7 +2523,7 @@ function DlqConsole({ basePath = "/api", className }) {
2414
2523
  children: "Replay"
2415
2524
  }
2416
2525
  ),
2417
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2526
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2418
2527
  "button",
2419
2528
  {
2420
2529
  type: "button",
@@ -2426,12 +2535,12 @@ function DlqConsole({ basePath = "/api", className }) {
2426
2535
  )
2427
2536
  ] }) })
2428
2537
  ] }),
2429
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("tr", { className: "border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("td", { colSpan: 6, className: "bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DlqMessageDetailRow, { id: row.id, basePath }) }) })
2538
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tr", { className: "border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { colSpan: 6, className: "bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DlqMessageDetailRow, { id: row.id, basePath }) }) })
2430
2539
  ] }, row.id);
2431
2540
  }) })
2432
2541
  ] }),
2433
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("nav", { "aria-label": "Dead-letter pagination", className: "flex items-center justify-between", children: [
2434
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2542
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("nav", { "aria-label": "Dead-letter pagination", className: "flex items-center justify-between", children: [
2543
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2435
2544
  "button",
2436
2545
  {
2437
2546
  type: "button",
@@ -2441,13 +2550,13 @@ function DlqConsole({ basePath = "/api", className }) {
2441
2550
  children: "Previous"
2442
2551
  }
2443
2552
  ),
2444
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
2553
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
2445
2554
  "Page ",
2446
2555
  page,
2447
2556
  " of ",
2448
2557
  totalPages
2449
2558
  ] }),
2450
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2559
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2451
2560
  "button",
2452
2561
  {
2453
2562
  type: "button",
@@ -2461,9 +2570,9 @@ function DlqConsole({ basePath = "/api", className }) {
2461
2570
  ] });
2462
2571
  }
2463
2572
  }
2464
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("section", { "aria-label": "Dead-letter queue", className: (0, import_react_ui21.cn)("flex flex-col gap-4", className), children: [
2465
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("header", { className: "flex items-center justify-between", children: [
2466
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Dead-letter queue" }),
2573
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("section", { "aria-label": "Dead-letter queue", className: (0, import_react_ui22.cn)("flex flex-col gap-4", className), children: [
2574
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("header", { className: "flex items-center justify-between", children: [
2575
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Dead-letter queue" }),
2467
2576
  filterControl
2468
2577
  ] }),
2469
2578
  body
@@ -2471,10 +2580,10 @@ function DlqConsole({ basePath = "/api", className }) {
2471
2580
  }
2472
2581
 
2473
2582
  // src/catalog-editor.tsx
2474
- var import_react14 = require("react");
2475
- var import_react_ui22 = require("@quanticjs/react-ui");
2583
+ var import_react15 = require("react");
2584
+ var import_react_ui23 = require("@quanticjs/react-ui");
2476
2585
  var import_react_query20 = require("@quanticjs/react-query");
2477
- var import_jsx_runtime23 = require("react/jsx-runtime");
2586
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2478
2587
  function normalize2(data) {
2479
2588
  if (!data) return [];
2480
2589
  if (Array.isArray(data)) return data;
@@ -2486,13 +2595,13 @@ function normalize2(data) {
2486
2595
  );
2487
2596
  }
2488
2597
  function CatalogEditor({ basePath = "/api", className }) {
2489
- const toast = (0, import_react_ui22.useToast)();
2490
- const [filter, setFilter] = (0, import_react14.useState)("");
2491
- const [editingId, setEditingId] = (0, import_react14.useState)(null);
2492
- const [editValue, setEditValue] = (0, import_react14.useState)("");
2493
- const [newKey, setNewKey] = (0, import_react14.useState)("");
2494
- const [newLocale, setNewLocale] = (0, import_react14.useState)("");
2495
- const [newValue, setNewValue] = (0, import_react14.useState)("");
2598
+ const toast = (0, import_react_ui23.useToast)();
2599
+ const [filter, setFilter] = (0, import_react15.useState)("");
2600
+ const [editingId, setEditingId] = (0, import_react15.useState)(null);
2601
+ const [editValue, setEditValue] = (0, import_react15.useState)("");
2602
+ const [newKey, setNewKey] = (0, import_react15.useState)("");
2603
+ const [newLocale, setNewLocale] = (0, import_react15.useState)("");
2604
+ const [newValue, setNewValue] = (0, import_react15.useState)("");
2496
2605
  const { data, isLoading, isError, refetch } = (0, import_react_query20.useApiQuery)(["i18n-catalog"], (client) => client.get(`${basePath}/i18n/catalog/export`));
2497
2606
  const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
2498
2607
  description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
@@ -2542,8 +2651,8 @@ function CatalogEditor({ basePath = "/api", className }) {
2542
2651
  onError: onMutationError
2543
2652
  }
2544
2653
  );
2545
- const entries = (0, import_react14.useMemo)(() => normalize2(data), [data]);
2546
- const filtered = (0, import_react14.useMemo)(() => {
2654
+ const entries = (0, import_react15.useMemo)(() => normalize2(data), [data]);
2655
+ const filtered = (0, import_react15.useMemo)(() => {
2547
2656
  const q = filter.trim().toLowerCase();
2548
2657
  if (!q) return entries;
2549
2658
  return entries.filter((e) => e.key.toLowerCase().includes(q));
@@ -2556,10 +2665,10 @@ function CatalogEditor({ basePath = "/api", className }) {
2556
2665
  setEditingId(`${entry.key}:${entry.locale}`);
2557
2666
  setEditValue(entry.value);
2558
2667
  };
2559
- const addForm = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
2560
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", children: [
2561
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: "catalog-new-key", className: "text-sm font-medium text-foreground", children: "Key" }),
2562
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2668
+ const addForm = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
2669
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-1", children: [
2670
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "catalog-new-key", className: "text-sm font-medium text-foreground", children: "Key" }),
2671
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2563
2672
  "input",
2564
2673
  {
2565
2674
  id: "catalog-new-key",
@@ -2570,9 +2679,9 @@ function CatalogEditor({ basePath = "/api", className }) {
2570
2679
  }
2571
2680
  )
2572
2681
  ] }),
2573
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", children: [
2574
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: "catalog-new-locale", className: "text-sm font-medium text-foreground", children: "Locale" }),
2575
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2682
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-1", children: [
2683
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "catalog-new-locale", className: "text-sm font-medium text-foreground", children: "Locale" }),
2684
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2576
2685
  "input",
2577
2686
  {
2578
2687
  id: "catalog-new-locale",
@@ -2583,9 +2692,9 @@ function CatalogEditor({ basePath = "/api", className }) {
2583
2692
  }
2584
2693
  )
2585
2694
  ] }),
2586
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", children: [
2587
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: "catalog-new-value", className: "text-sm font-medium text-foreground", children: "Value" }),
2588
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2695
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-1", children: [
2696
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "catalog-new-value", className: "text-sm font-medium text-foreground", children: "Value" }),
2697
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2589
2698
  "input",
2590
2699
  {
2591
2700
  id: "catalog-new-value",
@@ -2596,7 +2705,7 @@ function CatalogEditor({ basePath = "/api", className }) {
2596
2705
  }
2597
2706
  )
2598
2707
  ] }),
2599
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2708
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2600
2709
  "button",
2601
2710
  {
2602
2711
  type: "submit",
@@ -2606,9 +2715,9 @@ function CatalogEditor({ basePath = "/api", className }) {
2606
2715
  }
2607
2716
  )
2608
2717
  ] });
2609
- const filterInput = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", children: [
2610
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: "catalog-filter", className: "text-sm font-medium text-foreground", children: "Filter by key" }),
2611
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2718
+ const filterInput = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-1", children: [
2719
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "catalog-filter", className: "text-sm font-medium text-foreground", children: "Filter by key" }),
2720
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2612
2721
  "input",
2613
2722
  {
2614
2723
  id: "catalog-filter",
@@ -2621,14 +2730,14 @@ function CatalogEditor({ basePath = "/api", className }) {
2621
2730
  ] });
2622
2731
  let body;
2623
2732
  if (isLoading) {
2624
- body = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "status", "aria-label": "Loading catalog", className: "flex flex-col gap-2 p-4", children: [
2625
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: "Loading catalog" }),
2626
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2733
+ body = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { role: "status", "aria-label": "Loading catalog", className: "flex flex-col gap-2 p-4", children: [
2734
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: "Loading catalog" }),
2735
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2627
2736
  ] });
2628
2737
  } else if (isError) {
2629
- body = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2630
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load catalog" }),
2631
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2738
+ body = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2739
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load catalog" }),
2740
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2632
2741
  "button",
2633
2742
  {
2634
2743
  type: "button",
@@ -2639,22 +2748,22 @@ function CatalogEditor({ basePath = "/api", className }) {
2639
2748
  )
2640
2749
  ] });
2641
2750
  } else if (filtered.length === 0) {
2642
- body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: entries.length === 0 ? "No catalog entries" : "No entries match your filter" });
2751
+ body = /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: entries.length === 0 ? "No catalog entries" : "No entries match your filter" });
2643
2752
  } else {
2644
- body = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("table", { className: "w-full text-sm", children: [
2645
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2646
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
2647
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
2648
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Value" }),
2649
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: "Actions" }) })
2753
+ body = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("table", { className: "w-full text-sm", children: [
2754
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2755
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
2756
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
2757
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Value" }),
2758
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: "Actions" }) })
2650
2759
  ] }) }),
2651
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tbody", { children: filtered.map((entry) => {
2760
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("tbody", { children: filtered.map((entry) => {
2652
2761
  const rowId = `${entry.key}:${entry.locale}`;
2653
2762
  const isEditing = editingId === rowId;
2654
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("tr", { className: "border-b border-border", children: [
2655
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: entry.key }),
2656
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3 text-foreground", children: entry.locale }),
2657
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3 text-foreground", children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2763
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("tr", { className: "border-b border-border", children: [
2764
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: entry.key }),
2765
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "px-4 py-3 text-foreground", children: entry.locale }),
2766
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "px-4 py-3 text-foreground", children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2658
2767
  "input",
2659
2768
  {
2660
2769
  type: "text",
@@ -2664,8 +2773,8 @@ function CatalogEditor({ basePath = "/api", className }) {
2664
2773
  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"
2665
2774
  }
2666
2775
  ) : entry.value }),
2667
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex items-center gap-2", children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
2668
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2776
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex items-center gap-2", children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
2777
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2669
2778
  "button",
2670
2779
  {
2671
2780
  type: "button",
@@ -2679,7 +2788,7 @@ function CatalogEditor({ basePath = "/api", className }) {
2679
2788
  children: "Save"
2680
2789
  }
2681
2790
  ),
2682
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2791
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2683
2792
  "button",
2684
2793
  {
2685
2794
  type: "button",
@@ -2688,8 +2797,8 @@ function CatalogEditor({ basePath = "/api", className }) {
2688
2797
  children: "Cancel"
2689
2798
  }
2690
2799
  )
2691
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
2692
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2800
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
2801
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2693
2802
  "button",
2694
2803
  {
2695
2804
  type: "button",
@@ -2698,7 +2807,7 @@ function CatalogEditor({ basePath = "/api", className }) {
2698
2807
  children: "Edit"
2699
2808
  }
2700
2809
  ),
2701
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2810
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2702
2811
  "button",
2703
2812
  {
2704
2813
  type: "button",
@@ -2713,7 +2822,7 @@ function CatalogEditor({ basePath = "/api", className }) {
2713
2822
  }) })
2714
2823
  ] });
2715
2824
  }
2716
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("section", { "aria-label": "Catalog editor", className: (0, import_react_ui22.cn)("flex flex-col gap-4", className), children: [
2825
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("section", { "aria-label": "Catalog editor", className: (0, import_react_ui23.cn)("flex flex-col gap-4", className), children: [
2717
2826
  addForm,
2718
2827
  filterInput,
2719
2828
  body
@@ -2721,9 +2830,9 @@ function CatalogEditor({ basePath = "/api", className }) {
2721
2830
  }
2722
2831
 
2723
2832
  // src/missing-translations-panel.tsx
2724
- var import_react_ui23 = require("@quanticjs/react-ui");
2833
+ var import_react_ui24 = require("@quanticjs/react-ui");
2725
2834
  var import_react_query21 = require("@quanticjs/react-query");
2726
- var import_jsx_runtime24 = require("react/jsx-runtime");
2835
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2727
2836
  function normalize3(data) {
2728
2837
  if (Array.isArray(data)) return data;
2729
2838
  return data?.missing ?? [];
@@ -2737,23 +2846,23 @@ function MissingTranslationsPanel({
2737
2846
  (client) => client.get(`${basePath}/i18n/catalog/missing`)
2738
2847
  );
2739
2848
  if (isLoading) {
2740
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2849
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2741
2850
  "div",
2742
2851
  {
2743
2852
  role: "status",
2744
2853
  "aria-label": "Loading missing translations",
2745
- className: (0, import_react_ui23.cn)("flex flex-col gap-2 p-4", className),
2854
+ className: (0, import_react_ui24.cn)("flex flex-col gap-2 p-4", className),
2746
2855
  children: [
2747
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: "Loading missing translations" }),
2748
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2856
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: "Loading missing translations" }),
2857
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2749
2858
  ]
2750
2859
  }
2751
2860
  );
2752
2861
  }
2753
2862
  if (isError) {
2754
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: (0, import_react_ui23.cn)("flex flex-col items-start gap-3 p-4", className), children: [
2755
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load missing translations" }),
2756
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2863
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: (0, import_react_ui24.cn)("flex flex-col items-start gap-3 p-4", className), children: [
2864
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load missing translations" }),
2865
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2757
2866
  "button",
2758
2867
  {
2759
2868
  type: "button",
@@ -2766,26 +2875,26 @@ function MissingTranslationsPanel({
2766
2875
  }
2767
2876
  const rows = normalize3(data);
2768
2877
  if (rows.length === 0) {
2769
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: (0, import_react_ui23.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No missing translations" });
2878
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: (0, import_react_ui24.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No missing translations" });
2770
2879
  }
2771
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("section", { "aria-label": "Missing translations", className: (0, import_react_ui23.cn)("flex flex-col gap-3", className), children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("table", { className: "w-full text-sm", children: [
2772
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2773
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
2774
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
2775
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" })
2880
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("section", { "aria-label": "Missing translations", className: (0, import_react_ui24.cn)("flex flex-col gap-3", className), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("table", { className: "w-full text-sm", children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2882
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
2883
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
2884
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" })
2776
2885
  ] }) }),
2777
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("tr", { className: "border-b border-border", children: [
2778
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
2779
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.locale }),
2780
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.type ?? "\u2014" })
2886
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("tr", { className: "border-b border-border", children: [
2887
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
2888
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.locale }),
2889
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.type ?? "\u2014" })
2781
2890
  ] }, `${row.key}:${row.locale}:${i}`)) })
2782
2891
  ] }) });
2783
2892
  }
2784
2893
 
2785
2894
  // src/fallback-report-panel.tsx
2786
- var import_react_ui24 = require("@quanticjs/react-ui");
2895
+ var import_react_ui25 = require("@quanticjs/react-ui");
2787
2896
  var import_react_query22 = require("@quanticjs/react-query");
2788
- var import_jsx_runtime25 = require("react/jsx-runtime");
2897
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2789
2898
  function normalize4(data) {
2790
2899
  if (Array.isArray(data)) return data;
2791
2900
  return data?.entries ?? [];
@@ -2796,23 +2905,23 @@ function FallbackReportPanel({ basePath = "/api", className }) {
2796
2905
  (client) => client.get(`${basePath}/i18n/catalog/fallback-report`)
2797
2906
  );
2798
2907
  if (isLoading) {
2799
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
2800
2909
  "div",
2801
2910
  {
2802
2911
  role: "status",
2803
2912
  "aria-label": "Loading fallback report",
2804
- className: (0, import_react_ui24.cn)("flex flex-col gap-2 p-4", className),
2913
+ className: (0, import_react_ui25.cn)("flex flex-col gap-2 p-4", className),
2805
2914
  children: [
2806
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: "Loading fallback report" }),
2807
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2915
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: "Loading fallback report" }),
2916
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2808
2917
  ]
2809
2918
  }
2810
2919
  );
2811
2920
  }
2812
2921
  if (isError) {
2813
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: (0, import_react_ui24.cn)("flex flex-col items-start gap-3 p-4", className), children: [
2814
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load fallback report" }),
2815
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2922
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: (0, import_react_ui25.cn)("flex flex-col items-start gap-3 p-4", className), children: [
2923
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load fallback report" }),
2924
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2816
2925
  "button",
2817
2926
  {
2818
2927
  type: "button",
@@ -2825,38 +2934,38 @@ function FallbackReportPanel({ basePath = "/api", className }) {
2825
2934
  }
2826
2935
  const rows = normalize4(data);
2827
2936
  if (rows.length === 0) {
2828
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: (0, import_react_ui24.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No fallbacks reported" });
2937
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: (0, import_react_ui25.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No fallbacks reported" });
2829
2938
  }
2830
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("section", { "aria-label": "Fallback report", className: (0, import_react_ui24.cn)("flex flex-col gap-3", className), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("table", { className: "w-full text-sm", children: [
2831
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2832
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
2833
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Requested" }),
2834
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Resolved" }),
2835
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Chain" })
2939
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("section", { "aria-label": "Fallback report", className: (0, import_react_ui25.cn)("flex flex-col gap-3", className), children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("table", { className: "w-full text-sm", children: [
2940
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2941
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
2942
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Requested" }),
2943
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Resolved" }),
2944
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Chain" })
2836
2945
  ] }) }),
2837
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("tr", { className: "border-b border-border", children: [
2838
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
2839
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.requestedLocale }),
2840
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.resolvedLocale }),
2841
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.steps && row.steps.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("ol", { className: "flex flex-wrap items-center gap-1", children: row.steps.map((step, si) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("li", { className: "flex items-center gap-1", children: [
2842
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-foreground", children: step }),
2843
- si < (row.steps?.length ?? 0) - 1 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2192" })
2946
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("tr", { className: "border-b border-border", children: [
2947
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
2948
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.requestedLocale }),
2949
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.resolvedLocale }),
2950
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.steps && row.steps.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("ol", { className: "flex flex-wrap items-center gap-1", children: row.steps.map((step, si) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("li", { className: "flex items-center gap-1", children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-foreground", children: step }),
2952
+ si < (row.steps?.length ?? 0) - 1 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2192" })
2844
2953
  ] }, `${step}:${si}`)) }) : "\u2014" })
2845
2954
  ] }, `${row.key}:${row.requestedLocale}:${i}`)) })
2846
2955
  ] }) });
2847
2956
  }
2848
2957
 
2849
2958
  // src/recipient-admin-panel.tsx
2850
- var import_react15 = require("react");
2851
- var import_react_ui25 = require("@quanticjs/react-ui");
2959
+ var import_react16 = require("react");
2960
+ var import_react_ui26 = require("@quanticjs/react-ui");
2852
2961
  var import_react_query23 = require("@quanticjs/react-query");
2853
- var import_jsx_runtime26 = require("react/jsx-runtime");
2962
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2854
2963
  var LIMIT5 = 20;
2855
2964
  function RecipientAdminPanel({ basePath = "/api", className }) {
2856
- const toast = (0, import_react_ui25.useToast)();
2857
- const [page, setPage] = (0, import_react15.useState)(1);
2858
- const [search, setSearch] = (0, import_react15.useState)("");
2859
- const [query, setQuery] = (0, import_react15.useState)("");
2965
+ const toast = (0, import_react_ui26.useToast)();
2966
+ const [page, setPage] = (0, import_react16.useState)(1);
2967
+ const [search, setSearch] = (0, import_react16.useState)("");
2968
+ const [query, setQuery] = (0, import_react16.useState)("");
2860
2969
  const { data, isLoading, isError, refetch } = (0, import_react_query23.useApiQuery)(
2861
2970
  ["recipients", page, query],
2862
2971
  (client) => client.get(
@@ -2901,10 +3010,10 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
2901
3010
  if (row.consentSms) active.push("sms");
2902
3011
  return active.length > 0 ? active.join(", ") : "none";
2903
3012
  };
2904
- const searchForm = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("form", { onSubmit: onSearch, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
2905
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-1", children: [
2906
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { htmlFor: "recipient-search", className: "text-sm font-medium text-foreground", children: "Search recipients" }),
2907
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3013
+ const searchForm = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("form", { onSubmit: onSearch, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
3014
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-1", children: [
3015
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("label", { htmlFor: "recipient-search", className: "text-sm font-medium text-foreground", children: "Search recipients" }),
3016
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2908
3017
  "input",
2909
3018
  {
2910
3019
  id: "recipient-search",
@@ -2915,7 +3024,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
2915
3024
  }
2916
3025
  )
2917
3026
  ] }),
2918
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3027
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2919
3028
  "button",
2920
3029
  {
2921
3030
  type: "submit",
@@ -2926,14 +3035,14 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
2926
3035
  ] });
2927
3036
  let body;
2928
3037
  if (isLoading) {
2929
- body = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", "aria-label": "Loading recipients", className: "flex flex-col gap-2 p-4", children: [
2930
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: "Loading recipients" }),
2931
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3038
+ body = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", "aria-label": "Loading recipients", className: "flex flex-col gap-2 p-4", children: [
3039
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: "Loading recipients" }),
3040
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
2932
3041
  ] });
2933
3042
  } else if (isError) {
2934
- body = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
2935
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load recipients" }),
2936
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3043
+ body = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
3044
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load recipients" }),
3045
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2937
3046
  "button",
2938
3047
  {
2939
3048
  type: "button",
@@ -2947,26 +3056,26 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
2947
3056
  const rows = data?.items ?? [];
2948
3057
  const totalPages = data?.totalPages ?? 1;
2949
3058
  if (rows.length === 0) {
2950
- body = /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No recipients" });
3059
+ body = /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No recipients" });
2951
3060
  } else {
2952
- body = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
2953
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("table", { className: "w-full text-sm", children: [
2954
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
2955
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "User" }),
2956
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Email" }),
2957
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Phone" }),
2958
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Consents" }),
2959
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
2960
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: "Actions" }) })
3061
+ body = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
3062
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("table", { className: "w-full text-sm", children: [
3063
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3064
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "User" }),
3065
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Email" }),
3066
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Phone" }),
3067
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Consents" }),
3068
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
3069
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: "Actions" }) })
2961
3070
  ] }) }),
2962
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("tr", { className: "border-b border-border", children: [
2963
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.userId }),
2964
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.email ?? "\u2014" }),
2965
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.phone ?? "\u2014" }),
2966
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: consents(row) }),
2967
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui25.formatDateTime)(row.createdAt) }),
2968
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2", children: [
2969
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3071
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("tr", { className: "border-b border-border", children: [
3072
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.userId }),
3073
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.email ?? "\u2014" }),
3074
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.phone ?? "\u2014" }),
3075
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: consents(row) }),
3076
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui26.formatDateTime)(row.createdAt) }),
3077
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2", children: [
3078
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2970
3079
  "button",
2971
3080
  {
2972
3081
  type: "button",
@@ -2976,7 +3085,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
2976
3085
  children: "Export"
2977
3086
  }
2978
3087
  ),
2979
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3088
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2980
3089
  "button",
2981
3090
  {
2982
3091
  type: "button",
@@ -2989,8 +3098,8 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
2989
3098
  ] }) })
2990
3099
  ] }, row.userId)) })
2991
3100
  ] }),
2992
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("nav", { "aria-label": "Recipient pagination", className: "flex items-center justify-between", children: [
2993
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3101
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("nav", { "aria-label": "Recipient pagination", className: "flex items-center justify-between", children: [
3102
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2994
3103
  "button",
2995
3104
  {
2996
3105
  type: "button",
@@ -3000,13 +3109,13 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
3000
3109
  children: "Previous"
3001
3110
  }
3002
3111
  ),
3003
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
3112
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
3004
3113
  "Page ",
3005
3114
  page,
3006
3115
  " of ",
3007
3116
  totalPages
3008
3117
  ] }),
3009
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3118
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3010
3119
  "button",
3011
3120
  {
3012
3121
  type: "button",
@@ -3020,17 +3129,17 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
3020
3129
  ] });
3021
3130
  }
3022
3131
  }
3023
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("section", { "aria-label": "Recipient administration", className: (0, import_react_ui25.cn)("flex flex-col gap-4", className), children: [
3132
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { "aria-label": "Recipient administration", className: (0, import_react_ui26.cn)("flex flex-col gap-4", className), children: [
3024
3133
  searchForm,
3025
3134
  body
3026
3135
  ] });
3027
3136
  }
3028
3137
 
3029
3138
  // src/webhook-endpoint-manager.tsx
3030
- var import_react16 = require("react");
3031
- var import_react_ui26 = require("@quanticjs/react-ui");
3139
+ var import_react17 = require("react");
3140
+ var import_react_ui27 = require("@quanticjs/react-ui");
3032
3141
  var import_react_query24 = require("@quanticjs/react-query");
3033
- var import_jsx_runtime27 = require("react/jsx-runtime");
3142
+ var import_jsx_runtime28 = require("react/jsx-runtime");
3034
3143
  var EVENT_TYPES = [
3035
3144
  "notification.sent",
3036
3145
  "notification.delivered",
@@ -3056,15 +3165,15 @@ function WebhookDeliveries({ endpointId, basePath }) {
3056
3165
  (client) => client.get(`${basePath}/webhook-endpoints/${endpointId}/deliveries`)
3057
3166
  );
3058
3167
  if (isLoading) {
3059
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", "aria-label": "Loading deliveries", className: "flex flex-col gap-2 p-3", children: [
3060
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: "Loading deliveries" }),
3061
- [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "aria-hidden": "true", className: "h-8 animate-pulse rounded bg-muted" }, i))
3168
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { role: "status", "aria-label": "Loading deliveries", className: "flex flex-col gap-2 p-3", children: [
3169
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "sr-only", children: "Loading deliveries" }),
3170
+ [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "aria-hidden": "true", className: "h-8 animate-pulse rounded bg-muted" }, i))
3062
3171
  ] });
3063
3172
  }
3064
3173
  if (isError) {
3065
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col items-start gap-2 p-3", children: [
3066
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load deliveries" }),
3067
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3174
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col items-start gap-2 p-3", children: [
3175
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load deliveries" }),
3176
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3068
3177
  "button",
3069
3178
  {
3070
3179
  type: "button",
@@ -3077,18 +3186,18 @@ function WebhookDeliveries({ endpointId, basePath }) {
3077
3186
  }
3078
3187
  const rows = normalizeDeliveries(data);
3079
3188
  if (rows.length === 0) {
3080
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "p-3 text-center text-sm text-muted-foreground", children: "No deliveries" });
3189
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "p-3 text-center text-sm text-muted-foreground", children: "No deliveries" });
3081
3190
  }
3082
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("table", { className: "w-full text-sm", children: [
3083
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3084
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivery" }),
3085
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
3086
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
3191
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("table", { className: "w-full text-sm", children: [
3192
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3193
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivery" }),
3194
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
3195
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
3087
3196
  ] }) }),
3088
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("tr", { className: "border-b border-border", children: [
3089
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "py-2 pe-4 font-mono text-foreground", children: row.id }),
3090
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-2 text-muted-foreground", children: row.status }),
3091
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-2 text-muted-foreground", children: (0, import_react_ui26.formatDateTime)(row.createdAt) })
3197
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b border-border", children: [
3198
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "py-2 pe-4 font-mono text-foreground", children: row.id }),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-2 text-muted-foreground", children: row.status }),
3200
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-2 text-muted-foreground", children: (0, import_react_ui27.formatDateTime)(row.createdAt) })
3092
3201
  ] }, row.id)) })
3093
3202
  ] });
3094
3203
  }
@@ -3096,12 +3205,12 @@ function WebhookEndpointManager({
3096
3205
  basePath = "/api",
3097
3206
  className
3098
3207
  }) {
3099
- const toast = (0, import_react_ui26.useToast)();
3100
- const [url, setUrl] = (0, import_react16.useState)("");
3101
- const [events, setEvents] = (0, import_react16.useState)([]);
3102
- const [active, setActive] = (0, import_react16.useState)(true);
3103
- const [urlError, setUrlError] = (0, import_react16.useState)();
3104
- const [expandedId, setExpandedId] = (0, import_react16.useState)(null);
3208
+ const toast = (0, import_react_ui27.useToast)();
3209
+ const [url, setUrl] = (0, import_react17.useState)("");
3210
+ const [events, setEvents] = (0, import_react17.useState)([]);
3211
+ const [active, setActive] = (0, import_react17.useState)(true);
3212
+ const [urlError, setUrlError] = (0, import_react17.useState)();
3213
+ const [expandedId, setExpandedId] = (0, import_react17.useState)(null);
3105
3214
  const { data, isLoading, isError, refetch } = (0, import_react_query24.useApiQuery)(["webhook-endpoints"], (client) => client.get(`${basePath}/webhook-endpoints`));
3106
3215
  const create = (0, import_react_query24.useApiMutation)(
3107
3216
  (client, payload) => client.post(`${basePath}/webhook-endpoints`, payload),
@@ -3163,10 +3272,10 @@ function WebhookEndpointManager({
3163
3272
  remove.mutate(id);
3164
3273
  }
3165
3274
  };
3166
- const createForm = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("form", { onSubmit: onCreate, className: "flex flex-col gap-3", noValidate: true, children: [
3167
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-1", children: [
3168
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("label", { htmlFor: "webhook-url", className: "text-sm font-medium text-foreground", children: "Endpoint URL" }),
3169
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3275
+ const createForm = /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("form", { onSubmit: onCreate, className: "flex flex-col gap-3", noValidate: true, children: [
3276
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-1", children: [
3277
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("label", { htmlFor: "webhook-url", className: "text-sm font-medium text-foreground", children: "Endpoint URL" }),
3278
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3170
3279
  "input",
3171
3280
  {
3172
3281
  id: "webhook-url",
@@ -3178,19 +3287,19 @@ function WebhookEndpointManager({
3178
3287
  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"
3179
3288
  }
3180
3289
  ),
3181
- urlError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { id: "webhook-url-error", className: "text-xs text-destructive", children: urlError })
3290
+ urlError && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { id: "webhook-url-error", className: "text-xs text-destructive", children: urlError })
3182
3291
  ] }),
3183
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("fieldset", { className: "flex flex-col gap-2", children: [
3184
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("legend", { className: "text-sm font-medium text-foreground", children: "Events" }),
3185
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex flex-wrap gap-3", children: EVENT_TYPES.map((evt) => {
3292
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("fieldset", { className: "flex flex-col gap-2", children: [
3293
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("legend", { className: "text-sm font-medium text-foreground", children: "Events" }),
3294
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-wrap gap-3", children: EVENT_TYPES.map((evt) => {
3186
3295
  const id = `webhook-event-${evt}`;
3187
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3296
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
3188
3297
  "label",
3189
3298
  {
3190
3299
  htmlFor: id,
3191
3300
  className: "flex items-center gap-2 text-sm text-foreground",
3192
3301
  children: [
3193
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3302
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3194
3303
  "input",
3195
3304
  {
3196
3305
  id,
@@ -3207,8 +3316,8 @@ function WebhookEndpointManager({
3207
3316
  );
3208
3317
  }) })
3209
3318
  ] }),
3210
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { htmlFor: "webhook-active", className: "flex items-center gap-2 text-sm text-foreground", children: [
3211
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3319
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("label", { htmlFor: "webhook-active", className: "flex items-center gap-2 text-sm text-foreground", children: [
3320
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3212
3321
  "input",
3213
3322
  {
3214
3323
  id: "webhook-active",
@@ -3220,7 +3329,7 @@ function WebhookEndpointManager({
3220
3329
  ),
3221
3330
  "Active"
3222
3331
  ] }),
3223
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3332
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3224
3333
  "button",
3225
3334
  {
3226
3335
  type: "submit",
@@ -3232,14 +3341,14 @@ function WebhookEndpointManager({
3232
3341
  ] });
3233
3342
  let body;
3234
3343
  if (isLoading) {
3235
- body = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", "aria-label": "Loading webhook endpoints", className: "flex flex-col gap-2 p-4", children: [
3236
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: "Loading webhook endpoints" }),
3237
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3344
+ body = /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { role: "status", "aria-label": "Loading webhook endpoints", className: "flex flex-col gap-2 p-4", children: [
3345
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "sr-only", children: "Loading webhook endpoints" }),
3346
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3238
3347
  ] });
3239
3348
  } else if (isError) {
3240
- body = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
3241
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load webhook endpoints" }),
3242
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3349
+ body = /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
3350
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load webhook endpoints" }),
3351
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3243
3352
  "button",
3244
3353
  {
3245
3354
  type: "button",
@@ -3252,26 +3361,26 @@ function WebhookEndpointManager({
3252
3361
  } else {
3253
3362
  const rows = normalizeEndpoints(data);
3254
3363
  if (rows.length === 0) {
3255
- body = /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No webhook endpoints" });
3364
+ body = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No webhook endpoints" });
3256
3365
  } else {
3257
- body = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("table", { className: "w-full text-sm", children: [
3258
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3259
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "URL" }),
3260
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Events" }),
3261
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Active" }),
3262
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
3263
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: "Actions" }) })
3366
+ body = /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("table", { className: "w-full text-sm", children: [
3367
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3368
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "URL" }),
3369
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Events" }),
3370
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Active" }),
3371
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
3372
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "sr-only", children: "Actions" }) })
3264
3373
  ] }) }),
3265
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("tbody", { children: rows.map((row) => {
3374
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tbody", { children: rows.map((row) => {
3266
3375
  const isExpanded = expandedId === row.id;
3267
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react16.Fragment, { children: [
3268
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("tr", { className: "border-b border-border", children: [
3269
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.url }),
3270
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.events.length > 0 ? row.events.join(", ") : "\u2014" }),
3271
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_ui26.StatusBadge, { variant: row.active ? "success" : "neutral", appearance: "dot", children: row.active ? "active" : "inactive" }) }),
3272
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui26.formatDateTime)(row.createdAt) }),
3273
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2", children: [
3274
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3376
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_react17.Fragment, { children: [
3377
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b border-border", children: [
3378
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.url }),
3379
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.events.length > 0 ? row.events.join(", ") : "\u2014" }),
3380
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_ui27.StatusBadge, { variant: row.active ? "success" : "neutral", appearance: "dot", children: row.active ? "active" : "inactive" }) }),
3381
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui27.formatDateTime)(row.createdAt) }),
3382
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2", children: [
3383
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3275
3384
  "button",
3276
3385
  {
3277
3386
  type: "button",
@@ -3281,7 +3390,7 @@ function WebhookEndpointManager({
3281
3390
  children: row.active ? "Disable" : "Enable"
3282
3391
  }
3283
3392
  ),
3284
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3393
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3285
3394
  "button",
3286
3395
  {
3287
3396
  type: "button",
@@ -3291,7 +3400,7 @@ function WebhookEndpointManager({
3291
3400
  children: "Deliveries"
3292
3401
  }
3293
3402
  ),
3294
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3403
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3295
3404
  "button",
3296
3405
  {
3297
3406
  type: "button",
@@ -3303,45 +3412,45 @@ function WebhookEndpointManager({
3303
3412
  )
3304
3413
  ] }) })
3305
3414
  ] }),
3306
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("tr", { className: "border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("td", { colSpan: 5, className: "bg-muted px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WebhookDeliveries, { endpointId: row.id, basePath }) }) })
3415
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tr", { className: "border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { colSpan: 5, className: "bg-muted px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(WebhookDeliveries, { endpointId: row.id, basePath }) }) })
3307
3416
  ] }, row.id);
3308
3417
  }) })
3309
3418
  ] });
3310
3419
  }
3311
3420
  }
3312
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { "aria-label": "Webhook endpoints", className: (0, import_react_ui26.cn)("flex flex-col gap-4", className), children: [
3421
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": "Webhook endpoints", className: (0, import_react_ui27.cn)("flex flex-col gap-4", className), children: [
3313
3422
  createForm,
3314
3423
  body
3315
3424
  ] });
3316
3425
  }
3317
3426
 
3318
3427
  // src/operations-overview.tsx
3319
- var import_react_ui27 = require("@quanticjs/react-ui");
3428
+ var import_react_ui28 = require("@quanticjs/react-ui");
3320
3429
  var import_react_query25 = require("@quanticjs/react-query");
3321
- var import_jsx_runtime28 = require("react/jsx-runtime");
3430
+ var import_jsx_runtime29 = require("react/jsx-runtime");
3322
3431
  function OperationsOverview({ basePath = "/api", className }) {
3323
3432
  const { data, isLoading, isError, refetch } = (0, import_react_query25.useApiQuery)(
3324
3433
  ["operations-overview"],
3325
3434
  (client) => client.get(`${basePath}/v1/admin/overview`)
3326
3435
  );
3327
3436
  if (isLoading) {
3328
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
3437
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
3329
3438
  "div",
3330
3439
  {
3331
3440
  role: "status",
3332
3441
  "aria-label": "Loading operations overview",
3333
- className: (0, import_react_ui27.cn)("flex flex-col gap-2 p-4", className),
3442
+ className: (0, import_react_ui28.cn)("flex flex-col gap-2 p-4", className),
3334
3443
  children: [
3335
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "sr-only", children: "Loading operations overview" }),
3336
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "aria-hidden": "true", className: "h-20 animate-pulse rounded bg-muted" }, i))
3444
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "sr-only", children: "Loading operations overview" }),
3445
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { "aria-hidden": "true", className: "h-20 animate-pulse rounded bg-muted" }, i))
3337
3446
  ]
3338
3447
  }
3339
3448
  );
3340
3449
  }
3341
3450
  if (isError) {
3342
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_react_ui27.cn)("flex flex-col items-start gap-3 p-4", className), children: [
3343
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load operations overview" }),
3344
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3451
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: (0, import_react_ui28.cn)("flex flex-col items-start gap-3 p-4", className), children: [
3452
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load operations overview" }),
3453
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3345
3454
  "button",
3346
3455
  {
3347
3456
  type: "button",
@@ -3353,7 +3462,7 @@ function OperationsOverview({ basePath = "/api", className }) {
3353
3462
  ] });
3354
3463
  }
3355
3464
  if (!data) {
3356
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: (0, import_react_ui27.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No overview data" });
3465
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: (0, import_react_ui28.cn)("p-6 text-center text-sm text-muted-foreground", className), children: "No overview data" });
3357
3466
  }
3358
3467
  const windowHours = data.windowHours;
3359
3468
  const channels = data.channels ?? [];
@@ -3363,51 +3472,51 @@ function OperationsOverview({ basePath = "/api", className }) {
3363
3472
  { label: `Delivered (${windowHours}h)`, value: data.totalDelivered },
3364
3473
  { label: `Failed (${windowHours}h)`, value: data.totalFailed }
3365
3474
  ];
3366
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": "Operations overview", className: (0, import_react_ui27.cn)("flex flex-col gap-4", className), children: [
3367
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", children: cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "rounded-md border border-border bg-card p-4", children: [
3368
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-xs font-medium text-muted-foreground", children: card.label }),
3369
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "mt-1 text-2xl font-semibold text-foreground", children: card.value })
3475
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("section", { "aria-label": "Operations overview", className: (0, import_react_ui28.cn)("flex flex-col gap-4", className), children: [
3476
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", children: cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "rounded-md border border-border bg-card p-4", children: [
3477
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-xs font-medium text-muted-foreground", children: card.label }),
3478
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "mt-1 text-2xl font-semibold text-foreground", children: card.value })
3370
3479
  ] }, card.label)) }),
3371
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap items-center gap-4", children: [
3372
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2", children: [
3373
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: "DLQ pending" }),
3374
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_ui27.StatusBadge, { variant: dlqPending > 0 ? "destructive" : "success", children: dlqPending })
3480
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap items-center gap-4", children: [
3481
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2", children: [
3482
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-sm text-muted-foreground", children: "DLQ pending" }),
3483
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_ui28.StatusBadge, { variant: dlqPending > 0 ? "destructive" : "success", children: dlqPending })
3375
3484
  ] }),
3376
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2", children: [
3377
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: "Broadcasts in flight" }),
3378
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm font-medium text-foreground", children: data.broadcastsInFlight })
3485
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2", children: [
3486
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-sm text-muted-foreground", children: "Broadcasts in flight" }),
3487
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-sm font-medium text-foreground", children: data.broadcastsInFlight })
3379
3488
  ] }),
3380
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2", children: [
3381
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-sm text-muted-foreground", children: "Queue" }),
3382
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_ui27.StatusBadge, { variant: data.queueHealthy ? "success" : "destructive", children: data.queueHealthy ? "Healthy" : "Unhealthy" })
3489
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2", children: [
3490
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-sm text-muted-foreground", children: "Queue" }),
3491
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_ui28.StatusBadge, { variant: data.queueHealthy ? "success" : "destructive", children: data.queueHealthy ? "Healthy" : "Unhealthy" })
3383
3492
  ] })
3384
3493
  ] }),
3385
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("table", { className: "w-full text-sm", children: [
3386
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3387
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
3388
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Sends" }),
3389
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Delivered" }),
3390
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Failed" })
3494
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("table", { className: "w-full text-sm", children: [
3495
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3496
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
3497
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Sends" }),
3498
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Delivered" }),
3499
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Failed" })
3391
3500
  ] }) }),
3392
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tbody", { children: channels.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tr", { className: "border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { colSpan: 4, className: "py-3 text-center text-muted-foreground", children: "No channel activity" }) }) : channels.map((row) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b border-border", children: [
3393
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.channel }),
3394
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.sends }),
3395
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.delivered }),
3396
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.failed })
3501
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("tbody", { children: channels.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("tr", { className: "border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { colSpan: 4, className: "py-3 text-center text-muted-foreground", children: "No channel activity" }) }) : channels.map((row) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("tr", { className: "border-b border-border", children: [
3502
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.channel }),
3503
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.sends }),
3504
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.delivered }),
3505
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.failed })
3397
3506
  ] }, row.channel)) })
3398
3507
  ] }),
3399
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
3508
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
3400
3509
  "Generated ",
3401
- (0, import_react_ui27.formatDateTime)(data.generatedAt)
3510
+ (0, import_react_ui28.formatDateTime)(data.generatedAt)
3402
3511
  ] })
3403
3512
  ] });
3404
3513
  }
3405
3514
 
3406
3515
  // src/delivery-log-explorer.tsx
3407
- var import_react17 = require("react");
3408
- var import_react_ui28 = require("@quanticjs/react-ui");
3516
+ var import_react18 = require("react");
3517
+ var import_react_ui29 = require("@quanticjs/react-ui");
3409
3518
  var import_react_query26 = require("@quanticjs/react-query");
3410
- var import_jsx_runtime29 = require("react/jsx-runtime");
3519
+ var import_jsx_runtime30 = require("react/jsx-runtime");
3411
3520
  var LIMIT6 = 20;
3412
3521
  var EMPTY_FILTERS = {
3413
3522
  channel: "",
@@ -3428,9 +3537,9 @@ function channelVariant(channel) {
3428
3537
  }
3429
3538
  }
3430
3539
  function DeliveryLogExplorer({ basePath = "/api", className }) {
3431
- const [page, setPage] = (0, import_react17.useState)(1);
3432
- const [draft, setDraft] = (0, import_react17.useState)(EMPTY_FILTERS);
3433
- const [applied, setApplied] = (0, import_react17.useState)(EMPTY_FILTERS);
3540
+ const [page, setPage] = (0, import_react18.useState)(1);
3541
+ const [draft, setDraft] = (0, import_react18.useState)(EMPTY_FILTERS);
3542
+ const [applied, setApplied] = (0, import_react18.useState)(EMPTY_FILTERS);
3434
3543
  const queryString = (() => {
3435
3544
  const params = new URLSearchParams();
3436
3545
  params.set("page", String(page));
@@ -3460,10 +3569,10 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3460
3569
  });
3461
3570
  };
3462
3571
  const setField = (key, value) => setDraft((prev) => ({ ...prev, [key]: value }));
3463
- const filterForm = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("form", { onSubmit: onApply, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
3464
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
3465
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "dle-channel", className: "text-sm font-medium text-foreground", children: "Channel" }),
3466
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
3572
+ const filterForm = /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("form", { onSubmit: onApply, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
3573
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3574
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "dle-channel", className: "text-sm font-medium text-foreground", children: "Channel" }),
3575
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
3467
3576
  "select",
3468
3577
  {
3469
3578
  id: "dle-channel",
@@ -3471,16 +3580,16 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3471
3580
  onChange: (e) => setField("channel", e.target.value),
3472
3581
  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",
3473
3582
  children: [
3474
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "", children: "All" }),
3475
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "email", children: "Email" }),
3476
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "sms", children: "SMS" })
3583
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("option", { value: "", children: "All" }),
3584
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("option", { value: "email", children: "Email" }),
3585
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("option", { value: "sms", children: "SMS" })
3477
3586
  ]
3478
3587
  }
3479
3588
  )
3480
3589
  ] }),
3481
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
3482
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "dle-status", className: "text-sm font-medium text-foreground", children: "Status" }),
3483
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3590
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3591
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "dle-status", className: "text-sm font-medium text-foreground", children: "Status" }),
3592
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3484
3593
  "input",
3485
3594
  {
3486
3595
  id: "dle-status",
@@ -3491,9 +3600,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3491
3600
  }
3492
3601
  )
3493
3602
  ] }),
3494
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
3495
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "dle-recipient", className: "text-sm font-medium text-foreground", children: "Recipient" }),
3496
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3603
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3604
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "dle-recipient", className: "text-sm font-medium text-foreground", children: "Recipient" }),
3605
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3497
3606
  "input",
3498
3607
  {
3499
3608
  id: "dle-recipient",
@@ -3504,9 +3613,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3504
3613
  }
3505
3614
  )
3506
3615
  ] }),
3507
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
3508
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "dle-user", className: "text-sm font-medium text-foreground", children: "User ID" }),
3509
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3616
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3617
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "dle-user", className: "text-sm font-medium text-foreground", children: "User ID" }),
3618
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3510
3619
  "input",
3511
3620
  {
3512
3621
  id: "dle-user",
@@ -3517,9 +3626,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3517
3626
  }
3518
3627
  )
3519
3628
  ] }),
3520
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
3521
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "dle-from", className: "text-sm font-medium text-foreground", children: "From" }),
3522
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3629
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3630
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "dle-from", className: "text-sm font-medium text-foreground", children: "From" }),
3631
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3523
3632
  "input",
3524
3633
  {
3525
3634
  id: "dle-from",
@@ -3530,9 +3639,9 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3530
3639
  }
3531
3640
  )
3532
3641
  ] }),
3533
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
3534
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "dle-to", className: "text-sm font-medium text-foreground", children: "To" }),
3535
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3642
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3643
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "dle-to", className: "text-sm font-medium text-foreground", children: "To" }),
3644
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3536
3645
  "input",
3537
3646
  {
3538
3647
  id: "dle-to",
@@ -3543,7 +3652,7 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3543
3652
  }
3544
3653
  )
3545
3654
  ] }),
3546
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3655
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3547
3656
  "button",
3548
3657
  {
3549
3658
  type: "submit",
@@ -3554,14 +3663,14 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3554
3663
  ] });
3555
3664
  let body;
3556
3665
  if (isLoading) {
3557
- body = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { role: "status", "aria-label": "Loading delivery logs", className: "flex flex-col gap-2 p-4", children: [
3558
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "sr-only", children: "Loading delivery logs" }),
3559
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3666
+ body = /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { role: "status", "aria-label": "Loading delivery logs", className: "flex flex-col gap-2 p-4", children: [
3667
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "sr-only", children: "Loading delivery logs" }),
3668
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3560
3669
  ] });
3561
3670
  } else if (isError) {
3562
- body = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
3563
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
3564
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3671
+ body = /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
3672
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
3673
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3565
3674
  "button",
3566
3675
  {
3567
3676
  type: "button",
@@ -3575,31 +3684,31 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3575
3684
  const rows = data?.items ?? [];
3576
3685
  const totalPages = data?.totalPages ?? 1;
3577
3686
  if (rows.length === 0) {
3578
- body = /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No delivery logs" });
3687
+ body = /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No delivery logs" });
3579
3688
  } else {
3580
- body = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
3581
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("table", { className: "w-full text-sm", children: [
3582
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3583
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
3584
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipient" }),
3585
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "User" }),
3586
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
3587
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Provider" }),
3588
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
3589
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
3689
+ body = /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
3690
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("table", { className: "w-full text-sm", children: [
3691
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3692
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
3693
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipient" }),
3694
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "User" }),
3695
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
3696
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Provider" }),
3697
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
3698
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
3590
3699
  ] }) }),
3591
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("tr", { className: "border-b border-border", children: [
3592
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "py-3 pe-4", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_ui28.StatusBadge, { variant: channelVariant(row.channel), appearance: "dot", children: row.channel }) }),
3593
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.recipient ?? "\u2014" }),
3594
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 font-mono text-foreground", children: row.userId }),
3595
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.status }),
3596
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.provider ?? "\u2014" }),
3597
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.attempts }),
3598
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui28.formatDateTime)(row.createdAt) })
3700
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("tr", { className: "border-b border-border", children: [
3701
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "py-3 pe-4", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_ui29.StatusBadge, { variant: channelVariant(row.channel), appearance: "dot", children: row.channel }) }),
3702
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.recipient ?? "\u2014" }),
3703
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "px-4 py-3 font-mono text-foreground", children: row.userId }),
3704
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "px-4 py-3 text-foreground", children: row.status }),
3705
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.provider ?? "\u2014" }),
3706
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.attempts }),
3707
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui29.formatDateTime)(row.createdAt) })
3599
3708
  ] }, row.id)) })
3600
3709
  ] }),
3601
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("nav", { "aria-label": "Delivery log pagination", className: "flex items-center justify-between", children: [
3602
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3710
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("nav", { "aria-label": "Delivery log pagination", className: "flex items-center justify-between", children: [
3711
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3603
3712
  "button",
3604
3713
  {
3605
3714
  type: "button",
@@ -3609,13 +3718,13 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3609
3718
  children: "Previous"
3610
3719
  }
3611
3720
  ),
3612
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
3721
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
3613
3722
  "Page ",
3614
3723
  page,
3615
3724
  " of ",
3616
3725
  totalPages
3617
3726
  ] }),
3618
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3727
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3619
3728
  "button",
3620
3729
  {
3621
3730
  type: "button",
@@ -3629,17 +3738,17 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
3629
3738
  ] });
3630
3739
  }
3631
3740
  }
3632
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("section", { "aria-label": "Delivery log explorer", className: (0, import_react_ui28.cn)("flex flex-col gap-4", className), children: [
3741
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("section", { "aria-label": "Delivery log explorer", className: (0, import_react_ui29.cn)("flex flex-col gap-4", className), children: [
3633
3742
  filterForm,
3634
3743
  body
3635
3744
  ] });
3636
3745
  }
3637
3746
 
3638
3747
  // src/quiet-hours-form.tsx
3639
- var import_react18 = require("react");
3640
- var import_react_ui29 = require("@quanticjs/react-ui");
3748
+ var import_react19 = require("react");
3749
+ var import_react_ui30 = require("@quanticjs/react-ui");
3641
3750
  var import_react_query27 = require("@quanticjs/react-query");
3642
- var import_jsx_runtime30 = require("react/jsx-runtime");
3751
+ var import_jsx_runtime31 = require("react/jsx-runtime");
3643
3752
  var DEFAULTS = {
3644
3753
  enabled: false,
3645
3754
  start: "22:00",
@@ -3656,14 +3765,14 @@ function normalize5(raw) {
3656
3765
  };
3657
3766
  }
3658
3767
  function QuietHoursForm({ basePath = "/api", className }) {
3659
- const toast = (0, import_react_ui29.useToast)();
3768
+ const toast = (0, import_react_ui30.useToast)();
3660
3769
  const url = `${basePath}/notifications/config/quiet-hours`;
3661
3770
  const { data, isLoading, isError, refetch } = (0, import_react_query27.useApiQuery)(
3662
3771
  ["quiet-hours"],
3663
3772
  (client) => client.get(url)
3664
3773
  );
3665
- const [form, setForm] = (0, import_react18.useState)(DEFAULTS);
3666
- (0, import_react18.useEffect)(() => {
3774
+ const [form, setForm] = (0, import_react19.useState)(DEFAULTS);
3775
+ (0, import_react19.useEffect)(() => {
3667
3776
  if (data !== void 0) {
3668
3777
  setForm(normalize5(data));
3669
3778
  }
@@ -3680,23 +3789,23 @@ function QuietHoursForm({ basePath = "/api", className }) {
3680
3789
  save.mutate(form);
3681
3790
  };
3682
3791
  if (isLoading) {
3683
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
3792
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
3684
3793
  "div",
3685
3794
  {
3686
3795
  role: "status",
3687
3796
  "aria-label": "Loading quiet hours",
3688
- className: (0, import_react_ui29.cn)("flex flex-col gap-2 p-4", className),
3797
+ className: (0, import_react_ui30.cn)("flex flex-col gap-2 p-4", className),
3689
3798
  children: [
3690
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "sr-only", children: "Loading quiet hours" }),
3691
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3799
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "sr-only", children: "Loading quiet hours" }),
3800
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3692
3801
  ]
3693
3802
  }
3694
3803
  );
3695
3804
  }
3696
3805
  if (isError) {
3697
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: (0, import_react_ui29.cn)("flex flex-col items-start gap-3 p-4", className), children: [
3698
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load quiet hours" }),
3699
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3806
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: (0, import_react_ui30.cn)("flex flex-col items-start gap-3 p-4", className), children: [
3807
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load quiet hours" }),
3808
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3700
3809
  "button",
3701
3810
  {
3702
3811
  type: "button",
@@ -3707,10 +3816,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
3707
3816
  )
3708
3817
  ] });
3709
3818
  }
3710
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("form", { onSubmit, className: (0, import_react_ui29.cn)("flex flex-col gap-4", className), noValidate: true, children: [
3711
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Quiet hours" }),
3712
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
3713
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3819
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("form", { onSubmit, className: (0, import_react_ui30.cn)("flex flex-col gap-4", className), noValidate: true, children: [
3820
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Quiet hours" }),
3821
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
3822
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3714
3823
  "input",
3715
3824
  {
3716
3825
  type: "checkbox",
@@ -3721,10 +3830,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
3721
3830
  ),
3722
3831
  "Enable quiet hours"
3723
3832
  ] }),
3724
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-wrap gap-4", children: [
3725
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3726
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "qh-start", className: "text-sm font-medium text-foreground", children: "Start" }),
3727
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3833
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-wrap gap-4", children: [
3834
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-1", children: [
3835
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("label", { htmlFor: "qh-start", className: "text-sm font-medium text-foreground", children: "Start" }),
3836
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3728
3837
  "input",
3729
3838
  {
3730
3839
  id: "qh-start",
@@ -3735,9 +3844,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
3735
3844
  }
3736
3845
  )
3737
3846
  ] }),
3738
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3739
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "qh-end", className: "text-sm font-medium text-foreground", children: "End" }),
3740
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3847
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-1", children: [
3848
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("label", { htmlFor: "qh-end", className: "text-sm font-medium text-foreground", children: "End" }),
3849
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3741
3850
  "input",
3742
3851
  {
3743
3852
  id: "qh-end",
@@ -3748,9 +3857,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
3748
3857
  }
3749
3858
  )
3750
3859
  ] }),
3751
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", children: [
3752
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "qh-tz", className: "text-sm font-medium text-foreground", children: "Timezone" }),
3753
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3860
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-1", children: [
3861
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("label", { htmlFor: "qh-tz", className: "text-sm font-medium text-foreground", children: "Timezone" }),
3862
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3754
3863
  "input",
3755
3864
  {
3756
3865
  id: "qh-tz",
@@ -3762,7 +3871,7 @@ function QuietHoursForm({ basePath = "/api", className }) {
3762
3871
  )
3763
3872
  ] })
3764
3873
  ] }),
3765
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3874
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3766
3875
  "button",
3767
3876
  {
3768
3877
  type: "submit",
@@ -3775,10 +3884,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
3775
3884
  }
3776
3885
 
3777
3886
  // src/frequency-cap-table.tsx
3778
- var import_react19 = require("react");
3779
- var import_react_ui30 = require("@quanticjs/react-ui");
3887
+ var import_react20 = require("react");
3888
+ var import_react_ui31 = require("@quanticjs/react-ui");
3780
3889
  var import_react_query28 = require("@quanticjs/react-query");
3781
- var import_jsx_runtime31 = require("react/jsx-runtime");
3890
+ var import_jsx_runtime32 = require("react/jsx-runtime");
3782
3891
  function normalize6(raw) {
3783
3892
  const list = Array.isArray(raw) ? raw : Array.isArray(raw?.caps) ? raw.caps : [];
3784
3893
  return list.map((entry) => {
@@ -3788,16 +3897,16 @@ function normalize6(raw) {
3788
3897
  });
3789
3898
  }
3790
3899
  function FrequencyCapTable({ basePath = "/api", className }) {
3791
- const toast = (0, import_react_ui30.useToast)();
3900
+ const toast = (0, import_react_ui31.useToast)();
3792
3901
  const url = `${basePath}/notifications/config/frequency-cap`;
3793
3902
  const { data, isLoading, isError, refetch } = (0, import_react_query28.useApiQuery)(
3794
3903
  ["frequency-cap"],
3795
3904
  (client) => client.get(url)
3796
3905
  );
3797
- const [caps, setCaps] = (0, import_react19.useState)([]);
3798
- const [newType, setNewType] = (0, import_react19.useState)("");
3799
- const [newMax, setNewMax] = (0, import_react19.useState)(0);
3800
- (0, import_react19.useEffect)(() => {
3906
+ const [caps, setCaps] = (0, import_react20.useState)([]);
3907
+ const [newType, setNewType] = (0, import_react20.useState)("");
3908
+ const [newMax, setNewMax] = (0, import_react20.useState)(0);
3909
+ (0, import_react20.useEffect)(() => {
3801
3910
  if (data !== void 0) {
3802
3911
  setCaps(normalize6(data));
3803
3912
  }
@@ -3823,23 +3932,23 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3823
3932
  setNewMax(0);
3824
3933
  };
3825
3934
  if (isLoading) {
3826
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
3935
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
3827
3936
  "div",
3828
3937
  {
3829
3938
  role: "status",
3830
3939
  "aria-label": "Loading frequency caps",
3831
- className: (0, import_react_ui30.cn)("flex flex-col gap-2 p-4", className),
3940
+ className: (0, import_react_ui31.cn)("flex flex-col gap-2 p-4", className),
3832
3941
  children: [
3833
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "sr-only", children: "Loading frequency caps" }),
3834
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3942
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "sr-only", children: "Loading frequency caps" }),
3943
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
3835
3944
  ]
3836
3945
  }
3837
3946
  );
3838
3947
  }
3839
3948
  if (isError) {
3840
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: (0, import_react_ui30.cn)("flex flex-col items-start gap-3 p-4", className), children: [
3841
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load frequency caps" }),
3842
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3949
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: (0, import_react_ui31.cn)("flex flex-col items-start gap-3 p-4", className), children: [
3950
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load frequency caps" }),
3951
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3843
3952
  "button",
3844
3953
  {
3845
3954
  type: "button",
@@ -3850,24 +3959,24 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3850
3959
  )
3851
3960
  ] });
3852
3961
  }
3853
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { "aria-label": "Frequency caps", className: (0, import_react_ui30.cn)("flex flex-col gap-4", className), children: [
3854
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Frequency caps" }),
3855
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("table", { className: "w-full text-sm", children: [
3856
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3857
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
3858
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Max per day" }),
3859
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "sr-only", children: "Actions" }) })
3962
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("section", { "aria-label": "Frequency caps", className: (0, import_react_ui31.cn)("flex flex-col gap-4", className), children: [
3963
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Frequency caps" }),
3964
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("table", { className: "w-full text-sm", children: [
3965
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
3966
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
3967
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Max per day" }),
3968
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "sr-only", children: "Actions" }) })
3860
3969
  ] }) }),
3861
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("tbody", { children: caps.map((cap, index) => {
3970
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tbody", { children: caps.map((cap, index) => {
3862
3971
  const inputId = `cap-${index}`;
3863
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("tr", { className: "border-b border-border", children: [
3864
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("td", { className: "py-3 pe-4 text-foreground", children: cap.type }),
3865
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("td", { className: "px-4 py-3", children: [
3866
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("label", { htmlFor: inputId, className: "sr-only", children: [
3972
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tr", { className: "border-b border-border", children: [
3973
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "py-3 pe-4 text-foreground", children: cap.type }),
3974
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("td", { className: "px-4 py-3", children: [
3975
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { htmlFor: inputId, className: "sr-only", children: [
3867
3976
  "Max per day for ",
3868
3977
  cap.type
3869
3978
  ] }),
3870
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3979
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3871
3980
  "input",
3872
3981
  {
3873
3982
  id: inputId,
@@ -3879,7 +3988,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3879
3988
  }
3880
3989
  )
3881
3990
  ] }),
3882
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3991
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3883
3992
  "button",
3884
3993
  {
3885
3994
  type: "button",
@@ -3891,10 +4000,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3891
4000
  ] }, `${cap.type}-${index}`);
3892
4001
  }) })
3893
4002
  ] }),
3894
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("form", { onSubmit: addRow, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
3895
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-1", children: [
3896
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("label", { htmlFor: "cap-new-type", className: "text-sm font-medium text-foreground", children: "New type" }),
3897
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
4003
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("form", { onSubmit: addRow, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
4004
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
4005
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("label", { htmlFor: "cap-new-type", className: "text-sm font-medium text-foreground", children: "New type" }),
4006
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3898
4007
  "input",
3899
4008
  {
3900
4009
  id: "cap-new-type",
@@ -3905,9 +4014,9 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3905
4014
  }
3906
4015
  )
3907
4016
  ] }),
3908
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-1", children: [
3909
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("label", { htmlFor: "cap-new-max", className: "text-sm font-medium text-foreground", children: "Max per day" }),
3910
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
4017
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
4018
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("label", { htmlFor: "cap-new-max", className: "text-sm font-medium text-foreground", children: "Max per day" }),
4019
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3911
4020
  "input",
3912
4021
  {
3913
4022
  id: "cap-new-max",
@@ -3919,7 +4028,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3919
4028
  }
3920
4029
  )
3921
4030
  ] }),
3922
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
4031
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3923
4032
  "button",
3924
4033
  {
3925
4034
  type: "submit",
@@ -3928,7 +4037,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3928
4037
  }
3929
4038
  )
3930
4039
  ] }),
3931
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
4040
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3932
4041
  "button",
3933
4042
  {
3934
4043
  type: "button",
@@ -3942,10 +4051,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
3942
4051
  }
3943
4052
 
3944
4053
  // src/tenant-config-form.tsx
3945
- var import_react20 = require("react");
3946
- var import_react_ui31 = require("@quanticjs/react-ui");
4054
+ var import_react21 = require("react");
4055
+ var import_react_ui32 = require("@quanticjs/react-ui");
3947
4056
  var import_react_query29 = require("@quanticjs/react-query");
3948
- var import_jsx_runtime32 = require("react/jsx-runtime");
4057
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3949
4058
  function normalize7(raw) {
3950
4059
  const obj = raw ?? {};
3951
4060
  const toList = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
@@ -3955,7 +4064,7 @@ function normalize7(raw) {
3955
4064
  };
3956
4065
  }
3957
4066
  function TagEditor({ id, label, values, onAdd, onRemove }) {
3958
- const [draft, setDraft] = (0, import_react20.useState)("");
4067
+ const [draft, setDraft] = (0, import_react21.useState)("");
3959
4068
  const add = (event) => {
3960
4069
  event.preventDefault();
3961
4070
  const value = draft.trim();
@@ -3963,15 +4072,15 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
3963
4072
  onAdd(value);
3964
4073
  setDraft("");
3965
4074
  };
3966
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-2", children: [
3967
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-sm font-medium text-foreground", children: label }),
3968
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ul", { className: "flex flex-wrap gap-2", children: values.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("li", { className: "text-sm text-muted-foreground", children: "None" }) : values.map((value) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
4075
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-2", children: [
4076
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-sm font-medium text-foreground", children: label }),
4077
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className: "flex flex-wrap gap-2", children: values.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { className: "text-sm text-muted-foreground", children: "None" }) : values.map((value) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
3969
4078
  "li",
3970
4079
  {
3971
4080
  className: "flex items-center gap-1 rounded-md border border-border bg-card px-2 py-1 text-sm text-foreground",
3972
4081
  children: [
3973
4082
  value,
3974
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4083
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3975
4084
  "button",
3976
4085
  {
3977
4086
  type: "button",
@@ -3985,13 +4094,13 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
3985
4094
  },
3986
4095
  value
3987
4096
  )) }),
3988
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("form", { onSubmit: add, className: "flex items-end gap-2", noValidate: true, children: [
3989
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
3990
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { htmlFor: id, className: "sr-only", children: [
4097
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("form", { onSubmit: add, className: "flex items-end gap-2", noValidate: true, children: [
4098
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-1", children: [
4099
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("label", { htmlFor: id, className: "sr-only", children: [
3991
4100
  "Add to ",
3992
4101
  label
3993
4102
  ] }),
3994
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4103
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3995
4104
  "input",
3996
4105
  {
3997
4106
  id,
@@ -4002,7 +4111,7 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
4002
4111
  }
4003
4112
  )
4004
4113
  ] }),
4005
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4114
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4006
4115
  "button",
4007
4116
  {
4008
4117
  type: "submit",
@@ -4014,18 +4123,18 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
4014
4123
  ] });
4015
4124
  }
4016
4125
  function TenantConfigForm({ basePath = "/api", className }) {
4017
- const toast = (0, import_react_ui31.useToast)();
4126
+ const toast = (0, import_react_ui32.useToast)();
4018
4127
  const url = `${basePath}/admin/notification-config`;
4019
4128
  const { data, isLoading, isError, refetch } = (0, import_react_query29.useApiQuery)(
4020
4129
  ["tenant-config"],
4021
4130
  (client) => client.get(url)
4022
4131
  );
4023
- const [config, setConfig] = (0, import_react20.useState)({
4132
+ const [config, setConfig] = (0, import_react21.useState)({
4024
4133
  notificationTypes: [],
4025
4134
  immediateEmailTypes: []
4026
4135
  });
4027
- const [subsetError, setSubsetError] = (0, import_react20.useState)(void 0);
4028
- (0, import_react20.useEffect)(() => {
4136
+ const [subsetError, setSubsetError] = (0, import_react21.useState)(void 0);
4137
+ (0, import_react21.useEffect)(() => {
4029
4138
  if (data !== void 0) {
4030
4139
  setConfig(normalize7(data));
4031
4140
  }
@@ -4067,23 +4176,23 @@ function TenantConfigForm({ basePath = "/api", className }) {
4067
4176
  save.mutate(config);
4068
4177
  };
4069
4178
  if (isLoading) {
4070
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
4179
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
4071
4180
  "div",
4072
4181
  {
4073
4182
  role: "status",
4074
4183
  "aria-label": "Loading tenant configuration",
4075
- className: (0, import_react_ui31.cn)("flex flex-col gap-2 p-4", className),
4184
+ className: (0, import_react_ui32.cn)("flex flex-col gap-2 p-4", className),
4076
4185
  children: [
4077
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "sr-only", children: "Loading tenant configuration" }),
4078
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4186
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "sr-only", children: "Loading tenant configuration" }),
4187
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4079
4188
  ]
4080
4189
  }
4081
4190
  );
4082
4191
  }
4083
4192
  if (isError) {
4084
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: (0, import_react_ui31.cn)("flex flex-col items-start gap-3 p-4", className), children: [
4085
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load tenant configuration" }),
4086
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4193
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: (0, import_react_ui32.cn)("flex flex-col items-start gap-3 p-4", className), children: [
4194
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load tenant configuration" }),
4195
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4087
4196
  "button",
4088
4197
  {
4089
4198
  type: "button",
@@ -4095,17 +4204,17 @@ function TenantConfigForm({ basePath = "/api", className }) {
4095
4204
  ] });
4096
4205
  }
4097
4206
  const errorId = "tenant-config-subset-error";
4098
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
4207
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
4099
4208
  "form",
4100
4209
  {
4101
4210
  onSubmit,
4102
- className: (0, import_react_ui31.cn)("flex flex-col gap-5", className),
4211
+ className: (0, import_react_ui32.cn)("flex flex-col gap-5", className),
4103
4212
  noValidate: true,
4104
4213
  "aria-invalid": subsetError ? "true" : void 0,
4105
4214
  "aria-describedby": subsetError ? errorId : void 0,
4106
4215
  children: [
4107
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Notification configuration" }),
4108
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4216
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Notification configuration" }),
4217
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4109
4218
  TagEditor,
4110
4219
  {
4111
4220
  id: "tc-notification-types",
@@ -4115,7 +4224,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
4115
4224
  onRemove: removeType
4116
4225
  }
4117
4226
  ),
4118
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4227
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4119
4228
  TagEditor,
4120
4229
  {
4121
4230
  id: "tc-immediate-email-types",
@@ -4125,8 +4234,8 @@ function TenantConfigForm({ basePath = "/api", className }) {
4125
4234
  onRemove: removeImmediate
4126
4235
  }
4127
4236
  ),
4128
- subsetError && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { id: errorId, className: "text-xs text-destructive", children: subsetError }),
4129
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4237
+ subsetError && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { id: errorId, className: "text-xs text-destructive", children: subsetError }),
4238
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4130
4239
  "button",
4131
4240
  {
4132
4241
  type: "submit",
@@ -4141,10 +4250,10 @@ function TenantConfigForm({ basePath = "/api", className }) {
4141
4250
  }
4142
4251
 
4143
4252
  // src/tracking-config-form.tsx
4144
- var import_react21 = require("react");
4145
- var import_react_ui32 = require("@quanticjs/react-ui");
4253
+ var import_react22 = require("react");
4254
+ var import_react_ui33 = require("@quanticjs/react-ui");
4146
4255
  var import_react_query30 = require("@quanticjs/react-query");
4147
- var import_jsx_runtime33 = require("react/jsx-runtime");
4256
+ var import_jsx_runtime34 = require("react/jsx-runtime");
4148
4257
  function normalize8(raw) {
4149
4258
  const obj = raw ?? {};
4150
4259
  const bool = (...keys) => {
@@ -4159,17 +4268,17 @@ function normalize8(raw) {
4159
4268
  };
4160
4269
  }
4161
4270
  function TrackingConfigForm({ basePath = "/api", className }) {
4162
- const toast = (0, import_react_ui32.useToast)();
4271
+ const toast = (0, import_react_ui33.useToast)();
4163
4272
  const url = `${basePath}/analytics/notifications/tracking-config`;
4164
4273
  const { data, isLoading, isError, refetch } = (0, import_react_query30.useApiQuery)(
4165
4274
  ["tracking-config"],
4166
4275
  (client) => client.get(url)
4167
4276
  );
4168
- const [form, setForm] = (0, import_react21.useState)({
4277
+ const [form, setForm] = (0, import_react22.useState)({
4169
4278
  openTrackingEnabled: false,
4170
4279
  clickTrackingEnabled: false
4171
4280
  });
4172
- (0, import_react21.useEffect)(() => {
4281
+ (0, import_react22.useEffect)(() => {
4173
4282
  if (data !== void 0) {
4174
4283
  setForm(normalize8(data));
4175
4284
  }
@@ -4189,23 +4298,23 @@ function TrackingConfigForm({ basePath = "/api", className }) {
4189
4298
  save.mutate(form);
4190
4299
  };
4191
4300
  if (isLoading) {
4192
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
4301
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
4193
4302
  "div",
4194
4303
  {
4195
4304
  role: "status",
4196
4305
  "aria-label": "Loading tracking configuration",
4197
- className: (0, import_react_ui32.cn)("flex flex-col gap-2 p-4", className),
4306
+ className: (0, import_react_ui33.cn)("flex flex-col gap-2 p-4", className),
4198
4307
  children: [
4199
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "sr-only", children: "Loading tracking configuration" }),
4200
- [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4308
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "sr-only", children: "Loading tracking configuration" }),
4309
+ [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4201
4310
  ]
4202
4311
  }
4203
4312
  );
4204
4313
  }
4205
4314
  if (isError) {
4206
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: (0, import_react_ui32.cn)("flex flex-col items-start gap-3 p-4", className), children: [
4207
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load tracking configuration" }),
4208
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4315
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: (0, import_react_ui33.cn)("flex flex-col items-start gap-3 p-4", className), children: [
4316
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load tracking configuration" }),
4317
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4209
4318
  "button",
4210
4319
  {
4211
4320
  type: "button",
@@ -4216,10 +4325,10 @@ function TrackingConfigForm({ basePath = "/api", className }) {
4216
4325
  )
4217
4326
  ] });
4218
4327
  }
4219
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("form", { onSubmit, className: (0, import_react_ui32.cn)("flex flex-col gap-4", className), noValidate: true, children: [
4220
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Tracking configuration" }),
4221
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
4222
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4328
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("form", { onSubmit, className: (0, import_react_ui33.cn)("flex flex-col gap-4", className), noValidate: true, children: [
4329
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h2", { className: "text-sm font-semibold text-foreground", children: "Tracking configuration" }),
4330
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
4331
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4223
4332
  "input",
4224
4333
  {
4225
4334
  type: "checkbox",
@@ -4230,8 +4339,8 @@ function TrackingConfigForm({ basePath = "/api", className }) {
4230
4339
  ),
4231
4340
  "Open tracking"
4232
4341
  ] }),
4233
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
4234
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4342
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
4343
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4235
4344
  "input",
4236
4345
  {
4237
4346
  type: "checkbox",
@@ -4242,7 +4351,7 @@ function TrackingConfigForm({ basePath = "/api", className }) {
4242
4351
  ),
4243
4352
  "Click tracking"
4244
4353
  ] }),
4245
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4354
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4246
4355
  "button",
4247
4356
  {
4248
4357
  type: "submit",
@@ -4255,23 +4364,23 @@ function TrackingConfigForm({ basePath = "/api", className }) {
4255
4364
  }
4256
4365
 
4257
4366
  // src/api-key-manager.tsx
4258
- var import_react22 = require("react");
4259
- var import_react_ui33 = require("@quanticjs/react-ui");
4367
+ var import_react23 = require("react");
4368
+ var import_react_ui34 = require("@quanticjs/react-ui");
4260
4369
  var import_react_query31 = require("@quanticjs/react-query");
4261
- var import_jsx_runtime34 = require("react/jsx-runtime");
4370
+ var import_jsx_runtime35 = require("react/jsx-runtime");
4262
4371
  function normalize9(raw) {
4263
4372
  const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
4264
4373
  return list;
4265
4374
  }
4266
4375
  function ApiKeyManager({ basePath = "/api", className }) {
4267
- const toast = (0, import_react_ui33.useToast)();
4376
+ const toast = (0, import_react_ui34.useToast)();
4268
4377
  const url = `${basePath}/v1/admin/api-keys`;
4269
4378
  const { data, isLoading, isError, refetch } = (0, import_react_query31.useApiQuery)(
4270
4379
  ["api-keys"],
4271
4380
  (client) => client.get(url)
4272
4381
  );
4273
- const [name, setName] = (0, import_react22.useState)("");
4274
- const [applicationKey, setApplicationKey] = (0, import_react22.useState)("");
4382
+ const [name, setName] = (0, import_react23.useState)("");
4383
+ const [applicationKey, setApplicationKey] = (0, import_react23.useState)("");
4275
4384
  const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
4276
4385
  description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
4277
4386
  });
@@ -4316,10 +4425,10 @@ function ApiKeyManager({ basePath = "/api", className }) {
4316
4425
  revoke.mutate(id);
4317
4426
  }
4318
4427
  };
4319
- const createForm = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("form", { onSubmit: onCreate, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
4320
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-col gap-1", children: [
4321
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("label", { htmlFor: "api-key-name", className: "text-sm font-medium text-foreground", children: "New key name" }),
4322
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4428
+ const createForm = /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("form", { onSubmit: onCreate, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
4429
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
4430
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { htmlFor: "api-key-name", className: "text-sm font-medium text-foreground", children: "New key name" }),
4431
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4323
4432
  "input",
4324
4433
  {
4325
4434
  id: "api-key-name",
@@ -4330,9 +4439,9 @@ function ApiKeyManager({ basePath = "/api", className }) {
4330
4439
  }
4331
4440
  )
4332
4441
  ] }),
4333
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-col gap-1", children: [
4334
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("label", { htmlFor: "api-key-app", className: "text-sm font-medium text-foreground", children: "Application (optional)" }),
4335
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4442
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
4443
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { htmlFor: "api-key-app", className: "text-sm font-medium text-foreground", children: "Application (optional)" }),
4444
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4336
4445
  "input",
4337
4446
  {
4338
4447
  id: "api-key-app",
@@ -4344,7 +4453,7 @@ function ApiKeyManager({ basePath = "/api", className }) {
4344
4453
  }
4345
4454
  )
4346
4455
  ] }),
4347
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4456
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4348
4457
  "button",
4349
4458
  {
4350
4459
  type: "submit",
@@ -4356,14 +4465,14 @@ function ApiKeyManager({ basePath = "/api", className }) {
4356
4465
  ] });
4357
4466
  let body;
4358
4467
  if (isLoading) {
4359
- body = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { role: "status", "aria-label": "Loading API keys", className: "flex flex-col gap-2 p-4", children: [
4360
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "sr-only", children: "Loading API keys" }),
4361
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4468
+ body = /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { role: "status", "aria-label": "Loading API keys", className: "flex flex-col gap-2 p-4", children: [
4469
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "sr-only", children: "Loading API keys" }),
4470
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4362
4471
  ] });
4363
4472
  } else if (isError) {
4364
- body = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
4365
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load API keys" }),
4366
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4473
+ body = /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col items-start gap-3 p-4", children: [
4474
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load API keys" }),
4475
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4367
4476
  "button",
4368
4477
  {
4369
4478
  type: "button",
@@ -4376,26 +4485,26 @@ function ApiKeyManager({ basePath = "/api", className }) {
4376
4485
  } else {
4377
4486
  const rows = normalize9(data);
4378
4487
  if (rows.length === 0) {
4379
- body = /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No API keys" });
4488
+ body = /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No API keys" });
4380
4489
  } else {
4381
- body = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("table", { className: "w-full text-sm", children: [
4382
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
4383
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
4384
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Prefix" }),
4385
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Application" }),
4386
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
4387
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
4388
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last used" }),
4389
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "sr-only", children: "Actions" }) })
4490
+ body = /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("table", { className: "w-full text-sm", children: [
4491
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
4492
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
4493
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Prefix" }),
4494
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Application" }),
4495
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
4496
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
4497
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last used" }),
4498
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "sr-only", children: "Actions" }) })
4390
4499
  ] }) }),
4391
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("tr", { className: "border-b border-border", children: [
4392
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.name }),
4393
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.prefix ?? "\u2014" }),
4394
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.applicationKey ?? "\u2014" }),
4395
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react_ui33.StatusBadge, { variant: row.revoked ? "destructive" : "success", children: row.revoked ? "Revoked" : "Active" }) }),
4396
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui33.formatDateTime)(row.createdAt) }),
4397
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastUsedAt ? (0, import_react_ui33.formatDateTime)(row.lastUsedAt) : "\u2014" }),
4398
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4500
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("tr", { className: "border-b border-border", children: [
4501
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "py-3 pe-4 text-foreground", children: row.name }),
4502
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.prefix ?? "\u2014" }),
4503
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.applicationKey ?? "\u2014" }),
4504
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_react_ui34.StatusBadge, { variant: row.revoked ? "destructive" : "success", children: row.revoked ? "Revoked" : "Active" }) }),
4505
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: (0, import_react_ui34.formatDateTime)(row.createdAt) }),
4506
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastUsedAt ? (0, import_react_ui34.formatDateTime)(row.lastUsedAt) : "\u2014" }),
4507
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4399
4508
  "button",
4400
4509
  {
4401
4510
  type: "button",
@@ -4409,17 +4518,17 @@ function ApiKeyManager({ basePath = "/api", className }) {
4409
4518
  ] });
4410
4519
  }
4411
4520
  }
4412
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("section", { "aria-label": "API key management", className: (0, import_react_ui33.cn)("flex flex-col gap-4", className), children: [
4521
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("section", { "aria-label": "API key management", className: (0, import_react_ui34.cn)("flex flex-col gap-4", className), children: [
4413
4522
  createForm,
4414
4523
  body
4415
4524
  ] });
4416
4525
  }
4417
4526
 
4418
4527
  // src/application-registry-panel.tsx
4419
- var import_react23 = require("react");
4420
- var import_react_ui34 = require("@quanticjs/react-ui");
4528
+ var import_react24 = require("react");
4529
+ var import_react_ui35 = require("@quanticjs/react-ui");
4421
4530
  var import_react_query32 = require("@quanticjs/react-query");
4422
- var import_jsx_runtime35 = require("react/jsx-runtime");
4531
+ var import_jsx_runtime36 = require("react/jsx-runtime");
4423
4532
  function normalize10(raw) {
4424
4533
  const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
4425
4534
  return list;
@@ -4428,15 +4537,15 @@ function ApplicationRegistryPanel({
4428
4537
  basePath = "/api",
4429
4538
  className
4430
4539
  }) {
4431
- const toast = (0, import_react_ui34.useToast)();
4540
+ const toast = (0, import_react_ui35.useToast)();
4432
4541
  const url = `${basePath}/admin/applications`;
4433
4542
  const { data, isLoading, isError, refetch } = (0, import_react_query32.useApiQuery)(
4434
4543
  ["applications"],
4435
4544
  (client) => client.get(url)
4436
4545
  );
4437
- const [key, setKey] = (0, import_react23.useState)("");
4438
- const [displayName, setDisplayName] = (0, import_react23.useState)("");
4439
- const [description, setDescription] = (0, import_react23.useState)("");
4546
+ const [key, setKey] = (0, import_react24.useState)("");
4547
+ const [displayName, setDisplayName] = (0, import_react24.useState)("");
4548
+ const [description, setDescription] = (0, import_react24.useState)("");
4440
4549
  const onMutationError = (error) => toast.error(error.isServerError ? "Something went wrong" : error.title, {
4441
4550
  description: error.isServerError ? `Please try again. (ref: ${error.correlationId ?? "unknown"})` : `${error.detail ?? ""} (ref: ${error.correlationId ?? "unknown"})`
4442
4551
  });
@@ -4465,10 +4574,10 @@ function ApplicationRegistryPanel({
4465
4574
  if (!k || !name) return;
4466
4575
  register.mutate({ key: k, displayName: name, description: description.trim() || void 0 });
4467
4576
  };
4468
- const registerForm = /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("form", { onSubmit: onRegister, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
4469
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
4470
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { htmlFor: "application-key", className: "text-sm font-medium text-foreground", children: "Key (slug)" }),
4471
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4577
+ const registerForm = /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("form", { onSubmit: onRegister, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
4578
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1", children: [
4579
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: "application-key", className: "text-sm font-medium text-foreground", children: "Key (slug)" }),
4580
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4472
4581
  "input",
4473
4582
  {
4474
4583
  id: "application-key",
@@ -4480,9 +4589,9 @@ function ApplicationRegistryPanel({
4480
4589
  }
4481
4590
  )
4482
4591
  ] }),
4483
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
4484
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { htmlFor: "application-name", className: "text-sm font-medium text-foreground", children: "Display name" }),
4485
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4592
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1", children: [
4593
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: "application-name", className: "text-sm font-medium text-foreground", children: "Display name" }),
4594
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4486
4595
  "input",
4487
4596
  {
4488
4597
  id: "application-name",
@@ -4494,9 +4603,9 @@ function ApplicationRegistryPanel({
4494
4603
  }
4495
4604
  )
4496
4605
  ] }),
4497
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
4498
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { htmlFor: "application-description", className: "text-sm font-medium text-foreground", children: "Description (optional)" }),
4499
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4606
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1", children: [
4607
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: "application-description", className: "text-sm font-medium text-foreground", children: "Description (optional)" }),
4608
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4500
4609
  "input",
4501
4610
  {
4502
4611
  id: "application-description",
@@ -4507,7 +4616,7 @@ function ApplicationRegistryPanel({
4507
4616
  }
4508
4617
  )
4509
4618
  ] }),
4510
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4619
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4511
4620
  "button",
4512
4621
  {
4513
4622
  type: "submit",
@@ -4518,23 +4627,23 @@ function ApplicationRegistryPanel({
4518
4627
  )
4519
4628
  ] });
4520
4629
  if (isLoading) {
4521
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
4630
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
4522
4631
  "div",
4523
4632
  {
4524
4633
  role: "status",
4525
4634
  "aria-label": "Loading applications",
4526
- className: (0, import_react_ui34.cn)("flex flex-col gap-2 p-4", className),
4635
+ className: (0, import_react_ui35.cn)("flex flex-col gap-2 p-4", className),
4527
4636
  children: [
4528
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "sr-only", children: "Loading applications" }),
4529
- [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4637
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "sr-only", children: "Loading applications" }),
4638
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
4530
4639
  ]
4531
4640
  }
4532
4641
  );
4533
4642
  }
4534
4643
  if (isError) {
4535
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: (0, import_react_ui34.cn)("flex flex-col items-start gap-3 p-4", className), children: [
4536
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load applications" }),
4537
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4644
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: (0, import_react_ui35.cn)("flex flex-col items-start gap-3 p-4", className), children: [
4645
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-sm text-foreground", children: "Failed to load applications" }),
4646
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4538
4647
  "button",
4539
4648
  {
4540
4649
  type: "button",
@@ -4546,22 +4655,22 @@ function ApplicationRegistryPanel({
4546
4655
  ] });
4547
4656
  }
4548
4657
  const apps = normalize10(data);
4549
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("section", { "aria-label": "Applications", className: (0, import_react_ui34.cn)("flex flex-col gap-4 p-4", className), children: [
4658
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { "aria-label": "Applications", className: (0, import_react_ui35.cn)("flex flex-col gap-4 p-4", className), children: [
4550
4659
  registerForm,
4551
- apps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "p-6 text-center text-sm text-muted-foreground", children: "No applications registered" }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("table", { className: "w-full text-sm", children: [
4552
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
4553
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { className: "py-2 font-medium", children: "Key" }),
4554
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { className: "py-2 font-medium", children: "Name" }),
4555
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { className: "py-2 font-medium", children: "Status" }),
4556
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { className: "py-2 font-medium", children: "Created" }),
4557
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("th", { className: "py-2 font-medium", children: "Actions" })
4660
+ apps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "p-6 text-center text-sm text-muted-foreground", children: "No applications registered" }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("table", { className: "w-full text-sm", children: [
4661
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
4662
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { className: "py-2 font-medium", children: "Key" }),
4663
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { className: "py-2 font-medium", children: "Name" }),
4664
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { className: "py-2 font-medium", children: "Status" }),
4665
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { className: "py-2 font-medium", children: "Created" }),
4666
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("th", { className: "py-2 font-medium", children: "Actions" })
4558
4667
  ] }) }),
4559
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("tbody", { children: apps.map((app) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("tr", { className: "border-b border-border", children: [
4560
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "py-2 font-mono text-foreground", children: app.key }),
4561
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "py-2 text-foreground", children: app.displayName }),
4562
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "py-2", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_react_ui34.StatusBadge, { variant: app.status === "active" ? "success" : "neutral", children: app.status }) }),
4563
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "py-2 text-muted-foreground", children: (0, import_react_ui34.formatDateTime)(app.createdAt) }),
4564
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "py-2", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4668
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tbody", { children: apps.map((app) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("tr", { className: "border-b border-border", children: [
4669
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-2 font-mono text-foreground", children: app.key }),
4670
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-2 text-foreground", children: app.displayName }),
4671
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-2", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_ui35.StatusBadge, { variant: app.status === "active" ? "success" : "neutral", children: app.status }) }),
4672
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-2 text-muted-foreground", children: (0, import_react_ui35.formatDateTime)(app.createdAt) }),
4673
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "py-2", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4565
4674
  "button",
4566
4675
  {
4567
4676
  type: "button",
@@ -4595,6 +4704,7 @@ function ApplicationRegistryPanel({
4595
4704
  FunnelStats,
4596
4705
  MissingTranslationsPanel,
4597
4706
  NotificationBell,
4707
+ NotificationCenter,
4598
4708
  NotificationInbox,
4599
4709
  NotificationPreferences,
4600
4710
  NotificationProvider,