@contractspec/example.saas-boilerplate 3.7.7 → 3.8.4

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.
Files changed (52) hide show
  1. package/.turbo/turbo-build.log +36 -24
  2. package/CHANGELOG.md +72 -0
  3. package/README.md +1 -0
  4. package/dist/browser/index.js +371 -92
  5. package/dist/browser/saas-boilerplate.feature.js +208 -0
  6. package/dist/browser/ui/SaasDashboard.js +311 -60
  7. package/dist/browser/ui/SaasDashboard.visualizations.js +249 -0
  8. package/dist/browser/ui/index.js +362 -92
  9. package/dist/browser/ui/renderers/index.js +229 -3
  10. package/dist/browser/ui/renderers/project-list.markdown.js +229 -3
  11. package/dist/browser/visualizations/catalog.js +155 -0
  12. package/dist/browser/visualizations/index.js +217 -0
  13. package/dist/browser/visualizations/selectors.js +210 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +371 -92
  16. package/dist/node/index.js +371 -92
  17. package/dist/node/saas-boilerplate.feature.js +208 -0
  18. package/dist/node/ui/SaasDashboard.js +311 -60
  19. package/dist/node/ui/SaasDashboard.visualizations.js +249 -0
  20. package/dist/node/ui/index.js +362 -92
  21. package/dist/node/ui/renderers/index.js +229 -3
  22. package/dist/node/ui/renderers/project-list.markdown.js +229 -3
  23. package/dist/node/visualizations/catalog.js +155 -0
  24. package/dist/node/visualizations/index.js +217 -0
  25. package/dist/node/visualizations/selectors.js +210 -0
  26. package/dist/saas-boilerplate.feature.js +208 -0
  27. package/dist/ui/SaasDashboard.js +311 -60
  28. package/dist/ui/SaasDashboard.visualizations.d.ts +5 -0
  29. package/dist/ui/SaasDashboard.visualizations.js +250 -0
  30. package/dist/ui/index.js +362 -92
  31. package/dist/ui/renderers/index.js +229 -3
  32. package/dist/ui/renderers/project-list.markdown.d.ts +1 -1
  33. package/dist/ui/renderers/project-list.markdown.js +229 -3
  34. package/dist/ui/renderers/project-list.renderer.d.ts +1 -1
  35. package/dist/visualizations/catalog.d.ts +11 -0
  36. package/dist/visualizations/catalog.js +156 -0
  37. package/dist/visualizations/index.d.ts +2 -0
  38. package/dist/visualizations/index.js +218 -0
  39. package/dist/visualizations/selectors.d.ts +8 -0
  40. package/dist/visualizations/selectors.js +211 -0
  41. package/dist/visualizations/selectors.test.d.ts +1 -0
  42. package/package.json +70 -13
  43. package/src/index.ts +1 -0
  44. package/src/saas-boilerplate.feature.ts +3 -0
  45. package/src/ui/SaasDashboard.tsx +8 -0
  46. package/src/ui/SaasDashboard.visualizations.tsx +41 -0
  47. package/src/ui/renderers/project-list.markdown.ts +39 -15
  48. package/src/ui/renderers/project-list.renderer.tsx +1 -1
  49. package/src/visualizations/catalog.ts +153 -0
  50. package/src/visualizations/index.ts +2 -0
  51. package/src/visualizations/selectors.test.ts +25 -0
  52. package/src/visualizations/selectors.ts +85 -0
@@ -344,6 +344,213 @@ function createSaasHandlers(db) {
344
344
  getSubscription
345
345
  };
346
346
  }
347
+ // src/visualizations/catalog.ts
348
+ import {
349
+ defineVisualization,
350
+ VisualizationRegistry
351
+ } from "@contractspec/lib.contracts-spec/visualizations";
352
+ var PROJECT_LIST_REF = {
353
+ key: "saas.project.list",
354
+ version: "1.0.0"
355
+ };
356
+ var META = {
357
+ version: "1.0.0",
358
+ domain: "saas",
359
+ stability: "experimental",
360
+ owners: ["@example.saas-boilerplate"],
361
+ tags: ["saas", "visualization", "projects"]
362
+ };
363
+ var SaasProjectUsageVisualization = defineVisualization({
364
+ meta: {
365
+ ...META,
366
+ key: "saas-boilerplate.visualization.project-usage",
367
+ title: "Project Capacity",
368
+ description: "Current project count against the current plan limit.",
369
+ goal: "Show usage against the active plan allowance.",
370
+ context: "SaaS account overview."
371
+ },
372
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
373
+ visualization: {
374
+ kind: "metric",
375
+ measure: "totalProjects",
376
+ comparisonMeasure: "projectLimit",
377
+ measures: [
378
+ {
379
+ key: "totalProjects",
380
+ label: "Projects",
381
+ dataPath: "totalProjects",
382
+ format: "number"
383
+ },
384
+ {
385
+ key: "projectLimit",
386
+ label: "Plan Limit",
387
+ dataPath: "projectLimit",
388
+ format: "number"
389
+ }
390
+ ],
391
+ table: { caption: "Current project count and plan limit." }
392
+ }
393
+ });
394
+ var SaasProjectStatusVisualization = defineVisualization({
395
+ meta: {
396
+ ...META,
397
+ key: "saas-boilerplate.visualization.project-status",
398
+ title: "Project Status",
399
+ description: "Distribution of project states.",
400
+ goal: "Show the mix of active, draft, and archived projects.",
401
+ context: "Project portfolio overview."
402
+ },
403
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
404
+ visualization: {
405
+ kind: "pie",
406
+ nameDimension: "status",
407
+ valueMeasure: "projects",
408
+ dimensions: [
409
+ { key: "status", label: "Status", dataPath: "status", type: "category" }
410
+ ],
411
+ measures: [
412
+ {
413
+ key: "projects",
414
+ label: "Projects",
415
+ dataPath: "projects",
416
+ format: "number"
417
+ }
418
+ ],
419
+ table: { caption: "Project counts by status." }
420
+ }
421
+ });
422
+ var SaasProjectTierVisualization = defineVisualization({
423
+ meta: {
424
+ ...META,
425
+ key: "saas-boilerplate.visualization.project-tiers",
426
+ title: "Tier Comparison",
427
+ description: "Distribution of projects across tiers.",
428
+ goal: "Compare how the current portfolio is distributed by tier.",
429
+ context: "Plan and packaging overview."
430
+ },
431
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
432
+ visualization: {
433
+ kind: "cartesian",
434
+ variant: "bar",
435
+ xDimension: "tier",
436
+ yMeasures: ["projects"],
437
+ dimensions: [
438
+ { key: "tier", label: "Tier", dataPath: "tier", type: "category" }
439
+ ],
440
+ measures: [
441
+ {
442
+ key: "projects",
443
+ label: "Projects",
444
+ dataPath: "projects",
445
+ format: "number",
446
+ color: "#1d4ed8"
447
+ }
448
+ ],
449
+ table: { caption: "Project counts by tier." }
450
+ }
451
+ });
452
+ var SaasProjectActivityVisualization = defineVisualization({
453
+ meta: {
454
+ ...META,
455
+ key: "saas-boilerplate.visualization.project-activity",
456
+ title: "Recent Project Activity",
457
+ description: "Daily project creation activity.",
458
+ goal: "Show recent project activity over time.",
459
+ context: "Project portfolio trend view."
460
+ },
461
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
462
+ visualization: {
463
+ kind: "cartesian",
464
+ variant: "line",
465
+ xDimension: "day",
466
+ yMeasures: ["projects"],
467
+ dimensions: [{ key: "day", label: "Day", dataPath: "day", type: "time" }],
468
+ measures: [
469
+ {
470
+ key: "projects",
471
+ label: "Projects",
472
+ dataPath: "projects",
473
+ format: "number",
474
+ color: "#0f766e"
475
+ }
476
+ ],
477
+ table: { caption: "Daily project creation counts." }
478
+ }
479
+ });
480
+ var SaasVisualizationSpecs = [
481
+ SaasProjectUsageVisualization,
482
+ SaasProjectStatusVisualization,
483
+ SaasProjectTierVisualization,
484
+ SaasProjectActivityVisualization
485
+ ];
486
+ var SaasVisualizationRegistry = new VisualizationRegistry([
487
+ ...SaasVisualizationSpecs
488
+ ]);
489
+ var SaasVisualizationRefs = SaasVisualizationSpecs.map((spec) => ({
490
+ key: spec.meta.key,
491
+ version: spec.meta.version
492
+ }));
493
+
494
+ // src/visualizations/selectors.ts
495
+ function toDayKey(value) {
496
+ const date = value instanceof Date ? value : new Date(value);
497
+ return date.toISOString().slice(0, 10);
498
+ }
499
+ function createSaasVisualizationItems(projects, projectLimit = 10) {
500
+ const statusCounts = new Map;
501
+ const tierCounts = new Map;
502
+ const activityCounts = new Map;
503
+ for (const project of projects) {
504
+ statusCounts.set(project.status, (statusCounts.get(project.status) ?? 0) + 1);
505
+ tierCounts.set(project.tier, (tierCounts.get(project.tier) ?? 0) + 1);
506
+ const day = toDayKey(project.createdAt);
507
+ activityCounts.set(day, (activityCounts.get(day) ?? 0) + 1);
508
+ }
509
+ return [
510
+ {
511
+ key: "saas-capacity",
512
+ spec: SaasProjectUsageVisualization,
513
+ data: { data: [{ totalProjects: projects.length, projectLimit }] },
514
+ title: "Project Capacity",
515
+ description: "Current project count compared to the active limit.",
516
+ height: 220
517
+ },
518
+ {
519
+ key: "saas-status",
520
+ spec: SaasProjectStatusVisualization,
521
+ data: {
522
+ data: Array.from(statusCounts.entries()).map(([status, count]) => ({
523
+ status,
524
+ projects: count
525
+ }))
526
+ },
527
+ title: "Project Status",
528
+ description: "Status mix across the current project portfolio.",
529
+ height: 260
530
+ },
531
+ {
532
+ key: "saas-tier",
533
+ spec: SaasProjectTierVisualization,
534
+ data: {
535
+ data: Array.from(tierCounts.entries()).map(([tier, count]) => ({
536
+ tier,
537
+ projects: count
538
+ }))
539
+ },
540
+ title: "Tier Comparison",
541
+ description: "How projects are distributed across tiers."
542
+ },
543
+ {
544
+ key: "saas-activity",
545
+ spec: SaasProjectActivityVisualization,
546
+ data: {
547
+ data: Array.from(activityCounts.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([day, count]) => ({ day, projects: count }))
548
+ },
549
+ title: "Recent Project Activity",
550
+ description: "Daily project creation activity."
551
+ }
552
+ ];
553
+ }
347
554
  // src/ui/hooks/useProjectList.ts
348
555
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
349
556
  import { useCallback, useEffect, useMemo, useState } from "react";
@@ -1040,6 +1247,18 @@ var saasOverlays = [
1040
1247
  saasDemoOverlay
1041
1248
  ];
1042
1249
  // src/ui/renderers/project-list.markdown.ts
1250
+ var PROJECT_TIERS = [
1251
+ "FREE",
1252
+ "PRO",
1253
+ "ENTERPRISE"
1254
+ ];
1255
+ function toVisualizationProject(project, index) {
1256
+ return {
1257
+ status: project.status === "DELETED" ? "ARCHIVED" : project.status,
1258
+ tier: PROJECT_TIERS[index % PROJECT_TIERS.length] ?? "FREE",
1259
+ createdAt: project.createdAt
1260
+ };
1261
+ }
1043
1262
  var projectListMarkdownRenderer = {
1044
1263
  target: "markdown",
1045
1264
  render: async (desc, _ctx) => {
@@ -1050,7 +1269,7 @@ var projectListMarkdownRenderer = {
1050
1269
  limit: 20,
1051
1270
  offset: 0
1052
1271
  });
1053
- const items = data.projects ?? data.items ?? [];
1272
+ const items = data.projects ?? [];
1054
1273
  const lines = [
1055
1274
  "# Projects",
1056
1275
  "",
@@ -1087,6 +1306,7 @@ var saasDashboardMarkdownRenderer = {
1087
1306
  const projects = projectsData.projects ?? [];
1088
1307
  const activeProjects = projects.filter((p) => p.status === "ACTIVE").length;
1089
1308
  const archivedProjects = projects.filter((p) => p.status === "ARCHIVED").length;
1309
+ const visualizations = createSaasVisualizationItems(projects.map(toVisualizationProject), 10);
1090
1310
  const lines = [
1091
1311
  "# SaaS Dashboard",
1092
1312
  "",
@@ -1101,10 +1321,16 @@ var saasDashboardMarkdownRenderer = {
1101
1321
  `| Archived Projects | ${archivedProjects} |`,
1102
1322
  `| Subscription Plan | ${subscription.planName} |`,
1103
1323
  `| Subscription Status | ${subscription.status} |`,
1104
- "",
1105
- "## Projects",
1106
1324
  ""
1107
1325
  ];
1326
+ lines.push("## Visualization Overview");
1327
+ lines.push("");
1328
+ for (const item of visualizations) {
1329
+ lines.push(`- **${item.title}** via \`${item.spec.meta.key}\``);
1330
+ }
1331
+ lines.push("");
1332
+ lines.push("## Projects");
1333
+ lines.push("");
1108
1334
  if (projects.length === 0) {
1109
1335
  lines.push("_No projects yet._");
1110
1336
  } else {
@@ -1298,6 +1524,46 @@ var projectListReactRenderer = {
1298
1524
  return /* @__PURE__ */ jsxDEV4(SaasProjectList, {}, undefined, false, undefined, this);
1299
1525
  }
1300
1526
  };
1527
+ // src/ui/SaasDashboard.visualizations.tsx
1528
+ import {
1529
+ VisualizationCard,
1530
+ VisualizationGrid
1531
+ } from "@contractspec/lib.design-system";
1532
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1533
+ "use client";
1534
+ function SaasVisualizationOverview({
1535
+ projects,
1536
+ projectLimit
1537
+ }) {
1538
+ const items = createSaasVisualizationItems(projects, projectLimit);
1539
+ return /* @__PURE__ */ jsxDEV5("section", {
1540
+ className: "space-y-3",
1541
+ children: [
1542
+ /* @__PURE__ */ jsxDEV5("div", {
1543
+ children: [
1544
+ /* @__PURE__ */ jsxDEV5("h3", {
1545
+ className: "font-semibold text-lg",
1546
+ children: "Portfolio Visualizations"
1547
+ }, undefined, false, undefined, this),
1548
+ /* @__PURE__ */ jsxDEV5("p", {
1549
+ className: "text-muted-foreground text-sm",
1550
+ children: "Contract-backed charts for project mix, capacity, and activity."
1551
+ }, undefined, false, undefined, this)
1552
+ ]
1553
+ }, undefined, true, undefined, this),
1554
+ /* @__PURE__ */ jsxDEV5(VisualizationGrid, {
1555
+ children: items.map((item) => /* @__PURE__ */ jsxDEV5(VisualizationCard, {
1556
+ data: item.data,
1557
+ description: item.description,
1558
+ height: item.height,
1559
+ spec: item.spec,
1560
+ title: item.title
1561
+ }, item.key, false, undefined, this))
1562
+ }, undefined, false, undefined, this)
1563
+ ]
1564
+ }, undefined, true, undefined, this);
1565
+ }
1566
+
1301
1567
  // src/ui/SaasDashboard.tsx
1302
1568
  import {
1303
1569
  Button as Button4,
@@ -1310,7 +1576,7 @@ import {
1310
1576
  StatusChip as StatusChip2
1311
1577
  } from "@contractspec/lib.design-system";
1312
1578
  import { useCallback as useCallback3, useState as useState5 } from "react";
1313
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1579
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1314
1580
  "use client";
1315
1581
  function getStatusTone2(status) {
1316
1582
  switch (status) {
@@ -1345,32 +1611,32 @@ function SaasDashboard() {
1345
1611
  { id: "settings", label: "Settings", icon: "⚙️" }
1346
1612
  ];
1347
1613
  if (loading && !data) {
1348
- return /* @__PURE__ */ jsxDEV5(LoaderBlock2, {
1614
+ return /* @__PURE__ */ jsxDEV6(LoaderBlock2, {
1349
1615
  label: "Loading dashboard..."
1350
1616
  }, undefined, false, undefined, this);
1351
1617
  }
1352
1618
  if (error) {
1353
- return /* @__PURE__ */ jsxDEV5(ErrorState2, {
1619
+ return /* @__PURE__ */ jsxDEV6(ErrorState2, {
1354
1620
  title: "Failed to load dashboard",
1355
1621
  description: error.message,
1356
1622
  onRetry: refetch,
1357
1623
  retryLabel: "Retry"
1358
1624
  }, undefined, false, undefined, this);
1359
1625
  }
1360
- return /* @__PURE__ */ jsxDEV5("div", {
1626
+ return /* @__PURE__ */ jsxDEV6("div", {
1361
1627
  className: "space-y-6",
1362
1628
  children: [
1363
- /* @__PURE__ */ jsxDEV5("div", {
1629
+ /* @__PURE__ */ jsxDEV6("div", {
1364
1630
  className: "flex items-center justify-between",
1365
1631
  children: [
1366
- /* @__PURE__ */ jsxDEV5("h2", {
1632
+ /* @__PURE__ */ jsxDEV6("h2", {
1367
1633
  className: "font-bold text-2xl",
1368
1634
  children: "SaaS Dashboard"
1369
1635
  }, undefined, false, undefined, this),
1370
- activeTab === "projects" && /* @__PURE__ */ jsxDEV5(Button4, {
1636
+ activeTab === "projects" && /* @__PURE__ */ jsxDEV6(Button4, {
1371
1637
  onPress: () => setIsCreateModalOpen(true),
1372
1638
  children: [
1373
- /* @__PURE__ */ jsxDEV5("span", {
1639
+ /* @__PURE__ */ jsxDEV6("span", {
1374
1640
  className: "mr-2",
1375
1641
  children: "+"
1376
1642
  }, undefined, false, undefined, this),
@@ -1379,59 +1645,63 @@ function SaasDashboard() {
1379
1645
  }, undefined, true, undefined, this)
1380
1646
  ]
1381
1647
  }, undefined, true, undefined, this),
1382
- stats && subscription && /* @__PURE__ */ jsxDEV5(StatCardGroup2, {
1648
+ stats && subscription && /* @__PURE__ */ jsxDEV6(StatCardGroup2, {
1383
1649
  children: [
1384
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1650
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1385
1651
  label: "Projects",
1386
1652
  value: stats.total.toString()
1387
1653
  }, undefined, false, undefined, this),
1388
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1654
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1389
1655
  label: "Active",
1390
1656
  value: stats.activeCount.toString()
1391
1657
  }, undefined, false, undefined, this),
1392
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1658
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1393
1659
  label: "Draft",
1394
1660
  value: stats.draftCount.toString()
1395
1661
  }, undefined, false, undefined, this),
1396
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1662
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1397
1663
  label: "Plan",
1398
1664
  value: subscription.plan,
1399
1665
  hint: subscription.status
1400
1666
  }, undefined, false, undefined, this)
1401
1667
  ]
1402
1668
  }, undefined, true, undefined, this),
1403
- /* @__PURE__ */ jsxDEV5("nav", {
1669
+ data && stats && /* @__PURE__ */ jsxDEV6(SaasVisualizationOverview, {
1670
+ projectLimit: stats.projectLimit,
1671
+ projects: data.items
1672
+ }, undefined, false, undefined, this),
1673
+ /* @__PURE__ */ jsxDEV6("nav", {
1404
1674
  className: "flex gap-1 rounded-lg bg-muted p-1",
1405
1675
  role: "tablist",
1406
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV5("button", {
1676
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV6("button", {
1407
1677
  type: "button",
1408
1678
  role: "tab",
1409
1679
  "aria-selected": activeTab === tab.id,
1410
1680
  onClick: () => setActiveTab(tab.id),
1411
1681
  className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1412
1682
  children: [
1413
- /* @__PURE__ */ jsxDEV5("span", {
1683
+ /* @__PURE__ */ jsxDEV6("span", {
1414
1684
  children: tab.icon
1415
1685
  }, undefined, false, undefined, this),
1416
1686
  tab.label
1417
1687
  ]
1418
1688
  }, tab.id, true, undefined, this))
1419
1689
  }, undefined, false, undefined, this),
1420
- /* @__PURE__ */ jsxDEV5("div", {
1690
+ /* @__PURE__ */ jsxDEV6("div", {
1421
1691
  className: "min-h-[400px]",
1422
1692
  role: "tabpanel",
1423
1693
  children: [
1424
- activeTab === "projects" && /* @__PURE__ */ jsxDEV5(ProjectsTab, {
1694
+ activeTab === "projects" && /* @__PURE__ */ jsxDEV6(ProjectsTab, {
1425
1695
  data,
1426
1696
  onProjectClick: handleProjectClick
1427
1697
  }, undefined, false, undefined, this),
1428
- activeTab === "billing" && /* @__PURE__ */ jsxDEV5(BillingTab, {
1698
+ activeTab === "billing" && /* @__PURE__ */ jsxDEV6(BillingTab, {
1429
1699
  subscription
1430
1700
  }, undefined, false, undefined, this),
1431
- activeTab === "settings" && /* @__PURE__ */ jsxDEV5(SettingsTab, {}, undefined, false, undefined, this)
1701
+ activeTab === "settings" && /* @__PURE__ */ jsxDEV6(SettingsTab, {}, undefined, false, undefined, this)
1432
1702
  ]
1433
1703
  }, undefined, true, undefined, this),
1434
- /* @__PURE__ */ jsxDEV5(CreateProjectModal, {
1704
+ /* @__PURE__ */ jsxDEV6(CreateProjectModal, {
1435
1705
  isOpen: isCreateModalOpen,
1436
1706
  onClose: () => setIsCreateModalOpen(false),
1437
1707
  onSubmit: async (input) => {
@@ -1439,7 +1709,7 @@ function SaasDashboard() {
1439
1709
  },
1440
1710
  isLoading: mutations.createState.loading
1441
1711
  }, undefined, false, undefined, this),
1442
- /* @__PURE__ */ jsxDEV5(ProjectActionsModal, {
1712
+ /* @__PURE__ */ jsxDEV6(ProjectActionsModal, {
1443
1713
  isOpen: isProjectActionsOpen,
1444
1714
  project: selectedProject,
1445
1715
  onClose: () => {
@@ -1465,34 +1735,34 @@ function SaasDashboard() {
1465
1735
  }
1466
1736
  function ProjectsTab({ data, onProjectClick }) {
1467
1737
  if (!data?.items.length) {
1468
- return /* @__PURE__ */ jsxDEV5(EmptyState2, {
1738
+ return /* @__PURE__ */ jsxDEV6(EmptyState2, {
1469
1739
  title: "No projects yet",
1470
1740
  description: "Create your first project to get started."
1471
1741
  }, undefined, false, undefined, this);
1472
1742
  }
1473
- return /* @__PURE__ */ jsxDEV5("div", {
1743
+ return /* @__PURE__ */ jsxDEV6("div", {
1474
1744
  className: "space-y-4",
1475
- children: /* @__PURE__ */ jsxDEV5("div", {
1745
+ children: /* @__PURE__ */ jsxDEV6("div", {
1476
1746
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
1477
- children: data.items.map((project) => /* @__PURE__ */ jsxDEV5(EntityCard2, {
1747
+ children: data.items.map((project) => /* @__PURE__ */ jsxDEV6(EntityCard2, {
1478
1748
  cardTitle: project.name,
1479
1749
  cardSubtitle: project.tier,
1480
- meta: /* @__PURE__ */ jsxDEV5("p", {
1750
+ meta: /* @__PURE__ */ jsxDEV6("p", {
1481
1751
  className: "text-muted-foreground text-sm",
1482
1752
  children: project.description
1483
1753
  }, undefined, false, undefined, this),
1484
- chips: /* @__PURE__ */ jsxDEV5(StatusChip2, {
1754
+ chips: /* @__PURE__ */ jsxDEV6(StatusChip2, {
1485
1755
  tone: getStatusTone2(project.status),
1486
1756
  label: project.status
1487
1757
  }, undefined, false, undefined, this),
1488
- footer: /* @__PURE__ */ jsxDEV5("div", {
1758
+ footer: /* @__PURE__ */ jsxDEV6("div", {
1489
1759
  className: "flex w-full items-center justify-between",
1490
1760
  children: [
1491
- /* @__PURE__ */ jsxDEV5("span", {
1761
+ /* @__PURE__ */ jsxDEV6("span", {
1492
1762
  className: "text-muted-foreground text-xs",
1493
1763
  children: project.updatedAt.toLocaleDateString()
1494
1764
  }, undefined, false, undefined, this),
1495
- /* @__PURE__ */ jsxDEV5(Button4, {
1765
+ /* @__PURE__ */ jsxDEV6(Button4, {
1496
1766
  variant: "ghost",
1497
1767
  size: "sm",
1498
1768
  onPress: () => onProjectClick?.(project),
@@ -1507,25 +1777,25 @@ function ProjectsTab({ data, onProjectClick }) {
1507
1777
  function BillingTab({ subscription }) {
1508
1778
  if (!subscription)
1509
1779
  return null;
1510
- return /* @__PURE__ */ jsxDEV5("div", {
1780
+ return /* @__PURE__ */ jsxDEV6("div", {
1511
1781
  className: "space-y-6",
1512
1782
  children: [
1513
- /* @__PURE__ */ jsxDEV5("div", {
1783
+ /* @__PURE__ */ jsxDEV6("div", {
1514
1784
  className: "rounded-xl border border-border bg-card p-6",
1515
1785
  children: [
1516
- /* @__PURE__ */ jsxDEV5("div", {
1786
+ /* @__PURE__ */ jsxDEV6("div", {
1517
1787
  className: "flex items-start justify-between",
1518
1788
  children: [
1519
- /* @__PURE__ */ jsxDEV5("div", {
1789
+ /* @__PURE__ */ jsxDEV6("div", {
1520
1790
  children: [
1521
- /* @__PURE__ */ jsxDEV5("h3", {
1791
+ /* @__PURE__ */ jsxDEV6("h3", {
1522
1792
  className: "font-semibold text-lg",
1523
1793
  children: [
1524
1794
  subscription.plan,
1525
1795
  " Plan"
1526
1796
  ]
1527
1797
  }, undefined, true, undefined, this),
1528
- /* @__PURE__ */ jsxDEV5("p", {
1798
+ /* @__PURE__ */ jsxDEV6("p", {
1529
1799
  className: "text-muted-foreground text-sm",
1530
1800
  children: [
1531
1801
  "Current period:",
@@ -1536,7 +1806,7 @@ function BillingTab({ subscription }) {
1536
1806
  subscription.currentPeriodEnd.toLocaleDateString()
1537
1807
  ]
1538
1808
  }, undefined, true, undefined, this),
1539
- /* @__PURE__ */ jsxDEV5("p", {
1809
+ /* @__PURE__ */ jsxDEV6("p", {
1540
1810
  className: "text-muted-foreground text-sm",
1541
1811
  children: [
1542
1812
  "Billing cycle: ",
@@ -1545,21 +1815,21 @@ function BillingTab({ subscription }) {
1545
1815
  }, undefined, true, undefined, this)
1546
1816
  ]
1547
1817
  }, undefined, true, undefined, this),
1548
- /* @__PURE__ */ jsxDEV5(StatusChip2, {
1818
+ /* @__PURE__ */ jsxDEV6(StatusChip2, {
1549
1819
  tone: "success",
1550
1820
  label: subscription.status
1551
1821
  }, undefined, false, undefined, this)
1552
1822
  ]
1553
1823
  }, undefined, true, undefined, this),
1554
- /* @__PURE__ */ jsxDEV5("div", {
1824
+ /* @__PURE__ */ jsxDEV6("div", {
1555
1825
  className: "mt-4 flex gap-3",
1556
1826
  children: [
1557
- /* @__PURE__ */ jsxDEV5(Button4, {
1827
+ /* @__PURE__ */ jsxDEV6(Button4, {
1558
1828
  variant: "outline",
1559
1829
  onPress: () => alert("Upgrade clicked!"),
1560
1830
  children: "Upgrade Plan"
1561
1831
  }, undefined, false, undefined, this),
1562
- /* @__PURE__ */ jsxDEV5(Button4, {
1832
+ /* @__PURE__ */ jsxDEV6(Button4, {
1563
1833
  variant: "ghost",
1564
1834
  onPress: () => alert("Manage Billing clicked!"),
1565
1835
  children: "Manage Billing"
@@ -1568,9 +1838,9 @@ function BillingTab({ subscription }) {
1568
1838
  }, undefined, true, undefined, this)
1569
1839
  ]
1570
1840
  }, undefined, true, undefined, this),
1571
- subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV5("div", {
1841
+ subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV6("div", {
1572
1842
  className: "rounded-xl border border-border bg-destructive/10 p-4 text-destructive",
1573
- children: /* @__PURE__ */ jsxDEV5("p", {
1843
+ children: /* @__PURE__ */ jsxDEV6("p", {
1574
1844
  className: "font-medium text-sm",
1575
1845
  children: "⚠️ Your subscription will be cancelled at the end of the current period."
1576
1846
  }, undefined, false, undefined, this)
@@ -1579,26 +1849,26 @@ function BillingTab({ subscription }) {
1579
1849
  }, undefined, true, undefined, this);
1580
1850
  }
1581
1851
  function SettingsTab() {
1582
- return /* @__PURE__ */ jsxDEV5("div", {
1852
+ return /* @__PURE__ */ jsxDEV6("div", {
1583
1853
  className: "space-y-6",
1584
- children: /* @__PURE__ */ jsxDEV5("div", {
1854
+ children: /* @__PURE__ */ jsxDEV6("div", {
1585
1855
  className: "rounded-xl border border-border bg-card p-6",
1586
1856
  children: [
1587
- /* @__PURE__ */ jsxDEV5("h3", {
1857
+ /* @__PURE__ */ jsxDEV6("h3", {
1588
1858
  className: "mb-4 font-semibold text-lg",
1589
1859
  children: "Organization Settings"
1590
1860
  }, undefined, false, undefined, this),
1591
- /* @__PURE__ */ jsxDEV5("div", {
1861
+ /* @__PURE__ */ jsxDEV6("div", {
1592
1862
  className: "space-y-4",
1593
1863
  children: [
1594
- /* @__PURE__ */ jsxDEV5("div", {
1864
+ /* @__PURE__ */ jsxDEV6("div", {
1595
1865
  children: [
1596
- /* @__PURE__ */ jsxDEV5("label", {
1866
+ /* @__PURE__ */ jsxDEV6("label", {
1597
1867
  htmlFor: "org-name",
1598
1868
  className: "font-medium text-sm",
1599
1869
  children: "Organization Name"
1600
1870
  }, undefined, false, undefined, this),
1601
- /* @__PURE__ */ jsxDEV5("input", {
1871
+ /* @__PURE__ */ jsxDEV6("input", {
1602
1872
  id: "org-name",
1603
1873
  type: "text",
1604
1874
  defaultValue: "Demo Organization",
@@ -1606,36 +1876,36 @@ function SettingsTab() {
1606
1876
  }, undefined, false, undefined, this)
1607
1877
  ]
1608
1878
  }, undefined, true, undefined, this),
1609
- /* @__PURE__ */ jsxDEV5("div", {
1879
+ /* @__PURE__ */ jsxDEV6("div", {
1610
1880
  children: [
1611
- /* @__PURE__ */ jsxDEV5("label", {
1881
+ /* @__PURE__ */ jsxDEV6("label", {
1612
1882
  htmlFor: "timezone",
1613
1883
  className: "font-medium text-sm",
1614
1884
  children: "Default Timezone"
1615
1885
  }, undefined, false, undefined, this),
1616
- /* @__PURE__ */ jsxDEV5("select", {
1886
+ /* @__PURE__ */ jsxDEV6("select", {
1617
1887
  id: "timezone",
1618
1888
  className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
1619
1889
  children: [
1620
- /* @__PURE__ */ jsxDEV5("option", {
1890
+ /* @__PURE__ */ jsxDEV6("option", {
1621
1891
  children: "UTC"
1622
1892
  }, undefined, false, undefined, this),
1623
- /* @__PURE__ */ jsxDEV5("option", {
1893
+ /* @__PURE__ */ jsxDEV6("option", {
1624
1894
  children: "America/New_York"
1625
1895
  }, undefined, false, undefined, this),
1626
- /* @__PURE__ */ jsxDEV5("option", {
1896
+ /* @__PURE__ */ jsxDEV6("option", {
1627
1897
  children: "Europe/London"
1628
1898
  }, undefined, false, undefined, this),
1629
- /* @__PURE__ */ jsxDEV5("option", {
1899
+ /* @__PURE__ */ jsxDEV6("option", {
1630
1900
  children: "Asia/Tokyo"
1631
1901
  }, undefined, false, undefined, this)
1632
1902
  ]
1633
1903
  }, undefined, true, undefined, this)
1634
1904
  ]
1635
1905
  }, undefined, true, undefined, this),
1636
- /* @__PURE__ */ jsxDEV5("div", {
1906
+ /* @__PURE__ */ jsxDEV6("div", {
1637
1907
  className: "pt-2",
1638
- children: /* @__PURE__ */ jsxDEV5(Button4, {
1908
+ children: /* @__PURE__ */ jsxDEV6(Button4, {
1639
1909
  onPress: () => alert("Settings saved!"),
1640
1910
  children: "Save Settings"
1641
1911
  }, undefined, false, undefined, this)
@@ -1650,32 +1920,32 @@ function SettingsTab() {
1650
1920
  // src/ui/SaasSettingsPanel.tsx
1651
1921
  import { Button as Button5 } from "@contractspec/lib.design-system";
1652
1922
  import { useState as useState6 } from "react";
1653
- import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1923
+ import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
1654
1924
  "use client";
1655
1925
  function SaasSettingsPanel() {
1656
1926
  const [orgName, setOrgName] = useState6("Demo Organization");
1657
1927
  const [timezone, setTimezone] = useState6("UTC");
1658
- return /* @__PURE__ */ jsxDEV6("div", {
1928
+ return /* @__PURE__ */ jsxDEV7("div", {
1659
1929
  className: "space-y-6",
1660
1930
  children: [
1661
- /* @__PURE__ */ jsxDEV6("div", {
1931
+ /* @__PURE__ */ jsxDEV7("div", {
1662
1932
  className: "rounded-xl border border-border bg-card p-6",
1663
1933
  children: [
1664
- /* @__PURE__ */ jsxDEV6("h3", {
1934
+ /* @__PURE__ */ jsxDEV7("h3", {
1665
1935
  className: "mb-4 font-semibold text-lg",
1666
1936
  children: "Organization Settings"
1667
1937
  }, undefined, false, undefined, this),
1668
- /* @__PURE__ */ jsxDEV6("div", {
1938
+ /* @__PURE__ */ jsxDEV7("div", {
1669
1939
  className: "space-y-4",
1670
1940
  children: [
1671
- /* @__PURE__ */ jsxDEV6("div", {
1941
+ /* @__PURE__ */ jsxDEV7("div", {
1672
1942
  children: [
1673
- /* @__PURE__ */ jsxDEV6("label", {
1943
+ /* @__PURE__ */ jsxDEV7("label", {
1674
1944
  htmlFor: "setting-org-name",
1675
1945
  className: "block font-medium text-sm",
1676
1946
  children: "Organization Name"
1677
1947
  }, undefined, false, undefined, this),
1678
- /* @__PURE__ */ jsxDEV6("input", {
1948
+ /* @__PURE__ */ jsxDEV7("input", {
1679
1949
  id: "setting-org-name",
1680
1950
  type: "text",
1681
1951
  value: orgName,
@@ -1684,32 +1954,32 @@ function SaasSettingsPanel() {
1684
1954
  }, undefined, false, undefined, this)
1685
1955
  ]
1686
1956
  }, undefined, true, undefined, this),
1687
- /* @__PURE__ */ jsxDEV6("div", {
1957
+ /* @__PURE__ */ jsxDEV7("div", {
1688
1958
  children: [
1689
- /* @__PURE__ */ jsxDEV6("label", {
1959
+ /* @__PURE__ */ jsxDEV7("label", {
1690
1960
  htmlFor: "setting-timezone",
1691
1961
  className: "block font-medium text-sm",
1692
1962
  children: "Default Timezone"
1693
1963
  }, undefined, false, undefined, this),
1694
- /* @__PURE__ */ jsxDEV6("select", {
1964
+ /* @__PURE__ */ jsxDEV7("select", {
1695
1965
  id: "setting-timezone",
1696
1966
  value: timezone,
1697
1967
  onChange: (e) => setTimezone(e.target.value),
1698
1968
  className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
1699
1969
  children: [
1700
- /* @__PURE__ */ jsxDEV6("option", {
1970
+ /* @__PURE__ */ jsxDEV7("option", {
1701
1971
  value: "UTC",
1702
1972
  children: "UTC"
1703
1973
  }, undefined, false, undefined, this),
1704
- /* @__PURE__ */ jsxDEV6("option", {
1974
+ /* @__PURE__ */ jsxDEV7("option", {
1705
1975
  value: "America/New_York",
1706
1976
  children: "America/New_York"
1707
1977
  }, undefined, false, undefined, this),
1708
- /* @__PURE__ */ jsxDEV6("option", {
1978
+ /* @__PURE__ */ jsxDEV7("option", {
1709
1979
  value: "Europe/London",
1710
1980
  children: "Europe/London"
1711
1981
  }, undefined, false, undefined, this),
1712
- /* @__PURE__ */ jsxDEV6("option", {
1982
+ /* @__PURE__ */ jsxDEV7("option", {
1713
1983
  value: "Asia/Tokyo",
1714
1984
  children: "Asia/Tokyo"
1715
1985
  }, undefined, false, undefined, this)
@@ -1719,37 +1989,37 @@ function SaasSettingsPanel() {
1719
1989
  }, undefined, true, undefined, this)
1720
1990
  ]
1721
1991
  }, undefined, true, undefined, this),
1722
- /* @__PURE__ */ jsxDEV6("div", {
1992
+ /* @__PURE__ */ jsxDEV7("div", {
1723
1993
  className: "mt-6",
1724
- children: /* @__PURE__ */ jsxDEV6(Button5, {
1994
+ children: /* @__PURE__ */ jsxDEV7(Button5, {
1725
1995
  variant: "default",
1726
1996
  children: "Save Changes"
1727
1997
  }, undefined, false, undefined, this)
1728
1998
  }, undefined, false, undefined, this)
1729
1999
  ]
1730
2000
  }, undefined, true, undefined, this),
1731
- /* @__PURE__ */ jsxDEV6("div", {
2001
+ /* @__PURE__ */ jsxDEV7("div", {
1732
2002
  className: "rounded-xl border border-border bg-card p-6",
1733
2003
  children: [
1734
- /* @__PURE__ */ jsxDEV6("h3", {
2004
+ /* @__PURE__ */ jsxDEV7("h3", {
1735
2005
  className: "mb-4 font-semibold text-lg",
1736
2006
  children: "Notifications"
1737
2007
  }, undefined, false, undefined, this),
1738
- /* @__PURE__ */ jsxDEV6("div", {
2008
+ /* @__PURE__ */ jsxDEV7("div", {
1739
2009
  className: "space-y-3",
1740
2010
  children: [
1741
2011
  { label: "Email notifications", defaultChecked: true },
1742
2012
  { label: "Usage alerts", defaultChecked: true },
1743
2013
  { label: "Weekly digest", defaultChecked: false }
1744
- ].map((item) => /* @__PURE__ */ jsxDEV6("label", {
2014
+ ].map((item) => /* @__PURE__ */ jsxDEV7("label", {
1745
2015
  className: "flex items-center gap-3",
1746
2016
  children: [
1747
- /* @__PURE__ */ jsxDEV6("input", {
2017
+ /* @__PURE__ */ jsxDEV7("input", {
1748
2018
  type: "checkbox",
1749
2019
  defaultChecked: item.defaultChecked,
1750
2020
  className: "h-4 w-4 rounded border-input"
1751
2021
  }, undefined, false, undefined, this),
1752
- /* @__PURE__ */ jsxDEV6("span", {
2022
+ /* @__PURE__ */ jsxDEV7("span", {
1753
2023
  className: "text-sm",
1754
2024
  children: item.label
1755
2025
  }, undefined, false, undefined, this)
@@ -1758,26 +2028,26 @@ function SaasSettingsPanel() {
1758
2028
  }, undefined, false, undefined, this)
1759
2029
  ]
1760
2030
  }, undefined, true, undefined, this),
1761
- /* @__PURE__ */ jsxDEV6("div", {
2031
+ /* @__PURE__ */ jsxDEV7("div", {
1762
2032
  className: "rounded-xl border border-red-200 bg-red-50 p-6 dark:border-red-900 dark:bg-red-950/20",
1763
2033
  children: [
1764
- /* @__PURE__ */ jsxDEV6("h3", {
2034
+ /* @__PURE__ */ jsxDEV7("h3", {
1765
2035
  className: "mb-2 font-semibold text-lg text-red-700 dark:text-red-400",
1766
2036
  children: "Danger Zone"
1767
2037
  }, undefined, false, undefined, this),
1768
- /* @__PURE__ */ jsxDEV6("p", {
2038
+ /* @__PURE__ */ jsxDEV7("p", {
1769
2039
  className: "mb-4 text-red-600 text-sm dark:text-red-300",
1770
2040
  children: "These actions are irreversible. Please proceed with caution."
1771
2041
  }, undefined, false, undefined, this),
1772
- /* @__PURE__ */ jsxDEV6("div", {
2042
+ /* @__PURE__ */ jsxDEV7("div", {
1773
2043
  className: "flex gap-3",
1774
2044
  children: [
1775
- /* @__PURE__ */ jsxDEV6(Button5, {
2045
+ /* @__PURE__ */ jsxDEV7(Button5, {
1776
2046
  variant: "secondary",
1777
2047
  size: "sm",
1778
2048
  children: "Export Data"
1779
2049
  }, undefined, false, undefined, this),
1780
- /* @__PURE__ */ jsxDEV6(Button5, {
2050
+ /* @__PURE__ */ jsxDEV7(Button5, {
1781
2051
  variant: "secondary",
1782
2052
  size: "sm",
1783
2053
  children: "Delete Organization"