@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.
- package/.turbo/turbo-build.log +36 -24
- package/CHANGELOG.md +72 -0
- package/README.md +1 -0
- package/dist/browser/index.js +371 -92
- package/dist/browser/saas-boilerplate.feature.js +208 -0
- package/dist/browser/ui/SaasDashboard.js +311 -60
- package/dist/browser/ui/SaasDashboard.visualizations.js +249 -0
- package/dist/browser/ui/index.js +362 -92
- package/dist/browser/ui/renderers/index.js +229 -3
- package/dist/browser/ui/renderers/project-list.markdown.js +229 -3
- package/dist/browser/visualizations/catalog.js +155 -0
- package/dist/browser/visualizations/index.js +217 -0
- package/dist/browser/visualizations/selectors.js +210 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +371 -92
- package/dist/node/index.js +371 -92
- package/dist/node/saas-boilerplate.feature.js +208 -0
- package/dist/node/ui/SaasDashboard.js +311 -60
- package/dist/node/ui/SaasDashboard.visualizations.js +249 -0
- package/dist/node/ui/index.js +362 -92
- package/dist/node/ui/renderers/index.js +229 -3
- package/dist/node/ui/renderers/project-list.markdown.js +229 -3
- package/dist/node/visualizations/catalog.js +155 -0
- package/dist/node/visualizations/index.js +217 -0
- package/dist/node/visualizations/selectors.js +210 -0
- package/dist/saas-boilerplate.feature.js +208 -0
- package/dist/ui/SaasDashboard.js +311 -60
- package/dist/ui/SaasDashboard.visualizations.d.ts +5 -0
- package/dist/ui/SaasDashboard.visualizations.js +250 -0
- package/dist/ui/index.js +362 -92
- package/dist/ui/renderers/index.js +229 -3
- package/dist/ui/renderers/project-list.markdown.d.ts +1 -1
- package/dist/ui/renderers/project-list.markdown.js +229 -3
- package/dist/ui/renderers/project-list.renderer.d.ts +1 -1
- package/dist/visualizations/catalog.d.ts +11 -0
- package/dist/visualizations/catalog.js +156 -0
- package/dist/visualizations/index.d.ts +2 -0
- package/dist/visualizations/index.js +218 -0
- package/dist/visualizations/selectors.d.ts +8 -0
- package/dist/visualizations/selectors.js +211 -0
- package/dist/visualizations/selectors.test.d.ts +1 -0
- package/package.json +70 -13
- package/src/index.ts +1 -0
- package/src/saas-boilerplate.feature.ts +3 -0
- package/src/ui/SaasDashboard.tsx +8 -0
- package/src/ui/SaasDashboard.visualizations.tsx +41 -0
- package/src/ui/renderers/project-list.markdown.ts +39 -15
- package/src/ui/renderers/project-list.renderer.tsx +1 -1
- package/src/visualizations/catalog.ts +153 -0
- package/src/visualizations/index.ts +2 -0
- package/src/visualizations/selectors.test.ts +25 -0
- package/src/visualizations/selectors.ts +85 -0
|
@@ -1,3 +1,210 @@
|
|
|
1
|
+
// src/visualizations/catalog.ts
|
|
2
|
+
import {
|
|
3
|
+
defineVisualization,
|
|
4
|
+
VisualizationRegistry
|
|
5
|
+
} from "@contractspec/lib.contracts-spec/visualizations";
|
|
6
|
+
var PROJECT_LIST_REF = {
|
|
7
|
+
key: "saas.project.list",
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
};
|
|
10
|
+
var META = {
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
domain: "saas",
|
|
13
|
+
stability: "experimental",
|
|
14
|
+
owners: ["@example.saas-boilerplate"],
|
|
15
|
+
tags: ["saas", "visualization", "projects"]
|
|
16
|
+
};
|
|
17
|
+
var SaasProjectUsageVisualization = defineVisualization({
|
|
18
|
+
meta: {
|
|
19
|
+
...META,
|
|
20
|
+
key: "saas-boilerplate.visualization.project-usage",
|
|
21
|
+
title: "Project Capacity",
|
|
22
|
+
description: "Current project count against the current plan limit.",
|
|
23
|
+
goal: "Show usage against the active plan allowance.",
|
|
24
|
+
context: "SaaS account overview."
|
|
25
|
+
},
|
|
26
|
+
source: { primary: PROJECT_LIST_REF, resultPath: "data" },
|
|
27
|
+
visualization: {
|
|
28
|
+
kind: "metric",
|
|
29
|
+
measure: "totalProjects",
|
|
30
|
+
comparisonMeasure: "projectLimit",
|
|
31
|
+
measures: [
|
|
32
|
+
{
|
|
33
|
+
key: "totalProjects",
|
|
34
|
+
label: "Projects",
|
|
35
|
+
dataPath: "totalProjects",
|
|
36
|
+
format: "number"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: "projectLimit",
|
|
40
|
+
label: "Plan Limit",
|
|
41
|
+
dataPath: "projectLimit",
|
|
42
|
+
format: "number"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
table: { caption: "Current project count and plan limit." }
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var SaasProjectStatusVisualization = defineVisualization({
|
|
49
|
+
meta: {
|
|
50
|
+
...META,
|
|
51
|
+
key: "saas-boilerplate.visualization.project-status",
|
|
52
|
+
title: "Project Status",
|
|
53
|
+
description: "Distribution of project states.",
|
|
54
|
+
goal: "Show the mix of active, draft, and archived projects.",
|
|
55
|
+
context: "Project portfolio overview."
|
|
56
|
+
},
|
|
57
|
+
source: { primary: PROJECT_LIST_REF, resultPath: "data" },
|
|
58
|
+
visualization: {
|
|
59
|
+
kind: "pie",
|
|
60
|
+
nameDimension: "status",
|
|
61
|
+
valueMeasure: "projects",
|
|
62
|
+
dimensions: [
|
|
63
|
+
{ key: "status", label: "Status", dataPath: "status", type: "category" }
|
|
64
|
+
],
|
|
65
|
+
measures: [
|
|
66
|
+
{
|
|
67
|
+
key: "projects",
|
|
68
|
+
label: "Projects",
|
|
69
|
+
dataPath: "projects",
|
|
70
|
+
format: "number"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
table: { caption: "Project counts by status." }
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
var SaasProjectTierVisualization = defineVisualization({
|
|
77
|
+
meta: {
|
|
78
|
+
...META,
|
|
79
|
+
key: "saas-boilerplate.visualization.project-tiers",
|
|
80
|
+
title: "Tier Comparison",
|
|
81
|
+
description: "Distribution of projects across tiers.",
|
|
82
|
+
goal: "Compare how the current portfolio is distributed by tier.",
|
|
83
|
+
context: "Plan and packaging overview."
|
|
84
|
+
},
|
|
85
|
+
source: { primary: PROJECT_LIST_REF, resultPath: "data" },
|
|
86
|
+
visualization: {
|
|
87
|
+
kind: "cartesian",
|
|
88
|
+
variant: "bar",
|
|
89
|
+
xDimension: "tier",
|
|
90
|
+
yMeasures: ["projects"],
|
|
91
|
+
dimensions: [
|
|
92
|
+
{ key: "tier", label: "Tier", dataPath: "tier", type: "category" }
|
|
93
|
+
],
|
|
94
|
+
measures: [
|
|
95
|
+
{
|
|
96
|
+
key: "projects",
|
|
97
|
+
label: "Projects",
|
|
98
|
+
dataPath: "projects",
|
|
99
|
+
format: "number",
|
|
100
|
+
color: "#1d4ed8"
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
table: { caption: "Project counts by tier." }
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
var SaasProjectActivityVisualization = defineVisualization({
|
|
107
|
+
meta: {
|
|
108
|
+
...META,
|
|
109
|
+
key: "saas-boilerplate.visualization.project-activity",
|
|
110
|
+
title: "Recent Project Activity",
|
|
111
|
+
description: "Daily project creation activity.",
|
|
112
|
+
goal: "Show recent project activity over time.",
|
|
113
|
+
context: "Project portfolio trend view."
|
|
114
|
+
},
|
|
115
|
+
source: { primary: PROJECT_LIST_REF, resultPath: "data" },
|
|
116
|
+
visualization: {
|
|
117
|
+
kind: "cartesian",
|
|
118
|
+
variant: "line",
|
|
119
|
+
xDimension: "day",
|
|
120
|
+
yMeasures: ["projects"],
|
|
121
|
+
dimensions: [{ key: "day", label: "Day", dataPath: "day", type: "time" }],
|
|
122
|
+
measures: [
|
|
123
|
+
{
|
|
124
|
+
key: "projects",
|
|
125
|
+
label: "Projects",
|
|
126
|
+
dataPath: "projects",
|
|
127
|
+
format: "number",
|
|
128
|
+
color: "#0f766e"
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
table: { caption: "Daily project creation counts." }
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
var SaasVisualizationSpecs = [
|
|
135
|
+
SaasProjectUsageVisualization,
|
|
136
|
+
SaasProjectStatusVisualization,
|
|
137
|
+
SaasProjectTierVisualization,
|
|
138
|
+
SaasProjectActivityVisualization
|
|
139
|
+
];
|
|
140
|
+
var SaasVisualizationRegistry = new VisualizationRegistry([
|
|
141
|
+
...SaasVisualizationSpecs
|
|
142
|
+
]);
|
|
143
|
+
var SaasVisualizationRefs = SaasVisualizationSpecs.map((spec) => ({
|
|
144
|
+
key: spec.meta.key,
|
|
145
|
+
version: spec.meta.version
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
// src/visualizations/selectors.ts
|
|
149
|
+
function toDayKey(value) {
|
|
150
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
151
|
+
return date.toISOString().slice(0, 10);
|
|
152
|
+
}
|
|
153
|
+
function createSaasVisualizationItems(projects, projectLimit = 10) {
|
|
154
|
+
const statusCounts = new Map;
|
|
155
|
+
const tierCounts = new Map;
|
|
156
|
+
const activityCounts = new Map;
|
|
157
|
+
for (const project of projects) {
|
|
158
|
+
statusCounts.set(project.status, (statusCounts.get(project.status) ?? 0) + 1);
|
|
159
|
+
tierCounts.set(project.tier, (tierCounts.get(project.tier) ?? 0) + 1);
|
|
160
|
+
const day = toDayKey(project.createdAt);
|
|
161
|
+
activityCounts.set(day, (activityCounts.get(day) ?? 0) + 1);
|
|
162
|
+
}
|
|
163
|
+
return [
|
|
164
|
+
{
|
|
165
|
+
key: "saas-capacity",
|
|
166
|
+
spec: SaasProjectUsageVisualization,
|
|
167
|
+
data: { data: [{ totalProjects: projects.length, projectLimit }] },
|
|
168
|
+
title: "Project Capacity",
|
|
169
|
+
description: "Current project count compared to the active limit.",
|
|
170
|
+
height: 220
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
key: "saas-status",
|
|
174
|
+
spec: SaasProjectStatusVisualization,
|
|
175
|
+
data: {
|
|
176
|
+
data: Array.from(statusCounts.entries()).map(([status, count]) => ({
|
|
177
|
+
status,
|
|
178
|
+
projects: count
|
|
179
|
+
}))
|
|
180
|
+
},
|
|
181
|
+
title: "Project Status",
|
|
182
|
+
description: "Status mix across the current project portfolio.",
|
|
183
|
+
height: 260
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
key: "saas-tier",
|
|
187
|
+
spec: SaasProjectTierVisualization,
|
|
188
|
+
data: {
|
|
189
|
+
data: Array.from(tierCounts.entries()).map(([tier, count]) => ({
|
|
190
|
+
tier,
|
|
191
|
+
projects: count
|
|
192
|
+
}))
|
|
193
|
+
},
|
|
194
|
+
title: "Tier Comparison",
|
|
195
|
+
description: "How projects are distributed across tiers."
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: "saas-activity",
|
|
199
|
+
spec: SaasProjectActivityVisualization,
|
|
200
|
+
data: {
|
|
201
|
+
data: Array.from(activityCounts.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([day, count]) => ({ day, projects: count }))
|
|
202
|
+
},
|
|
203
|
+
title: "Recent Project Activity",
|
|
204
|
+
description: "Daily project creation activity."
|
|
205
|
+
}
|
|
206
|
+
];
|
|
207
|
+
}
|
|
1
208
|
// src/ui/hooks/useProjectList.ts
|
|
2
209
|
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
3
210
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
@@ -635,6 +842,46 @@ function ProjectActionsModal({
|
|
|
635
842
|
}, undefined, true, undefined, this);
|
|
636
843
|
}
|
|
637
844
|
|
|
845
|
+
// src/ui/SaasDashboard.visualizations.tsx
|
|
846
|
+
import {
|
|
847
|
+
VisualizationCard,
|
|
848
|
+
VisualizationGrid
|
|
849
|
+
} from "@contractspec/lib.design-system";
|
|
850
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
851
|
+
"use client";
|
|
852
|
+
function SaasVisualizationOverview({
|
|
853
|
+
projects,
|
|
854
|
+
projectLimit
|
|
855
|
+
}) {
|
|
856
|
+
const items = createSaasVisualizationItems(projects, projectLimit);
|
|
857
|
+
return /* @__PURE__ */ jsxDEV3("section", {
|
|
858
|
+
className: "space-y-3",
|
|
859
|
+
children: [
|
|
860
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
861
|
+
children: [
|
|
862
|
+
/* @__PURE__ */ jsxDEV3("h3", {
|
|
863
|
+
className: "font-semibold text-lg",
|
|
864
|
+
children: "Portfolio Visualizations"
|
|
865
|
+
}, undefined, false, undefined, this),
|
|
866
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
867
|
+
className: "text-muted-foreground text-sm",
|
|
868
|
+
children: "Contract-backed charts for project mix, capacity, and activity."
|
|
869
|
+
}, undefined, false, undefined, this)
|
|
870
|
+
]
|
|
871
|
+
}, undefined, true, undefined, this),
|
|
872
|
+
/* @__PURE__ */ jsxDEV3(VisualizationGrid, {
|
|
873
|
+
children: items.map((item) => /* @__PURE__ */ jsxDEV3(VisualizationCard, {
|
|
874
|
+
data: item.data,
|
|
875
|
+
description: item.description,
|
|
876
|
+
height: item.height,
|
|
877
|
+
spec: item.spec,
|
|
878
|
+
title: item.title
|
|
879
|
+
}, item.key, false, undefined, this))
|
|
880
|
+
}, undefined, false, undefined, this)
|
|
881
|
+
]
|
|
882
|
+
}, undefined, true, undefined, this);
|
|
883
|
+
}
|
|
884
|
+
|
|
638
885
|
// src/ui/SaasDashboard.tsx
|
|
639
886
|
import {
|
|
640
887
|
Button as Button3,
|
|
@@ -647,7 +894,7 @@ import {
|
|
|
647
894
|
StatusChip
|
|
648
895
|
} from "@contractspec/lib.design-system";
|
|
649
896
|
import { useCallback as useCallback3, useState as useState5 } from "react";
|
|
650
|
-
import { jsxDEV as
|
|
897
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
651
898
|
"use client";
|
|
652
899
|
function getStatusTone(status) {
|
|
653
900
|
switch (status) {
|
|
@@ -682,32 +929,32 @@ function SaasDashboard() {
|
|
|
682
929
|
{ id: "settings", label: "Settings", icon: "⚙️" }
|
|
683
930
|
];
|
|
684
931
|
if (loading && !data) {
|
|
685
|
-
return /* @__PURE__ */
|
|
932
|
+
return /* @__PURE__ */ jsxDEV4(LoaderBlock, {
|
|
686
933
|
label: "Loading dashboard..."
|
|
687
934
|
}, undefined, false, undefined, this);
|
|
688
935
|
}
|
|
689
936
|
if (error) {
|
|
690
|
-
return /* @__PURE__ */
|
|
937
|
+
return /* @__PURE__ */ jsxDEV4(ErrorState, {
|
|
691
938
|
title: "Failed to load dashboard",
|
|
692
939
|
description: error.message,
|
|
693
940
|
onRetry: refetch,
|
|
694
941
|
retryLabel: "Retry"
|
|
695
942
|
}, undefined, false, undefined, this);
|
|
696
943
|
}
|
|
697
|
-
return /* @__PURE__ */
|
|
944
|
+
return /* @__PURE__ */ jsxDEV4("div", {
|
|
698
945
|
className: "space-y-6",
|
|
699
946
|
children: [
|
|
700
|
-
/* @__PURE__ */
|
|
947
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
701
948
|
className: "flex items-center justify-between",
|
|
702
949
|
children: [
|
|
703
|
-
/* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsxDEV4("h2", {
|
|
704
951
|
className: "font-bold text-2xl",
|
|
705
952
|
children: "SaaS Dashboard"
|
|
706
953
|
}, undefined, false, undefined, this),
|
|
707
|
-
activeTab === "projects" && /* @__PURE__ */
|
|
954
|
+
activeTab === "projects" && /* @__PURE__ */ jsxDEV4(Button3, {
|
|
708
955
|
onPress: () => setIsCreateModalOpen(true),
|
|
709
956
|
children: [
|
|
710
|
-
/* @__PURE__ */
|
|
957
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
711
958
|
className: "mr-2",
|
|
712
959
|
children: "+"
|
|
713
960
|
}, undefined, false, undefined, this),
|
|
@@ -716,59 +963,63 @@ function SaasDashboard() {
|
|
|
716
963
|
}, undefined, true, undefined, this)
|
|
717
964
|
]
|
|
718
965
|
}, undefined, true, undefined, this),
|
|
719
|
-
stats && subscription && /* @__PURE__ */
|
|
966
|
+
stats && subscription && /* @__PURE__ */ jsxDEV4(StatCardGroup, {
|
|
720
967
|
children: [
|
|
721
|
-
/* @__PURE__ */
|
|
968
|
+
/* @__PURE__ */ jsxDEV4(StatCard, {
|
|
722
969
|
label: "Projects",
|
|
723
970
|
value: stats.total.toString()
|
|
724
971
|
}, undefined, false, undefined, this),
|
|
725
|
-
/* @__PURE__ */
|
|
972
|
+
/* @__PURE__ */ jsxDEV4(StatCard, {
|
|
726
973
|
label: "Active",
|
|
727
974
|
value: stats.activeCount.toString()
|
|
728
975
|
}, undefined, false, undefined, this),
|
|
729
|
-
/* @__PURE__ */
|
|
976
|
+
/* @__PURE__ */ jsxDEV4(StatCard, {
|
|
730
977
|
label: "Draft",
|
|
731
978
|
value: stats.draftCount.toString()
|
|
732
979
|
}, undefined, false, undefined, this),
|
|
733
|
-
/* @__PURE__ */
|
|
980
|
+
/* @__PURE__ */ jsxDEV4(StatCard, {
|
|
734
981
|
label: "Plan",
|
|
735
982
|
value: subscription.plan,
|
|
736
983
|
hint: subscription.status
|
|
737
984
|
}, undefined, false, undefined, this)
|
|
738
985
|
]
|
|
739
986
|
}, undefined, true, undefined, this),
|
|
740
|
-
/* @__PURE__ */
|
|
987
|
+
data && stats && /* @__PURE__ */ jsxDEV4(SaasVisualizationOverview, {
|
|
988
|
+
projectLimit: stats.projectLimit,
|
|
989
|
+
projects: data.items
|
|
990
|
+
}, undefined, false, undefined, this),
|
|
991
|
+
/* @__PURE__ */ jsxDEV4("nav", {
|
|
741
992
|
className: "flex gap-1 rounded-lg bg-muted p-1",
|
|
742
993
|
role: "tablist",
|
|
743
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
994
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxDEV4("button", {
|
|
744
995
|
type: "button",
|
|
745
996
|
role: "tab",
|
|
746
997
|
"aria-selected": activeTab === tab.id,
|
|
747
998
|
onClick: () => setActiveTab(tab.id),
|
|
748
999
|
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"}`,
|
|
749
1000
|
children: [
|
|
750
|
-
/* @__PURE__ */
|
|
1001
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
751
1002
|
children: tab.icon
|
|
752
1003
|
}, undefined, false, undefined, this),
|
|
753
1004
|
tab.label
|
|
754
1005
|
]
|
|
755
1006
|
}, tab.id, true, undefined, this))
|
|
756
1007
|
}, undefined, false, undefined, this),
|
|
757
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
758
1009
|
className: "min-h-[400px]",
|
|
759
1010
|
role: "tabpanel",
|
|
760
1011
|
children: [
|
|
761
|
-
activeTab === "projects" && /* @__PURE__ */
|
|
1012
|
+
activeTab === "projects" && /* @__PURE__ */ jsxDEV4(ProjectsTab, {
|
|
762
1013
|
data,
|
|
763
1014
|
onProjectClick: handleProjectClick
|
|
764
1015
|
}, undefined, false, undefined, this),
|
|
765
|
-
activeTab === "billing" && /* @__PURE__ */
|
|
1016
|
+
activeTab === "billing" && /* @__PURE__ */ jsxDEV4(BillingTab, {
|
|
766
1017
|
subscription
|
|
767
1018
|
}, undefined, false, undefined, this),
|
|
768
|
-
activeTab === "settings" && /* @__PURE__ */
|
|
1019
|
+
activeTab === "settings" && /* @__PURE__ */ jsxDEV4(SettingsTab, {}, undefined, false, undefined, this)
|
|
769
1020
|
]
|
|
770
1021
|
}, undefined, true, undefined, this),
|
|
771
|
-
/* @__PURE__ */
|
|
1022
|
+
/* @__PURE__ */ jsxDEV4(CreateProjectModal, {
|
|
772
1023
|
isOpen: isCreateModalOpen,
|
|
773
1024
|
onClose: () => setIsCreateModalOpen(false),
|
|
774
1025
|
onSubmit: async (input) => {
|
|
@@ -776,7 +1027,7 @@ function SaasDashboard() {
|
|
|
776
1027
|
},
|
|
777
1028
|
isLoading: mutations.createState.loading
|
|
778
1029
|
}, undefined, false, undefined, this),
|
|
779
|
-
/* @__PURE__ */
|
|
1030
|
+
/* @__PURE__ */ jsxDEV4(ProjectActionsModal, {
|
|
780
1031
|
isOpen: isProjectActionsOpen,
|
|
781
1032
|
project: selectedProject,
|
|
782
1033
|
onClose: () => {
|
|
@@ -802,34 +1053,34 @@ function SaasDashboard() {
|
|
|
802
1053
|
}
|
|
803
1054
|
function ProjectsTab({ data, onProjectClick }) {
|
|
804
1055
|
if (!data?.items.length) {
|
|
805
|
-
return /* @__PURE__ */
|
|
1056
|
+
return /* @__PURE__ */ jsxDEV4(EmptyState, {
|
|
806
1057
|
title: "No projects yet",
|
|
807
1058
|
description: "Create your first project to get started."
|
|
808
1059
|
}, undefined, false, undefined, this);
|
|
809
1060
|
}
|
|
810
|
-
return /* @__PURE__ */
|
|
1061
|
+
return /* @__PURE__ */ jsxDEV4("div", {
|
|
811
1062
|
className: "space-y-4",
|
|
812
|
-
children: /* @__PURE__ */
|
|
1063
|
+
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
813
1064
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
814
|
-
children: data.items.map((project) => /* @__PURE__ */
|
|
1065
|
+
children: data.items.map((project) => /* @__PURE__ */ jsxDEV4(EntityCard, {
|
|
815
1066
|
cardTitle: project.name,
|
|
816
1067
|
cardSubtitle: project.tier,
|
|
817
|
-
meta: /* @__PURE__ */
|
|
1068
|
+
meta: /* @__PURE__ */ jsxDEV4("p", {
|
|
818
1069
|
className: "text-muted-foreground text-sm",
|
|
819
1070
|
children: project.description
|
|
820
1071
|
}, undefined, false, undefined, this),
|
|
821
|
-
chips: /* @__PURE__ */
|
|
1072
|
+
chips: /* @__PURE__ */ jsxDEV4(StatusChip, {
|
|
822
1073
|
tone: getStatusTone(project.status),
|
|
823
1074
|
label: project.status
|
|
824
1075
|
}, undefined, false, undefined, this),
|
|
825
|
-
footer: /* @__PURE__ */
|
|
1076
|
+
footer: /* @__PURE__ */ jsxDEV4("div", {
|
|
826
1077
|
className: "flex w-full items-center justify-between",
|
|
827
1078
|
children: [
|
|
828
|
-
/* @__PURE__ */
|
|
1079
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
829
1080
|
className: "text-muted-foreground text-xs",
|
|
830
1081
|
children: project.updatedAt.toLocaleDateString()
|
|
831
1082
|
}, undefined, false, undefined, this),
|
|
832
|
-
/* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ jsxDEV4(Button3, {
|
|
833
1084
|
variant: "ghost",
|
|
834
1085
|
size: "sm",
|
|
835
1086
|
onPress: () => onProjectClick?.(project),
|
|
@@ -844,25 +1095,25 @@ function ProjectsTab({ data, onProjectClick }) {
|
|
|
844
1095
|
function BillingTab({ subscription }) {
|
|
845
1096
|
if (!subscription)
|
|
846
1097
|
return null;
|
|
847
|
-
return /* @__PURE__ */
|
|
1098
|
+
return /* @__PURE__ */ jsxDEV4("div", {
|
|
848
1099
|
className: "space-y-6",
|
|
849
1100
|
children: [
|
|
850
|
-
/* @__PURE__ */
|
|
1101
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
851
1102
|
className: "rounded-xl border border-border bg-card p-6",
|
|
852
1103
|
children: [
|
|
853
|
-
/* @__PURE__ */
|
|
1104
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
854
1105
|
className: "flex items-start justify-between",
|
|
855
1106
|
children: [
|
|
856
|
-
/* @__PURE__ */
|
|
1107
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
857
1108
|
children: [
|
|
858
|
-
/* @__PURE__ */
|
|
1109
|
+
/* @__PURE__ */ jsxDEV4("h3", {
|
|
859
1110
|
className: "font-semibold text-lg",
|
|
860
1111
|
children: [
|
|
861
1112
|
subscription.plan,
|
|
862
1113
|
" Plan"
|
|
863
1114
|
]
|
|
864
1115
|
}, undefined, true, undefined, this),
|
|
865
|
-
/* @__PURE__ */
|
|
1116
|
+
/* @__PURE__ */ jsxDEV4("p", {
|
|
866
1117
|
className: "text-muted-foreground text-sm",
|
|
867
1118
|
children: [
|
|
868
1119
|
"Current period:",
|
|
@@ -873,7 +1124,7 @@ function BillingTab({ subscription }) {
|
|
|
873
1124
|
subscription.currentPeriodEnd.toLocaleDateString()
|
|
874
1125
|
]
|
|
875
1126
|
}, undefined, true, undefined, this),
|
|
876
|
-
/* @__PURE__ */
|
|
1127
|
+
/* @__PURE__ */ jsxDEV4("p", {
|
|
877
1128
|
className: "text-muted-foreground text-sm",
|
|
878
1129
|
children: [
|
|
879
1130
|
"Billing cycle: ",
|
|
@@ -882,21 +1133,21 @@ function BillingTab({ subscription }) {
|
|
|
882
1133
|
}, undefined, true, undefined, this)
|
|
883
1134
|
]
|
|
884
1135
|
}, undefined, true, undefined, this),
|
|
885
|
-
/* @__PURE__ */
|
|
1136
|
+
/* @__PURE__ */ jsxDEV4(StatusChip, {
|
|
886
1137
|
tone: "success",
|
|
887
1138
|
label: subscription.status
|
|
888
1139
|
}, undefined, false, undefined, this)
|
|
889
1140
|
]
|
|
890
1141
|
}, undefined, true, undefined, this),
|
|
891
|
-
/* @__PURE__ */
|
|
1142
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
892
1143
|
className: "mt-4 flex gap-3",
|
|
893
1144
|
children: [
|
|
894
|
-
/* @__PURE__ */
|
|
1145
|
+
/* @__PURE__ */ jsxDEV4(Button3, {
|
|
895
1146
|
variant: "outline",
|
|
896
1147
|
onPress: () => alert("Upgrade clicked!"),
|
|
897
1148
|
children: "Upgrade Plan"
|
|
898
1149
|
}, undefined, false, undefined, this),
|
|
899
|
-
/* @__PURE__ */
|
|
1150
|
+
/* @__PURE__ */ jsxDEV4(Button3, {
|
|
900
1151
|
variant: "ghost",
|
|
901
1152
|
onPress: () => alert("Manage Billing clicked!"),
|
|
902
1153
|
children: "Manage Billing"
|
|
@@ -905,9 +1156,9 @@ function BillingTab({ subscription }) {
|
|
|
905
1156
|
}, undefined, true, undefined, this)
|
|
906
1157
|
]
|
|
907
1158
|
}, undefined, true, undefined, this),
|
|
908
|
-
subscription.cancelAtPeriodEnd && /* @__PURE__ */
|
|
1159
|
+
subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV4("div", {
|
|
909
1160
|
className: "rounded-xl border border-border bg-destructive/10 p-4 text-destructive",
|
|
910
|
-
children: /* @__PURE__ */
|
|
1161
|
+
children: /* @__PURE__ */ jsxDEV4("p", {
|
|
911
1162
|
className: "font-medium text-sm",
|
|
912
1163
|
children: "⚠️ Your subscription will be cancelled at the end of the current period."
|
|
913
1164
|
}, undefined, false, undefined, this)
|
|
@@ -916,26 +1167,26 @@ function BillingTab({ subscription }) {
|
|
|
916
1167
|
}, undefined, true, undefined, this);
|
|
917
1168
|
}
|
|
918
1169
|
function SettingsTab() {
|
|
919
|
-
return /* @__PURE__ */
|
|
1170
|
+
return /* @__PURE__ */ jsxDEV4("div", {
|
|
920
1171
|
className: "space-y-6",
|
|
921
|
-
children: /* @__PURE__ */
|
|
1172
|
+
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
922
1173
|
className: "rounded-xl border border-border bg-card p-6",
|
|
923
1174
|
children: [
|
|
924
|
-
/* @__PURE__ */
|
|
1175
|
+
/* @__PURE__ */ jsxDEV4("h3", {
|
|
925
1176
|
className: "mb-4 font-semibold text-lg",
|
|
926
1177
|
children: "Organization Settings"
|
|
927
1178
|
}, undefined, false, undefined, this),
|
|
928
|
-
/* @__PURE__ */
|
|
1179
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
929
1180
|
className: "space-y-4",
|
|
930
1181
|
children: [
|
|
931
|
-
/* @__PURE__ */
|
|
1182
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
932
1183
|
children: [
|
|
933
|
-
/* @__PURE__ */
|
|
1184
|
+
/* @__PURE__ */ jsxDEV4("label", {
|
|
934
1185
|
htmlFor: "org-name",
|
|
935
1186
|
className: "font-medium text-sm",
|
|
936
1187
|
children: "Organization Name"
|
|
937
1188
|
}, undefined, false, undefined, this),
|
|
938
|
-
/* @__PURE__ */
|
|
1189
|
+
/* @__PURE__ */ jsxDEV4("input", {
|
|
939
1190
|
id: "org-name",
|
|
940
1191
|
type: "text",
|
|
941
1192
|
defaultValue: "Demo Organization",
|
|
@@ -943,36 +1194,36 @@ function SettingsTab() {
|
|
|
943
1194
|
}, undefined, false, undefined, this)
|
|
944
1195
|
]
|
|
945
1196
|
}, undefined, true, undefined, this),
|
|
946
|
-
/* @__PURE__ */
|
|
1197
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
947
1198
|
children: [
|
|
948
|
-
/* @__PURE__ */
|
|
1199
|
+
/* @__PURE__ */ jsxDEV4("label", {
|
|
949
1200
|
htmlFor: "timezone",
|
|
950
1201
|
className: "font-medium text-sm",
|
|
951
1202
|
children: "Default Timezone"
|
|
952
1203
|
}, undefined, false, undefined, this),
|
|
953
|
-
/* @__PURE__ */
|
|
1204
|
+
/* @__PURE__ */ jsxDEV4("select", {
|
|
954
1205
|
id: "timezone",
|
|
955
1206
|
className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
|
|
956
1207
|
children: [
|
|
957
|
-
/* @__PURE__ */
|
|
1208
|
+
/* @__PURE__ */ jsxDEV4("option", {
|
|
958
1209
|
children: "UTC"
|
|
959
1210
|
}, undefined, false, undefined, this),
|
|
960
|
-
/* @__PURE__ */
|
|
1211
|
+
/* @__PURE__ */ jsxDEV4("option", {
|
|
961
1212
|
children: "America/New_York"
|
|
962
1213
|
}, undefined, false, undefined, this),
|
|
963
|
-
/* @__PURE__ */
|
|
1214
|
+
/* @__PURE__ */ jsxDEV4("option", {
|
|
964
1215
|
children: "Europe/London"
|
|
965
1216
|
}, undefined, false, undefined, this),
|
|
966
|
-
/* @__PURE__ */
|
|
1217
|
+
/* @__PURE__ */ jsxDEV4("option", {
|
|
967
1218
|
children: "Asia/Tokyo"
|
|
968
1219
|
}, undefined, false, undefined, this)
|
|
969
1220
|
]
|
|
970
1221
|
}, undefined, true, undefined, this)
|
|
971
1222
|
]
|
|
972
1223
|
}, undefined, true, undefined, this),
|
|
973
|
-
/* @__PURE__ */
|
|
1224
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
974
1225
|
className: "pt-2",
|
|
975
|
-
children: /* @__PURE__ */
|
|
1226
|
+
children: /* @__PURE__ */ jsxDEV4(Button3, {
|
|
976
1227
|
onPress: () => alert("Settings saved!"),
|
|
977
1228
|
children: "Save Settings"
|
|
978
1229
|
}, undefined, false, undefined, this)
|