@nivaro/react 0.3.22 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,13 @@
1
1
  import { jsx as a, jsxs as n, Fragment as F } from "react/jsx-runtime";
2
- import { useQuery as X } from "@tanstack/react-query";
3
- import { Lock as G } from "lucide-react";
4
- import { useState as _, useMemo as z, useEffect as B } from "react";
5
- import { get as Y } from "../../lib/commands.js";
2
+ import { useQuery as z } from "@tanstack/react-query";
3
+ import { Lock as I } from "lucide-react";
4
+ import { useState as _, useMemo as Y, useEffect as B } from "react";
5
+ import { get as Z } from "../../lib/commands.js";
6
6
  import { cn as N } from "../../lib/utils.js";
7
7
  import { Popover as A, PopoverTrigger as D, PopoverContent as j } from "../ui/popover.js";
8
- function Z(t) {
9
- const { series: e, value: r, periodLabel: l, whole: s, children: i } = t, [d, g] = _(!1), c = e.details ?? [];
10
- if (c.length === 0 && e.total == null) return /* @__PURE__ */ a(F, { children: i });
8
+ function ee(t) {
9
+ const { series: e, value: r, periodLabel: l, whole: s, children: o } = t, [d, g] = _(!1), c = e.details ?? [];
10
+ if (c.length === 0 && e.total == null) return /* @__PURE__ */ a(F, { children: o });
11
11
  const x = e.total ?? null, h = x && x > 5e-3 ? Math.round(r / x * 1e3) / 10 : null;
12
12
  return /* @__PURE__ */ n(A, { open: d, onOpenChange: g, children: [
13
13
  /* @__PURE__ */ a(D, { asChild: !0, children: /* @__PURE__ */ a(
@@ -17,7 +17,7 @@ function Z(t) {
17
17
  "data-compare-series-details": e.key,
18
18
  "data-tip": "",
19
19
  className: "rounded px-0.5 underline decoration-dotted underline-offset-2 hover:decoration-solid focus-visible:decoration-solid",
20
- children: i
20
+ children: o
21
21
  }
22
22
  ) }),
23
23
  /* @__PURE__ */ n(j, { align: "end", sideOffset: 6, className: "w-[360px] p-0 text-[12px]", children: [
@@ -41,47 +41,47 @@ function Z(t) {
41
41
  ] }),
42
42
  c.length > 0 ? /* @__PURE__ */ n(F, { children: [
43
43
  e.details_label ? /* @__PURE__ */ a("p", { className: "px-3 pt-1.5 text-[10.5px] font-medium text-slate-500 dark:text-slate-400", children: e.details_label }) : null,
44
- /* @__PURE__ */ a("ul", { className: "max-h-[200px] overflow-y-auto overscroll-contain px-3 py-1", "data-compare-series-list": "", children: c.map((o) => {
44
+ /* @__PURE__ */ a("ul", { className: "max-h-[200px] overflow-y-auto overscroll-contain px-3 py-1", "data-compare-series-list": "", children: c.map((i) => {
45
45
  var p;
46
- return /* @__PURE__ */ n("li", { className: "py-1", "data-compare-series-row": String(o.id), children: [
46
+ return /* @__PURE__ */ n("li", { className: "py-1", "data-compare-series-row": String(i.id), children: [
47
47
  /* @__PURE__ */ n("div", { className: "flex items-baseline gap-2", children: [
48
48
  /* @__PURE__ */ n("span", { className: "min-w-0 flex-1 truncate text-slate-700 dark:text-slate-200", children: [
49
- o.label,
50
- o.sub ? /* @__PURE__ */ a("span", { className: "text-slate-500 dark:text-slate-400", children: ` · ${o.sub}` }) : null
49
+ i.label,
50
+ i.sub ? /* @__PURE__ */ a("span", { className: "text-slate-500 dark:text-slate-400", children: ` · ${i.sub}` }) : null
51
51
  ] }),
52
- /* @__PURE__ */ a("span", { className: "tabular-nums text-slate-800 dark:text-slate-100", children: m(o.amount) })
52
+ /* @__PURE__ */ a("span", { className: "tabular-nums text-slate-800 dark:text-slate-100", children: m(i.amount) })
53
53
  ] }),
54
- (o.date || (((p = o.meta) == null ? void 0 : p.length) ?? 0) > 0 || o.note) && /* @__PURE__ */ a("p", { className: "truncate text-[10.5px] text-slate-500 dark:text-slate-400", children: [o.date, ...(o.meta ?? []).map((y) => `${y.label} ${y.value}`), o.note].filter(Boolean).join(" · ") })
55
- ] }, String(o.id));
54
+ (i.date || (((p = i.meta) == null ? void 0 : p.length) ?? 0) > 0 || i.note) && /* @__PURE__ */ a("p", { className: "truncate text-[10.5px] text-slate-500 dark:text-slate-400", children: [i.date, ...(i.meta ?? []).map((y) => `${y.label} ${y.value}`), i.note].filter(Boolean).join(" · ") })
55
+ ] }, String(i.id));
56
56
  }) }),
57
57
  /* @__PURE__ */ a("p", { className: "border-t border-slate-100 px-3 py-1 text-[10.5px] tabular-nums text-slate-500 dark:border-border dark:text-slate-400", children: `${c.length} ${c.length === 1 ? "record" : "records"}` })
58
58
  ] }) : /* @__PURE__ */ a("p", { className: "px-3 py-2 text-slate-500 dark:text-slate-400", children: "Nothing listed behind this line." })
59
59
  ] })
60
60
  ] });
61
61
  }
62
- function ee(t, e, r) {
63
- const l = t.rows.find((i) => String(i.key) === String(e)), s = l == null ? void 0 : l.values[r];
62
+ function te(t, e, r) {
63
+ const l = t.rows.find((o) => String(o.key) === String(e)), s = l == null ? void 0 : l.values[r];
64
64
  return typeof s == "number" && Number.isFinite(s) ? s : null;
65
65
  }
66
- function te(t, e, r) {
66
+ function ae(t, e, r) {
67
67
  const l = r[t.key_field];
68
- let s = 0, i = 0;
68
+ let s = 0, o = 0;
69
69
  for (const d of t.columns) {
70
70
  if (!U(d) || !R(t, l, d)) continue;
71
71
  const g = Number(r[d]) || 0, c = (e == null ? void 0 : e.values[d]) ?? 0;
72
- g === 0 && c === 0 || (i++, s += c - g);
72
+ g === 0 && c === 0 || (o++, s += c - g);
73
73
  }
74
- return i ? { diff: s, months: i } : null;
74
+ return o ? { diff: s, months: o } : null;
75
75
  }
76
- function ae(t, e, r) {
76
+ function re(t, e, r) {
77
77
  const l = $.indexOf(r);
78
78
  return t.columns.filter(
79
79
  (s) => U(s) && $.indexOf(s) > l && !R(t, e, s)
80
80
  );
81
81
  }
82
- function re(t) {
82
+ function ne(t) {
83
83
  const e = $.indexOf(t);
84
- return e < 0 ? t : I[e];
84
+ return e < 0 ? t : Q[e];
85
85
  }
86
86
  function T(t) {
87
87
  return $.indexOf(t) < 0 ? t : t.charAt(0).toUpperCase() + t.slice(1);
@@ -99,21 +99,21 @@ const $ = [
99
99
  "october",
100
100
  "november",
101
101
  "december"
102
- ], I = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
102
+ ], Q = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
103
103
  function be(t, e) {
104
104
  let r = !1;
105
- const l = t.replace(/\{\{\s*\$parent\.(\w+)\s*\}\}/g, (s, i) => {
106
- const d = e == null ? void 0 : e[i];
105
+ const l = t.replace(/\{\{\s*\$parent\.(\w+)\s*\}\}/g, (s, o) => {
106
+ const d = e == null ? void 0 : e[o];
107
107
  return d == null || d === "" || d === "new" ? (r = !0, "") : encodeURIComponent(String(d));
108
108
  });
109
109
  return r ? null : l;
110
110
  }
111
111
  function fe(t) {
112
- return X({
112
+ return z({
113
113
  queryKey: ["o2m-compare", t.endpoint ?? ""],
114
114
  queryFn: async () => {
115
115
  if (!t.client || !t.endpoint) return null;
116
- const e = await t.client.request(Y(t.endpoint));
116
+ const e = await t.client.request(Z(t.endpoint));
117
117
  return (e == null ? void 0 : e.data) ?? null;
118
118
  },
119
119
  enabled: t.enabled && !!t.endpoint && !!t.client,
@@ -132,13 +132,13 @@ function R(t, e, r) {
132
132
  if (l < 0) return !1;
133
133
  const s = Number(e);
134
134
  if (!Number.isFinite(s)) return !1;
135
- const [i, d] = t.closed_through.split("-").map(Number);
136
- return s * 12 + l <= i * 12 + (d - 1);
135
+ const [o, d] = t.closed_through.split("-").map(Number);
136
+ return s * 12 + l <= o * 12 + (d - 1);
137
137
  }
138
- function ne(t) {
138
+ function le(t) {
139
139
  if (!t) return null;
140
140
  const [e, r] = t.split("-").map(Number);
141
- return !Number.isFinite(e) || !Number.isFinite(r) ? null : `${I[r - 1] ?? ""} ${e}`.trim();
141
+ return !Number.isFinite(e) || !Number.isFinite(r) ? null : `${Q[r - 1] ?? ""} ${e}`.trim();
142
142
  }
143
143
  const U = (t) => $.includes(t);
144
144
  function m(t, e = !1) {
@@ -159,31 +159,31 @@ const L = {
159
159
  warn: "text-[color:var(--nvr-role-warning,#b45309)] dark:text-[color:var(--nvr-role-warning-dark,#d4936a)]",
160
160
  danger: "text-[color:var(--nvr-role-negative,#dc2626)] dark:text-[color:var(--nvr-role-negative-dark,#e08383)]",
161
161
  neutral: "text-slate-500 dark:text-slate-400"
162
- }, le = {
162
+ }, se = {
163
163
  ok: "bg-[color:var(--nvr-role-positive,#15803d)] dark:bg-[color:var(--nvr-role-positive-dark,#9fbf8a)]",
164
164
  warn: "bg-[color:var(--nvr-role-warning,#b45309)] dark:bg-[color:var(--nvr-role-warning-dark,#d4936a)]",
165
165
  danger: "bg-[color:var(--nvr-role-negative,#dc2626)] dark:bg-[color:var(--nvr-role-negative-dark,#e08383)]",
166
166
  neutral: "bg-slate-400"
167
167
  };
168
- function Q(t, e, r) {
168
+ function X(t, e, r) {
169
169
  const l = e - t;
170
170
  return Math.abs(l) < 5e-3 ? t === 0 ? "neutral" : "ok" : r ? "warn" : l > 0 ? "danger" : "neutral";
171
171
  }
172
- function se(t) {
173
- const { column: e, plannedRow: r, actual: l, target: s } = t, i = Number(r[e]) || 0, d = Math.round((i - l) * 100) / 100, g = { [e]: l };
172
+ function oe(t) {
173
+ const { column: e, plannedRow: r, actual: l, target: s } = t, o = Number(r[e]) || 0, d = Math.round((o - l) * 100) / 100, g = { [e]: l };
174
174
  let c = 0, x = 0;
175
175
  if (s && Math.abs(d) >= 5e-3) {
176
- const h = Number(r[s]) || 0, o = Math.max(0, Math.round((h + d) * 100) / 100);
177
- c = Math.round((o - h) * 100) / 100, x = Math.round((h + d - o) * 100) / 100, g[s] = o;
176
+ const h = Number(r[s]) || 0, i = Math.max(0, Math.round((h + d) * 100) / 100);
177
+ c = Math.round((i - h) * 100) / 100, x = Math.round((h + d - i) * 100) / 100, g[s] = i;
178
178
  }
179
179
  return { patch: g, moved: c, targetShort: x };
180
180
  }
181
181
  function V(t) {
182
- const { data: e, rowKey: r, column: l, columnLabel: s, plannedRow: i, actual: d, onApply: g, variant: c = "link" } = t, [x, h] = _(!1), o = Number(i[l]) || 0, p = Math.round((o - d) * 100) / 100, y = z(() => ae(e, r, l), [e, r, l]), [v, O] = _(null);
182
+ const { data: e, rowKey: r, column: l, columnLabel: s, plannedRow: o, actual: d, onApply: g, variant: c = "link" } = t, [x, h] = _(!1), i = Number(o[l]) || 0, p = Math.round((i - d) * 100) / 100, y = Y(() => re(e, r, l), [e, r, l]), [v, O] = _(null);
183
183
  B(() => {
184
184
  x && O(y[0] ?? null);
185
185
  }, [x, y]);
186
- const f = se({ column: l, plannedRow: i, actual: d, target: v }), S = () => {
186
+ const f = oe({ column: l, plannedRow: o, actual: d, target: v }), S = () => {
187
187
  const u = `Reconciled ${s} ${String(r)} to invoiced (${m(d)})`;
188
188
  return !v || Math.abs(f.moved) < 5e-3 ? u : p > 0 ? `${u} — moved ${m(f.moved)} to ${T(v)}` : `${u} — took ${m(-f.moved)} from ${T(v)}`;
189
189
  }, [w, M] = _("");
@@ -245,7 +245,7 @@ function V(t) {
245
245
  " ",
246
246
  /* @__PURE__ */ n("span", { className: "text-slate-400", children: [
247
247
  "(was ",
248
- m(o),
248
+ m(i),
249
249
  ")"
250
250
  ] })
251
251
  ] }),
@@ -275,7 +275,7 @@ function V(t) {
275
275
  "rounded-full border px-2 py-px text-[11px]",
276
276
  v === u ? "border-nvr-cyan bg-nvr-cyan/10 font-semibold text-slate-800 dark:text-slate-100" : "border-slate-200 text-slate-600 hover:bg-muted dark:border-border dark:text-slate-300"
277
277
  ),
278
- children: re(u)
278
+ children: ne(u)
279
279
  },
280
280
  u
281
281
  )),
@@ -297,7 +297,7 @@ function V(t) {
297
297
  f.targetShort > 5e-3 && /* @__PURE__ */ n("span", { className: N("block text-[11px]", L.warn), children: [
298
298
  T(v ?? ""),
299
299
  " only holds ",
300
- m(Number(i[v ?? ""]) || 0),
300
+ m(Number(o[v ?? ""]) || 0),
301
301
  " —",
302
302
  " ",
303
303
  m(f.targetShort),
@@ -345,9 +345,9 @@ function V(t) {
345
345
  }
346
346
  function ve(t) {
347
347
  var q;
348
- const { data: e, row: r, rowKey: l, column: s, planned: i, columnLabel: d, compact: g, plannedRow: c, onAdjust: x } = t;
348
+ const { data: e, row: r, rowKey: l, column: s, planned: o, columnLabel: d, compact: g, plannedRow: c, onAdjust: x } = t;
349
349
  if (!e.columns.includes(s)) return null;
350
- const h = r == null ? void 0 : r.values[s], o = R(e, l, s), p = Number(i) || 0, y = (e.series ?? []).map((b) => ({ s: b, v: ee(b, l, s) })).filter((b) => b.v != null && Math.abs(b.v) >= 5e-3), v = y.length > 0 && /* @__PURE__ */ a("div", { className: "flex flex-wrap items-baseline gap-x-1", "data-compare-extra": "", children: y.map(({ s: b, v: H }) => {
350
+ const h = r == null ? void 0 : r.values[s], i = R(e, l, s), p = Number(o) || 0, y = (e.series ?? []).map((b) => ({ s: b, v: te(b, l, s) })).filter((b) => b.v != null && Math.abs(b.v) >= 5e-3), v = y.length > 0 && /* @__PURE__ */ a("div", { className: "flex flex-wrap items-baseline gap-x-1", "data-compare-extra": "", children: y.map(({ s: b, v: H }) => {
351
351
  var J;
352
352
  return /* @__PURE__ */ n(
353
353
  "span",
@@ -358,7 +358,7 @@ function ve(t) {
358
358
  children: [
359
359
  /* @__PURE__ */ a("span", { className: "font-mono text-[9px] uppercase tracking-wide", children: b.label }),
360
360
  /* @__PURE__ */ a(
361
- Z,
361
+ ee,
362
362
  {
363
363
  series: b,
364
364
  value: H,
@@ -370,7 +370,7 @@ function ve(t) {
370
370
  },
371
371
  b.key
372
372
  );
373
- }) }), f = e.columns[e.columns.length - 1] === s && !U(s) && c ? te(e, r, c) : null, S = f && /* @__PURE__ */ n(
373
+ }) }), f = e.columns[e.columns.length - 1] === s && !U(s) && c ? ae(e, r, c) : null, S = f && /* @__PURE__ */ n(
374
374
  "div",
375
375
  {
376
376
  "data-compare-variance": f.diff > 0 ? "over" : "under",
@@ -391,7 +391,7 @@ function ve(t) {
391
391
  }
392
392
  );
393
393
  if (!r || h == null) {
394
- const b = o && x && c && p !== 0 ? /* @__PURE__ */ a(
394
+ const b = i && x && c && p !== 0 ? /* @__PURE__ */ a(
395
395
  V,
396
396
  {
397
397
  data: e,
@@ -419,12 +419,12 @@ function ve(t) {
419
419
  }
420
420
  );
421
421
  }
422
- const w = ((q = r.details) == null ? void 0 : q[s]) ?? [], M = Q(p, h, o), k = h - p, P = Math.abs(k) >= 5e-3 && p !== 0, u = o && !!x && !!c && Math.abs(k) >= 5e-3, E = w.length > 0 || u, K = /* @__PURE__ */ a(
422
+ const w = ((q = r.details) == null ? void 0 : q[s]) ?? [], M = X(p, h, i), k = h - p, P = Math.abs(k) >= 5e-3 && p !== 0, u = i && !!x && !!c && Math.abs(k) >= 5e-3, K = w.length > 0 || u, E = /* @__PURE__ */ a(
423
423
  "span",
424
424
  {
425
425
  className: N(
426
426
  "tabular-nums font-medium",
427
- E && "cursor-pointer underline decoration-dotted decoration-slate-300 underline-offset-2 hover:decoration-slate-500 dark:decoration-slate-600",
427
+ K && "cursor-pointer underline decoration-dotted decoration-slate-300 underline-offset-2 hover:decoration-slate-500 dark:decoration-slate-600",
428
428
  "text-slate-700 dark:text-slate-200"
429
429
  ),
430
430
  children: m(h, g)
@@ -438,7 +438,7 @@ function ve(t) {
438
438
  className: "mt-0.5 flex flex-wrap items-baseline gap-x-1 text-[11px] leading-4",
439
439
  children: [
440
440
  /* @__PURE__ */ a("span", { className: "font-mono text-[9px] uppercase tracking-wide text-slate-500 dark:text-slate-400", children: e.label }),
441
- E ? /* @__PURE__ */ n(A, { children: [
441
+ K ? /* @__PURE__ */ n(A, { children: [
442
442
  /* @__PURE__ */ a(D, { asChild: !0, children: /* @__PURE__ */ a(
443
443
  "button",
444
444
  {
@@ -449,11 +449,11 @@ function ve(t) {
449
449
  onClick: (b) => b.stopPropagation(),
450
450
  onPointerDown: (b) => b.stopPropagation(),
451
451
  className: "rounded-sm text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-nvr-cyan/60",
452
- children: K
452
+ children: E
453
453
  }
454
454
  ) }),
455
455
  /* @__PURE__ */ a(
456
- oe,
456
+ ie,
457
457
  {
458
458
  title: `${d} ${String(l)}`,
459
459
  label: e.label,
@@ -461,7 +461,7 @@ function ve(t) {
461
461
  unit: W(e, w.length),
462
462
  actual: h,
463
463
  planned: p,
464
- closed: o,
464
+ closed: i,
465
465
  rows: w,
466
466
  reconcile: u && c ? /* @__PURE__ */ a(
467
467
  V,
@@ -477,13 +477,13 @@ function ve(t) {
477
477
  ) : null
478
478
  }
479
479
  )
480
- ] }) : K,
480
+ ] }) : E,
481
481
  P && /* @__PURE__ */ n(
482
482
  "span",
483
483
  {
484
484
  "data-compare-delta": !0,
485
485
  className: N("tabular-nums text-[10.5px]", L[M]),
486
- "data-tip": o ? `Closed month — ${m(Math.abs(k))} ${k > 0 ? "more" : "less"} than the ${C(e).toLowerCase()}` : k > 0 ? `Already ${m(k)} over the ${C(e).toLowerCase()} with the month still open` : `${m(-k)} of the ${C(e).toLowerCase()} still to come`,
486
+ "data-tip": i ? `Closed month — ${m(Math.abs(k))} ${k > 0 ? "more" : "less"} than the ${C(e).toLowerCase()}` : k > 0 ? `Already ${m(k)} over the ${C(e).toLowerCase()} with the month still open` : `${m(-k)} of the ${C(e).toLowerCase()} still to come`,
487
487
  children: [
488
488
  k > 0 ? "+" : "−",
489
489
  m(Math.abs(k), !0)
@@ -542,14 +542,14 @@ function W(t, e) {
542
542
  const r = t == null ? void 0 : t.unit;
543
543
  return r != null && r.one && (r != null && r.many) ? e === 1 ? r.one : r.many : e === 1 ? "entry" : "entries";
544
544
  }
545
- function oe(t) {
546
- const { title: e, label: r, planLabel: l, unit: s, actual: i, planned: d, closed: g, rows: c, reconcile: x } = t, h = i - d;
545
+ function ie(t) {
546
+ const { title: e, label: r, planLabel: l, unit: s, actual: o, planned: d, closed: g, rows: c, reconcile: x } = t, h = o - d;
547
547
  return /* @__PURE__ */ n(
548
548
  j,
549
549
  {
550
550
  align: "start",
551
551
  sideOffset: 6,
552
- onOpenAutoFocus: (o) => o.preventDefault(),
552
+ onOpenAutoFocus: (i) => i.preventDefault(),
553
553
  className: "w-[400px] max-w-[calc(100vw-32px)] p-0 text-[12px]",
554
554
  "data-compare-popover": !0,
555
555
  children: [
@@ -563,7 +563,7 @@ function oe(t) {
563
563
  className: "inline-flex items-center gap-0.5 rounded-full bg-slate-100 px-1.5 py-px text-[10px] font-medium uppercase tracking-wide text-slate-500 dark:bg-white/[0.06] dark:text-slate-400",
564
564
  "data-tip": "This month is closed — its actuals are final",
565
565
  children: [
566
- /* @__PURE__ */ a(G, { className: "h-2.5 w-2.5", "aria-hidden": "true" }),
566
+ /* @__PURE__ */ a(I, { className: "h-2.5 w-2.5", "aria-hidden": "true" }),
567
567
  " Closed"
568
568
  ]
569
569
  }
@@ -573,14 +573,14 @@ function oe(t) {
573
573
  /* @__PURE__ */ n("span", { children: [
574
574
  r,
575
575
  " ",
576
- /* @__PURE__ */ a("b", { className: "font-semibold text-slate-700 dark:text-slate-200", children: m(i) })
576
+ /* @__PURE__ */ a("b", { className: "font-semibold text-slate-700 dark:text-slate-200", children: m(o) })
577
577
  ] }),
578
578
  /* @__PURE__ */ n("span", { children: [
579
579
  l,
580
580
  " ",
581
581
  /* @__PURE__ */ a("b", { className: "font-semibold text-slate-700 dark:text-slate-200", children: m(d) })
582
582
  ] }),
583
- Math.abs(h) >= 5e-3 && /* @__PURE__ */ n("span", { className: L[Q(d, i, g)], children: [
583
+ Math.abs(h) >= 5e-3 && /* @__PURE__ */ n("span", { className: L[X(d, o, g)], children: [
584
584
  h > 0 ? "+" : "−",
585
585
  m(Math.abs(h))
586
586
  ] })
@@ -600,7 +600,7 @@ function oe(t) {
600
600
  ] }),
601
601
  x
602
602
  ] }),
603
- /* @__PURE__ */ a("ul", { className: "max-h-72 overflow-y-auto py-1", "data-compare-details-list": !0, children: c.map((o) => /* @__PURE__ */ n(
603
+ /* @__PURE__ */ a("ul", { className: "max-h-72 overflow-y-auto py-1", "data-compare-details-list": !0, children: c.map((i) => /* @__PURE__ */ n(
604
604
  "li",
605
605
  {
606
606
  className: "flex items-start justify-between gap-3 px-3.5 py-1.5 hover:bg-muted",
@@ -608,35 +608,36 @@ function oe(t) {
608
608
  children: [
609
609
  /* @__PURE__ */ n("div", { className: "min-w-0", children: [
610
610
  /* @__PURE__ */ n("div", { className: "truncate font-medium text-slate-800 dark:text-foreground", children: [
611
- o.label,
612
- o.sub && /* @__PURE__ */ a("span", { className: "ml-1.5 font-normal text-slate-500 dark:text-muted-foreground", children: o.sub })
611
+ i.label,
612
+ i.sub && /* @__PURE__ */ a("span", { className: "ml-1.5 font-normal text-slate-500 dark:text-muted-foreground", children: i.sub })
613
613
  ] }),
614
614
  /* @__PURE__ */ n("div", { className: "mt-px flex flex-wrap gap-x-2 text-[10.5px] text-slate-500 dark:text-muted-foreground", children: [
615
- o.date && /* @__PURE__ */ a("span", { children: o.date }),
616
- (o.meta ?? []).map((p) => /* @__PURE__ */ n("span", { children: [
615
+ i.date && /* @__PURE__ */ a("span", { children: i.date }),
616
+ (i.meta ?? []).map((p) => /* @__PURE__ */ n("span", { children: [
617
617
  /* @__PURE__ */ a("span", { className: "text-slate-400 dark:text-slate-500", children: p.label }),
618
618
  " ",
619
619
  p.value
620
620
  ] }, p.label))
621
621
  ] }),
622
- o.note && /* @__PURE__ */ a("div", { className: N("mt-px text-[10.5px] font-medium", L[o.tone ?? "neutral"]), children: o.note })
622
+ i.note && /* @__PURE__ */ a("div", { className: N("mt-px text-[10.5px] font-medium", L[i.tone ?? "neutral"]), children: i.note })
623
623
  ] }),
624
- /* @__PURE__ */ a("span", { className: "shrink-0 tabular-nums font-medium text-slate-800 dark:text-foreground", children: m(o.amount) })
624
+ /* @__PURE__ */ a("span", { className: "shrink-0 tabular-nums font-medium text-slate-800 dark:text-foreground", children: m(i.amount) })
625
625
  ]
626
626
  },
627
- String(o.id)
627
+ String(i.id)
628
628
  )) })
629
629
  ]
630
630
  }
631
631
  );
632
632
  }
633
- function ie(t) {
634
- const e = t.value, r = e == null ? "—" : t.format === "currency" ? e.toLocaleString("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 2 }) : e.toLocaleString("en-US", { maximumFractionDigits: 2 });
633
+ function G(t) {
634
+ const e = t.value, r = t.text != null ? t.text : e == null ? "—" : t.format === "currency" ? e.toLocaleString("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 2 }) : e.toLocaleString("en-US", { maximumFractionDigits: 2 });
635
635
  return /* @__PURE__ */ n(
636
636
  "div",
637
637
  {
638
638
  "data-o2m-stat": t.dataKey ?? t.label,
639
639
  "data-stat-negative": t.negative ? "true" : void 0,
640
+ "data-tip": t.tip || void 0,
640
641
  className: N(
641
642
  "flex items-baseline gap-2 rounded-md border px-2.5 py-1",
642
643
  t.negative ? "border-red-200 bg-red-50 dark:border-red-900/50 dark:bg-red-950/30" : "border-slate-200 bg-slate-50 dark:border-border dark:bg-muted/40"
@@ -678,18 +679,18 @@ function Ne(t) {
678
679
  }
679
680
  );
680
681
  if (!e) return null;
681
- const s = ne(e.closed_through);
682
+ const s = le(e.closed_through);
682
683
  return /* @__PURE__ */ n(F, { children: [
683
684
  e.status && /* @__PURE__ */ n(
684
685
  "div",
685
686
  {
686
687
  "data-compare-status": e.status.key,
687
688
  "data-tip": e.status.reason || void 0,
688
- className: "flex max-w-[420px] items-center gap-2 rounded-md border border-slate-200 bg-white px-2.5 py-1 dark:border-border dark:bg-card",
689
+ className: "flex items-center gap-2 rounded-md border border-slate-200 bg-white px-2.5 py-1 dark:border-border dark:bg-card",
689
690
  children: [
690
- /* @__PURE__ */ a("span", { className: N("h-2 w-2 shrink-0 rounded-full", le[e.status.tone]), "aria-hidden": "true" }),
691
+ /* @__PURE__ */ a("span", { className: N("h-2 w-2 shrink-0 rounded-full", se[e.status.tone]), "aria-hidden": "true" }),
691
692
  /* @__PURE__ */ a("span", { className: "shrink-0 whitespace-nowrap text-[12px] font-semibold text-slate-800 dark:text-slate-100", children: e.status.label }),
692
- e.status.reason && /* @__PURE__ */ a("span", { className: "min-w-0 truncate text-[11px] text-slate-500 dark:text-muted-foreground", children: e.status.reason })
693
+ e.status.reason && /* @__PURE__ */ a("span", { className: "sr-only", children: e.status.reason })
693
694
  ]
694
695
  }
695
696
  ),
@@ -700,21 +701,22 @@ function Ne(t) {
700
701
  "data-tip": e.closed_rule,
701
702
  className: "flex items-center gap-1.5 rounded-md border border-slate-200 bg-slate-50 px-2.5 py-1 text-[11px] text-slate-600 dark:border-border dark:bg-muted/40 dark:text-slate-300",
702
703
  children: [
703
- /* @__PURE__ */ a(G, { className: "h-3 w-3 text-slate-400", "aria-hidden": "true" }),
704
+ /* @__PURE__ */ a(I, { className: "h-3 w-3 text-slate-400", "aria-hidden": "true" }),
704
705
  "Closed through ",
705
706
  /* @__PURE__ */ a("b", { className: "font-semibold", children: s })
706
707
  ]
707
708
  }
708
709
  ),
709
- (e.figures ?? []).map((i) => /* @__PURE__ */ a(ie, { label: i.label, value: i.value, format: i.format, dataKey: `compare:${i.label}` }, i.label))
710
+ (e.facts ?? []).map((o) => /* @__PURE__ */ a(G, { label: o.label, value: null, text: o.value, tip: o.tip, dataKey: `compare:${o.label}` }, o.label)),
711
+ (e.figures ?? []).map((o) => /* @__PURE__ */ a(G, { label: o.label, value: o.value, format: o.format, dataKey: `compare:${o.label}` }, o.label))
710
712
  ] });
711
713
  }
712
714
  function ye(t, e) {
713
715
  if (!t || !t.columns.includes(e)) return null;
714
716
  let r = !1, l = 0;
715
717
  for (const s of t.rows) {
716
- const i = s.values[e];
717
- i != null && (r = !0, l += i);
718
+ const o = s.values[e];
719
+ o != null && (r = !0, l += o);
718
720
  }
719
721
  return r ? l : null;
720
722
  }
@@ -722,22 +724,22 @@ export {
722
724
  ve as CompareCell,
723
725
  ke as CompareProposalBanner,
724
726
  Ne as CompareStripChips,
725
- ie as GridStatChip,
727
+ G as GridStatChip,
726
728
  V as ReconcileAction,
727
- Z as SeriesFigurePopover,
728
- ne as closedThroughLabel,
729
- te as closedVariance,
729
+ ee as SeriesFigurePopover,
730
+ le as closedThroughLabel,
731
+ ae as closedVariance,
730
732
  R as compareColumnClosed,
731
733
  ye as compareColumnSum,
732
734
  ge as compareRowFor,
733
- Q as compareTone,
734
- ee as extraSeriesValue,
735
+ X as compareTone,
736
+ te as extraSeriesValue,
735
737
  m as fmtMoney,
736
- re as monthLabel,
738
+ ne as monthLabel,
737
739
  T as monthLabelLong,
738
- ae as openColumnsAfter,
740
+ re as openColumnsAfter,
739
741
  C as planLabel,
740
- se as reconcilePlan,
742
+ oe as reconcilePlan,
741
743
  be as resolveCompareEndpoint,
742
744
  W as unitWord,
743
745
  fe as useCompareSeries
@@ -1,17 +1,17 @@
1
1
  import { jsx as m, jsxs as f, Fragment as h } from "react/jsx-runtime";
2
- import { Inbox as b, Bell as u, Mail as k, MessageSquare as x } from "lucide-react";
3
- const y = {
2
+ import { Inbox as b, Bell as u, Mail as k, Users as x, MessageSquare as y } from "lucide-react";
3
+ const g = {
4
4
  ok: "text-emerald-700 dark:text-emerald-400",
5
5
  muted: "text-slate-400 dark:text-slate-500",
6
6
  warn: "text-amber-700 dark:text-amber-400",
7
7
  bad: "text-red-600 dark:text-red-400"
8
8
  };
9
- function $(i) {
10
- return c(i);
9
+ function S(n) {
10
+ return c(n);
11
11
  }
12
- function c(i) {
13
- var o, a, r, n;
14
- const e = i ?? { inapp: { status: "delivered" } }, s = [], l = ((o = e.inapp) == null ? void 0 : o.status) ?? "delivered";
12
+ function c(n) {
13
+ var o, a, r, i;
14
+ const e = n ?? { inapp: { status: "delivered" } }, s = [], l = ((o = e.inapp) == null ? void 0 : o.status) ?? "delivered";
15
15
  if (s.push({
16
16
  key: "inapp",
17
17
  icon: b,
@@ -39,41 +39,51 @@ function c(i) {
39
39
  mailLogId: e.email.mail_log_id ?? null
40
40
  });
41
41
  }
42
- return ((r = e.escalation) != null && r.email_at || (n = e.escalation) != null && n.push_at) && s.push({
42
+ if (((r = e.escalation) != null && r.email_at || (i = e.escalation) != null && i.push_at) && s.push({
43
43
  key: "escalation",
44
44
  icon: u,
45
45
  label: e.escalation.email_at ? "Escalated · email" : "Escalated · push",
46
46
  tone: "warn",
47
47
  tip: `Still unread, so it climbed channels${e.escalation.push_at ? ` · pushed ${new Date(e.escalation.push_at).toLocaleString()}` : ""}${e.escalation.email_at ? ` · emailed ${new Date(e.escalation.email_at).toLocaleString()}` : ""}`,
48
48
  mailLogId: e.escalation.email_log_id ?? null
49
- }), e.sms && e.sms.status !== "not_requested" && s.push({
49
+ }), e.teams) {
50
+ const t = e.teams.status;
51
+ s.push({
52
+ key: "teams",
53
+ icon: x,
54
+ label: t === "sent" ? "Teams" : `Teams · ${t.replace(/_/g, " ")}`,
55
+ tone: t === "sent" ? "ok" : t === "failed" ? "bad" : "muted",
56
+ tip: t === "sent" ? "Sent in Microsoft Teams" : t === "not_connected" ? "Teams not connected" : e.teams.reason ?? `Teams ${t}`
57
+ });
58
+ }
59
+ return e.sms && e.sms.status !== "not_requested" && s.push({
50
60
  key: "sms",
51
- icon: x,
61
+ icon: y,
52
62
  label: "SMS",
53
63
  tone: e.sms.status === "sent" ? "ok" : e.sms.status === "failed" ? "bad" : "muted",
54
64
  tip: e.sms.status === "sent" ? "Text sent" : e.sms.reason ?? `SMS ${e.sms.status}`
55
65
  }), s;
56
66
  }
57
- function w({ delivery: i, mailLogUrl: e, onNavigate: s, className: l }) {
58
- const o = c(i);
67
+ function w({ delivery: n, mailLogUrl: e, onNavigate: s, className: l }) {
68
+ const o = c(n);
59
69
  return /* @__PURE__ */ m(
60
70
  "span",
61
71
  {
62
72
  className: `inline-flex flex-wrap items-center gap-1 ${l ?? ""}`,
63
73
  "data-nvr-delivery": !0,
64
74
  children: o.map((a) => {
65
- const r = a.icon, n = a.mailLogId != null && e ? e(a.mailLogId) : null, t = /* @__PURE__ */ f(h, { children: [
75
+ const r = a.icon, i = a.mailLogId != null && e ? e(a.mailLogId) : null, t = /* @__PURE__ */ f(h, { children: [
66
76
  /* @__PURE__ */ m(r, { className: "h-2.5 w-2.5", strokeWidth: 2 }),
67
77
  a.label
68
- ] }), d = `inline-flex items-center gap-0.5 rounded border border-slate-200/70 px-1 py-px text-[9.5px] font-medium leading-none dark:border-border ${y[a.tone]}`;
69
- return n ? /* @__PURE__ */ m(
78
+ ] }), d = `inline-flex items-center gap-0.5 rounded border border-slate-200/70 px-1 py-px text-[9.5px] font-medium leading-none dark:border-border ${g[a.tone]}`;
79
+ return i ? /* @__PURE__ */ m(
70
80
  "button",
71
81
  {
72
82
  type: "button",
73
83
  "data-tip": `${a.tip} · open mail log`,
74
84
  title: a.tip,
75
85
  onClick: (p) => {
76
- p.stopPropagation(), s == null || s(n);
86
+ p.stopPropagation(), s == null || s(i);
77
87
  },
78
88
  className: `${d} underline decoration-dotted underline-offset-2`,
79
89
  children: t
@@ -86,5 +96,5 @@ function w({ delivery: i, mailLogUrl: e, onNavigate: s, className: l }) {
86
96
  }
87
97
  export {
88
98
  w as DeliveryChips,
89
- $ as describeDelivery
99
+ S as describeDelivery
90
100
  };
@@ -0,0 +1,71 @@
1
+ import { jsxs as t, Fragment as m, jsx as e } from "react/jsx-runtime";
2
+ import { useQueryClient as l, useMutation as c } from "@tanstack/react-query";
3
+ import { useState as u } from "react";
4
+ import { useNivaroClient as f } from "../../context.js";
5
+ import { del as x } from "../../lib/commands.js";
6
+ import { Popover as p, PopoverTrigger as g, PopoverContent as h } from "../ui/popover.js";
7
+ import { ConfirmButton as k } from "./primitives.js";
8
+ function P({ linked: a, linkedAt: r }) {
9
+ const i = f(), d = l(), [s, n] = u(!1), o = c({
10
+ mutationFn: () => (n(!1), i.request(x("/teams/link"))),
11
+ onError: () => n(!0),
12
+ onSettled: () => {
13
+ d.invalidateQueries({ queryKey: ["nvr-profile-teams"] });
14
+ }
15
+ });
16
+ return a ? /* @__PURE__ */ t(m, { children: [
17
+ /* @__PURE__ */ t(
18
+ "span",
19
+ {
20
+ className: "inline-flex flex-wrap items-center justify-center gap-1 text-[10.5px] font-normal normal-case tracking-normal text-emerald-700 dark:text-emerald-400",
21
+ "data-teams-connected": "",
22
+ title: r ? `Connected ${new Date(r).toLocaleString()}` : void 0,
23
+ children: [
24
+ "Connected ·",
25
+ " ",
26
+ /* @__PURE__ */ e(
27
+ k,
28
+ {
29
+ onConfirm: () => o.mutate(),
30
+ confirmLabel: "Disconnect Teams?",
31
+ disabled: o.isPending,
32
+ className: "font-medium text-slate-500 underline decoration-dotted underline-offset-2 hover:text-slate-800 dark:text-muted-foreground dark:hover:text-foreground",
33
+ armedClassName: "font-medium text-red-600 dark:text-red-400",
34
+ children: "Disconnect"
35
+ }
36
+ )
37
+ ]
38
+ }
39
+ ),
40
+ s && /* @__PURE__ */ e(
41
+ "p",
42
+ {
43
+ role: "alert",
44
+ "data-teams-disconnect-error": "",
45
+ className: "mt-0.5 text-[10.5px] font-normal normal-case tracking-normal text-red-600 dark:text-red-400",
46
+ children: "Could not disconnect Teams. Try again; if it keeps failing, ask an admin."
47
+ }
48
+ )
49
+ ] }) : /* @__PURE__ */ t(p, { children: [
50
+ /* @__PURE__ */ e(g, { asChild: !0, children: /* @__PURE__ */ e(
51
+ "button",
52
+ {
53
+ type: "button",
54
+ "data-teams-connect": "",
55
+ className: "rounded border border-slate-200 px-1.5 py-0.5 text-[10.5px] font-medium normal-case tracking-normal text-slate-600 hover:border-slate-400 hover:text-slate-800 dark:border-border dark:text-muted-foreground dark:hover:text-foreground",
56
+ children: "Connect Teams"
57
+ }
58
+ ) }),
59
+ /* @__PURE__ */ e(
60
+ h,
61
+ {
62
+ align: "end",
63
+ className: "w-64 text-[12px] font-normal normal-case tracking-normal text-slate-600 dark:text-muted-foreground",
64
+ children: "Open Nivaro in Teams and say hi, or sign in with Microsoft once, then turn categories on."
65
+ }
66
+ )
67
+ ] });
68
+ }
69
+ export {
70
+ P as TeamsConnect
71
+ };