@dreamtree-org/landing-kit 0.9.0 → 0.10.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/platform.js CHANGED
@@ -4,7 +4,7 @@
4
4
  var PLATFORM_API_BASE = "/api/platform";
5
5
  var PLATFORM_LOGIN_PATH = "/platform/login";
6
6
  var STEP_UP_REQUIRED = "STEP_UP_REQUIRED";
7
- var PLATFORM_FEATURES = ["overview", "companies", "jobs", "plans", "audit", "support", "settings", "admins"];
7
+ var PLATFORM_FEATURES = ["overview", "companies", "jobs", "plans", "audit", "support", "settings", "domains", "admins"];
8
8
  var SHIPPED_FEATURES = ["overview", "companies", "jobs", "admins"];
9
9
  var SAFE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
10
10
  var CSRF_HEADER = "x-csrf-token";
@@ -147,8 +147,8 @@ function timeAgo(value, now = Date.now()) {
147
147
  }
148
148
 
149
149
  // src/platform/PlatformConsole.jsx
150
- import React13, { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo3, useState as useState11 } from "react";
151
- import { EmptyState as EmptyState4, LoadingState as LoadingState6 } from "@dreamtree-org/twreact-ui";
150
+ import React16, { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo3, useState as useState14 } from "react";
151
+ import { EmptyState as EmptyState7, LoadingState as LoadingState9 } from "@dreamtree-org/twreact-ui";
152
152
 
153
153
  // src/platform/context.jsx
154
154
  import React, { createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useState } from "react";
@@ -400,6 +400,23 @@ var IconArchive = make(/* @__PURE__ */ jsxs2(Fragment, { children: [
400
400
  /* @__PURE__ */ jsx3("path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8M10 12h4" })
401
401
  ] }));
402
402
  var IconDownload = make(/* @__PURE__ */ jsx3("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3" }));
403
+ var IconTag = make(/* @__PURE__ */ jsxs2(Fragment, { children: [
404
+ /* @__PURE__ */ jsx3("path", { d: "M12.6 2.6A2 2 0 0 0 11.2 2H4a2 2 0 0 0-2 2v7.2a2 2 0 0 0 .6 1.4l8.7 8.7a2.4 2.4 0 0 0 3.4 0l6.6-6.6a2.4 2.4 0 0 0 0-3.4Z" }),
405
+ /* @__PURE__ */ jsx3("circle", { cx: "7.5", cy: "7.5", r: "1.5" })
406
+ ] }));
407
+ var IconLifebuoy = make(/* @__PURE__ */ jsxs2(Fragment, { children: [
408
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
409
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "4" }),
410
+ /* @__PURE__ */ jsx3("path", { d: "m4.93 4.93 4.24 4.24M14.83 14.83l4.24 4.24M14.83 9.17l4.24-4.24M4.93 19.07l4.24-4.24" })
411
+ ] }));
412
+ var IconGlobe = make(/* @__PURE__ */ jsxs2(Fragment, { children: [
413
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
414
+ /* @__PURE__ */ jsx3("path", { d: "M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })
415
+ ] }));
416
+ var IconSettings = make(/* @__PURE__ */ jsxs2(Fragment, { children: [
417
+ /* @__PURE__ */ jsx3("path", { d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" }),
418
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "3" })
419
+ ] }));
403
420
 
404
421
  // src/platform/PlatformShell.jsx
405
422
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -473,7 +490,13 @@ var STATUS_MAP = {
473
490
  running: { label: "Running", tone: "info" },
474
491
  pending: { label: "Pending", tone: "neutral" },
475
492
  queued: { label: "Queued", tone: "neutral" },
476
- cancelled: { label: "Cancelled", tone: "muted" }
493
+ cancelled: { label: "Cancelled", tone: "muted" },
494
+ trial: { label: "Trial", tone: "info" },
495
+ past_due: { label: "Past due", tone: "warning" },
496
+ expired: { label: "Expired", tone: "muted" },
497
+ requested: { label: "Awaiting approval", tone: "warning" },
498
+ revoked: { label: "Revoked", tone: "muted" },
499
+ verified: { label: "Verified", tone: "success" }
477
500
  };
478
501
  function StatusPill({ status }) {
479
502
  return /* @__PURE__ */ jsx5(TwStatusPill, { status: String(status != null ? status : ""), map: STATUS_MAP });
@@ -630,8 +653,31 @@ var ACTION_LABEL = {
630
653
  "platform.admin.roles": "changed platform admin roles",
631
654
  "platform.admin.disable": "disabled platform admin",
632
655
  "platform.admin.enable": "enabled platform admin",
633
- "audit.export": "exported the audit log"
656
+ "audit.export": "exported the audit log",
657
+ "plan.create": "created plan",
658
+ "plan.update": "updated plan",
659
+ "subscription.update": "changed subscription",
660
+ "settings.update": "changed settings",
661
+ "support.grant.request": "requested support access",
662
+ "support.grant.approve": "approved support access",
663
+ "support.grant.revoke": "revoked support access",
664
+ "domain.add": "added domain",
665
+ "domain.verify": "verified domain",
666
+ "domain.primary": "set primary domain",
667
+ "domain.remove": "removed domain"
634
668
  };
669
+ function formatPrice(priceMinor, currency = "INR", interval) {
670
+ var _a;
671
+ const amount = Number(priceMinor != null ? priceMinor : 0) / 100;
672
+ let text;
673
+ try {
674
+ text = new Intl.NumberFormat(void 0, { style: "currency", currency }).format(amount);
675
+ } catch {
676
+ text = `${currency} ${amount.toFixed(2)}`;
677
+ }
678
+ const per = (_a = { month: " / month", year: " / year", "one-time": " once" }[interval]) != null ? _a : "";
679
+ return `${text}${per}`;
680
+ }
635
681
  function describeAction(action) {
636
682
  var _a;
637
683
  return (_a = ACTION_LABEL[action]) != null ? _a : String(action != null ? action : "").replace(/[._]/g, " ");
@@ -1108,30 +1154,514 @@ function NewCompanyView() {
1108
1154
  }
1109
1155
 
1110
1156
  // src/platform/views/CompanyDetail.jsx
1111
- import React9, { useCallback as useCallback3, useEffect as useEffect4, useState as useState7 } from "react";
1157
+ import React11, { useCallback as useCallback3, useEffect as useEffect5, useState as useState9 } from "react";
1112
1158
  import {
1113
- Alert as Alert3,
1114
- Button as Button6,
1115
- ConfirmDialog,
1116
- Dialog as Dialog2,
1117
- EmptyState as EmptyState2,
1118
- ErrorState as ErrorState3,
1119
- Input as Input4,
1120
- LoadingState as LoadingState3,
1121
- PageHeader as PageHeader4,
1159
+ Alert as Alert4,
1160
+ Button as Button8,
1161
+ ConfirmDialog as ConfirmDialog2,
1162
+ Dialog as Dialog4,
1163
+ EmptyState as EmptyState4,
1164
+ ErrorState as ErrorState5,
1165
+ Input as Input6,
1166
+ LoadingState as LoadingState5,
1167
+ PageHeader as PageHeader5,
1122
1168
  Tabs,
1123
- Textarea
1169
+ Textarea as Textarea3
1124
1170
  } from "@dreamtree-org/twreact-ui";
1125
- import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1171
+
1172
+ // src/platform/views/CompanyFeatures.jsx
1173
+ import React10, { useEffect as useEffect4, useState as useState8 } from "react";
1174
+ import { Badge as Badge2, Button as Button7, ConfirmDialog, Dialog as Dialog3, EmptyState as EmptyState3, ErrorState as ErrorState4, Input as Input5, LoadingState as LoadingState4, Select as Select2, Switch, Textarea as Textarea2 } from "@dreamtree-org/twreact-ui";
1175
+
1176
+ // src/platform/views/SupportAccess.jsx
1177
+ import React9, { useState as useState7 } from "react";
1178
+ import { Alert as Alert3, Button as Button6, Dialog as Dialog2, EmptyState as EmptyState2, ErrorState as ErrorState3, Input as Input4, LoadingState as LoadingState3, PageHeader as PageHeader4, SegmentedControl as SegmentedControl2, Select, Textarea } from "@dreamtree-org/twreact-ui";
1179
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1180
+ var FILTERS2 = [
1181
+ { value: "", label: "All" },
1182
+ { value: "requested", label: "Awaiting approval" },
1183
+ { value: "active", label: "Active" },
1184
+ { value: "expired", label: "Expired" },
1185
+ { value: "revoked", label: "Revoked" }
1186
+ ];
1187
+ var DURATIONS = [
1188
+ { value: "30", label: "30 minutes" },
1189
+ { value: "60", label: "1 hour" },
1190
+ { value: "120", label: "2 hours" },
1191
+ { value: "240", label: "4 hours" },
1192
+ { value: "480", label: "8 hours" }
1193
+ ];
1194
+ function until(value) {
1195
+ const ms = new Date(value).getTime() - Date.now();
1196
+ if (!Number.isFinite(ms) || ms <= 0) return "now";
1197
+ const m = Math.round(ms / 6e4);
1198
+ return m < 60 ? `in ${m} min` : `in ${Math.floor(m / 60)} h ${m % 60} min`;
1199
+ }
1200
+ function SupportGrants({ companyId, companyName }) {
1201
+ var _a, _b;
1202
+ const { client, can, me } = usePlatform();
1203
+ const sensitive = useSensitive();
1204
+ const [status, setStatus] = useState7(companyId ? "" : "requested");
1205
+ const { data, error, loading, reload } = useLoad("support-access", { company: companyId || void 0, status: status || void 0 });
1206
+ const [flash, setFlash] = useState7(null);
1207
+ const [requesting, setRequesting] = useState7(false);
1208
+ const canGrant = can("support.grant");
1209
+ const myId = (_a = me == null ? void 0 : me.admin) == null ? void 0 : _a.id;
1210
+ const grants = (_b = data == null ? void 0 : data.grants) != null ? _b : [];
1211
+ const act = async (g, action) => {
1212
+ var _a2;
1213
+ setFlash(null);
1214
+ try {
1215
+ await sensitive(() => client.post(`support-access/${encodeURIComponent(g.id)}`, { action }));
1216
+ setFlash({ kind: "success", msg: action === "approve" ? `Approved access to ${(_a2 = g.companyName) != null ? _a2 : "the company"}` : "Access revoked" });
1217
+ await reload();
1218
+ } catch (e) {
1219
+ const msg = errorText(e);
1220
+ if (msg) setFlash({ kind: "error", msg });
1221
+ }
1222
+ };
1223
+ return /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
1224
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
1225
+ /* @__PURE__ */ jsx10("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsx10(SegmentedControl2, { "aria-label": "Filter by status", options: FILTERS2, value: status, onChange: (v) => setStatus(String(v)) }) }),
1226
+ can("support.request") && /* @__PURE__ */ jsx10(Button6, { variant: companyId ? "outline" : "primary", leftIcon: /* @__PURE__ */ jsx10(IconPlus, {}), onClick: () => setRequesting(true), children: "Request access" })
1227
+ ] }),
1228
+ flash && /* @__PURE__ */ jsx10(Alert3, { variant: flash.kind, dismissible: true, onDismiss: () => setFlash(null), children: flash.msg }),
1229
+ error && !data ? /* @__PURE__ */ jsx10(ErrorState3, { description: error.message, onRetry: reload }) : loading && !data ? /* @__PURE__ */ jsx10(LoadingState3, { variant: "table", rows: 3 }) : grants.length === 0 ? /* @__PURE__ */ jsx10(
1230
+ EmptyState2,
1231
+ {
1232
+ compact: true,
1233
+ icon: /* @__PURE__ */ jsx10(IconLifebuoy, { size: 24 }),
1234
+ title: status ? "No grants with this status" : "No support access yet",
1235
+ description: "Support access lets a platform admin work in one company for a limited time, after another admin approves it."
1236
+ }
1237
+ ) : /* @__PURE__ */ jsx10("ul", { className: "divide-y divide-line rounded-xl border border-line bg-surface", children: grants.map((g) => {
1238
+ var _a2, _b2;
1239
+ const mine = myId && g.requestedById === myId;
1240
+ return /* @__PURE__ */ jsxs9("li", { className: "flex flex-wrap items-start gap-3 px-4 py-3", children: [
1241
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
1242
+ /* @__PURE__ */ jsxs9("div", { className: "text-sm font-medium text-foreground", children: [
1243
+ g.requestedBy,
1244
+ !companyId && g.companyName ? /* @__PURE__ */ jsxs9("span", { className: "text-muted", children: [
1245
+ " \u2192 ",
1246
+ g.companyName
1247
+ ] }) : null
1248
+ ] }),
1249
+ /* @__PURE__ */ jsx10("div", { className: "mt-0.5 break-words text-sm text-foreground", children: g.reason }),
1250
+ /* @__PURE__ */ jsxs9("div", { className: "mt-0.5 text-xs text-muted", children: [
1251
+ g.status === "requested" && `${(_a2 = g.minutes) != null ? _a2 : "\u2014"} min once approved \xB7 requested ${timeAgo(g.createdAt)}`,
1252
+ g.status === "active" && `Approved by ${(_b2 = g.approvedBy) != null ? _b2 : "\u2014"} \xB7 ends ${until(g.expiresAt)}`,
1253
+ g.status === "expired" && `Ended ${formatDate(g.expiresAt)}`,
1254
+ g.status === "revoked" && `Revoked ${formatDate(g.revokedAt)}`
1255
+ ] })
1256
+ ] }),
1257
+ /* @__PURE__ */ jsx10(StatusPill, { status: g.status }),
1258
+ canGrant && (g.status === "requested" || g.status === "active") && /* @__PURE__ */ jsxs9("div", { className: "flex gap-1", children: [
1259
+ g.status === "requested" && !mine && /* @__PURE__ */ jsx10(Button6, { size: "sm", onClick: () => act(g, "approve"), children: "Approve" }),
1260
+ /* @__PURE__ */ jsx10(Button6, { size: "sm", variant: "ghost", onClick: () => act(g, "revoke"), children: g.status === "requested" ? "Decline" : "Revoke" })
1261
+ ] })
1262
+ ] }, g.id);
1263
+ }) }),
1264
+ requesting && /* @__PURE__ */ jsx10(
1265
+ RequestDialog,
1266
+ {
1267
+ companyId,
1268
+ companyName,
1269
+ onClose: () => setRequesting(false),
1270
+ onDone: async (g) => {
1271
+ var _a2;
1272
+ setRequesting(false);
1273
+ setFlash({ kind: "success", msg: `Requested access to ${(_a2 = g.companyName) != null ? _a2 : "the company"}. Another admin has to approve it.` });
1274
+ await reload();
1275
+ }
1276
+ }
1277
+ )
1278
+ ] });
1279
+ }
1280
+ function RequestDialog({ companyId, companyName, onClose, onDone }) {
1281
+ var _a, _b;
1282
+ const { client } = usePlatform();
1283
+ const companies = useLoad(companyId ? null : "companies");
1284
+ const [company, setCompany] = useState7(companyId != null ? companyId : "");
1285
+ const [reason, setReason] = useState7("");
1286
+ const [minutes, setMinutes] = useState7("60");
1287
+ const [busy, setBusy] = useState7(false);
1288
+ const [err, setErr] = useState7(null);
1289
+ const options = ((_b = (_a = companies.data) == null ? void 0 : _a.companies) != null ? _b : []).map((c) => {
1290
+ var _a2;
1291
+ return { value: c.id, label: (_a2 = c.displayName) != null ? _a2 : c.slug };
1292
+ });
1293
+ const submit = async () => {
1294
+ setBusy(true);
1295
+ setErr(null);
1296
+ try {
1297
+ const r = await client.post("support-access", { companyId: company, reason: reason.trim(), minutes: Number(minutes) });
1298
+ await onDone(r.grant);
1299
+ } catch (e) {
1300
+ setErr(errorText(e));
1301
+ } finally {
1302
+ setBusy(false);
1303
+ }
1304
+ };
1305
+ return /* @__PURE__ */ jsx10(
1306
+ Dialog2,
1307
+ {
1308
+ isOpen: true,
1309
+ onClose,
1310
+ title: "Request support access",
1311
+ size: "sm",
1312
+ footer: /* @__PURE__ */ jsxs9("div", { className: "flex justify-end gap-2", children: [
1313
+ /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: onClose, children: "Cancel" }),
1314
+ /* @__PURE__ */ jsx10(Button6, { loading: busy, disabled: !company || reason.trim().length < 8, onClick: submit, children: "Request" })
1315
+ ] }),
1316
+ children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
1317
+ err && /* @__PURE__ */ jsx10(Alert3, { variant: "error", children: err }),
1318
+ companyId ? /* @__PURE__ */ jsx10(Input4, { label: "Company", value: companyName != null ? companyName : companyId, disabled: true }) : /* @__PURE__ */ jsx10(Select, { label: "Company", searchable: true, options, loading: companies.loading, value: company, onChange: (v) => setCompany(String(v)), placeholder: "Pick a company" }),
1319
+ /* @__PURE__ */ jsx10(Textarea, { label: "Reason", rows: 3, value: reason, onChange: (e) => setReason(e.target.value), helperText: "At least 8 characters, e.g. the ticket number. The company's audit trail shows it." }),
1320
+ /* @__PURE__ */ jsx10(Select, { label: "For", options: DURATIONS, value: minutes, onChange: (v) => setMinutes(String(v)), helperText: "Counted from approval" })
1321
+ ] })
1322
+ }
1323
+ );
1324
+ }
1325
+ function SupportAccessView() {
1326
+ const { Link } = usePlatform();
1327
+ return /* @__PURE__ */ jsxs9("div", { className: "mx-auto max-w-5xl space-y-6 px-4 py-6 sm:px-6", children: [
1328
+ /* @__PURE__ */ jsx10(PageHeader4, { title: "Support access", subtitle: "Time-boxed access to one company, approved by a second platform admin", linkAs: Link }),
1329
+ /* @__PURE__ */ jsx10(SupportGrants, {})
1330
+ ] });
1331
+ }
1332
+
1333
+ // src/platform/views/CompanyFeatures.jsx
1334
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1335
+ var SUB_STATUSES = [
1336
+ { value: "active", label: "Active" },
1337
+ { value: "trial", label: "Trial" },
1338
+ { value: "past_due", label: "Past due" },
1339
+ { value: "cancelled", label: "Cancelled" },
1340
+ { value: "expired", label: "Expired" }
1341
+ ];
1342
+ var day = (v) => v ? String(v).slice(0, 10) : "";
1343
+ function featureTabs({ features, can }) {
1344
+ return [
1345
+ features.includes("plans") && can("plans.read") && { id: "subscription", label: "Subscription", Component: SubscriptionTab },
1346
+ features.includes("domains") && can("domains.read") && { id: "domains", label: "Domains", Component: DomainsTab },
1347
+ features.includes("settings") && can("settings.read") && { id: "settings", label: "Settings", Component: SettingsTab },
1348
+ features.includes("support") && can("support.request") && { id: "support", label: "Support", Component: SupportTab }
1349
+ ].filter(Boolean);
1350
+ }
1351
+ function SubscriptionTab({ company, setFlash }) {
1352
+ var _a, _b, _c, _d, _e, _f;
1353
+ const { client, can } = usePlatform();
1354
+ const sensitive = useSensitive();
1355
+ const id = encodeURIComponent(company.id);
1356
+ const { data, error, loading, reload } = useLoad(`companies/${id}/subscription`);
1357
+ const plans = useLoad(can("plans.write") ? "plans" : null);
1358
+ const [editing, setEditing] = useState8(null);
1359
+ const [busy, setBusy] = useState8(false);
1360
+ const current = data == null ? void 0 : data.subscription;
1361
+ const history = (_a = data == null ? void 0 : data.history) != null ? _a : [];
1362
+ const planOptions = ((_c = (_b = plans.data) == null ? void 0 : _b.plans) != null ? _c : []).filter((p) => p.status === "active" || p.id === (current == null ? void 0 : current.planId)).map((p) => ({ value: p.id, label: `${p.name} \xB7 ${formatPrice(p.priceMinor, p.currency, p.interval)}` }));
1363
+ const save = async () => {
1364
+ setBusy(true);
1365
+ try {
1366
+ await sensitive(
1367
+ () => client.put(`companies/${id}/subscription`, {
1368
+ planId: editing.planId,
1369
+ status: editing.status,
1370
+ startsAt: editing.startsAt || void 0,
1371
+ endsAt: editing.endsAt || null,
1372
+ seats: editing.seats === "" ? null : Number(editing.seats),
1373
+ notes: editing.notes || null
1374
+ })
1375
+ );
1376
+ setEditing(null);
1377
+ setFlash({ kind: "success", msg: "Subscription updated" });
1378
+ await reload();
1379
+ } catch (e) {
1380
+ const msg = errorText(e);
1381
+ if (msg) setFlash({ kind: "error", msg });
1382
+ } finally {
1383
+ setBusy(false);
1384
+ }
1385
+ };
1386
+ if (error && !data) return /* @__PURE__ */ jsx11(ErrorState4, { description: error.message, onRetry: reload });
1387
+ if (loading && !data) return /* @__PURE__ */ jsx11(LoadingState4, { variant: "detail" });
1388
+ const open = () => {
1389
+ var _a2, _b2;
1390
+ return setEditing({
1391
+ planId: (_a2 = current == null ? void 0 : current.planId) != null ? _a2 : "",
1392
+ status: (_b2 = current == null ? void 0 : current.status) != null ? _b2 : "active",
1393
+ startsAt: "",
1394
+ endsAt: day(current == null ? void 0 : current.endsAt),
1395
+ seats: (current == null ? void 0 : current.seats) == null ? "" : String(current.seats),
1396
+ notes: ""
1397
+ });
1398
+ };
1399
+ return /* @__PURE__ */ jsxs10("div", { className: "space-y-4", children: [
1400
+ /* @__PURE__ */ jsx11(
1401
+ Card,
1402
+ {
1403
+ title: "Current plan",
1404
+ actions: can("plans.write") && /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "outline", onClick: open, children: current ? "Change" : "Assign a plan" }),
1405
+ children: current ? /* @__PURE__ */ jsx11(
1406
+ Facts,
1407
+ {
1408
+ rows: [
1409
+ ["Plan", (_e = (_d = current.planName) != null ? _d : current.planCode) != null ? _e : current.planId],
1410
+ ["Status", /* @__PURE__ */ jsx11(StatusPill, { status: current.status }, "s")],
1411
+ ["Started", formatDate(current.startsAt)],
1412
+ ["Ends", current.endsAt ? formatDate(current.endsAt) : "No end date"],
1413
+ ["Seats", (_f = current.seats) != null ? _f : "Plan default"],
1414
+ ...current.notes ? [["Notes", current.notes]] : []
1415
+ ]
1416
+ }
1417
+ ) : /* @__PURE__ */ jsx11(EmptyState3, { compact: true, icon: /* @__PURE__ */ jsx11(IconTag, { size: 24 }), title: "No plan yet", description: "This company is not on a plan." })
1418
+ }
1419
+ ),
1420
+ history.length > 0 && /* @__PURE__ */ jsx11(Card, { title: "History", children: /* @__PURE__ */ jsx11("ul", { className: "divide-y divide-line", children: history.map((s) => {
1421
+ var _a2, _b2;
1422
+ return /* @__PURE__ */ jsxs10("li", { className: "flex flex-wrap items-center gap-3 py-2 text-sm", children: [
1423
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 flex-1 text-foreground", children: (_b2 = (_a2 = s.planName) != null ? _a2 : s.planCode) != null ? _b2 : s.planId }),
1424
+ /* @__PURE__ */ jsx11(StatusPill, { status: s.status }),
1425
+ /* @__PURE__ */ jsxs10("span", { className: "text-xs text-muted", children: [
1426
+ "from ",
1427
+ formatDate(s.startsAt)
1428
+ ] })
1429
+ ] }, s.id);
1430
+ }) }) }),
1431
+ /* @__PURE__ */ jsx11(
1432
+ Dialog3,
1433
+ {
1434
+ isOpen: editing !== null,
1435
+ onClose: () => setEditing(null),
1436
+ title: current ? "Change subscription" : "Assign a plan",
1437
+ size: "sm",
1438
+ footer: /* @__PURE__ */ jsxs10("div", { className: "flex justify-end gap-2", children: [
1439
+ /* @__PURE__ */ jsx11(Button7, { variant: "outline", onClick: () => setEditing(null), children: "Cancel" }),
1440
+ /* @__PURE__ */ jsx11(Button7, { loading: busy, disabled: !(editing == null ? void 0 : editing.planId), onClick: save, children: "Save" })
1441
+ ] }),
1442
+ children: editing && /* @__PURE__ */ jsxs10("div", { className: "space-y-4", children: [
1443
+ /* @__PURE__ */ jsx11(Select2, { label: "Plan", options: planOptions, loading: plans.loading, value: editing.planId, onChange: (v) => setEditing((s) => ({ ...s, planId: String(v) })), placeholder: "Pick a plan" }),
1444
+ /* @__PURE__ */ jsx11(Select2, { label: "Status", options: SUB_STATUSES, value: editing.status, onChange: (v) => setEditing((s) => ({ ...s, status: String(v) })) }),
1445
+ /* @__PURE__ */ jsxs10("div", { className: "grid gap-4 sm:grid-cols-2", children: [
1446
+ /* @__PURE__ */ jsx11(Input5, { label: "Starts", type: "date", value: editing.startsAt, onChange: (e) => setEditing((s) => ({ ...s, startsAt: e.target.value })), helperText: "Empty: today" }),
1447
+ /* @__PURE__ */ jsx11(Input5, { label: "Ends", type: "date", value: editing.endsAt, onChange: (e) => setEditing((s) => ({ ...s, endsAt: e.target.value })), helperText: "Empty: no end date" })
1448
+ ] }),
1449
+ /* @__PURE__ */ jsx11(Input5, { label: "Seats", type: "number", min: "1", value: editing.seats, onChange: (e) => setEditing((s) => ({ ...s, seats: e.target.value })), helperText: "Empty: the plan's default" }),
1450
+ /* @__PURE__ */ jsx11(Textarea2, { label: "Notes", rows: 2, value: editing.notes, onChange: (e) => setEditing((s) => ({ ...s, notes: e.target.value })) })
1451
+ ] })
1452
+ }
1453
+ )
1454
+ ] });
1455
+ }
1456
+ function DomainsTab({ company, setFlash }) {
1457
+ var _a;
1458
+ const { client, can } = usePlatform();
1459
+ const sensitive = useSensitive();
1460
+ const id = encodeURIComponent(company.id);
1461
+ const { data, error, loading, reload } = useLoad(`companies/${id}/domains`);
1462
+ const [host, setHost] = useState8("");
1463
+ const [adding, setAdding] = useState8(false);
1464
+ const [busy, setBusy] = useState8(null);
1465
+ const [removing, setRemoving] = useState8(null);
1466
+ const writable = can("domains.write");
1467
+ const domains = (_a = data == null ? void 0 : data.domains) != null ? _a : [];
1468
+ const act = async (d, action) => {
1469
+ setBusy(`${d.id}:${action}`);
1470
+ setFlash(null);
1471
+ try {
1472
+ const call = () => client.post(`companies/${id}/domains/${encodeURIComponent(d.id)}`, { action });
1473
+ const r = await (action === "remove" ? sensitive(call) : call());
1474
+ if (action === "verify") {
1475
+ setFlash(r.verified ? { kind: "success", msg: `${d.host} is verified` } : { kind: "warning", msg: `The TXT record for ${d.host} was not found yet. DNS changes can take a while to appear.` });
1476
+ } else setFlash({ kind: "success", msg: action === "remove" ? `${d.host} removed` : `${d.host} is now the primary domain` });
1477
+ await reload();
1478
+ } catch (e) {
1479
+ const msg = errorText(e);
1480
+ if (msg) setFlash({ kind: "error", msg });
1481
+ } finally {
1482
+ setBusy(null);
1483
+ }
1484
+ };
1485
+ const add = async () => {
1486
+ setBusy("add");
1487
+ setFlash(null);
1488
+ try {
1489
+ await client.post(`companies/${id}/domains`, { host: host.trim() });
1490
+ setHost("");
1491
+ setAdding(false);
1492
+ setFlash({ kind: "success", msg: "Domain added. Publish the TXT record below, then verify." });
1493
+ await reload();
1494
+ } catch (e) {
1495
+ const msg = errorText(e);
1496
+ if (msg) setFlash({ kind: "error", msg });
1497
+ } finally {
1498
+ setBusy(null);
1499
+ }
1500
+ };
1501
+ if (error && !data) return /* @__PURE__ */ jsx11(ErrorState4, { description: error.message, onRetry: reload });
1502
+ if (loading && !data) return /* @__PURE__ */ jsx11(LoadingState4, { variant: "table", rows: 2 });
1503
+ return /* @__PURE__ */ jsxs10("div", { className: "space-y-4", children: [
1504
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
1505
+ /* @__PURE__ */ jsx11("p", { className: "text-sm text-muted", children: "Custom host names for this company. A domain routes only after its TXT record is verified." }),
1506
+ writable && /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "outline", leftIcon: /* @__PURE__ */ jsx11(IconPlus, {}), onClick: () => setAdding(true), children: "Add domain" })
1507
+ ] }),
1508
+ domains.length === 0 ? /* @__PURE__ */ jsx11(EmptyState3, { compact: true, icon: /* @__PURE__ */ jsx11(IconGlobe, { size: 24 }), title: "No custom domains", description: "The company signs in on the platform's own address." }) : /* @__PURE__ */ jsx11("ul", { className: "space-y-3", children: domains.map((d) => {
1509
+ var _a2;
1510
+ return /* @__PURE__ */ jsxs10("li", { className: "rounded-xl border border-line bg-surface p-4", children: [
1511
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-2", children: [
1512
+ /* @__PURE__ */ jsx11("span", { className: "w-full break-all font-mono text-sm text-foreground sm:w-auto sm:min-w-0 sm:flex-1", children: d.host }),
1513
+ d.primary && /* @__PURE__ */ jsx11(Badge2, { variant: "primary", size: "sm", children: "Primary" }),
1514
+ /* @__PURE__ */ jsx11(StatusPill, { status: (_a2 = d.status) != null ? _a2 : d.verifiedAt ? "verified" : "pending" }),
1515
+ writable && /* @__PURE__ */ jsxs10("div", { className: "flex gap-1", children: [
1516
+ !d.verifiedAt && /* @__PURE__ */ jsx11(Button7, { size: "sm", loading: busy === `${d.id}:verify`, onClick: () => act(d, "verify"), children: "Verify" }),
1517
+ d.verifiedAt && !d.primary && /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "ghost", loading: busy === `${d.id}:make-primary`, onClick: () => act(d, "make-primary"), children: "Make primary" }),
1518
+ /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "ghost", onClick: () => setRemoving(d), children: "Remove" })
1519
+ ] })
1520
+ ] }),
1521
+ d.verifiedAt && /* @__PURE__ */ jsxs10("p", { className: "mt-1 text-xs text-muted", children: [
1522
+ "Verified ",
1523
+ formatDate(d.verifiedAt)
1524
+ ] }),
1525
+ !d.verifiedAt && d.verification && /* @__PURE__ */ jsxs10("div", { className: "mt-3 space-y-2 rounded-lg bg-background p-3", children: [
1526
+ /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted", children: "Add this TXT record at the domain's DNS provider:" }),
1527
+ [
1528
+ ["Name", d.verification.name],
1529
+ ["Value", d.verification.value]
1530
+ ].map(([k, v]) => /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
1531
+ /* @__PURE__ */ jsx11("span", { className: "text-xs text-muted", children: k }),
1532
+ /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 items-center gap-2", children: [
1533
+ /* @__PURE__ */ jsx11("span", { className: "break-all font-mono text-xs text-foreground", children: v }),
1534
+ /* @__PURE__ */ jsx11(CopyButton, { value: v })
1535
+ ] })
1536
+ ] }, k))
1537
+ ] })
1538
+ ] }, d.id);
1539
+ }) }),
1540
+ /* @__PURE__ */ jsx11(
1541
+ Dialog3,
1542
+ {
1543
+ isOpen: adding,
1544
+ onClose: () => setAdding(false),
1545
+ title: "Add domain",
1546
+ size: "sm",
1547
+ footer: /* @__PURE__ */ jsxs10("div", { className: "flex justify-end gap-2", children: [
1548
+ /* @__PURE__ */ jsx11(Button7, { variant: "outline", onClick: () => setAdding(false), children: "Cancel" }),
1549
+ /* @__PURE__ */ jsx11(Button7, { loading: busy === "add", disabled: !host.trim().includes("."), onClick: add, children: "Add domain" })
1550
+ ] }),
1551
+ children: /* @__PURE__ */ jsx11(Input5, { label: "Host name", autoFocus: true, placeholder: "app.example.com", value: host, onChange: (e) => setHost(e.target.value), helperText: "The company points this host at the platform and proves it with a TXT record." })
1552
+ }
1553
+ ),
1554
+ /* @__PURE__ */ jsx11(
1555
+ ConfirmDialog,
1556
+ {
1557
+ isOpen: removing !== null,
1558
+ title: `Remove ${removing == null ? void 0 : removing.host}?`,
1559
+ description: "The company can no longer sign in on this host.",
1560
+ confirmLabel: "Remove",
1561
+ destructive: true,
1562
+ onCancel: () => setRemoving(null),
1563
+ onConfirm: () => {
1564
+ const d = removing;
1565
+ setRemoving(null);
1566
+ void act(d, "remove");
1567
+ }
1568
+ }
1569
+ )
1570
+ ] });
1571
+ }
1572
+ function SettingsTab({ company, setFlash }) {
1573
+ var _a;
1574
+ const { can } = usePlatform();
1575
+ const { data, error, loading, reload } = useLoad("settings", { company: company.id });
1576
+ if (error && !data) return /* @__PURE__ */ jsx11(ErrorState4, { description: error.message, onRetry: reload });
1577
+ if (loading && !data) return /* @__PURE__ */ jsx11(LoadingState4, { variant: "detail" });
1578
+ const families = (_a = data == null ? void 0 : data.families) != null ? _a : [];
1579
+ if (!families.length) return /* @__PURE__ */ jsx11(EmptyState3, { compact: true, icon: /* @__PURE__ */ jsx11(IconSettings, { size: 24 }), title: "No settings", description: "This product defines no company settings." });
1580
+ return /* @__PURE__ */ jsx11("div", { className: "space-y-4", children: families.map((f) => /* @__PURE__ */ jsx11(SettingsFamily, { family: f, companyId: company.id, version: data.version, writable: can("settings.write"), setFlash, onSaved: reload }, f.family)) });
1581
+ }
1582
+ var initialValues = (family) => Object.fromEntries(family.fields.map((f) => {
1583
+ var _a;
1584
+ return [f.key, f.type === "secret" ? "" : (_a = f.value) != null ? _a : f.type === "boolean" ? false : ""];
1585
+ }));
1586
+ function SettingsFamily({ family, companyId, version, writable, setFlash, onSaved }) {
1587
+ const { client } = usePlatform();
1588
+ const sensitive = useSensitive();
1589
+ const [values, setValues] = useState8(() => initialValues(family));
1590
+ const [busy, setBusy] = useState8(false);
1591
+ useEffect4(() => setValues(initialValues(family)), [family]);
1592
+ const changed = family.fields.filter((f) => {
1593
+ var _a;
1594
+ return f.type === "secret" ? values[f.key] !== "" : JSON.stringify(values[f.key]) !== JSON.stringify((_a = f.value) != null ? _a : f.type === "boolean" ? false : "");
1595
+ });
1596
+ const save = async () => {
1597
+ setBusy(true);
1598
+ setFlash(null);
1599
+ try {
1600
+ const body = Object.fromEntries(changed.map((f) => [f.key, f.type === "number" ? values[f.key] === "" ? null : Number(values[f.key]) : values[f.key]]));
1601
+ await sensitive(() => client.put(`settings/${encodeURIComponent(family.family)}`, { companyId, version, values: body }));
1602
+ setFlash({ kind: "success", msg: `${family.label} saved` });
1603
+ await onSaved();
1604
+ } catch (e) {
1605
+ const msg = errorText(e);
1606
+ if (msg) setFlash({ kind: "error", msg });
1607
+ } finally {
1608
+ setBusy(false);
1609
+ }
1610
+ };
1611
+ const set = (key) => (v) => setValues((s) => ({ ...s, [key]: v }));
1612
+ return /* @__PURE__ */ jsx11(
1613
+ Card,
1614
+ {
1615
+ title: family.label,
1616
+ actions: writable && /* @__PURE__ */ jsx11(Button7, { size: "sm", loading: busy, disabled: !changed.length, onClick: save, children: "Save" }),
1617
+ children: /* @__PURE__ */ jsx11("div", { className: "grid gap-4 sm:grid-cols-2", children: family.fields.map((f) => {
1618
+ var _a, _b, _c;
1619
+ const help = [f.help, f.source === "default" ? "Using the default" : null].filter(Boolean).join(" \xB7 ") || void 0;
1620
+ if (f.type === "boolean") {
1621
+ return /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-3 rounded-lg border border-line px-3 py-2", children: [
1622
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
1623
+ /* @__PURE__ */ jsx11("div", { className: "text-sm text-foreground", children: f.label }),
1624
+ help && /* @__PURE__ */ jsx11("div", { className: "text-xs text-muted", children: help })
1625
+ ] }),
1626
+ /* @__PURE__ */ jsx11(Switch, { checked: Boolean(values[f.key]), disabled: !writable, onChange: set(f.key), ariaLabel: f.label })
1627
+ ] }, f.key);
1628
+ }
1629
+ if (f.type === "select") {
1630
+ return /* @__PURE__ */ jsx11(Select2, { label: f.label, options: (_a = f.options) != null ? _a : [], value: (_b = values[f.key]) != null ? _b : "", disabled: !writable, onChange: (v) => set(f.key)(String(v)), helperText: help }, f.key);
1631
+ }
1632
+ return /* @__PURE__ */ jsx11(
1633
+ Input5,
1634
+ {
1635
+ label: f.label,
1636
+ type: f.type === "secret" ? "password" : f.type === "number" ? "number" : f.type === "email" ? "email" : f.type === "url" ? "url" : "text",
1637
+ autoComplete: f.type === "secret" ? "new-password" : void 0,
1638
+ placeholder: f.type === "secret" ? f.set ? "Configured \xB7 leave blank to keep" : "Not set" : void 0,
1639
+ value: (_c = values[f.key]) != null ? _c : "",
1640
+ disabled: !writable,
1641
+ onChange: (e) => set(f.key)(e.target.value),
1642
+ helperText: help
1643
+ },
1644
+ f.key
1645
+ );
1646
+ }) })
1647
+ }
1648
+ );
1649
+ }
1650
+ function SupportTab({ company }) {
1651
+ return /* @__PURE__ */ jsx11(SupportGrants, { companyId: company.id, companyName: company.displayName });
1652
+ }
1653
+
1654
+ // src/platform/views/CompanyDetail.jsx
1655
+ import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1126
1656
  var SETUP_STATES = ["draft", "provisioning", "provisioning_failed"];
1127
1657
  function CompanyDetailView({ companyId }) {
1128
1658
  var _a;
1129
- const { client, Link, href, can, companyTabs, companyLoginUrl, companyLoginPath } = usePlatform();
1659
+ const { client, Link, href, can, companyTabs, companyLoginUrl, companyLoginPath, features = [] } = usePlatform();
1130
1660
  const sensitive = useSensitive();
1131
1661
  const { data, error, reload } = useLoad(`companies/${encodeURIComponent(companyId)}`);
1132
- const [tab, setTab] = useState7(0);
1133
- const [flash, setFlash] = useState7(null);
1134
- const [secret, setSecret] = useState7(null);
1662
+ const [tab, setTab] = useState9(0);
1663
+ const [flash, setFlash] = useState9(null);
1664
+ const [secret, setSecret] = useState9(null);
1135
1665
  const run = useCallback3(
1136
1666
  async (fn, ok, { stepUp = false } = {}) => {
1137
1667
  setFlash(null);
@@ -1148,69 +1678,70 @@ function CompanyDetailView({ companyId }) {
1148
1678
  },
1149
1679
  [reload, sensitive]
1150
1680
  );
1151
- if (error && !data) return /* @__PURE__ */ jsx10("div", { className: "mx-auto max-w-6xl px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsx10(ErrorState3, { description: error.message, onRetry: reload }) });
1152
- if (!data) return /* @__PURE__ */ jsx10("div", { className: "mx-auto max-w-6xl px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsx10(LoadingState3, { variant: "detail" }) });
1681
+ if (error && !data) return /* @__PURE__ */ jsx12("div", { className: "mx-auto max-w-6xl px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsx12(ErrorState5, { description: error.message, onRetry: reload }) });
1682
+ if (!data) return /* @__PURE__ */ jsx12("div", { className: "mx-auto max-w-6xl px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsx12(LoadingState5, { variant: "detail" }) });
1153
1683
  const company = data.company;
1154
1684
  const database = (_a = company.database) != null ? _a : { configured: false };
1155
1685
  const ctx = { company, users: data.users, run, setFlash, setSecret, client, can, reload };
1156
1686
  const tabs = [
1157
- { id: "overview", label: "Overview", render: () => /* @__PURE__ */ jsx10(OverviewTab, { ...ctx }) },
1158
- { id: "branches", label: "Branches", render: () => /* @__PURE__ */ jsx10(BranchesTab, { ...ctx }) },
1159
- { id: "database", label: "Database", render: () => /* @__PURE__ */ jsx10(DatabaseTab, { ...ctx }) },
1160
- { id: "admins", label: "Admins", render: () => /* @__PURE__ */ jsx10(AdminsTab, { ...ctx }) },
1687
+ { id: "overview", label: "Overview", render: () => /* @__PURE__ */ jsx12(OverviewTab, { ...ctx }) },
1688
+ { id: "branches", label: "Branches", render: () => /* @__PURE__ */ jsx12(BranchesTab, { ...ctx }) },
1689
+ { id: "database", label: "Database", render: () => /* @__PURE__ */ jsx12(DatabaseTab, { ...ctx }) },
1690
+ { id: "admins", label: "Admins", render: () => /* @__PURE__ */ jsx12(AdminsTab, { ...ctx }) },
1691
+ ...featureTabs({ features, can }).map(({ id, label, Component }) => ({ id, label, render: () => /* @__PURE__ */ jsx12(Component, { ...ctx }) })),
1161
1692
  ...(companyTabs != null ? companyTabs : []).map((t) => ({ id: t.id, label: t.label, render: () => t.render({ company, reload, client, sensitive }) })),
1162
- { id: "activity", label: "Activity", render: () => /* @__PURE__ */ jsx10(ActivityTab, { ...ctx }) }
1693
+ { id: "activity", label: "Activity", render: () => /* @__PURE__ */ jsx12(ActivityTab, { ...ctx }) }
1163
1694
  ];
1164
- return /* @__PURE__ */ jsxs9("div", { className: "mx-auto max-w-6xl space-y-5 px-4 py-6 sm:px-6", children: [
1165
- /* @__PURE__ */ jsx10(
1166
- PageHeader4,
1695
+ return /* @__PURE__ */ jsxs11("div", { className: "mx-auto max-w-6xl space-y-5 px-4 py-6 sm:px-6", children: [
1696
+ /* @__PURE__ */ jsx12(
1697
+ PageHeader5,
1167
1698
  {
1168
1699
  title: company.displayName,
1169
- subtitle: /* @__PURE__ */ jsxs9("span", { className: "flex flex-wrap items-center gap-2", children: [
1170
- /* @__PURE__ */ jsx10("span", { className: "font-mono", children: companyLoginPath(company.slug) }),
1171
- /* @__PURE__ */ jsx10(StatusPill, { status: company.status }),
1172
- /* @__PURE__ */ jsx10(ModePill, { mode: database.configured ? database.mode : null })
1700
+ subtitle: /* @__PURE__ */ jsxs11("span", { className: "flex flex-wrap items-center gap-2", children: [
1701
+ /* @__PURE__ */ jsx12("span", { className: "font-mono", children: companyLoginPath(company.slug) }),
1702
+ /* @__PURE__ */ jsx12(StatusPill, { status: company.status }),
1703
+ /* @__PURE__ */ jsx12(ModePill, { mode: database.configured ? database.mode : null })
1173
1704
  ] }),
1174
1705
  back: { href: href("companies"), label: "Companies" },
1175
1706
  linkAs: Link
1176
1707
  }
1177
1708
  ),
1178
- flash && /* @__PURE__ */ jsx10(Alert3, { variant: flash.kind, dismissible: true, onDismiss: () => setFlash(null), children: flash.msg }),
1179
- secret && /* @__PURE__ */ jsx10(OneTimeSecret, { title: secret.title, loginUrl: companyLoginUrl(company.slug), email: secret.email, password: secret.password, onDone: () => setSecret(null) }),
1180
- /* @__PURE__ */ jsxs9(Tabs, { index: tab, onChange: setTab, variant: "line", children: [
1181
- /* @__PURE__ */ jsx10(Tabs.List, { children: tabs.map((t) => /* @__PURE__ */ jsx10(Tabs.Tab, { children: t.label }, t.id)) }),
1182
- /* @__PURE__ */ jsx10(Tabs.Panels, { children: tabs.map((t, i) => /* @__PURE__ */ jsx10(Tabs.Panel, { children: i === tab ? /* @__PURE__ */ jsx10("div", { className: "pt-4", children: t.render() }) : null }, t.id)) })
1709
+ flash && /* @__PURE__ */ jsx12(Alert4, { variant: flash.kind, dismissible: true, onDismiss: () => setFlash(null), children: flash.msg }),
1710
+ secret && /* @__PURE__ */ jsx12(OneTimeSecret, { title: secret.title, loginUrl: companyLoginUrl(company.slug), email: secret.email, password: secret.password, onDone: () => setSecret(null) }),
1711
+ /* @__PURE__ */ jsxs11(Tabs, { index: tab, onChange: setTab, variant: "line", children: [
1712
+ /* @__PURE__ */ jsx12(Tabs.List, { children: tabs.map((t) => /* @__PURE__ */ jsx12(Tabs.Tab, { children: t.label }, t.id)) }),
1713
+ /* @__PURE__ */ jsx12(Tabs.Panels, { children: tabs.map((t, i) => /* @__PURE__ */ jsx12(Tabs.Panel, { children: i === tab ? /* @__PURE__ */ jsx12("div", { className: "pt-4", children: t.render() }) : null }, t.id)) })
1183
1714
  ] })
1184
1715
  ] });
1185
1716
  }
1186
1717
  function OverviewTab({ company, users, run, setSecret, client, can }) {
1187
1718
  var _a, _b, _c, _d, _e, _f;
1188
1719
  const { companyLoginUrl } = usePlatform();
1189
- const [confirm, setConfirm] = useState7(null);
1190
- const [editing, setEditing] = useState7(false);
1720
+ const [confirm, setConfirm] = useState9(null);
1721
+ const [editing, setEditing] = useState9(false);
1191
1722
  const setup = SETUP_STATES.includes(company.status);
1192
1723
  const writable = can("companies.write");
1193
1724
  const db = (_a = company.database) != null ? _a : {};
1194
1725
  const url = companyLoginUrl(company.slug);
1195
1726
  const LABEL = { active: "Activate", suspended: "Suspend", archived: "Archive" };
1196
- return /* @__PURE__ */ jsxs9("div", { className: "grid gap-5 [grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr))]", children: [
1197
- /* @__PURE__ */ jsxs9("div", { className: "space-y-5", children: [
1198
- setup && writable && /* @__PURE__ */ jsx10(SetupPanel, { company, run, setSecret, client }),
1199
- /* @__PURE__ */ jsx10(
1727
+ return /* @__PURE__ */ jsxs11("div", { className: "grid gap-5 [grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr))]", children: [
1728
+ /* @__PURE__ */ jsxs11("div", { className: "space-y-5", children: [
1729
+ setup && writable && /* @__PURE__ */ jsx12(SetupPanel, { company, run, setSecret, client }),
1730
+ /* @__PURE__ */ jsx12(
1200
1731
  Card,
1201
1732
  {
1202
1733
  title: "Company",
1203
- actions: writable && /* @__PURE__ */ jsx10(Button6, { size: "sm", variant: "outline", onClick: () => setEditing(true), children: "Edit details" }),
1204
- children: /* @__PURE__ */ jsx10(
1734
+ actions: writable && /* @__PURE__ */ jsx12(Button8, { size: "sm", variant: "outline", onClick: () => setEditing(true), children: "Edit details" }),
1735
+ children: /* @__PURE__ */ jsx12(
1205
1736
  Facts,
1206
1737
  {
1207
1738
  rows: [
1208
1739
  ["Name", company.displayName],
1209
1740
  [
1210
1741
  "Sign-in address",
1211
- /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-2", children: [
1212
- /* @__PURE__ */ jsx10("span", { className: "truncate font-mono text-xs", children: url }),
1213
- /* @__PURE__ */ jsx10(CopyButton, { value: url })
1742
+ /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2", children: [
1743
+ /* @__PURE__ */ jsx12("span", { className: "truncate font-mono text-xs", children: url }),
1744
+ /* @__PURE__ */ jsx12(CopyButton, { value: url })
1214
1745
  ] }, "l")
1215
1746
  ],
1216
1747
  ["Branches", (_c = (_b = company.branches) == null ? void 0 : _b.length) != null ? _c : "\u2014"],
@@ -1223,17 +1754,17 @@ function OverviewTab({ company, users, run, setSecret, client, can }) {
1223
1754
  }
1224
1755
  )
1225
1756
  ] }),
1226
- /* @__PURE__ */ jsx10(Card, { title: "Lifecycle", children: setup ? /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted", children: "Activation, suspension and archiving become available once the company's database is set up." }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
1227
- /* @__PURE__ */ jsx10("p", { className: "mb-3 text-sm text-muted", children: "Suspending immediately blocks every sign-in and request for this company. Data is kept." }),
1228
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
1229
- writable && company.status !== "active" && /* @__PURE__ */ jsx10(Button6, { variant: "outline", leftIcon: /* @__PURE__ */ jsx10(IconPlay, {}), onClick: () => setConfirm("active"), children: "Activate" }),
1230
- writable && company.status === "active" && /* @__PURE__ */ jsx10(Button6, { variant: "outline", leftIcon: /* @__PURE__ */ jsx10(IconPause, {}), onClick: () => setConfirm("suspended"), children: "Suspend" }),
1231
- writable && company.status !== "archived" && /* @__PURE__ */ jsx10(Button6, { variant: "outline", leftIcon: /* @__PURE__ */ jsx10(IconArchive, {}), onClick: () => setConfirm("archived"), children: "Archive" })
1757
+ /* @__PURE__ */ jsx12(Card, { title: "Lifecycle", children: setup ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted", children: "Activation, suspension and archiving become available once the company's database is set up." }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
1758
+ /* @__PURE__ */ jsx12("p", { className: "mb-3 text-sm text-muted", children: "Suspending immediately blocks every sign-in and request for this company. Data is kept." }),
1759
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
1760
+ writable && company.status !== "active" && /* @__PURE__ */ jsx12(Button8, { variant: "outline", leftIcon: /* @__PURE__ */ jsx12(IconPlay, {}), onClick: () => setConfirm("active"), children: "Activate" }),
1761
+ writable && company.status === "active" && /* @__PURE__ */ jsx12(Button8, { variant: "outline", leftIcon: /* @__PURE__ */ jsx12(IconPause, {}), onClick: () => setConfirm("suspended"), children: "Suspend" }),
1762
+ writable && company.status !== "archived" && /* @__PURE__ */ jsx12(Button8, { variant: "outline", leftIcon: /* @__PURE__ */ jsx12(IconArchive, {}), onClick: () => setConfirm("archived"), children: "Archive" })
1232
1763
  ] })
1233
1764
  ] }) }),
1234
- editing && /* @__PURE__ */ jsx10(EditDetails, { company, run, client, onClose: () => setEditing(false) }),
1235
- /* @__PURE__ */ jsx10(
1236
- ConfirmDialog,
1765
+ editing && /* @__PURE__ */ jsx12(EditDetails, { company, run, client, onClose: () => setEditing(false) }),
1766
+ /* @__PURE__ */ jsx12(
1767
+ ConfirmDialog2,
1237
1768
  {
1238
1769
  isOpen: confirm !== null,
1239
1770
  title: `${(_e = LABEL[confirm]) != null ? _e : ""} ${company.displayName}?`,
@@ -1252,11 +1783,11 @@ function OverviewTab({ company, users, run, setSecret, client, can }) {
1252
1783
  }
1253
1784
  function EditDetails({ company, run, client, onClose }) {
1254
1785
  const { companyLoginPath } = usePlatform();
1255
- const [name, setName] = useState7(company.displayName);
1256
- const [slug, setSlug] = useState7(company.slug);
1257
- const [slugState, setSlugState] = useState7({ available: true });
1258
- const [busy, setBusy] = useState7(false);
1259
- useEffect4(() => {
1786
+ const [name, setName] = useState9(company.displayName);
1787
+ const [slug, setSlug] = useState9(company.slug);
1788
+ const [slugState, setSlugState] = useState9({ available: true });
1789
+ const [busy, setBusy] = useState9(false);
1790
+ useEffect5(() => {
1260
1791
  if (slug === company.slug) {
1261
1792
  setSlugState({ available: true });
1262
1793
  return void 0;
@@ -1270,17 +1801,17 @@ function EditDetails({ company, run, client, onClose }) {
1270
1801
  }, 350);
1271
1802
  return () => clearTimeout(t);
1272
1803
  }, [slug, company.slug, client]);
1273
- return /* @__PURE__ */ jsx10(
1274
- Dialog2,
1804
+ return /* @__PURE__ */ jsx12(
1805
+ Dialog4,
1275
1806
  {
1276
1807
  isOpen: true,
1277
1808
  onClose,
1278
1809
  title: "Edit company details",
1279
1810
  size: "md",
1280
- footer: /* @__PURE__ */ jsxs9("div", { className: "flex justify-end gap-2", children: [
1281
- /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: onClose, children: "Cancel" }),
1282
- /* @__PURE__ */ jsx10(
1283
- Button6,
1811
+ footer: /* @__PURE__ */ jsxs11("div", { className: "flex justify-end gap-2", children: [
1812
+ /* @__PURE__ */ jsx12(Button8, { variant: "outline", onClick: onClose, children: "Cancel" }),
1813
+ /* @__PURE__ */ jsx12(
1814
+ Button8,
1284
1815
  {
1285
1816
  loading: busy,
1286
1817
  disabled: !name.trim() || slugState.available !== true,
@@ -1298,10 +1829,10 @@ function EditDetails({ company, run, client, onClose }) {
1298
1829
  }
1299
1830
  )
1300
1831
  ] }),
1301
- children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
1302
- /* @__PURE__ */ jsx10(Input4, { label: "Company name", value: name, onChange: (e) => setName(e.target.value) }),
1303
- /* @__PURE__ */ jsx10(
1304
- Input4,
1832
+ children: /* @__PURE__ */ jsxs11("div", { className: "space-y-4", children: [
1833
+ /* @__PURE__ */ jsx12(Input6, { label: "Company name", value: name, onChange: (e) => setName(e.target.value) }),
1834
+ /* @__PURE__ */ jsx12(
1835
+ Input6,
1305
1836
  {
1306
1837
  label: "URL slug",
1307
1838
  value: slug,
@@ -1319,10 +1850,10 @@ function SetupPanel({ company, run, setSecret, client }) {
1319
1850
  const provisioner = useProvisioner();
1320
1851
  const job = company.lastJob;
1321
1852
  const stored = ((_a = company.database) == null ? void 0 : _a.configured) ? company.database.mode : null;
1322
- const [db, setDb] = useState7({ mode: stored === "external" ? "external" : "managed", url: "", report: null, testedUrl: null });
1323
- const [adminName, setAdminName] = useState7("");
1324
- const [adminEmail, setAdminEmail] = useState7("");
1325
- const [busy, setBusy] = useState7(false);
1853
+ const [db, setDb] = useState9({ mode: stored === "external" ? "external" : "managed", url: "", report: null, testedUrl: null });
1854
+ const [adminName, setAdminName] = useState9("");
1855
+ const [adminEmail, setAdminEmail] = useState9("");
1856
+ const [busy, setBusy] = useState9(false);
1326
1857
  const ready = databaseReady(db, provisioner, { acceptStates: ["empty", "company"], keepStored: stored === "external" });
1327
1858
  const adminOk = !adminName.trim() && !adminEmail.trim() || adminName.trim() && EMAIL_RE.test(adminEmail.trim());
1328
1859
  const provision = async () => {
@@ -1343,13 +1874,13 @@ function SetupPanel({ company, run, setSecret, client }) {
1343
1874
  setBusy(false);
1344
1875
  };
1345
1876
  const lastError = (_b = job == null ? void 0 : job.lastError) != null ? _b : job == null ? void 0 : job.last_error;
1346
- return /* @__PURE__ */ jsx10(Card, { title: "Finish setup", children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
1347
- /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted", children: "This company's database is not ready yet, so nobody can sign in." }),
1348
- (job == null ? void 0 : job.status) === "failed" && /* @__PURE__ */ jsxs9(Alert3, { variant: "error", title: `Last attempt failed${job.step ? ` at \u201C${job.step}\u201D` : ""}`, children: [
1349
- /* @__PURE__ */ jsx10("span", { className: "block break-words font-mono text-xs", children: lastError }),
1350
- jobErrorHint(lastError) && /* @__PURE__ */ jsx10("span", { className: "mt-1 block", children: jobErrorHint(lastError) })
1877
+ return /* @__PURE__ */ jsx12(Card, { title: "Finish setup", children: /* @__PURE__ */ jsxs11("div", { className: "space-y-4", children: [
1878
+ /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted", children: "This company's database is not ready yet, so nobody can sign in." }),
1879
+ (job == null ? void 0 : job.status) === "failed" && /* @__PURE__ */ jsxs11(Alert4, { variant: "error", title: `Last attempt failed${job.step ? ` at \u201C${job.step}\u201D` : ""}`, children: [
1880
+ /* @__PURE__ */ jsx12("span", { className: "block break-words font-mono text-xs", children: lastError }),
1881
+ jobErrorHint(lastError) && /* @__PURE__ */ jsx12("span", { className: "mt-1 block", children: jobErrorHint(lastError) })
1351
1882
  ] }),
1352
- /* @__PURE__ */ jsx10(
1883
+ /* @__PURE__ */ jsx12(
1353
1884
  DatabaseChoice,
1354
1885
  {
1355
1886
  value: db,
@@ -1361,25 +1892,25 @@ function SetupPanel({ company, run, setSecret, client }) {
1361
1892
  compact: true
1362
1893
  }
1363
1894
  ),
1364
- /* @__PURE__ */ jsxs9("div", { children: [
1365
- /* @__PURE__ */ jsx10("div", { className: "text-sm font-medium text-foreground", children: "First admin (recommended)" }),
1366
- /* @__PURE__ */ jsx10("p", { className: "mb-2 text-xs text-muted", children: "A temporary password is generated and shown once when setup finishes." }),
1367
- /* @__PURE__ */ jsxs9("div", { className: "grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(12rem,1fr))]", children: [
1368
- /* @__PURE__ */ jsx10(Input4, { "aria-label": "First admin full name", placeholder: "Full name", value: adminName, onChange: (e) => setAdminName(e.target.value) }),
1369
- /* @__PURE__ */ jsx10(Input4, { "aria-label": "First admin email", type: "email", placeholder: "email@company.com", value: adminEmail, onChange: (e) => setAdminEmail(e.target.value) })
1895
+ /* @__PURE__ */ jsxs11("div", { children: [
1896
+ /* @__PURE__ */ jsx12("div", { className: "text-sm font-medium text-foreground", children: "First admin (recommended)" }),
1897
+ /* @__PURE__ */ jsx12("p", { className: "mb-2 text-xs text-muted", children: "A temporary password is generated and shown once when setup finishes." }),
1898
+ /* @__PURE__ */ jsxs11("div", { className: "grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(12rem,1fr))]", children: [
1899
+ /* @__PURE__ */ jsx12(Input6, { "aria-label": "First admin full name", placeholder: "Full name", value: adminName, onChange: (e) => setAdminName(e.target.value) }),
1900
+ /* @__PURE__ */ jsx12(Input6, { "aria-label": "First admin email", type: "email", placeholder: "email@company.com", value: adminEmail, onChange: (e) => setAdminEmail(e.target.value) })
1370
1901
  ] })
1371
1902
  ] }),
1372
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-3", children: [
1373
- /* @__PURE__ */ jsx10(Button6, { loading: busy, disabled: !ready || !adminOk, leftIcon: /* @__PURE__ */ jsx10(IconRefresh, {}), onClick: provision, children: (job == null ? void 0 : job.status) === "failed" ? "Retry setup" : "Provision database" }),
1374
- busy && /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted", children: "Applying the schema. This can take a minute\u2026" })
1903
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-3", children: [
1904
+ /* @__PURE__ */ jsx12(Button8, { loading: busy, disabled: !ready || !adminOk, leftIcon: /* @__PURE__ */ jsx12(IconRefresh, {}), onClick: provision, children: (job == null ? void 0 : job.status) === "failed" ? "Retry setup" : "Provision database" }),
1905
+ busy && /* @__PURE__ */ jsx12("span", { className: "text-xs text-muted", children: "Applying the schema. This can take a minute\u2026" })
1375
1906
  ] })
1376
1907
  ] }) });
1377
1908
  }
1378
1909
  function BranchesTab({ company, run, client, can }) {
1379
1910
  var _a;
1380
- const [editing, setEditing] = useState7(null);
1381
- const [code, setCode] = useState7("");
1382
- const [name, setName] = useState7("");
1911
+ const [editing, setEditing] = useState9(null);
1912
+ const [code, setCode] = useState9("");
1913
+ const [name, setName] = useState9("");
1383
1914
  const writable = can("companies.write");
1384
1915
  const branches = (_a = company.branches) != null ? _a : [];
1385
1916
  const open = (b) => {
@@ -1392,23 +1923,23 @@ function BranchesTab({ company, run, client, can }) {
1392
1923
  const ok = editing.id ? await run(() => client.patch(`companies/${company.id}/branches/${editing.id}`, { name: name.trim() }), "Branch renamed") : await run(() => client.post(`companies/${company.id}/branches`, { code: code.trim().toUpperCase(), name: name.trim() }), "Branch added");
1393
1924
  if (ok) setEditing(null);
1394
1925
  };
1395
- return /* @__PURE__ */ jsxs9(
1926
+ return /* @__PURE__ */ jsxs11(
1396
1927
  Card,
1397
1928
  {
1398
1929
  title: "Branches",
1399
- actions: writable && /* @__PURE__ */ jsx10(Button6, { size: "sm", leftIcon: /* @__PURE__ */ jsx10(IconPlus, {}), onClick: () => open(null), children: "Add branch" }),
1930
+ actions: writable && /* @__PURE__ */ jsx12(Button8, { size: "sm", leftIcon: /* @__PURE__ */ jsx12(IconPlus, {}), onClick: () => open(null), children: "Add branch" }),
1400
1931
  children: [
1401
- branches.length === 0 ? /* @__PURE__ */ jsx10(EmptyState2, { title: "No branches", compact: true }) : /* @__PURE__ */ jsx10("ul", { className: "divide-y divide-line", children: branches.map((b) => /* @__PURE__ */ jsxs9("li", { className: "flex flex-wrap items-center gap-3 py-2.5", children: [
1402
- /* @__PURE__ */ jsx10("span", { className: "w-20 shrink-0 font-mono text-xs text-muted", children: b.code }),
1403
- /* @__PURE__ */ jsxs9("span", { className: "min-w-0 flex-1 text-sm text-foreground", children: [
1932
+ branches.length === 0 ? /* @__PURE__ */ jsx12(EmptyState4, { title: "No branches", compact: true }) : /* @__PURE__ */ jsx12("ul", { className: "divide-y divide-line", children: branches.map((b) => /* @__PURE__ */ jsxs11("li", { className: "flex flex-wrap items-center gap-3 py-2.5", children: [
1933
+ /* @__PURE__ */ jsx12("span", { className: "w-20 shrink-0 font-mono text-xs text-muted", children: b.code }),
1934
+ /* @__PURE__ */ jsxs11("span", { className: "min-w-0 flex-1 text-sm text-foreground", children: [
1404
1935
  b.name,
1405
- b.id === company.defaultBranchId && /* @__PURE__ */ jsx10("span", { className: "ml-2 text-xs text-muted", children: "default" })
1936
+ b.id === company.defaultBranchId && /* @__PURE__ */ jsx12("span", { className: "ml-2 text-xs text-muted", children: "default" })
1406
1937
  ] }),
1407
- /* @__PURE__ */ jsx10(StatusPill, { status: b.status }),
1408
- writable && /* @__PURE__ */ jsxs9("div", { className: "flex gap-1", children: [
1409
- /* @__PURE__ */ jsx10(Button6, { size: "sm", variant: "ghost", onClick: () => open(b), children: "Rename" }),
1410
- b.id !== company.defaultBranchId && /* @__PURE__ */ jsx10(
1411
- Button6,
1938
+ /* @__PURE__ */ jsx12(StatusPill, { status: b.status }),
1939
+ writable && /* @__PURE__ */ jsxs11("div", { className: "flex gap-1", children: [
1940
+ /* @__PURE__ */ jsx12(Button8, { size: "sm", variant: "ghost", onClick: () => open(b), children: "Rename" }),
1941
+ b.id !== company.defaultBranchId && /* @__PURE__ */ jsx12(
1942
+ Button8,
1412
1943
  {
1413
1944
  size: "sm",
1414
1945
  variant: "ghost",
@@ -1421,20 +1952,20 @@ function BranchesTab({ company, run, client, can }) {
1421
1952
  )
1422
1953
  ] })
1423
1954
  ] }, b.id)) }),
1424
- /* @__PURE__ */ jsx10(
1425
- Dialog2,
1955
+ /* @__PURE__ */ jsx12(
1956
+ Dialog4,
1426
1957
  {
1427
1958
  isOpen: editing !== null,
1428
1959
  onClose: () => setEditing(null),
1429
1960
  title: (editing == null ? void 0 : editing.id) ? `Rename ${editing.code}` : "Add branch",
1430
1961
  size: "sm",
1431
- footer: /* @__PURE__ */ jsxs9("div", { className: "flex justify-end gap-2", children: [
1432
- /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: () => setEditing(null), children: "Cancel" }),
1433
- /* @__PURE__ */ jsx10(Button6, { disabled: !name.trim() || !(editing == null ? void 0 : editing.id) && !/^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/.test(code), onClick: save, children: "Save" })
1962
+ footer: /* @__PURE__ */ jsxs11("div", { className: "flex justify-end gap-2", children: [
1963
+ /* @__PURE__ */ jsx12(Button8, { variant: "outline", onClick: () => setEditing(null), children: "Cancel" }),
1964
+ /* @__PURE__ */ jsx12(Button8, { disabled: !name.trim() || !(editing == null ? void 0 : editing.id) && !/^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/.test(code), onClick: save, children: "Save" })
1434
1965
  ] }),
1435
- children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
1436
- !(editing == null ? void 0 : editing.id) && /* @__PURE__ */ jsx10(Input4, { label: "Code", value: code, onChange: (e) => setCode(e.target.value.toUpperCase()), helperText: "Letters, digits, - and _. Cannot be changed later." }),
1437
- /* @__PURE__ */ jsx10(Input4, { label: "Name", value: name, onChange: (e) => setName(e.target.value) })
1966
+ children: /* @__PURE__ */ jsxs11("div", { className: "space-y-4", children: [
1967
+ !(editing == null ? void 0 : editing.id) && /* @__PURE__ */ jsx12(Input6, { label: "Code", value: code, onChange: (e) => setCode(e.target.value.toUpperCase()), helperText: "Letters, digits, - and _. Cannot be changed later." }),
1968
+ /* @__PURE__ */ jsx12(Input6, { label: "Name", value: name, onChange: (e) => setName(e.target.value) })
1438
1969
  ] })
1439
1970
  }
1440
1971
  )
@@ -1445,29 +1976,29 @@ function BranchesTab({ company, run, client, can }) {
1445
1976
  function DatabaseTab({ company, run, setFlash, client, can }) {
1446
1977
  var _a, _b, _c, _d, _e;
1447
1978
  const db = (_a = company.database) != null ? _a : { configured: false };
1448
- const [busy, setBusy] = useState7(null);
1449
- const [steps, setSteps] = useState7(null);
1450
- const [replacing, setReplacing] = useState7(false);
1451
- const [newUrl, setNewUrl] = useState7("");
1452
- const [report, setReport] = useState7(null);
1453
- const [revealing, setRevealing] = useState7(false);
1454
- const [reason, setReason] = useState7("");
1455
- const [revealed, setRevealed] = useState7(null);
1456
- if (!db.configured) return /* @__PURE__ */ jsx10(Card, { title: "Database", children: /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted", children: "No database yet. Provision it from the Overview tab." }) });
1979
+ const [busy, setBusy] = useState9(null);
1980
+ const [steps, setSteps] = useState9(null);
1981
+ const [replacing, setReplacing] = useState9(false);
1982
+ const [newUrl, setNewUrl] = useState9("");
1983
+ const [report, setReport] = useState9(null);
1984
+ const [revealing, setRevealing] = useState9(false);
1985
+ const [reason, setReason] = useState9("");
1986
+ const [revealed, setRevealed] = useState9(null);
1987
+ if (!db.configured) return /* @__PURE__ */ jsx12(Card, { title: "Database", children: /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted", children: "No database yet. Provision it from the Overview tab." }) });
1457
1988
  const writable = can("db.write");
1458
- return /* @__PURE__ */ jsxs9("div", { className: "grid gap-5 [grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr))]", children: [
1459
- /* @__PURE__ */ jsxs9(Card, { title: "Connection", children: [
1460
- /* @__PURE__ */ jsx10(
1989
+ return /* @__PURE__ */ jsxs11("div", { className: "grid gap-5 [grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr))]", children: [
1990
+ /* @__PURE__ */ jsxs11(Card, { title: "Connection", children: [
1991
+ /* @__PURE__ */ jsx12(
1461
1992
  Facts,
1462
1993
  {
1463
1994
  rows: [
1464
- ["Type", /* @__PURE__ */ jsx10(ModePill, { mode: db.mode }, "m")],
1465
- ["Target", /* @__PURE__ */ jsx10("span", { className: "font-mono text-xs", children: (_b = db.target) != null ? _b : "\u2014" }, "t")],
1466
- ["Status", /* @__PURE__ */ jsx10(StatusPill, { status: db.status }, "s")],
1467
- ["Health", /* @__PURE__ */ jsxs9("span", { children: [
1468
- /* @__PURE__ */ jsx10(HealthDot, { ok: db.lastCheckOk }),
1995
+ ["Type", /* @__PURE__ */ jsx12(ModePill, { mode: db.mode }, "m")],
1996
+ ["Target", /* @__PURE__ */ jsx12("span", { className: "font-mono text-xs", children: (_b = db.target) != null ? _b : "\u2014" }, "t")],
1997
+ ["Status", /* @__PURE__ */ jsx12(StatusPill, { status: db.status }, "s")],
1998
+ ["Health", /* @__PURE__ */ jsxs11("span", { children: [
1999
+ /* @__PURE__ */ jsx12(HealthDot, { ok: db.lastCheckOk }),
1469
2000
  " ",
1470
- db.lastCheckAt && /* @__PURE__ */ jsxs9("span", { className: "text-xs text-muted", children: [
2001
+ db.lastCheckAt && /* @__PURE__ */ jsxs11("span", { className: "text-xs text-muted", children: [
1471
2002
  "\xB7 ",
1472
2003
  timeAgo(db.lastCheckAt)
1473
2004
  ] })
@@ -1479,23 +2010,23 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1479
2010
  ]
1480
2011
  }
1481
2012
  ),
1482
- db.lastCheckOk === false && db.lastCheckError && /* @__PURE__ */ jsx10("div", { className: "mt-4 rounded-lg bg-error-50 p-3 font-mono text-xs text-error-800", children: db.lastCheckError }),
1483
- steps && /* @__PURE__ */ jsx10("ul", { className: "mt-4 space-y-1 rounded-lg bg-background p-3 text-xs text-muted", children: steps.map((s) => /* @__PURE__ */ jsxs9("li", { children: [
2013
+ db.lastCheckOk === false && db.lastCheckError && /* @__PURE__ */ jsx12("div", { className: "mt-4 rounded-lg bg-error-50 p-3 font-mono text-xs text-error-800", children: db.lastCheckError }),
2014
+ steps && /* @__PURE__ */ jsx12("ul", { className: "mt-4 space-y-1 rounded-lg bg-background p-3 text-xs text-muted", children: steps.map((s) => /* @__PURE__ */ jsxs11("li", { children: [
1484
2015
  "\u2713 ",
1485
2016
  s
1486
2017
  ] }, s)) }),
1487
- revealed && /* @__PURE__ */ jsxs9("div", { className: "mt-4 rounded-lg border border-warning-200 bg-warning-50 p-3", children: [
1488
- /* @__PURE__ */ jsx10("div", { className: "mb-1 text-xs font-medium text-warning-800", children: "Database URL (audited, shown once)" }),
1489
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
1490
- /* @__PURE__ */ jsx10("code", { className: "min-w-0 flex-1 break-all text-xs text-foreground", children: revealed }),
1491
- /* @__PURE__ */ jsx10(CopyButton, { value: revealed })
2018
+ revealed && /* @__PURE__ */ jsxs11("div", { className: "mt-4 rounded-lg border border-warning-200 bg-warning-50 p-3", children: [
2019
+ /* @__PURE__ */ jsx12("div", { className: "mb-1 text-xs font-medium text-warning-800", children: "Database URL (audited, shown once)" }),
2020
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
2021
+ /* @__PURE__ */ jsx12("code", { className: "min-w-0 flex-1 break-all text-xs text-foreground", children: revealed }),
2022
+ /* @__PURE__ */ jsx12(CopyButton, { value: revealed })
1492
2023
  ] }),
1493
- /* @__PURE__ */ jsx10("button", { type: "button", className: "mt-2 text-xs text-muted underline", onClick: () => setRevealed(null), children: "Hide" })
2024
+ /* @__PURE__ */ jsx12("button", { type: "button", className: "mt-2 text-xs text-muted underline", onClick: () => setRevealed(null), children: "Hide" })
1494
2025
  ] })
1495
2026
  ] }),
1496
- writable && /* @__PURE__ */ jsx10(Card, { title: "Actions", children: /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
1497
- /* @__PURE__ */ jsx10(
1498
- Button6,
2027
+ writable && /* @__PURE__ */ jsx12(Card, { title: "Actions", children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
2028
+ /* @__PURE__ */ jsx12(
2029
+ Button8,
1499
2030
  {
1500
2031
  variant: "outline",
1501
2032
  loading: busy === "test",
@@ -1512,8 +2043,8 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1512
2043
  children: "Test connection"
1513
2044
  }
1514
2045
  ),
1515
- /* @__PURE__ */ jsx10(
1516
- Button6,
2046
+ /* @__PURE__ */ jsx12(
2047
+ Button8,
1517
2048
  {
1518
2049
  variant: "outline",
1519
2050
  loading: busy === "sync",
@@ -1526,12 +2057,12 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1526
2057
  children: "Sync schema"
1527
2058
  }
1528
2059
  ),
1529
- db.mode === "external" && /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: () => setReplacing(true), children: "Replace URL" }),
1530
- can("db.reveal") && /* @__PURE__ */ jsx10(Button6, { variant: "ghost", onClick: () => setRevealing(true), children: "Reveal URL\u2026" }),
1531
- /* @__PURE__ */ jsx10("p", { className: "mt-1 text-xs text-muted", children: "Sync adds missing tables, columns and indexes. It never drops or renames anything." })
2060
+ db.mode === "external" && /* @__PURE__ */ jsx12(Button8, { variant: "outline", onClick: () => setReplacing(true), children: "Replace URL" }),
2061
+ can("db.reveal") && /* @__PURE__ */ jsx12(Button8, { variant: "ghost", onClick: () => setRevealing(true), children: "Reveal URL\u2026" }),
2062
+ /* @__PURE__ */ jsx12("p", { className: "mt-1 text-xs text-muted", children: "Sync adds missing tables, columns and indexes. It never drops or renames anything." })
1532
2063
  ] }) }),
1533
- /* @__PURE__ */ jsxs9(
1534
- Dialog2,
2064
+ /* @__PURE__ */ jsxs11(
2065
+ Dialog4,
1535
2066
  {
1536
2067
  isOpen: replacing,
1537
2068
  onClose: () => {
@@ -1541,10 +2072,10 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1541
2072
  },
1542
2073
  title: "Replace database URL",
1543
2074
  size: "md",
1544
- footer: /* @__PURE__ */ jsxs9("div", { className: "flex justify-end gap-2", children: [
1545
- /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: () => setReplacing(false), children: "Cancel" }),
1546
- /* @__PURE__ */ jsx10(
1547
- Button6,
2075
+ footer: /* @__PURE__ */ jsxs11("div", { className: "flex justify-end gap-2", children: [
2076
+ /* @__PURE__ */ jsx12(Button8, { variant: "outline", onClick: () => setReplacing(false), children: "Cancel" }),
2077
+ /* @__PURE__ */ jsx12(
2078
+ Button8,
1548
2079
  {
1549
2080
  disabled: !(report == null ? void 0 : report.ok) || report.state !== "company",
1550
2081
  loading: busy === "replace",
@@ -1563,11 +2094,11 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1563
2094
  )
1564
2095
  ] }),
1565
2096
  children: [
1566
- /* @__PURE__ */ jsx10("p", { className: "mb-3 text-sm text-muted", children: "Use this after moving the database or rotating its password. The new URL must point at this company's existing database." }),
1567
- /* @__PURE__ */ jsxs9("div", { className: "flex items-end gap-2", children: [
1568
- /* @__PURE__ */ jsx10("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx10(Input4, { label: "New database URL", type: "password", autoComplete: "off", value: newUrl, onChange: (e) => (setNewUrl(e.target.value), setReport(null)) }) }),
1569
- /* @__PURE__ */ jsx10(
1570
- Button6,
2097
+ /* @__PURE__ */ jsx12("p", { className: "mb-3 text-sm text-muted", children: "Use this after moving the database or rotating its password. The new URL must point at this company's existing database." }),
2098
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-end gap-2", children: [
2099
+ /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12(Input6, { label: "New database URL", type: "password", autoComplete: "off", value: newUrl, onChange: (e) => (setNewUrl(e.target.value), setReport(null)) }) }),
2100
+ /* @__PURE__ */ jsx12(
2101
+ Button8,
1571
2102
  {
1572
2103
  variant: "outline",
1573
2104
  disabled: !newUrl.trim(),
@@ -1582,21 +2113,21 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1582
2113
  }
1583
2114
  )
1584
2115
  ] }),
1585
- report && /* @__PURE__ */ jsx10(InspectResult, { report })
2116
+ report && /* @__PURE__ */ jsx12(InspectResult, { report })
1586
2117
  ]
1587
2118
  }
1588
2119
  ),
1589
- /* @__PURE__ */ jsxs9(
1590
- Dialog2,
2120
+ /* @__PURE__ */ jsxs11(
2121
+ Dialog4,
1591
2122
  {
1592
2123
  isOpen: revealing,
1593
2124
  onClose: () => setRevealing(false),
1594
2125
  title: "Reveal database URL",
1595
2126
  size: "md",
1596
- footer: /* @__PURE__ */ jsxs9("div", { className: "flex justify-end gap-2", children: [
1597
- /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: () => setRevealing(false), children: "Cancel" }),
1598
- /* @__PURE__ */ jsx10(
1599
- Button6,
2127
+ footer: /* @__PURE__ */ jsxs11("div", { className: "flex justify-end gap-2", children: [
2128
+ /* @__PURE__ */ jsx12(Button8, { variant: "outline", onClick: () => setRevealing(false), children: "Cancel" }),
2129
+ /* @__PURE__ */ jsx12(
2130
+ Button8,
1600
2131
  {
1601
2132
  variant: "destructive",
1602
2133
  disabled: reason.trim().length < 8,
@@ -1613,8 +2144,8 @@ function DatabaseTab({ company, run, setFlash, client, can }) {
1613
2144
  )
1614
2145
  ] }),
1615
2146
  children: [
1616
- /* @__PURE__ */ jsx10("p", { className: "mb-3 text-sm text-muted", children: "Only credential custodians can do this. The reveal is recorded in the audit log with your reason before the URL is read." }),
1617
- /* @__PURE__ */ jsx10(Textarea, { label: "Reason", rows: 3, value: reason, onChange: (e) => setReason(e.target.value), helperText: "At least 8 characters, e.g. the incident or ticket number." })
2147
+ /* @__PURE__ */ jsx12("p", { className: "mb-3 text-sm text-muted", children: "Only credential custodians can do this. The reveal is recorded in the audit log with your reason before the URL is read." }),
2148
+ /* @__PURE__ */ jsx12(Textarea3, { label: "Reason", rows: 3, value: reason, onChange: (e) => setReason(e.target.value), helperText: "At least 8 characters, e.g. the incident or ticket number." })
1618
2149
  ]
1619
2150
  }
1620
2151
  )
@@ -1625,13 +2156,13 @@ function AdminsTab({ company, setSecret, setFlash, client, can }) {
1625
2156
  const sensitive = useSensitive();
1626
2157
  const ready = ((_a = company.database) == null ? void 0 : _a.configured) && ((_b = company.database) == null ? void 0 : _b.status) === "active";
1627
2158
  const { data, error, reload } = useLoad(ready ? `companies/${company.id}/admins` : null);
1628
- const [adding, setAdding] = useState7(false);
1629
- const [fullName, setFullName] = useState7("");
1630
- const [email, setEmail] = useState7("");
1631
- const [phone, setPhone] = useState7("");
1632
- const [busy, setBusy] = useState7(false);
2159
+ const [adding, setAdding] = useState9(false);
2160
+ const [fullName, setFullName] = useState9("");
2161
+ const [email, setEmail] = useState9("");
2162
+ const [phone, setPhone] = useState9("");
2163
+ const [busy, setBusy] = useState9(false);
1633
2164
  const writable = can("companies.write");
1634
- if (!ready) return /* @__PURE__ */ jsx10(Card, { title: "Company admins", children: /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted", children: "Admins can be added once the company's database is provisioned." }) });
2165
+ if (!ready) return /* @__PURE__ */ jsx12(Card, { title: "Company admins", children: /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted", children: "Admins can be added once the company's database is provisioned." }) });
1635
2166
  const act = async (a, action) => {
1636
2167
  var _a2;
1637
2168
  try {
@@ -1660,38 +2191,38 @@ function AdminsTab({ company, setSecret, setFlash, client, can }) {
1660
2191
  setBusy(false);
1661
2192
  }
1662
2193
  };
1663
- return /* @__PURE__ */ jsxs9(
2194
+ return /* @__PURE__ */ jsxs11(
1664
2195
  Card,
1665
2196
  {
1666
2197
  title: "Company admins",
1667
- actions: writable && /* @__PURE__ */ jsx10(Button6, { size: "sm", leftIcon: /* @__PURE__ */ jsx10(IconPlus, {}), onClick: () => setAdding(true), children: "Add admin" }),
2198
+ actions: writable && /* @__PURE__ */ jsx12(Button8, { size: "sm", leftIcon: /* @__PURE__ */ jsx12(IconPlus, {}), onClick: () => setAdding(true), children: "Add admin" }),
1668
2199
  children: [
1669
- error && !data ? /* @__PURE__ */ jsx10(ErrorState3, { description: error.message, onRetry: reload }) : !data ? /* @__PURE__ */ jsx10(LoadingState3, { variant: "table", rows: 2 }) : !((_c = data.admins) == null ? void 0 : _c.length) ? /* @__PURE__ */ jsx10(EmptyState2, { title: "No administrators yet", compact: true }) : /* @__PURE__ */ jsx10("ul", { className: "divide-y divide-line", children: data.admins.map((a) => /* @__PURE__ */ jsxs9("li", { className: "flex flex-wrap items-center gap-3 py-2.5", children: [
1670
- /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
1671
- /* @__PURE__ */ jsx10("div", { className: "truncate text-sm font-medium text-foreground", children: a.fullName }),
1672
- /* @__PURE__ */ jsx10("div", { className: "truncate text-xs text-muted", children: a.email })
2200
+ error && !data ? /* @__PURE__ */ jsx12(ErrorState5, { description: error.message, onRetry: reload }) : !data ? /* @__PURE__ */ jsx12(LoadingState5, { variant: "table", rows: 2 }) : !((_c = data.admins) == null ? void 0 : _c.length) ? /* @__PURE__ */ jsx12(EmptyState4, { title: "No administrators yet", compact: true }) : /* @__PURE__ */ jsx12("ul", { className: "divide-y divide-line", children: data.admins.map((a) => /* @__PURE__ */ jsxs11("li", { className: "flex flex-wrap items-center gap-3 py-2.5", children: [
2201
+ /* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
2202
+ /* @__PURE__ */ jsx12("div", { className: "truncate text-sm font-medium text-foreground", children: a.fullName }),
2203
+ /* @__PURE__ */ jsx12("div", { className: "truncate text-xs text-muted", children: a.email })
1673
2204
  ] }),
1674
- /* @__PURE__ */ jsx10(StatusPill, { status: a.status }),
1675
- writable && /* @__PURE__ */ jsxs9("div", { className: "flex gap-1", children: [
1676
- /* @__PURE__ */ jsx10(Button6, { size: "sm", variant: "ghost", onClick: () => act(a, "reset-password"), children: "Reset password" }),
1677
- /* @__PURE__ */ jsx10(Button6, { size: "sm", variant: "ghost", onClick: () => act(a, a.status === "active" ? "disable" : "enable"), children: a.status === "active" ? "Disable" : "Enable" })
2205
+ /* @__PURE__ */ jsx12(StatusPill, { status: a.status }),
2206
+ writable && /* @__PURE__ */ jsxs11("div", { className: "flex gap-1", children: [
2207
+ /* @__PURE__ */ jsx12(Button8, { size: "sm", variant: "ghost", onClick: () => act(a, "reset-password"), children: "Reset password" }),
2208
+ /* @__PURE__ */ jsx12(Button8, { size: "sm", variant: "ghost", onClick: () => act(a, a.status === "active" ? "disable" : "enable"), children: a.status === "active" ? "Disable" : "Enable" })
1678
2209
  ] })
1679
2210
  ] }, a.id)) }),
1680
- /* @__PURE__ */ jsx10(
1681
- Dialog2,
2211
+ /* @__PURE__ */ jsx12(
2212
+ Dialog4,
1682
2213
  {
1683
2214
  isOpen: adding,
1684
2215
  onClose: () => setAdding(false),
1685
2216
  title: "Add company admin",
1686
2217
  size: "sm",
1687
- footer: /* @__PURE__ */ jsxs9("div", { className: "flex justify-end gap-2", children: [
1688
- /* @__PURE__ */ jsx10(Button6, { variant: "outline", onClick: () => setAdding(false), children: "Cancel" }),
1689
- /* @__PURE__ */ jsx10(Button6, { loading: busy, disabled: !fullName.trim() || !EMAIL_RE.test(email.trim()), onClick: add, children: "Add admin" })
2218
+ footer: /* @__PURE__ */ jsxs11("div", { className: "flex justify-end gap-2", children: [
2219
+ /* @__PURE__ */ jsx12(Button8, { variant: "outline", onClick: () => setAdding(false), children: "Cancel" }),
2220
+ /* @__PURE__ */ jsx12(Button8, { loading: busy, disabled: !fullName.trim() || !EMAIL_RE.test(email.trim()), onClick: add, children: "Add admin" })
1690
2221
  ] }),
1691
- children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
1692
- /* @__PURE__ */ jsx10(Input4, { label: "Full name", autoFocus: true, value: fullName, onChange: (e) => setFullName(e.target.value) }),
1693
- /* @__PURE__ */ jsx10(Input4, { label: "Email", type: "email", value: email, onChange: (e) => setEmail(e.target.value) }),
1694
- /* @__PURE__ */ jsx10(Input4, { label: "Phone (optional)", type: "tel", value: phone, onChange: (e) => setPhone(e.target.value) })
2222
+ children: /* @__PURE__ */ jsxs11("div", { className: "space-y-4", children: [
2223
+ /* @__PURE__ */ jsx12(Input6, { label: "Full name", autoFocus: true, value: fullName, onChange: (e) => setFullName(e.target.value) }),
2224
+ /* @__PURE__ */ jsx12(Input6, { label: "Email", type: "email", value: email, onChange: (e) => setEmail(e.target.value) }),
2225
+ /* @__PURE__ */ jsx12(Input6, { label: "Phone (optional)", type: "tel", value: phone, onChange: (e) => setPhone(e.target.value) })
1695
2226
  ] })
1696
2227
  }
1697
2228
  )
@@ -1703,7 +2234,7 @@ function ActivityTab({ company, client, can }) {
1703
2234
  var _a, _b;
1704
2235
  const sensitive = useSensitive();
1705
2236
  const { data, error, reload } = useLoad(`companies/${company.id}/activity`);
1706
- const [retryError, setRetryError] = useState7(null);
2237
+ const [retryError, setRetryError] = useState9(null);
1707
2238
  const modeOf = (payload) => {
1708
2239
  try {
1709
2240
  const p = typeof payload === "string" ? JSON.parse(payload) : payload;
@@ -1712,27 +2243,27 @@ function ActivityTab({ company, client, can }) {
1712
2243
  return "managed";
1713
2244
  }
1714
2245
  };
1715
- if (error && !data) return /* @__PURE__ */ jsx10(ErrorState3, { description: error.message, onRetry: reload });
1716
- if (!data) return /* @__PURE__ */ jsx10(LoadingState3, { variant: "table", rows: 4 });
1717
- return /* @__PURE__ */ jsxs9("div", { className: "grid gap-5 [grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr))]", children: [
1718
- /* @__PURE__ */ jsxs9(Card, { title: "Provisioning jobs", children: [
1719
- retryError && /* @__PURE__ */ jsx10(Alert3, { variant: "error", children: retryError }),
1720
- !((_a = data.jobs) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted", children: "No provisioning jobs." }) : /* @__PURE__ */ jsx10("ul", { className: "divide-y divide-line", children: data.jobs.map((j) => {
2246
+ if (error && !data) return /* @__PURE__ */ jsx12(ErrorState5, { description: error.message, onRetry: reload });
2247
+ if (!data) return /* @__PURE__ */ jsx12(LoadingState5, { variant: "table", rows: 4 });
2248
+ return /* @__PURE__ */ jsxs11("div", { className: "grid gap-5 [grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr))]", children: [
2249
+ /* @__PURE__ */ jsxs11(Card, { title: "Provisioning jobs", children: [
2250
+ retryError && /* @__PURE__ */ jsx12(Alert4, { variant: "error", children: retryError }),
2251
+ !((_a = data.jobs) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted", children: "No provisioning jobs." }) : /* @__PURE__ */ jsx12("ul", { className: "divide-y divide-line", children: data.jobs.map((j) => {
1721
2252
  var _a2, _b2;
1722
2253
  const lastError = (_a2 = j.lastError) != null ? _a2 : j.last_error;
1723
- return /* @__PURE__ */ jsxs9("li", { className: "py-2.5", children: [
1724
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-2", children: [
1725
- /* @__PURE__ */ jsx10(StatusPill, { status: j.status }),
1726
- /* @__PURE__ */ jsxs9("span", { className: "text-xs text-muted", children: [
2254
+ return /* @__PURE__ */ jsxs11("li", { className: "py-2.5", children: [
2255
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2", children: [
2256
+ /* @__PURE__ */ jsx12(StatusPill, { status: j.status }),
2257
+ /* @__PURE__ */ jsxs11("span", { className: "text-xs text-muted", children: [
1727
2258
  modeOf(j.payload),
1728
2259
  " \xB7 step ",
1729
- /* @__PURE__ */ jsx10("span", { className: "font-mono", children: j.step }),
2260
+ /* @__PURE__ */ jsx12("span", { className: "font-mono", children: j.step }),
1730
2261
  " \xB7 ",
1731
2262
  j.attempts,
1732
2263
  " attempt(s)"
1733
2264
  ] }),
1734
- j.status === "failed" && can("companies.write") && /* @__PURE__ */ jsx10(
1735
- Button6,
2265
+ j.status === "failed" && can("companies.write") && /* @__PURE__ */ jsx12(
2266
+ Button8,
1736
2267
  {
1737
2268
  size: "sm",
1738
2269
  variant: "ghost",
@@ -1750,33 +2281,33 @@ function ActivityTab({ company, client, can }) {
1750
2281
  }
1751
2282
  )
1752
2283
  ] }),
1753
- lastError && j.status !== "succeeded" && /* @__PURE__ */ jsx10("div", { className: "mt-1 break-words font-mono text-xs text-error-700", children: lastError }),
1754
- /* @__PURE__ */ jsx10("div", { className: "mt-0.5 text-xs text-muted", children: formatDate((_b2 = j.updatedAt) != null ? _b2 : j.updated_at) })
2284
+ lastError && j.status !== "succeeded" && /* @__PURE__ */ jsx12("div", { className: "mt-1 break-words font-mono text-xs text-error-700", children: lastError }),
2285
+ /* @__PURE__ */ jsx12("div", { className: "mt-0.5 text-xs text-muted", children: formatDate((_b2 = j.updatedAt) != null ? _b2 : j.updated_at) })
1755
2286
  ] }, j.id);
1756
2287
  }) })
1757
2288
  ] }),
1758
- /* @__PURE__ */ jsx10(Card, { title: "Audit trail", children: !((_b = data.events) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted", children: "No events." }) : /* @__PURE__ */ jsx10("ol", { className: "divide-y divide-line", children: data.events.map(normalizeEvent).map((e, i) => {
2289
+ /* @__PURE__ */ jsx12(Card, { title: "Audit trail", children: !((_b = data.events) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted", children: "No events." }) : /* @__PURE__ */ jsx12("ol", { className: "divide-y divide-line", children: data.events.map(normalizeEvent).map((e, i) => {
1759
2290
  var _a2;
1760
- return /* @__PURE__ */ jsxs9("li", { className: "py-2.5", children: [
1761
- /* @__PURE__ */ jsxs9("div", { className: "text-sm text-foreground", children: [
1762
- /* @__PURE__ */ jsx10("span", { className: "font-medium", children: e.actor }),
2291
+ return /* @__PURE__ */ jsxs11("li", { className: "py-2.5", children: [
2292
+ /* @__PURE__ */ jsxs11("div", { className: "text-sm text-foreground", children: [
2293
+ /* @__PURE__ */ jsx12("span", { className: "font-medium", children: e.actor }),
1763
2294
  " ",
1764
2295
  describeAction(e.action),
1765
- e.target && /* @__PURE__ */ jsxs9("span", { className: "text-muted", children: [
2296
+ e.target && /* @__PURE__ */ jsxs11("span", { className: "text-muted", children: [
1766
2297
  " \xB7 ",
1767
2298
  e.target
1768
2299
  ] })
1769
2300
  ] }),
1770
- /* @__PURE__ */ jsx10("div", { className: "text-xs text-muted", children: formatDate(e.at) })
2301
+ /* @__PURE__ */ jsx12("div", { className: "text-xs text-muted", children: formatDate(e.at) })
1771
2302
  ] }, (_a2 = e.id) != null ? _a2 : i);
1772
2303
  }) }) })
1773
2304
  ] });
1774
2305
  }
1775
2306
 
1776
2307
  // src/platform/views/Admins.jsx
1777
- import React10, { useState as useState8 } from "react";
1778
- import { Alert as Alert4, Badge as Badge2, Button as Button7, ConfirmDialog as ConfirmDialog2, Dialog as Dialog3, ErrorState as ErrorState4, Input as Input5, LoadingState as LoadingState4, PageHeader as PageHeader5, Select } from "@dreamtree-org/twreact-ui";
1779
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2308
+ import React12, { useState as useState10 } from "react";
2309
+ import { Alert as Alert5, Badge as Badge3, Button as Button9, ConfirmDialog as ConfirmDialog3, Dialog as Dialog5, ErrorState as ErrorState6, Input as Input7, LoadingState as LoadingState6, PageHeader as PageHeader6, Select as Select3 } from "@dreamtree-org/twreact-ui";
2310
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1780
2311
  var ROLE_OPTIONS = [
1781
2312
  { value: "superadmin", label: "Superadmin: everything" },
1782
2313
  { value: "support", label: "Support: read-only" }
@@ -1786,13 +2317,13 @@ function AdminsView() {
1786
2317
  const { client, can, loginUrl, Link } = usePlatform();
1787
2318
  const sensitive = useSensitive();
1788
2319
  const { data, error, loading, reload } = useLoad("admins");
1789
- const [flash, setFlash] = useState8(null);
1790
- const [secret, setSecret] = useState8(null);
1791
- const [adding, setAdding] = useState8(false);
1792
- const [email, setEmail] = useState8("");
1793
- const [role, setRole] = useState8("superadmin");
1794
- const [busy, setBusy] = useState8(false);
1795
- const [confirm, setConfirm] = useState8(null);
2320
+ const [flash, setFlash] = useState10(null);
2321
+ const [secret, setSecret] = useState10(null);
2322
+ const [adding, setAdding] = useState10(false);
2323
+ const [email, setEmail] = useState10("");
2324
+ const [role, setRole] = useState10("superadmin");
2325
+ const [busy, setBusy] = useState10(false);
2326
+ const [confirm, setConfirm] = useState10(null);
1796
2327
  const writable = can("admins.write");
1797
2328
  const act = async (a, action, extra = {}) => {
1798
2329
  var _a2;
@@ -1823,63 +2354,63 @@ function AdminsView() {
1823
2354
  setBusy(false);
1824
2355
  }
1825
2356
  };
1826
- return /* @__PURE__ */ jsxs10("div", { className: "mx-auto max-w-5xl space-y-6 px-4 py-6 sm:px-6", children: [
1827
- /* @__PURE__ */ jsx11(
1828
- PageHeader5,
2357
+ return /* @__PURE__ */ jsxs12("div", { className: "mx-auto max-w-5xl space-y-6 px-4 py-6 sm:px-6", children: [
2358
+ /* @__PURE__ */ jsx13(
2359
+ PageHeader6,
1829
2360
  {
1830
2361
  title: "Platform admins",
1831
2362
  subtitle: "People who can create companies and manage the platform",
1832
2363
  linkAs: Link,
1833
- actions: writable && /* @__PURE__ */ jsx11(Button7, { leftIcon: /* @__PURE__ */ jsx11(IconPlus, {}), onClick: () => setAdding(true), children: "Add platform admin" })
2364
+ actions: writable && /* @__PURE__ */ jsx13(Button9, { leftIcon: /* @__PURE__ */ jsx13(IconPlus, {}), onClick: () => setAdding(true), children: "Add platform admin" })
1834
2365
  }
1835
2366
  ),
1836
- flash && /* @__PURE__ */ jsx11(Alert4, { variant: flash.kind, dismissible: true, onDismiss: () => setFlash(null), children: flash.msg }),
1837
- secret && /* @__PURE__ */ jsx11(OneTimeSecret, { title: secret.title, loginUrl, email: secret.email, password: secret.password, onDone: () => setSecret(null) }),
1838
- error && !data ? /* @__PURE__ */ jsx11(ErrorState4, { description: error.message, onRetry: reload }) : loading && !data ? /* @__PURE__ */ jsx11(LoadingState4, { variant: "table", rows: 3 }) : /* @__PURE__ */ jsx11("ul", { className: "divide-y divide-line rounded-xl border border-line bg-surface", children: ((_a = data == null ? void 0 : data.admins) != null ? _a : []).map((a) => {
2367
+ flash && /* @__PURE__ */ jsx13(Alert5, { variant: flash.kind, dismissible: true, onDismiss: () => setFlash(null), children: flash.msg }),
2368
+ secret && /* @__PURE__ */ jsx13(OneTimeSecret, { title: secret.title, loginUrl, email: secret.email, password: secret.password, onDone: () => setSecret(null) }),
2369
+ error && !data ? /* @__PURE__ */ jsx13(ErrorState6, { description: error.message, onRetry: reload }) : loading && !data ? /* @__PURE__ */ jsx13(LoadingState6, { variant: "table", rows: 3 }) : /* @__PURE__ */ jsx13("ul", { className: "divide-y divide-line rounded-xl border border-line bg-surface", children: ((_a = data == null ? void 0 : data.admins) != null ? _a : []).map((a) => {
1839
2370
  var _a2, _b, _c;
1840
2371
  const me = a.id === data.me;
1841
2372
  const roles = Array.isArray(a.roles) ? a.roles : [];
1842
- return /* @__PURE__ */ jsxs10("li", { className: "flex flex-wrap items-center gap-3 px-4 py-3", children: [
1843
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
1844
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-2 text-sm font-medium text-foreground", children: [
1845
- /* @__PURE__ */ jsx11("span", { className: "truncate", children: a.email }),
1846
- me && /* @__PURE__ */ jsx11(Badge2, { variant: "primary", size: "sm", children: "you" })
2373
+ return /* @__PURE__ */ jsxs12("li", { className: "flex flex-wrap items-center gap-3 px-4 py-3", children: [
2374
+ /* @__PURE__ */ jsxs12("div", { className: "min-w-0 flex-1", children: [
2375
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2 text-sm font-medium text-foreground", children: [
2376
+ /* @__PURE__ */ jsx13("span", { className: "truncate", children: a.email }),
2377
+ me && /* @__PURE__ */ jsx13(Badge3, { variant: "primary", size: "sm", children: "you" })
1847
2378
  ] }),
1848
- /* @__PURE__ */ jsxs10("div", { className: "text-xs text-muted", children: [
2379
+ /* @__PURE__ */ jsxs12("div", { className: "text-xs text-muted", children: [
1849
2380
  roles.length ? roles.join(", ") : "No role",
1850
2381
  " \xB7 last sign-in ",
1851
2382
  timeAgo((_a2 = a.lastLoginAt) != null ? _a2 : a.last_login_at),
1852
2383
  !((_b = a.totpEnrolled) != null ? _b : Number(a.strong_factor_enrolled)) && " \xB7 no authenticator yet"
1853
2384
  ] })
1854
2385
  ] }),
1855
- /* @__PURE__ */ jsx11(StatusPill, { status: a.status }),
1856
- writable && /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-1", children: [
1857
- /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "ghost", onClick: () => act(a, "reset-password"), children: "Reset password" }),
1858
- !me && ((_c = a.totpEnrolled) != null ? _c : Number(a.strong_factor_enrolled)) ? /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "ghost", onClick: () => setConfirm({ admin: a, action: "reset-totp" }), children: "Reset authenticator" }) : null,
1859
- !me && (a.status === "active" ? /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "ghost", onClick: () => setConfirm({ admin: a, action: "disable" }), children: "Disable" }) : /* @__PURE__ */ jsx11(Button7, { size: "sm", variant: "ghost", onClick: () => act(a, "enable"), children: "Enable" }))
2386
+ /* @__PURE__ */ jsx13(StatusPill, { status: a.status }),
2387
+ writable && /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-1", children: [
2388
+ /* @__PURE__ */ jsx13(Button9, { size: "sm", variant: "ghost", onClick: () => act(a, "reset-password"), children: "Reset password" }),
2389
+ !me && ((_c = a.totpEnrolled) != null ? _c : Number(a.strong_factor_enrolled)) ? /* @__PURE__ */ jsx13(Button9, { size: "sm", variant: "ghost", onClick: () => setConfirm({ admin: a, action: "reset-totp" }), children: "Reset authenticator" }) : null,
2390
+ !me && (a.status === "active" ? /* @__PURE__ */ jsx13(Button9, { size: "sm", variant: "ghost", onClick: () => setConfirm({ admin: a, action: "disable" }), children: "Disable" }) : /* @__PURE__ */ jsx13(Button9, { size: "sm", variant: "ghost", onClick: () => act(a, "enable"), children: "Enable" }))
1860
2391
  ] })
1861
2392
  ] }, a.id);
1862
2393
  }) }),
1863
- /* @__PURE__ */ jsx11(
1864
- Dialog3,
2394
+ /* @__PURE__ */ jsx13(
2395
+ Dialog5,
1865
2396
  {
1866
2397
  isOpen: adding,
1867
2398
  onClose: () => setAdding(false),
1868
2399
  title: "Add platform admin",
1869
2400
  size: "sm",
1870
- footer: /* @__PURE__ */ jsxs10("div", { className: "flex justify-end gap-2", children: [
1871
- /* @__PURE__ */ jsx11(Button7, { variant: "outline", onClick: () => setAdding(false), children: "Cancel" }),
1872
- /* @__PURE__ */ jsx11(Button7, { loading: busy, disabled: !EMAIL_RE.test(email.trim()), onClick: add, children: "Add admin" })
2401
+ footer: /* @__PURE__ */ jsxs12("div", { className: "flex justify-end gap-2", children: [
2402
+ /* @__PURE__ */ jsx13(Button9, { variant: "outline", onClick: () => setAdding(false), children: "Cancel" }),
2403
+ /* @__PURE__ */ jsx13(Button9, { loading: busy, disabled: !EMAIL_RE.test(email.trim()), onClick: add, children: "Add admin" })
1873
2404
  ] }),
1874
- children: /* @__PURE__ */ jsxs10("div", { className: "space-y-4", children: [
1875
- /* @__PURE__ */ jsx11("p", { className: "text-sm text-muted", children: "A temporary password is generated and shown once. They set up an authenticator app at first sign-in." }),
1876
- /* @__PURE__ */ jsx11(Input5, { label: "Email", type: "email", autoFocus: true, value: email, onChange: (e) => setEmail(e.target.value) }),
1877
- /* @__PURE__ */ jsx11(Select, { label: "Role", options: ROLE_OPTIONS, value: role, onChange: (v) => setRole(String(v)) })
2405
+ children: /* @__PURE__ */ jsxs12("div", { className: "space-y-4", children: [
2406
+ /* @__PURE__ */ jsx13("p", { className: "text-sm text-muted", children: "A temporary password is generated and shown once. They set up an authenticator app at first sign-in." }),
2407
+ /* @__PURE__ */ jsx13(Input7, { label: "Email", type: "email", autoFocus: true, value: email, onChange: (e) => setEmail(e.target.value) }),
2408
+ /* @__PURE__ */ jsx13(Select3, { label: "Role", options: ROLE_OPTIONS, value: role, onChange: (v) => setRole(String(v)) })
1878
2409
  ] })
1879
2410
  }
1880
2411
  ),
1881
- /* @__PURE__ */ jsx11(
1882
- ConfirmDialog2,
2412
+ /* @__PURE__ */ jsx13(
2413
+ ConfirmDialog3,
1883
2414
  {
1884
2415
  isOpen: confirm !== null,
1885
2416
  title: (confirm == null ? void 0 : confirm.action) === "disable" ? `Disable ${confirm == null ? void 0 : confirm.admin.email}?` : `Reset ${confirm == null ? void 0 : confirm.admin.email}'s authenticator?`,
@@ -1898,17 +2429,17 @@ function AdminsView() {
1898
2429
  }
1899
2430
 
1900
2431
  // src/platform/views/Audit.jsx
1901
- import React11, { useEffect as useEffect5, useState as useState9 } from "react";
1902
- import { Alert as Alert5, Button as Button8, EmptyState as EmptyState3, ErrorState as ErrorState5, Input as Input6, LoadingState as LoadingState5, PageHeader as PageHeader6 } from "@dreamtree-org/twreact-ui";
1903
- import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2432
+ import React13, { useEffect as useEffect6, useState as useState11 } from "react";
2433
+ import { Alert as Alert6, Button as Button10, EmptyState as EmptyState5, ErrorState as ErrorState7, Input as Input8, LoadingState as LoadingState7, PageHeader as PageHeader7 } from "@dreamtree-org/twreact-ui";
2434
+ import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1904
2435
  function AuditView() {
1905
2436
  const { client, Link, href } = usePlatform();
1906
- const [q, setQ] = useState9("");
1907
- const [applied, setApplied] = useState9("");
1908
- const [events, setEvents] = useState9([]);
1909
- const [cursor, setCursor] = useState9(null);
1910
- const [state, setState] = useState9({ loading: true, error: null });
1911
- const [exportError, setExportError] = useState9(null);
2437
+ const [q, setQ] = useState11("");
2438
+ const [applied, setApplied] = useState11("");
2439
+ const [events, setEvents] = useState11([]);
2440
+ const [cursor, setCursor] = useState11(null);
2441
+ const [state, setState] = useState11({ loading: true, error: null });
2442
+ const [exportError, setExportError] = useState11(null);
1912
2443
  const load = async (more = false) => {
1913
2444
  setState({ loading: true, error: null });
1914
2445
  try {
@@ -1920,7 +2451,7 @@ function AuditView() {
1920
2451
  setState({ loading: false, error: e });
1921
2452
  }
1922
2453
  };
1923
- useEffect5(() => {
2454
+ useEffect6(() => {
1924
2455
  void load(false);
1925
2456
  }, [applied]);
1926
2457
  const exportCsv = async () => {
@@ -1939,18 +2470,18 @@ function AuditView() {
1939
2470
  }
1940
2471
  };
1941
2472
  const rows = events.map(normalizeEvent);
1942
- return /* @__PURE__ */ jsxs11("div", { className: "mx-auto max-w-6xl space-y-6 px-4 py-6 sm:px-6", children: [
1943
- /* @__PURE__ */ jsx12(
1944
- PageHeader6,
2473
+ return /* @__PURE__ */ jsxs13("div", { className: "mx-auto max-w-6xl space-y-6 px-4 py-6 sm:px-6", children: [
2474
+ /* @__PURE__ */ jsx14(
2475
+ PageHeader7,
1945
2476
  {
1946
2477
  title: "Audit log",
1947
2478
  subtitle: "Every platform action: who did what, to which company",
1948
2479
  linkAs: Link,
1949
- actions: /* @__PURE__ */ jsx12(Button8, { variant: "outline", leftIcon: /* @__PURE__ */ jsx12(IconDownload, {}), onClick: exportCsv, children: "Export CSV" })
2480
+ actions: /* @__PURE__ */ jsx14(Button10, { variant: "outline", leftIcon: /* @__PURE__ */ jsx14(IconDownload, {}), onClick: exportCsv, children: "Export CSV" })
1950
2481
  }
1951
2482
  ),
1952
- exportError && /* @__PURE__ */ jsx12(Alert5, { variant: "error", children: exportError }),
1953
- /* @__PURE__ */ jsxs11(
2483
+ exportError && /* @__PURE__ */ jsx14(Alert6, { variant: "error", children: exportError }),
2484
+ /* @__PURE__ */ jsxs13(
1954
2485
  "form",
1955
2486
  {
1956
2487
  className: "flex gap-2",
@@ -1959,50 +2490,50 @@ function AuditView() {
1959
2490
  setApplied(q.trim());
1960
2491
  },
1961
2492
  children: [
1962
- /* @__PURE__ */ jsx12("div", { className: "flex-1", children: /* @__PURE__ */ jsx12(Input6, { type: "search", "aria-label": "Search the audit log", placeholder: "Search action, target or company", value: q, onChange: (e) => setQ(e.target.value) }) }),
1963
- /* @__PURE__ */ jsx12(Button8, { type: "submit", variant: "outline", children: "Search" })
2493
+ /* @__PURE__ */ jsx14("div", { className: "flex-1", children: /* @__PURE__ */ jsx14(Input8, { type: "search", "aria-label": "Search the audit log", placeholder: "Search action, target or company", value: q, onChange: (e) => setQ(e.target.value) }) }),
2494
+ /* @__PURE__ */ jsx14(Button10, { type: "submit", variant: "outline", children: "Search" })
1964
2495
  ]
1965
2496
  }
1966
2497
  ),
1967
- state.error && !rows.length ? /* @__PURE__ */ jsx12(ErrorState5, { description: state.error.message, onRetry: () => load(false) }) : state.loading && !rows.length ? /* @__PURE__ */ jsx12(LoadingState5, { variant: "table", rows: 8 }) : !rows.length ? /* @__PURE__ */ jsx12(EmptyState3, { icon: /* @__PURE__ */ jsx12(IconList, { size: 24 }), title: applied ? "Nothing matches" : "No events yet", compact: true }) : /* @__PURE__ */ jsxs11(Fragment5, { children: [
1968
- /* @__PURE__ */ jsx12("ol", { className: "divide-y divide-line rounded-xl border border-line bg-surface", children: rows.map((e, i) => {
2498
+ state.error && !rows.length ? /* @__PURE__ */ jsx14(ErrorState7, { description: state.error.message, onRetry: () => load(false) }) : state.loading && !rows.length ? /* @__PURE__ */ jsx14(LoadingState7, { variant: "table", rows: 8 }) : !rows.length ? /* @__PURE__ */ jsx14(EmptyState5, { icon: /* @__PURE__ */ jsx14(IconList, { size: 24 }), title: applied ? "Nothing matches" : "No events yet", compact: true }) : /* @__PURE__ */ jsxs13(Fragment5, { children: [
2499
+ /* @__PURE__ */ jsx14("ol", { className: "divide-y divide-line rounded-xl border border-line bg-surface", children: rows.map((e, i) => {
1969
2500
  var _a;
1970
- return /* @__PURE__ */ jsxs11("li", { className: "flex flex-wrap items-baseline gap-x-3 gap-y-1 px-4 py-2.5", children: [
1971
- /* @__PURE__ */ jsx12("span", { className: "w-40 shrink-0 text-xs text-muted", children: formatDate(e.at) }),
1972
- /* @__PURE__ */ jsxs11("span", { className: "min-w-0 flex-1 text-sm text-foreground", children: [
1973
- /* @__PURE__ */ jsx12("span", { className: "font-medium", children: e.actor }),
2501
+ return /* @__PURE__ */ jsxs13("li", { className: "flex flex-wrap items-baseline gap-x-3 gap-y-1 px-4 py-2.5", children: [
2502
+ /* @__PURE__ */ jsx14("span", { className: "w-40 shrink-0 text-xs text-muted", children: formatDate(e.at) }),
2503
+ /* @__PURE__ */ jsxs13("span", { className: "min-w-0 flex-1 text-sm text-foreground", children: [
2504
+ /* @__PURE__ */ jsx14("span", { className: "font-medium", children: e.actor }),
1974
2505
  " ",
1975
2506
  describeAction(e.action),
1976
- e.company && e.companyId && /* @__PURE__ */ jsxs11(Fragment5, { children: [
2507
+ e.company && e.companyId && /* @__PURE__ */ jsxs13(Fragment5, { children: [
1977
2508
  " \xB7 ",
1978
- /* @__PURE__ */ jsx12(Link, { href: href(`companies/${e.companyId}`), className: "text-primary-600 hover:underline", children: e.company })
2509
+ /* @__PURE__ */ jsx14(Link, { href: href(`companies/${e.companyId}`), className: "text-primary-600 hover:underline", children: e.company })
1979
2510
  ] }),
1980
- e.target && /* @__PURE__ */ jsxs11("span", { className: "text-muted", children: [
2511
+ e.target && /* @__PURE__ */ jsxs13("span", { className: "text-muted", children: [
1981
2512
  " \xB7 ",
1982
2513
  e.target
1983
2514
  ] })
1984
2515
  ] }),
1985
- /* @__PURE__ */ jsx12("code", { className: "text-xs text-muted", children: e.action })
2516
+ /* @__PURE__ */ jsx14("code", { className: "text-xs text-muted", children: e.action })
1986
2517
  ] }, (_a = e.id) != null ? _a : i);
1987
2518
  }) }),
1988
- cursor && /* @__PURE__ */ jsx12("div", { className: "text-center", children: /* @__PURE__ */ jsx12(Button8, { variant: "outline", loading: state.loading, onClick: () => load(true), children: "Load older" }) })
2519
+ cursor && /* @__PURE__ */ jsx14("div", { className: "text-center", children: /* @__PURE__ */ jsx14(Button10, { variant: "outline", loading: state.loading, onClick: () => load(true), children: "Load older" }) })
1989
2520
  ] })
1990
2521
  ] });
1991
2522
  }
1992
2523
 
1993
2524
  // src/platform/views/Security.jsx
1994
- import React12, { useState as useState10 } from "react";
1995
- import { Alert as Alert6, Button as Button9, Input as Input7, PageHeader as PageHeader7 } from "@dreamtree-org/twreact-ui";
1996
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2525
+ import React14, { useState as useState12 } from "react";
2526
+ import { Alert as Alert7, Button as Button11, Input as Input9, PageHeader as PageHeader8 } from "@dreamtree-org/twreact-ui";
2527
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1997
2528
  var grouped = (s) => String(s != null ? s : "").replace(/(.{4})/g, "$1 ").trim();
1998
2529
  function SecurityView({ gate = false }) {
1999
2530
  var _a, _b;
2000
2531
  const { client, me, reloadMe, Link } = usePlatform();
2001
2532
  const sensitive = useSensitive();
2002
- const [setup, setSetup] = useState10(null);
2003
- const [code, setCode] = useState10("");
2004
- const [busy, setBusy] = useState10(false);
2005
- const [error, setError] = useState10(null);
2533
+ const [setup, setSetup] = useState12(null);
2534
+ const [code, setCode] = useState12("");
2535
+ const [busy, setBusy] = useState12(false);
2536
+ const [error, setError] = useState12(null);
2006
2537
  const enrolled = (_a = me == null ? void 0 : me.admin) == null ? void 0 : _a.totpEnrolled;
2007
2538
  const begin = async () => {
2008
2539
  setBusy(true);
@@ -2030,36 +2561,187 @@ function SecurityView({ gate = false }) {
2030
2561
  setBusy(false);
2031
2562
  }
2032
2563
  };
2033
- return /* @__PURE__ */ jsxs12("div", { className: "mx-auto max-w-2xl space-y-6 px-4 py-6 sm:px-6", children: [
2034
- /* @__PURE__ */ jsx13(PageHeader7, { title: gate ? "Set up your authenticator" : "Security", subtitle: (_b = me == null ? void 0 : me.admin) == null ? void 0 : _b.email, linkAs: Link }),
2035
- gate && /* @__PURE__ */ jsx13(Alert6, { variant: "info", title: "One more step", children: "The platform console needs a second factor. Set up an authenticator app (Google Authenticator, 1Password, Authy, \u2026) to continue." }),
2036
- error && /* @__PURE__ */ jsx13(Alert6, { variant: "error", children: error }),
2037
- /* @__PURE__ */ jsx13(Card, { title: "Authenticator app", children: enrolled ? /* @__PURE__ */ jsxs12("p", { className: "flex items-center gap-2 text-sm text-success-700", children: [
2038
- /* @__PURE__ */ jsx13(IconCheck, {}),
2564
+ return /* @__PURE__ */ jsxs14("div", { className: "mx-auto max-w-2xl space-y-6 px-4 py-6 sm:px-6", children: [
2565
+ /* @__PURE__ */ jsx15(PageHeader8, { title: gate ? "Set up your authenticator" : "Security", subtitle: (_b = me == null ? void 0 : me.admin) == null ? void 0 : _b.email, linkAs: Link }),
2566
+ gate && /* @__PURE__ */ jsx15(Alert7, { variant: "info", title: "One more step", children: "The platform console needs a second factor. Set up an authenticator app (Google Authenticator, 1Password, Authy, \u2026) to continue." }),
2567
+ error && /* @__PURE__ */ jsx15(Alert7, { variant: "error", children: error }),
2568
+ /* @__PURE__ */ jsx15(Card, { title: "Authenticator app", children: enrolled ? /* @__PURE__ */ jsxs14("p", { className: "flex items-center gap-2 text-sm text-success-700", children: [
2569
+ /* @__PURE__ */ jsx15(IconCheck, {}),
2039
2570
  " An authenticator is set up. Sign-in and sensitive actions ask for its code. If you lose the device, ask another platform admin to reset it."
2040
- ] }) : !setup ? /* @__PURE__ */ jsxs12("div", { className: "space-y-3", children: [
2041
- /* @__PURE__ */ jsx13("p", { className: "text-sm text-muted", children: "You'll scan or type a setup key into the app, then enter the 6-digit code it shows." }),
2042
- /* @__PURE__ */ jsx13(Button9, { leftIcon: /* @__PURE__ */ jsx13(IconShield, {}), loading: busy, onClick: begin, children: "Start setup" })
2043
- ] }) : /* @__PURE__ */ jsxs12("form", { className: "space-y-4", onSubmit: verify, children: [
2044
- /* @__PURE__ */ jsxs12("ol", { className: "list-decimal space-y-3 pl-5 text-sm text-foreground", children: [
2045
- /* @__PURE__ */ jsxs12("li", { children: [
2571
+ ] }) : !setup ? /* @__PURE__ */ jsxs14("div", { className: "space-y-3", children: [
2572
+ /* @__PURE__ */ jsx15("p", { className: "text-sm text-muted", children: "You'll scan or type a setup key into the app, then enter the 6-digit code it shows." }),
2573
+ /* @__PURE__ */ jsx15(Button11, { leftIcon: /* @__PURE__ */ jsx15(IconShield, {}), loading: busy, onClick: begin, children: "Start setup" })
2574
+ ] }) : /* @__PURE__ */ jsxs14("form", { className: "space-y-4", onSubmit: verify, children: [
2575
+ /* @__PURE__ */ jsxs14("ol", { className: "list-decimal space-y-3 pl-5 text-sm text-foreground", children: [
2576
+ /* @__PURE__ */ jsxs14("li", { children: [
2046
2577
  "Add an account in your authenticator app with this setup key:",
2047
- /* @__PURE__ */ jsxs12("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: [
2048
- /* @__PURE__ */ jsx13("code", { className: "rounded-md bg-background px-2 py-1 font-mono text-sm tracking-wider", children: grouped(setup.secret) }),
2049
- /* @__PURE__ */ jsx13(CopyButton, { value: setup.secret, label: "Copy key" }),
2050
- /* @__PURE__ */ jsx13("a", { href: setup.otpauthUrl, className: "text-xs text-primary-600 underline", children: "Open in authenticator app" })
2578
+ /* @__PURE__ */ jsxs14("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: [
2579
+ /* @__PURE__ */ jsx15("code", { className: "rounded-md bg-background px-2 py-1 font-mono text-sm tracking-wider", children: grouped(setup.secret) }),
2580
+ /* @__PURE__ */ jsx15(CopyButton, { value: setup.secret, label: "Copy key" }),
2581
+ /* @__PURE__ */ jsx15("a", { href: setup.otpauthUrl, className: "text-xs text-primary-600 underline", children: "Open in authenticator app" })
2051
2582
  ] })
2052
2583
  ] }),
2053
- /* @__PURE__ */ jsx13("li", { children: "Enter the 6-digit code it shows." })
2584
+ /* @__PURE__ */ jsx15("li", { children: "Enter the 6-digit code it shows." })
2054
2585
  ] }),
2055
- /* @__PURE__ */ jsx13("div", { className: "max-w-xs", children: /* @__PURE__ */ jsx13(Input7, { label: "Code", otp: true, autoFocus: true, value: code, onChange: (e) => setCode(e.target.value.replace(/\s/g, "")) }) }),
2056
- /* @__PURE__ */ jsx13(Button9, { type: "submit", loading: busy, disabled: code.length < 6, children: "Verify and finish" })
2586
+ /* @__PURE__ */ jsx15("div", { className: "max-w-xs", children: /* @__PURE__ */ jsx15(Input9, { label: "Code", otp: true, autoFocus: true, value: code, onChange: (e) => setCode(e.target.value.replace(/\s/g, "")) }) }),
2587
+ /* @__PURE__ */ jsx15(Button11, { type: "submit", loading: busy, disabled: code.length < 6, children: "Verify and finish" })
2057
2588
  ] }) })
2058
2589
  ] });
2059
2590
  }
2060
2591
 
2592
+ // src/platform/views/Plans.jsx
2593
+ import React15, { useState as useState13 } from "react";
2594
+ import { Alert as Alert8, Button as Button12, Dialog as Dialog6, EmptyState as EmptyState6, ErrorState as ErrorState8, Input as Input10, LoadingState as LoadingState8, PageHeader as PageHeader9, Select as Select4, Textarea as Textarea4 } from "@dreamtree-org/twreact-ui";
2595
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
2596
+ var INTERVALS = [
2597
+ { value: "month", label: "Monthly" },
2598
+ { value: "year", label: "Yearly" },
2599
+ { value: "one-time", label: "One-time" }
2600
+ ];
2601
+ var blank = { code: "", name: "", price: "0", currency: "INR", interval: "month", seats: "", limits: "", features: "" };
2602
+ function toForm(plan) {
2603
+ var _a, _b, _c, _d, _e;
2604
+ return {
2605
+ code: plan.code,
2606
+ name: plan.name,
2607
+ price: String((Number((_a = plan.priceMinor) != null ? _a : 0) / 100).toFixed(2)).replace(/\.00$/, ""),
2608
+ currency: (_b = plan.currency) != null ? _b : "INR",
2609
+ interval: (_c = plan.interval) != null ? _c : "month",
2610
+ seats: plan.seats == null ? "" : String(plan.seats),
2611
+ limits: Object.entries((_d = plan.limits) != null ? _d : {}).map(([k, v]) => `${k} = ${v != null ? v : ""}`).join("\n"),
2612
+ features: ((_e = plan.features) != null ? _e : []).join(", ")
2613
+ };
2614
+ }
2615
+ function planBody(form) {
2616
+ const limits = {};
2617
+ for (const line of form.limits.split("\n")) {
2618
+ const [k, ...rest] = line.split("=");
2619
+ if (!k.trim()) continue;
2620
+ const v = rest.join("=").trim();
2621
+ limits[k.trim()] = v === "" ? null : Number(v);
2622
+ }
2623
+ return {
2624
+ code: form.code.trim().toLowerCase(),
2625
+ name: form.name.trim(),
2626
+ priceMinor: Math.round(Number(form.price || 0) * 100),
2627
+ currency: form.currency.trim().toUpperCase(),
2628
+ interval: form.interval,
2629
+ seats: form.seats.trim() === "" ? null : Number(form.seats),
2630
+ limits,
2631
+ features: form.features.split(",").map((f) => f.trim()).filter(Boolean)
2632
+ };
2633
+ }
2634
+ function PlansView() {
2635
+ var _a;
2636
+ const { client, can, Link } = usePlatform();
2637
+ const sensitive = useSensitive();
2638
+ const { data, error, loading, reload } = useLoad("plans");
2639
+ const [flash, setFlash] = useState13(null);
2640
+ const [editing, setEditing] = useState13(null);
2641
+ const [busy, setBusy] = useState13(false);
2642
+ const writable = can("plans.write");
2643
+ const plans = (_a = data == null ? void 0 : data.plans) != null ? _a : [];
2644
+ const save = async () => {
2645
+ setBusy(true);
2646
+ setFlash(null);
2647
+ try {
2648
+ const body = planBody(editing.form);
2649
+ if (editing.plan) {
2650
+ const { code: _code, ...patch } = body;
2651
+ await sensitive(() => client.patch(`plans/${encodeURIComponent(editing.plan.id)}`, patch));
2652
+ } else {
2653
+ await sensitive(() => client.post("plans", body));
2654
+ }
2655
+ setFlash({ kind: "success", msg: `${body.name} saved` });
2656
+ setEditing(null);
2657
+ await reload();
2658
+ } catch (e) {
2659
+ const msg = errorText(e);
2660
+ if (msg) setFlash({ kind: "error", msg });
2661
+ } finally {
2662
+ setBusy(false);
2663
+ }
2664
+ };
2665
+ const setStatus = async (plan, status) => {
2666
+ setFlash(null);
2667
+ try {
2668
+ await sensitive(() => client.patch(`plans/${encodeURIComponent(plan.id)}`, { status }));
2669
+ setFlash({ kind: "success", msg: `${plan.name} ${status === "archived" ? "archived" : "restored"}` });
2670
+ await reload();
2671
+ } catch (e) {
2672
+ const msg = errorText(e);
2673
+ if (msg) setFlash({ kind: "error", msg });
2674
+ }
2675
+ };
2676
+ const field = (key) => {
2677
+ var _a2;
2678
+ return {
2679
+ value: (_a2 = editing == null ? void 0 : editing.form[key]) != null ? _a2 : "",
2680
+ onChange: (e) => setEditing((s) => ({ ...s, form: { ...s.form, [key]: e.target.value } }))
2681
+ };
2682
+ };
2683
+ const valid = editing && /^[a-z0-9][a-z0-9_-]{0,47}$/.test(editing.form.code.trim().toLowerCase()) && editing.form.name.trim() && Number(editing.form.price) >= 0;
2684
+ return /* @__PURE__ */ jsxs15("div", { className: "mx-auto max-w-5xl space-y-6 px-4 py-6 sm:px-6", children: [
2685
+ /* @__PURE__ */ jsx16(
2686
+ PageHeader9,
2687
+ {
2688
+ title: "Plans",
2689
+ subtitle: "What companies can subscribe to. Archived plans stay on the companies already using them.",
2690
+ linkAs: Link,
2691
+ actions: writable && /* @__PURE__ */ jsx16(Button12, { leftIcon: /* @__PURE__ */ jsx16(IconPlus, {}), onClick: () => setEditing({ form: { ...blank } }), children: "New plan" })
2692
+ }
2693
+ ),
2694
+ flash && /* @__PURE__ */ jsx16(Alert8, { variant: flash.kind, dismissible: true, onDismiss: () => setFlash(null), children: flash.msg }),
2695
+ error && !data ? /* @__PURE__ */ jsx16(ErrorState8, { description: error.message, onRetry: reload }) : loading && !data ? /* @__PURE__ */ jsx16(LoadingState8, { variant: "table", rows: 3 }) : plans.length === 0 ? /* @__PURE__ */ jsx16(EmptyState6, { icon: /* @__PURE__ */ jsx16(IconTag, { size: 24 }), title: "No plans yet", description: writable ? "Create the first plan companies can subscribe to." : "A superadmin creates plans." }) : /* @__PURE__ */ jsx16("ul", { className: "divide-y divide-line rounded-xl border border-line bg-surface", children: plans.map((p) => {
2696
+ var _a2, _b;
2697
+ return /* @__PURE__ */ jsxs15("li", { className: "flex flex-wrap items-center gap-3 px-4 py-3", children: [
2698
+ /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
2699
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-wrap items-center gap-2 text-sm font-medium text-foreground", children: [
2700
+ /* @__PURE__ */ jsx16("span", { children: p.name }),
2701
+ /* @__PURE__ */ jsx16("span", { className: "font-mono text-xs text-muted", children: p.code })
2702
+ ] }),
2703
+ /* @__PURE__ */ jsxs15("div", { className: "text-xs text-muted", children: [
2704
+ formatPrice(p.priceMinor, p.currency, p.interval),
2705
+ p.seats ? ` \xB7 ${p.seats} seats` : "",
2706
+ Object.keys((_a2 = p.limits) != null ? _a2 : {}).length ? ` \xB7 ${Object.entries(p.limits).map(([k, v]) => `${k} ${v != null ? v : "\u221E"}`).join(", ")}` : ""
2707
+ ] }),
2708
+ ((_b = p.features) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx16("div", { className: "mt-1 text-xs text-muted", children: p.features.join(" \xB7 ") }) : null
2709
+ ] }),
2710
+ /* @__PURE__ */ jsx16(StatusPill, { status: p.status }),
2711
+ writable && /* @__PURE__ */ jsxs15("div", { className: "flex gap-1", children: [
2712
+ /* @__PURE__ */ jsx16(Button12, { size: "sm", variant: "ghost", onClick: () => setEditing({ plan: p, form: toForm(p) }), children: "Edit" }),
2713
+ /* @__PURE__ */ jsx16(Button12, { size: "sm", variant: "ghost", onClick: () => setStatus(p, p.status === "archived" ? "active" : "archived"), children: p.status === "archived" ? "Restore" : "Archive" })
2714
+ ] })
2715
+ ] }, p.id);
2716
+ }) }),
2717
+ /* @__PURE__ */ jsx16(
2718
+ Dialog6,
2719
+ {
2720
+ isOpen: editing !== null,
2721
+ onClose: () => setEditing(null),
2722
+ title: (editing == null ? void 0 : editing.plan) ? `Edit ${editing.plan.name}` : "New plan",
2723
+ size: "md",
2724
+ footer: /* @__PURE__ */ jsxs15("div", { className: "flex justify-end gap-2", children: [
2725
+ /* @__PURE__ */ jsx16(Button12, { variant: "outline", onClick: () => setEditing(null), children: "Cancel" }),
2726
+ /* @__PURE__ */ jsx16(Button12, { loading: busy, disabled: !valid, onClick: save, children: "Save plan" })
2727
+ ] }),
2728
+ children: editing && /* @__PURE__ */ jsxs15("div", { className: "grid gap-4 sm:grid-cols-2", children: [
2729
+ /* @__PURE__ */ jsx16(Input10, { label: "Name", autoFocus: true, ...field("name") }),
2730
+ /* @__PURE__ */ jsx16(Input10, { label: "Code", disabled: Boolean(editing.plan), helperText: editing.plan ? "Fixed once created" : "Lowercase, e.g. pro or team-yearly", ...field("code") }),
2731
+ /* @__PURE__ */ jsx16(Input10, { label: "Price", type: "number", min: "0", step: "0.01", ...field("price") }),
2732
+ /* @__PURE__ */ jsx16(Input10, { label: "Currency", maxLength: 3, ...field("currency") }),
2733
+ /* @__PURE__ */ jsx16(Select4, { label: "Billing", options: INTERVALS, value: editing.form.interval, onChange: (v) => setEditing((s) => ({ ...s, form: { ...s.form, interval: String(v) } })) }),
2734
+ /* @__PURE__ */ jsx16(Input10, { label: "Seats", type: "number", min: "1", helperText: "Leave empty for no seat limit", ...field("seats") }),
2735
+ /* @__PURE__ */ jsx16("div", { className: "sm:col-span-2", children: /* @__PURE__ */ jsx16(Textarea4, { label: "Limits", rows: 3, placeholder: "users = 10\nbranches =", helperText: "One per line: name = number. Leave the number empty for unlimited.", ...field("limits") }) }),
2736
+ /* @__PURE__ */ jsx16("div", { className: "sm:col-span-2", children: /* @__PURE__ */ jsx16(Input10, { label: "Features", placeholder: "gst, reports, api", helperText: "Comma-separated", ...field("features") }) })
2737
+ ] })
2738
+ }
2739
+ )
2740
+ ] });
2741
+ }
2742
+
2061
2743
  // src/platform/PlatformConsole.jsx
2062
- import { jsx as jsx14 } from "react/jsx-runtime";
2744
+ import { jsx as jsx17 } from "react/jsx-runtime";
2063
2745
  var trim = (s) => String(s != null ? s : "").replace(/^\/+|\/+$/g, "");
2064
2746
  function matchConsoleRoute(rel, pages = []) {
2065
2747
  const parts = trim(rel).split("/").filter(Boolean);
@@ -2071,7 +2753,8 @@ function matchConsoleRoute(rel, pages = []) {
2071
2753
  if (parts[1] === "new" && parts.length === 2) return { view: "new-company" };
2072
2754
  if (parts.length === 2) return { view: "company", id: decodeURIComponent(parts[1]) };
2073
2755
  }
2074
- if (parts.length === 1 && ["admins", "audit", "security"].includes(parts[0])) return { view: parts[0] };
2756
+ if (parts.length === 1 && ["admins", "audit", "security", "plans"].includes(parts[0])) return { view: parts[0] };
2757
+ if (parts.length === 1 && parts[0] === "support-access") return { view: "support" };
2075
2758
  return { view: "not-found" };
2076
2759
  }
2077
2760
  function PlatformConsole({
@@ -2103,7 +2786,7 @@ function PlatformConsole({
2103
2786
  [given, apiBasePath, loginPath, base2]
2104
2787
  );
2105
2788
  const Link = useMemo3(() => makeLink(linkAs, navigate), [linkAs, navigate]);
2106
- const [me, setMe] = useState11(initialMe);
2789
+ const [me, setMe] = useState14(initialMe);
2107
2790
  const reloadMe = useCallback4(async () => {
2108
2791
  try {
2109
2792
  setMe(await client.get("me"));
@@ -2111,7 +2794,7 @@ function PlatformConsole({
2111
2794
  if (e.status !== 401) setMe(null);
2112
2795
  }
2113
2796
  }, [client]);
2114
- useEffect6(() => {
2797
+ useEffect7(() => {
2115
2798
  void reloadMe();
2116
2799
  }, [reloadMe]);
2117
2800
  const href = useCallback4((rel2 = "") => `${base2}/${trim(rel2)}`.replace(/\/$/, "") || "/", [base2]);
@@ -2139,13 +2822,15 @@ function PlatformConsole({
2139
2822
  const route = matchConsoleRoute(rel, visiblePages);
2140
2823
  const gate = me && me.access && me.access.console === false;
2141
2824
  const active = (prefix) => prefix === "" ? route.view === "overview" : trim(rel) === prefix || trim(rel).startsWith(`${prefix}/`);
2142
- const nav = gate ? [{ id: "security", label: "Set up authenticator", href: href("security"), icon: /* @__PURE__ */ jsx14(IconShield, {}), active: true }] : [
2143
- enabled.includes("overview") && { id: "overview", label: "Overview", href: href(""), icon: /* @__PURE__ */ jsx14(IconDashboard, {}), active: active("") },
2144
- enabled.includes("companies") && { id: "companies", label: "Companies", href: href("companies"), icon: /* @__PURE__ */ jsx14(IconBuilding, {}), active: active("companies") },
2825
+ const nav = gate ? [{ id: "security", label: "Set up authenticator", href: href("security"), icon: /* @__PURE__ */ jsx17(IconShield, {}), active: true }] : [
2826
+ enabled.includes("overview") && { id: "overview", label: "Overview", href: href(""), icon: /* @__PURE__ */ jsx17(IconDashboard, {}), active: active("") },
2827
+ enabled.includes("companies") && { id: "companies", label: "Companies", href: href("companies"), icon: /* @__PURE__ */ jsx17(IconBuilding, {}), active: active("companies") },
2145
2828
  ...visiblePages.map((p) => ({ id: `page:${p.path}`, label: p.label, href: href(p.path), icon: p.icon, group: p.group, active: active(trim(p.path)) })),
2146
- enabled.includes("audit") && can("audit.read") && { id: "audit", label: "Audit log", href: href("audit"), icon: /* @__PURE__ */ jsx14(IconList, {}), active: active("audit"), group: "Platform" },
2147
- enabled.includes("admins") && can("admins.read") && { id: "admins", label: "Platform admins", href: href("admins"), icon: /* @__PURE__ */ jsx14(IconUsers, {}), active: active("admins"), group: "Platform" },
2148
- { id: "security", label: "Security", href: href("security"), icon: /* @__PURE__ */ jsx14(IconShield, {}), active: active("security"), group: "Platform" }
2829
+ enabled.includes("plans") && can("plans.read") && { id: "plans", label: "Plans", href: href("plans"), icon: /* @__PURE__ */ jsx17(IconTag, {}), active: active("plans") },
2830
+ enabled.includes("support") && can("support.request") && { id: "support", label: "Support access", href: href("support-access"), icon: /* @__PURE__ */ jsx17(IconLifebuoy, {}), active: active("support-access") },
2831
+ enabled.includes("audit") && can("audit.read") && { id: "audit", label: "Audit log", href: href("audit"), icon: /* @__PURE__ */ jsx17(IconList, {}), active: active("audit"), group: "Platform" },
2832
+ enabled.includes("admins") && can("admins.read") && { id: "admins", label: "Platform admins", href: href("admins"), icon: /* @__PURE__ */ jsx17(IconUsers, {}), active: active("admins"), group: "Platform" },
2833
+ { id: "security", label: "Security", href: href("security"), icon: /* @__PURE__ */ jsx17(IconShield, {}), active: active("security"), group: "Platform" }
2149
2834
  ].filter(Boolean);
2150
2835
  const value = {
2151
2836
  client,
@@ -2156,6 +2841,7 @@ function PlatformConsole({
2156
2841
  navigate,
2157
2842
  can,
2158
2843
  companyTabs,
2844
+ features: enabled,
2159
2845
  companyLoginPath,
2160
2846
  companyLoginUrl: (slug) => `${origin}${companyLoginPath(slug)}`,
2161
2847
  loginUrl: `${origin}${loginPath != null ? loginPath : `${base2}/login`}`,
@@ -2163,29 +2849,31 @@ function PlatformConsole({
2163
2849
  appName: appName != null ? appName : (_a = me == null ? void 0 : me.app) == null ? void 0 : _a.name
2164
2850
  };
2165
2851
  let body;
2166
- if (me === void 0) body = /* @__PURE__ */ jsx14("div", { className: "p-6", children: /* @__PURE__ */ jsx14(LoadingState6, { variant: "stats" }) });
2167
- else if (gate) body = /* @__PURE__ */ jsx14(SecurityView, { gate: true });
2168
- else if (route.view === "overview") body = /* @__PURE__ */ jsx14(OverviewView, {});
2169
- else if (route.view === "companies") body = /* @__PURE__ */ jsx14(CompaniesView, {});
2170
- else if (route.view === "new-company") body = /* @__PURE__ */ jsx14(NewCompanyView, {});
2171
- else if (route.view === "company") body = /* @__PURE__ */ jsx14(CompanyDetailView, { companyId: route.id }, route.id);
2172
- else if (route.view === "admins") body = /* @__PURE__ */ jsx14(AdminsView, {});
2173
- else if (route.view === "audit") body = /* @__PURE__ */ jsx14(AuditView, {});
2174
- else if (route.view === "security") body = /* @__PURE__ */ jsx14(SecurityView, {});
2852
+ if (me === void 0) body = /* @__PURE__ */ jsx17("div", { className: "p-6", children: /* @__PURE__ */ jsx17(LoadingState9, { variant: "stats" }) });
2853
+ else if (gate) body = /* @__PURE__ */ jsx17(SecurityView, { gate: true });
2854
+ else if (route.view === "overview") body = /* @__PURE__ */ jsx17(OverviewView, {});
2855
+ else if (route.view === "companies") body = /* @__PURE__ */ jsx17(CompaniesView, {});
2856
+ else if (route.view === "new-company") body = /* @__PURE__ */ jsx17(NewCompanyView, {});
2857
+ else if (route.view === "company") body = /* @__PURE__ */ jsx17(CompanyDetailView, { companyId: route.id }, route.id);
2858
+ else if (route.view === "admins") body = /* @__PURE__ */ jsx17(AdminsView, {});
2859
+ else if (route.view === "audit") body = /* @__PURE__ */ jsx17(AuditView, {});
2860
+ else if (route.view === "security") body = /* @__PURE__ */ jsx17(SecurityView, {});
2861
+ else if (route.view === "plans" && enabled.includes("plans") && can("plans.read")) body = /* @__PURE__ */ jsx17(PlansView, {});
2862
+ else if (route.view === "support" && enabled.includes("support") && can("support.request")) body = /* @__PURE__ */ jsx17(SupportAccessView, {});
2175
2863
  else if (route.view === "page") body = route.page.render({ client, path: route.rest, navigate, href, me });
2176
- else body = /* @__PURE__ */ jsx14("div", { className: "p-6", children: /* @__PURE__ */ jsx14(EmptyState4, { title: "Page not found", description: "This console page does not exist." }) });
2177
- return /* @__PURE__ */ jsx14(PlatformProvider, { value, children: /* @__PURE__ */ jsx14(StepUpProvider, { client, totpEnrolled: Boolean((_b = me == null ? void 0 : me.admin) == null ? void 0 : _b.totpEnrolled), children: /* @__PURE__ */ jsx14(PlatformShell, { brand, appName: value.appName, nav, adminEmail: (_d = (_c = me == null ? void 0 : me.admin) == null ? void 0 : _c.email) != null ? _d : adminEmail, onSignOut: signOut, linkAs: Link, pageTitle: (_e = nav.find((n) => n.active)) == null ? void 0 : _e.label, children: body }) }) });
2864
+ else body = /* @__PURE__ */ jsx17("div", { className: "p-6", children: /* @__PURE__ */ jsx17(EmptyState7, { title: "Page not found", description: "This console page does not exist." }) });
2865
+ return /* @__PURE__ */ jsx17(PlatformProvider, { value, children: /* @__PURE__ */ jsx17(StepUpProvider, { client, totpEnrolled: Boolean((_b = me == null ? void 0 : me.admin) == null ? void 0 : _b.totpEnrolled), children: /* @__PURE__ */ jsx17(PlatformShell, { brand, appName: value.appName, nav, adminEmail: (_d = (_c = me == null ? void 0 : me.admin) == null ? void 0 : _c.email) != null ? _d : adminEmail, onSignOut: signOut, linkAs: Link, pageTitle: (_e = nav.find((n) => n.active)) == null ? void 0 : _e.label, children: body }) }) });
2178
2866
  }
2179
2867
 
2180
2868
  // src/platform/PlatformLogin.jsx
2181
- import React14, { useMemo as useMemo4, useState as useState14 } from "react";
2182
- import { Alert as Alert7, Button as Button10, Input as Input8 } from "@dreamtree-org/twreact-ui";
2869
+ import React17, { useMemo as useMemo4, useState as useState17 } from "react";
2870
+ import { Alert as Alert9, Button as Button13, Input as Input11 } from "@dreamtree-org/twreact-ui";
2183
2871
 
2184
2872
  // src/AuthShell.jsx
2185
2873
  import { useId } from "react";
2186
2874
 
2187
2875
  // src/DemoAccounts.jsx
2188
- import { useEffect as useEffect7, useRef as useRef3, useState as useState12 } from "react";
2876
+ import { useEffect as useEffect8, useRef as useRef3, useState as useState15 } from "react";
2189
2877
 
2190
2878
  // src/demoFill.js
2191
2879
  function normalizeDemoAccounts(data) {
@@ -2199,12 +2887,12 @@ function normalizeDemoAccounts(data) {
2199
2887
  }
2200
2888
 
2201
2889
  // src/DemoAccounts.jsx
2202
- import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2890
+ import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2203
2891
  function DemoAccounts({ load, onSelect, className = "" }) {
2204
- const [state, setState] = useState12({ status: "loading", accounts: [] });
2205
- const [picked, setPicked] = useState12(null);
2892
+ const [state, setState] = useState15({ status: "loading", accounts: [] });
2893
+ const [picked, setPicked] = useState15(null);
2206
2894
  const loadRef = useRef3(load);
2207
- useEffect7(() => {
2895
+ useEffect8(() => {
2208
2896
  let live = true;
2209
2897
  Promise.resolve().then(() => loadRef.current()).then((data) => live && setState({ status: "ready", ...normalizeDemoAccounts(data) })).catch(() => live && setState({ status: "ready", accounts: [] }));
2210
2898
  return () => {
@@ -2216,10 +2904,10 @@ function DemoAccounts({ load, onSelect, className = "" }) {
2216
2904
  setPicked(i);
2217
2905
  onSelect == null ? void 0 : onSelect(account);
2218
2906
  };
2219
- return /* @__PURE__ */ jsxs13("div", { className: `dt-auth-demo ${className}`, "aria-busy": state.status === "loading" || void 0, children: [
2220
- /* @__PURE__ */ jsx15("p", { className: "dt-auth-demo-label", children: "Demo accounts" }),
2221
- state.status === "loading" ? /* @__PURE__ */ jsx15("div", { className: "dt-auth-demo-chips", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx15("span", { className: "dt-auth-demo-chip dt-auth-demo-chip--skeleton" }, i)) }) : /* @__PURE__ */ jsxs13(Fragment6, { children: [
2222
- /* @__PURE__ */ jsx15("div", { className: "dt-auth-demo-chips", children: state.accounts.map((a, i) => /* @__PURE__ */ jsx15(
2907
+ return /* @__PURE__ */ jsxs16("div", { className: `dt-auth-demo ${className}`, "aria-busy": state.status === "loading" || void 0, children: [
2908
+ /* @__PURE__ */ jsx18("p", { className: "dt-auth-demo-label", children: "Demo accounts" }),
2909
+ state.status === "loading" ? /* @__PURE__ */ jsx18("div", { className: "dt-auth-demo-chips", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx18("span", { className: "dt-auth-demo-chip dt-auth-demo-chip--skeleton" }, i)) }) : /* @__PURE__ */ jsxs16(Fragment6, { children: [
2910
+ /* @__PURE__ */ jsx18("div", { className: "dt-auth-demo-chips", children: state.accounts.map((a, i) => /* @__PURE__ */ jsx18(
2223
2911
  "button",
2224
2912
  {
2225
2913
  type: "button",
@@ -2231,9 +2919,9 @@ function DemoAccounts({ load, onSelect, className = "" }) {
2231
2919
  },
2232
2920
  `${a.label}-${a.identifier}`
2233
2921
  )) }),
2234
- /* @__PURE__ */ jsx15("p", { className: "dt-auth-demo-note", children: state.sharedPassword ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
2922
+ /* @__PURE__ */ jsx18("p", { className: "dt-auth-demo-note", children: state.sharedPassword ? /* @__PURE__ */ jsxs16(Fragment6, { children: [
2235
2923
  "Shared password ",
2236
- /* @__PURE__ */ jsx15("code", { children: state.sharedPassword }),
2924
+ /* @__PURE__ */ jsx18("code", { children: state.sharedPassword }),
2237
2925
  " \u2014 tap a role to fill."
2238
2926
  ] }) : "Tap a role to fill." })
2239
2927
  ] })
@@ -2241,9 +2929,9 @@ function DemoAccounts({ load, onSelect, className = "" }) {
2241
2929
  }
2242
2930
 
2243
2931
  // src/useTapReveal.js
2244
- import { useCallback as useCallback5, useRef as useRef4, useState as useState13 } from "react";
2932
+ import { useCallback as useCallback5, useRef as useRef4, useState as useState16 } from "react";
2245
2933
  function useTapReveal({ taps = 4, windowMs = 1500 } = {}) {
2246
- const [revealed, setRevealed] = useState13(false);
2934
+ const [revealed, setRevealed] = useState16(false);
2247
2935
  const count = useRef4(0);
2248
2936
  const last = useRef4(0);
2249
2937
  const onClick = useCallback5(() => {
@@ -2257,7 +2945,7 @@ function useTapReveal({ taps = 4, windowMs = 1500 } = {}) {
2257
2945
  }
2258
2946
 
2259
2947
  // src/AuthShell.jsx
2260
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2948
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
2261
2949
  var DEFAULT_LEGAL = [
2262
2950
  { label: "Privacy Policy", href: "/privacy" },
2263
2951
  { label: "Terms", href: "/terms" },
@@ -2265,10 +2953,10 @@ var DEFAULT_LEGAL = [
2265
2953
  ];
2266
2954
  function BrandMark({ brand, size }) {
2267
2955
  if (brand.logoSrc) {
2268
- return /* @__PURE__ */ jsx16("img", { className: "dt-auth-mark-img", src: brand.logoSrc, alt: "", width: size, height: size });
2956
+ return /* @__PURE__ */ jsx19("img", { className: "dt-auth-mark-img", src: brand.logoSrc, alt: "", width: size, height: size });
2269
2957
  }
2270
- if (brand.mark) return /* @__PURE__ */ jsx16("span", { className: "dt-auth-mark-node", children: brand.mark });
2271
- return /* @__PURE__ */ jsx16("span", { className: "dt-auth-monogram", style: { width: size, height: size }, "aria-hidden": "true", children: brand.name.charAt(0) });
2958
+ if (brand.mark) return /* @__PURE__ */ jsx19("span", { className: "dt-auth-mark-node", children: brand.mark });
2959
+ return /* @__PURE__ */ jsx19("span", { className: "dt-auth-monogram", style: { width: size, height: size }, "aria-hidden": "true", children: brand.name.charAt(0) });
2272
2960
  }
2273
2961
  function brandStyle(brand) {
2274
2962
  return {
@@ -2295,44 +2983,44 @@ function AuthShell({
2295
2983
  const isPlatform = variant === "platform";
2296
2984
  const headline = isPlatform ? brand.platformHeadline || "Platform administration" : brand.headline;
2297
2985
  const pitch = isPlatform ? brand.platformPitch || `Super administrator console for ${brand.name}. Every action here is audited.` : brand.pitch;
2298
- const renderLink = (l) => LinkComponent ? /* @__PURE__ */ jsx16(LinkComponent, { to: l.href, href: l.href, className: "dt-auth-legal-link", children: l.label }, l.href) : /* @__PURE__ */ jsx16("a", { href: l.href, className: "dt-auth-legal-link", children: l.label }, l.href);
2299
- return /* @__PURE__ */ jsxs14(
2986
+ const renderLink = (l) => LinkComponent ? /* @__PURE__ */ jsx19(LinkComponent, { to: l.href, href: l.href, className: "dt-auth-legal-link", children: l.label }, l.href) : /* @__PURE__ */ jsx19("a", { href: l.href, className: "dt-auth-legal-link", children: l.label }, l.href);
2987
+ return /* @__PURE__ */ jsxs17(
2300
2988
  "div",
2301
2989
  {
2302
2990
  className: `dt-auth ${isPlatform ? "dt-auth--platform" : ""} ${className}`,
2303
2991
  style: brandStyle(brand),
2304
2992
  "data-product": brand.id,
2305
2993
  children: [
2306
- /* @__PURE__ */ jsxs14("aside", { className: "dt-auth-panel", children: [
2307
- /* @__PURE__ */ jsxs14("a", { href: "/", className: "dt-auth-brand", children: [
2308
- /* @__PURE__ */ jsx16(BrandMark, { brand, size: 28 }),
2309
- /* @__PURE__ */ jsx16("span", { className: "dt-auth-brand-name", children: brand.name }),
2310
- isPlatform ? /* @__PURE__ */ jsx16("span", { className: "dt-auth-badge", children: "Platform" }) : null
2994
+ /* @__PURE__ */ jsxs17("aside", { className: "dt-auth-panel", children: [
2995
+ /* @__PURE__ */ jsxs17("a", { href: "/", className: "dt-auth-brand", children: [
2996
+ /* @__PURE__ */ jsx19(BrandMark, { brand, size: 28 }),
2997
+ /* @__PURE__ */ jsx19("span", { className: "dt-auth-brand-name", children: brand.name }),
2998
+ isPlatform ? /* @__PURE__ */ jsx19("span", { className: "dt-auth-badge", children: "Platform" }) : null
2311
2999
  ] }),
2312
- /* @__PURE__ */ jsxs14("div", { className: "dt-auth-pitch", children: [
2313
- /* @__PURE__ */ jsx16("h2", { children: headline }),
2314
- pitch ? /* @__PURE__ */ jsx16("p", { children: pitch }) : null,
2315
- !isPlatform && ((_b = brand.points) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx16("ul", { children: brand.points.map((p) => /* @__PURE__ */ jsx16("li", { children: p }, p)) }) : null
3000
+ /* @__PURE__ */ jsxs17("div", { className: "dt-auth-pitch", children: [
3001
+ /* @__PURE__ */ jsx19("h2", { children: headline }),
3002
+ pitch ? /* @__PURE__ */ jsx19("p", { children: pitch }) : null,
3003
+ !isPlatform && ((_b = brand.points) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx19("ul", { children: brand.points.map((p) => /* @__PURE__ */ jsx19("li", { children: p }, p)) }) : null
2316
3004
  ] }),
2317
- /* @__PURE__ */ jsx16("p", { className: "dt-auth-panel-foot", children: brand.category || "by Dreamtree-Org" })
3005
+ /* @__PURE__ */ jsx19("p", { className: "dt-auth-panel-foot", children: brand.category || "by Dreamtree-Org" })
2318
3006
  ] }),
2319
- /* @__PURE__ */ jsx16("main", { className: "dt-auth-main", children: /* @__PURE__ */ jsxs14("div", { className: "dt-auth-column", children: [
2320
- /* @__PURE__ */ jsxs14("a", { href: "/", className: "dt-auth-brand dt-auth-brand--mobile", children: [
2321
- /* @__PURE__ */ jsx16(BrandMark, { brand, size: 24 }),
2322
- /* @__PURE__ */ jsx16("span", { className: "dt-auth-brand-name", children: brand.name }),
2323
- isPlatform ? /* @__PURE__ */ jsx16("span", { className: "dt-auth-badge", children: "Platform" }) : null
3007
+ /* @__PURE__ */ jsx19("main", { className: "dt-auth-main", children: /* @__PURE__ */ jsxs17("div", { className: "dt-auth-column", children: [
3008
+ /* @__PURE__ */ jsxs17("a", { href: "/", className: "dt-auth-brand dt-auth-brand--mobile", children: [
3009
+ /* @__PURE__ */ jsx19(BrandMark, { brand, size: 24 }),
3010
+ /* @__PURE__ */ jsx19("span", { className: "dt-auth-brand-name", children: brand.name }),
3011
+ isPlatform ? /* @__PURE__ */ jsx19("span", { className: "dt-auth-badge", children: "Platform" }) : null
2324
3012
  ] }),
2325
- /* @__PURE__ */ jsxs14("section", { className: "dt-auth-card", "aria-labelledby": headingId, children: [
2326
- /* @__PURE__ */ jsxs14("header", { className: "dt-auth-head", children: [
2327
- /* @__PURE__ */ jsx16("h1", { id: headingId, ...demoAccounts ? tapProps : {}, children: title }),
2328
- subtitle ? /* @__PURE__ */ jsx16("p", { children: subtitle }) : null
3013
+ /* @__PURE__ */ jsxs17("section", { className: "dt-auth-card", "aria-labelledby": headingId, children: [
3014
+ /* @__PURE__ */ jsxs17("header", { className: "dt-auth-head", children: [
3015
+ /* @__PURE__ */ jsx19("h1", { id: headingId, ...demoAccounts ? tapProps : {}, children: title }),
3016
+ subtitle ? /* @__PURE__ */ jsx19("p", { children: subtitle }) : null
2329
3017
  ] }),
2330
3018
  children,
2331
- demoAccounts && revealed ? /* @__PURE__ */ jsx16(DemoAccounts, { load: demoAccounts.load, onSelect: demoAccounts.onSelect }) : null
3019
+ demoAccounts && revealed ? /* @__PURE__ */ jsx19(DemoAccounts, { load: demoAccounts.load, onSelect: demoAccounts.onSelect }) : null
2332
3020
  ] }),
2333
- footer ? /* @__PURE__ */ jsx16("div", { className: "dt-auth-footer", children: footer }) : null,
2334
- (legalLinks == null ? void 0 : legalLinks.length) ? /* @__PURE__ */ jsx16("nav", { className: "dt-auth-legal", "aria-label": "Legal", children: legalLinks.map((l, i) => /* @__PURE__ */ jsxs14("span", { className: "dt-auth-legal-item", children: [
2335
- i > 0 ? /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", children: "\xB7" }) : null,
3021
+ footer ? /* @__PURE__ */ jsx19("div", { className: "dt-auth-footer", children: footer }) : null,
3022
+ (legalLinks == null ? void 0 : legalLinks.length) ? /* @__PURE__ */ jsx19("nav", { className: "dt-auth-legal", "aria-label": "Legal", children: legalLinks.map((l, i) => /* @__PURE__ */ jsxs17("span", { className: "dt-auth-legal-item", children: [
3023
+ i > 0 ? /* @__PURE__ */ jsx19("span", { "aria-hidden": "true", children: "\xB7" }) : null,
2336
3024
  renderLink(l)
2337
3025
  ] }, l.href)) }) : null
2338
3026
  ] }) })
@@ -2342,17 +3030,17 @@ function AuthShell({
2342
3030
  }
2343
3031
 
2344
3032
  // src/platform/PlatformLogin.jsx
2345
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3033
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
2346
3034
  function PlatformLogin({ brand, basePath, client: given, onSignedIn, redirectTo = "/platform", title = "Platform administration", subtitle = "Administrator sign-in", linkComponent, legalLinks }) {
2347
3035
  const client = useMemo4(() => given != null ? given : createPlatformClient({ basePath, onUnauthorized: () => {
2348
3036
  } }), [given, basePath]);
2349
- const [step, setStep] = useState14("password");
2350
- const [email, setEmail] = useState14("");
2351
- const [password, setPassword] = useState14("");
2352
- const [ticket, setTicket] = useState14(null);
2353
- const [code, setCode] = useState14("");
2354
- const [busy, setBusy] = useState14(false);
2355
- const [error, setError] = useState14(null);
3037
+ const [step, setStep] = useState17("password");
3038
+ const [email, setEmail] = useState17("");
3039
+ const [password, setPassword] = useState17("");
3040
+ const [ticket, setTicket] = useState17(null);
3041
+ const [code, setCode] = useState17("");
3042
+ const [busy, setBusy] = useState17(false);
3043
+ const [error, setError] = useState17(null);
2356
3044
  const done = (res) => {
2357
3045
  if (onSignedIn) onSignedIn(res);
2358
3046
  else if (typeof window !== "undefined") window.location.assign(redirectTo);
@@ -2392,18 +3080,18 @@ function PlatformLogin({ brand, basePath, client: given, onSignedIn, redirectTo
2392
3080
  setBusy(false);
2393
3081
  }
2394
3082
  };
2395
- return /* @__PURE__ */ jsx17(AuthShell, { brand, variant: "platform", title, subtitle, linkComponent, legalLinks, children: step === "password" ? /* @__PURE__ */ jsxs15("form", { onSubmit: submitPassword, className: "flex flex-col gap-4", children: [
2396
- /* @__PURE__ */ jsx17(Input8, { label: "Admin email", type: "email", autoComplete: "username", autoFocus: true, value: email, onChange: (e) => setEmail(e.target.value) }),
2397
- /* @__PURE__ */ jsx17(Input8, { label: "Password", type: "password", autoComplete: "current-password", value: password, onChange: (e) => setPassword(e.target.value) }),
2398
- error && /* @__PURE__ */ jsx17(Alert7, { variant: "error", children: error }),
2399
- /* @__PURE__ */ jsx17(Button10, { type: "submit", loading: busy, disabled: !email || !password, fullWidth: true, children: "Sign in" })
2400
- ] }) : /* @__PURE__ */ jsxs15("form", { onSubmit: submitCode, className: "flex flex-col gap-4", children: [
2401
- /* @__PURE__ */ jsx17("p", { className: "text-sm", children: "Enter the 6-digit code from your authenticator app." }),
2402
- /* @__PURE__ */ jsx17(Input8, { label: "Authenticator code", otp: true, autoFocus: true, value: code, onChange: (e) => setCode(e.target.value.replace(/\s/g, "")) }),
2403
- error && /* @__PURE__ */ jsx17(Alert7, { variant: "error", children: error }),
2404
- /* @__PURE__ */ jsx17(Button10, { type: "submit", loading: busy, disabled: code.length < 6, fullWidth: true, children: "Verify" }),
2405
- /* @__PURE__ */ jsx17(
2406
- Button10,
3083
+ return /* @__PURE__ */ jsx20(AuthShell, { brand, variant: "platform", title, subtitle, linkComponent, legalLinks, children: step === "password" ? /* @__PURE__ */ jsxs18("form", { onSubmit: submitPassword, className: "flex flex-col gap-4", children: [
3084
+ /* @__PURE__ */ jsx20(Input11, { label: "Admin email", type: "email", autoComplete: "username", autoFocus: true, value: email, onChange: (e) => setEmail(e.target.value) }),
3085
+ /* @__PURE__ */ jsx20(Input11, { label: "Password", type: "password", autoComplete: "current-password", value: password, onChange: (e) => setPassword(e.target.value) }),
3086
+ error && /* @__PURE__ */ jsx20(Alert9, { variant: "error", children: error }),
3087
+ /* @__PURE__ */ jsx20(Button13, { type: "submit", loading: busy, disabled: !email || !password, fullWidth: true, children: "Sign in" })
3088
+ ] }) : /* @__PURE__ */ jsxs18("form", { onSubmit: submitCode, className: "flex flex-col gap-4", children: [
3089
+ /* @__PURE__ */ jsx20("p", { className: "text-sm", children: "Enter the 6-digit code from your authenticator app." }),
3090
+ /* @__PURE__ */ jsx20(Input11, { label: "Authenticator code", otp: true, autoFocus: true, value: code, onChange: (e) => setCode(e.target.value.replace(/\s/g, "")) }),
3091
+ error && /* @__PURE__ */ jsx20(Alert9, { variant: "error", children: error }),
3092
+ /* @__PURE__ */ jsx20(Button13, { type: "submit", loading: busy, disabled: code.length < 6, fullWidth: true, children: "Verify" }),
3093
+ /* @__PURE__ */ jsx20(
3094
+ Button13,
2407
3095
  {
2408
3096
  variant: "ghost",
2409
3097
  onClick: () => {
@@ -2419,6 +3107,7 @@ function PlatformLogin({ brand, basePath, client: given, onSignedIn, redirectTo
2419
3107
  export {
2420
3108
  Card,
2421
3109
  CopyButton,
3110
+ DomainsTab,
2422
3111
  Facts,
2423
3112
  HealthDot,
2424
3113
  InspectResult,
@@ -2427,19 +3116,26 @@ export {
2427
3116
  PLATFORM_API_BASE,
2428
3117
  PLATFORM_FEATURES,
2429
3118
  PLATFORM_LOGIN_PATH,
3119
+ PlansView,
2430
3120
  PlatformApiError,
2431
3121
  PlatformConsole,
2432
3122
  PlatformLogin,
2433
3123
  PlatformShell,
2434
3124
  SHIPPED_FEATURES,
2435
3125
  STEP_UP_REQUIRED,
3126
+ SettingsTab,
2436
3127
  StatusPill,
2437
3128
  StepUpProvider,
3129
+ SubscriptionTab,
3130
+ SupportAccessView,
3131
+ SupportGrants,
3132
+ SupportTab,
2438
3133
  createPlatformClient,
2439
3134
  createStepUp,
2440
3135
  describeAction,
2441
3136
  enabledFeatures,
2442
3137
  formatDate,
3138
+ formatPrice,
2443
3139
  isStepUpRequired,
2444
3140
  matchConsoleRoute,
2445
3141
  readPlatformCsrf,