@contractspec/example.saas-boilerplate 0.0.0-canary-20260113170453
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$colon$bundle.log +188 -0
- package/.turbo/turbo-build.log +189 -0
- package/CHANGELOG.md +440 -0
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/billing/billing.entity.d.ts +61 -0
- package/dist/billing/billing.entity.d.ts.map +1 -0
- package/dist/billing/billing.entity.js +122 -0
- package/dist/billing/billing.entity.js.map +1 -0
- package/dist/billing/billing.enum.d.ts +16 -0
- package/dist/billing/billing.enum.d.ts.map +1 -0
- package/dist/billing/billing.enum.js +27 -0
- package/dist/billing/billing.enum.js.map +1 -0
- package/dist/billing/billing.event.d.ts +86 -0
- package/dist/billing/billing.event.d.ts.map +1 -0
- package/dist/billing/billing.event.js +153 -0
- package/dist/billing/billing.event.js.map +1 -0
- package/dist/billing/billing.handler.d.ts +82 -0
- package/dist/billing/billing.handler.d.ts.map +1 -0
- package/dist/billing/billing.handler.js +58 -0
- package/dist/billing/billing.handler.js.map +1 -0
- package/dist/billing/billing.operations.d.ts +166 -0
- package/dist/billing/billing.operations.d.ts.map +1 -0
- package/dist/billing/billing.operations.js +181 -0
- package/dist/billing/billing.operations.js.map +1 -0
- package/dist/billing/billing.presentation.d.ts +14 -0
- package/dist/billing/billing.presentation.d.ts.map +1 -0
- package/dist/billing/billing.presentation.js +59 -0
- package/dist/billing/billing.presentation.js.map +1 -0
- package/dist/billing/billing.schema.d.ts +201 -0
- package/dist/billing/billing.schema.d.ts.map +1 -0
- package/dist/billing/billing.schema.js +214 -0
- package/dist/billing/billing.schema.js.map +1 -0
- package/dist/billing/index.d.ts +8 -0
- package/dist/billing/index.js +9 -0
- package/dist/dashboard/dashboard.presentation.d.ts +14 -0
- package/dist/dashboard/dashboard.presentation.d.ts.map +1 -0
- package/dist/dashboard/dashboard.presentation.js +55 -0
- package/dist/dashboard/dashboard.presentation.js.map +1 -0
- package/dist/dashboard/index.d.ts +2 -0
- package/dist/dashboard/index.js +3 -0
- package/dist/docs/index.d.ts +1 -0
- package/dist/docs/index.js +1 -0
- package/dist/docs/saas-boilerplate.docblock.d.ts +1 -0
- package/dist/docs/saas-boilerplate.docblock.js +100 -0
- package/dist/docs/saas-boilerplate.docblock.js.map +1 -0
- package/dist/example.d.ts +7 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +53 -0
- package/dist/example.js.map +1 -0
- package/dist/handlers/index.d.ts +4 -0
- package/dist/handlers/index.js +5 -0
- package/dist/handlers/saas.handlers.d.ts +68 -0
- package/dist/handlers/saas.handlers.d.ts.map +1 -0
- package/dist/handlers/saas.handlers.js +148 -0
- package/dist/handlers/saas.handlers.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/presentations/index.d.ts +17 -0
- package/dist/presentations/index.d.ts.map +1 -0
- package/dist/presentations/index.js +17 -0
- package/dist/presentations/index.js.map +1 -0
- package/dist/project/index.d.ts +8 -0
- package/dist/project/index.js +9 -0
- package/dist/project/project.entity.d.ts +40 -0
- package/dist/project/project.entity.d.ts.map +1 -0
- package/dist/project/project.entity.js +85 -0
- package/dist/project/project.entity.js.map +1 -0
- package/dist/project/project.enum.d.ts +16 -0
- package/dist/project/project.enum.d.ts.map +1 -0
- package/dist/project/project.enum.js +26 -0
- package/dist/project/project.enum.js.map +1 -0
- package/dist/project/project.event.d.ts +92 -0
- package/dist/project/project.event.d.ts.map +1 -0
- package/dist/project/project.event.js +165 -0
- package/dist/project/project.event.js.map +1 -0
- package/dist/project/project.handler.d.ts +72 -0
- package/dist/project/project.handler.d.ts.map +1 -0
- package/dist/project/project.handler.js +82 -0
- package/dist/project/project.handler.js.map +1 -0
- package/dist/project/project.operations.d.ts +419 -0
- package/dist/project/project.operations.d.ts.map +1 -0
- package/dist/project/project.operations.js +260 -0
- package/dist/project/project.operations.js.map +1 -0
- package/dist/project/project.presentation.d.ts +14 -0
- package/dist/project/project.presentation.d.ts.map +1 -0
- package/dist/project/project.presentation.js +65 -0
- package/dist/project/project.presentation.js.map +1 -0
- package/dist/project/project.schema.d.ts +235 -0
- package/dist/project/project.schema.d.ts.map +1 -0
- package/dist/project/project.schema.js +215 -0
- package/dist/project/project.schema.js.map +1 -0
- package/dist/saas-boilerplate.feature.d.ts +12 -0
- package/dist/saas-boilerplate.feature.d.ts.map +1 -0
- package/dist/saas-boilerplate.feature.js +208 -0
- package/dist/saas-boilerplate.feature.js.map +1 -0
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +19 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/settings/index.d.ts +3 -0
- package/dist/settings/index.js +4 -0
- package/dist/settings/settings.entity.d.ts +37 -0
- package/dist/settings/settings.entity.d.ts.map +1 -0
- package/dist/settings/settings.entity.js +78 -0
- package/dist/settings/settings.entity.js.map +1 -0
- package/dist/settings/settings.enum.d.ts +10 -0
- package/dist/settings/settings.enum.d.ts.map +1 -0
- package/dist/settings/settings.enum.js +21 -0
- package/dist/settings/settings.enum.js.map +1 -0
- package/dist/shared/mock-data.d.ts +86 -0
- package/dist/shared/mock-data.d.ts.map +1 -0
- package/dist/shared/mock-data.js +138 -0
- package/dist/shared/mock-data.js.map +1 -0
- package/dist/shared/overlay-types.d.ts +34 -0
- package/dist/shared/overlay-types.d.ts.map +1 -0
- package/dist/shared/overlay-types.js +0 -0
- package/dist/tests/operations.test-spec.d.ts +10 -0
- package/dist/tests/operations.test-spec.d.ts.map +1 -0
- package/dist/tests/operations.test-spec.js +123 -0
- package/dist/tests/operations.test-spec.js.map +1 -0
- package/dist/ui/SaasDashboard.d.ts +7 -0
- package/dist/ui/SaasDashboard.d.ts.map +1 -0
- package/dist/ui/SaasDashboard.js +298 -0
- package/dist/ui/SaasDashboard.js.map +1 -0
- package/dist/ui/SaasProjectList.d.ts +14 -0
- package/dist/ui/SaasProjectList.d.ts.map +1 -0
- package/dist/ui/SaasProjectList.js +76 -0
- package/dist/ui/SaasProjectList.js.map +1 -0
- package/dist/ui/SaasSettingsPanel.d.ts +7 -0
- package/dist/ui/SaasSettingsPanel.d.ts.map +1 -0
- package/dist/ui/SaasSettingsPanel.js +138 -0
- package/dist/ui/SaasSettingsPanel.js.map +1 -0
- package/dist/ui/hooks/index.d.ts +3 -0
- package/dist/ui/hooks/index.js +6 -0
- package/dist/ui/hooks/useProjectList.d.ts +34 -0
- package/dist/ui/hooks/useProjectList.d.ts.map +1 -0
- package/dist/ui/hooks/useProjectList.js +75 -0
- package/dist/ui/hooks/useProjectList.js.map +1 -0
- package/dist/ui/hooks/useProjectMutations.d.ts +28 -0
- package/dist/ui/hooks/useProjectMutations.d.ts.map +1 -0
- package/dist/ui/hooks/useProjectMutations.js +146 -0
- package/dist/ui/hooks/useProjectMutations.js.map +1 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/modals/CreateProjectModal.d.ts +23 -0
- package/dist/ui/modals/CreateProjectModal.d.ts.map +1 -0
- package/dist/ui/modals/CreateProjectModal.js +139 -0
- package/dist/ui/modals/CreateProjectModal.js.map +1 -0
- package/dist/ui/modals/ProjectActionsModal.d.ts +38 -0
- package/dist/ui/modals/ProjectActionsModal.d.ts.map +1 -0
- package/dist/ui/modals/ProjectActionsModal.js +292 -0
- package/dist/ui/modals/ProjectActionsModal.js.map +1 -0
- package/dist/ui/modals/index.d.ts +3 -0
- package/dist/ui/modals/index.js +4 -0
- package/dist/ui/overlays/demo-overlays.d.ts +19 -0
- package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
- package/dist/ui/overlays/demo-overlays.js +70 -0
- package/dist/ui/overlays/demo-overlays.js.map +1 -0
- package/dist/ui/overlays/index.d.ts +2 -0
- package/dist/ui/overlays/index.js +3 -0
- package/dist/ui/renderers/index.d.ts +3 -0
- package/dist/ui/renderers/index.js +4 -0
- package/dist/ui/renderers/project-list.markdown.d.ts +31 -0
- package/dist/ui/renderers/project-list.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/project-list.markdown.js +148 -0
- package/dist/ui/renderers/project-list.markdown.js.map +1 -0
- package/dist/ui/renderers/project-list.renderer.d.ts +9 -0
- package/dist/ui/renderers/project-list.renderer.d.ts.map +1 -0
- package/dist/ui/renderers/project-list.renderer.js +17 -0
- package/dist/ui/renderers/project-list.renderer.js.map +1 -0
- package/example.ts +1 -0
- package/package.json +135 -0
- package/src/billing/billing.entity.ts +158 -0
- package/src/billing/billing.enum.ts +23 -0
- package/src/billing/billing.event.ts +108 -0
- package/src/billing/billing.handler.ts +137 -0
- package/src/billing/billing.operations.ts +187 -0
- package/src/billing/billing.presentation.ts +56 -0
- package/src/billing/billing.schema.ts +133 -0
- package/src/billing/index.ts +64 -0
- package/src/dashboard/dashboard.presentation.ts +56 -0
- package/src/dashboard/index.ts +8 -0
- package/src/docs/index.ts +1 -0
- package/src/docs/saas-boilerplate.docblock.ts +98 -0
- package/src/example.ts +38 -0
- package/src/handlers/index.ts +23 -0
- package/src/handlers/saas.handlers.ts +300 -0
- package/src/index.ts +76 -0
- package/src/presentations/index.ts +36 -0
- package/src/project/index.ts +66 -0
- package/src/project/project.entity.ts +93 -0
- package/src/project/project.enum.ts +22 -0
- package/src/project/project.event.ts +128 -0
- package/src/project/project.handler.ts +168 -0
- package/src/project/project.operations.ts +272 -0
- package/src/project/project.presentation.ts +58 -0
- package/src/project/project.schema.ts +147 -0
- package/src/saas-boilerplate.feature.ts +113 -0
- package/src/seeders/index.ts +28 -0
- package/src/settings/index.ts +9 -0
- package/src/settings/settings.entity.ts +89 -0
- package/src/settings/settings.enum.ts +11 -0
- package/src/shared/mock-data.ts +110 -0
- package/src/shared/overlay-types.ts +39 -0
- package/src/tests/operations.test-spec.ts +109 -0
- package/src/ui/SaasDashboard.tsx +325 -0
- package/src/ui/SaasProjectList.tsx +113 -0
- package/src/ui/SaasSettingsPanel.tsx +96 -0
- package/src/ui/hooks/index.ts +10 -0
- package/src/ui/hooks/useProjectList.ts +95 -0
- package/src/ui/hooks/useProjectMutations.ts +166 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/modals/CreateProjectModal.tsx +176 -0
- package/src/ui/modals/ProjectActionsModal.tsx +346 -0
- package/src/ui/modals/index.ts +2 -0
- package/src/ui/overlays/demo-overlays.ts +74 -0
- package/src/ui/overlays/index.ts +1 -0
- package/src/ui/renderers/index.ts +7 -0
- package/src/ui/renderers/project-list.markdown.ts +239 -0
- package/src/ui/renderers/project-list.renderer.tsx +22 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.js +7 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/SaasSettingsPanel.d.ts
|
|
4
|
+
declare function SaasSettingsPanel(): react_jsx_runtime1.JSX.Element;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { SaasSettingsPanel };
|
|
7
|
+
//# sourceMappingURL=SaasSettingsPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SaasSettingsPanel.d.ts","names":[],"sources":["../../src/ui/SaasSettingsPanel.tsx"],"sourcesContent":[],"mappings":";;;iBAQgB,iBAAA,CAAA,GAAiB,kBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Button } from "@contractspec/lib.design-system";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/ui/SaasSettingsPanel.tsx
|
|
8
|
+
/**
|
|
9
|
+
* SaaS Settings Panel - Organization and user settings
|
|
10
|
+
*/
|
|
11
|
+
function SaasSettingsPanel() {
|
|
12
|
+
const [orgName, setOrgName] = useState("Demo Organization");
|
|
13
|
+
const [timezone, setTimezone] = useState("UTC");
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
className: "space-y-6",
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ jsxs("div", {
|
|
18
|
+
className: "border-border bg-card rounded-xl border p-6",
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsx("h3", {
|
|
21
|
+
className: "mb-4 text-lg font-semibold",
|
|
22
|
+
children: "Organization Settings"
|
|
23
|
+
}),
|
|
24
|
+
/* @__PURE__ */ jsxs("div", {
|
|
25
|
+
className: "space-y-4",
|
|
26
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
27
|
+
htmlFor: "setting-org-name",
|
|
28
|
+
className: "block text-sm font-medium",
|
|
29
|
+
children: "Organization Name"
|
|
30
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
31
|
+
id: "setting-org-name",
|
|
32
|
+
type: "text",
|
|
33
|
+
value: orgName,
|
|
34
|
+
onChange: (e) => setOrgName(e.target.value),
|
|
35
|
+
className: "border-input bg-background mt-1 block w-full rounded-md border px-3 py-2"
|
|
36
|
+
})] }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
|
|
37
|
+
htmlFor: "setting-timezone",
|
|
38
|
+
className: "block text-sm font-medium",
|
|
39
|
+
children: "Default Timezone"
|
|
40
|
+
}), /* @__PURE__ */ jsxs("select", {
|
|
41
|
+
id: "setting-timezone",
|
|
42
|
+
value: timezone,
|
|
43
|
+
onChange: (e) => setTimezone(e.target.value),
|
|
44
|
+
className: "border-input bg-background mt-1 block w-full rounded-md border px-3 py-2",
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ jsx("option", {
|
|
47
|
+
value: "UTC",
|
|
48
|
+
children: "UTC"
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ jsx("option", {
|
|
51
|
+
value: "America/New_York",
|
|
52
|
+
children: "America/New_York"
|
|
53
|
+
}),
|
|
54
|
+
/* @__PURE__ */ jsx("option", {
|
|
55
|
+
value: "Europe/London",
|
|
56
|
+
children: "Europe/London"
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ jsx("option", {
|
|
59
|
+
value: "Asia/Tokyo",
|
|
60
|
+
children: "Asia/Tokyo"
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
})] })]
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ jsx("div", {
|
|
66
|
+
className: "mt-6",
|
|
67
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
68
|
+
variant: "default",
|
|
69
|
+
children: "Save Changes"
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
}),
|
|
74
|
+
/* @__PURE__ */ jsxs("div", {
|
|
75
|
+
className: "border-border bg-card rounded-xl border p-6",
|
|
76
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
77
|
+
className: "mb-4 text-lg font-semibold",
|
|
78
|
+
children: "Notifications"
|
|
79
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
80
|
+
className: "space-y-3",
|
|
81
|
+
children: [
|
|
82
|
+
{
|
|
83
|
+
label: "Email notifications",
|
|
84
|
+
defaultChecked: true
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
label: "Usage alerts",
|
|
88
|
+
defaultChecked: true
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
label: "Weekly digest",
|
|
92
|
+
defaultChecked: false
|
|
93
|
+
}
|
|
94
|
+
].map((item) => /* @__PURE__ */ jsxs("label", {
|
|
95
|
+
className: "flex items-center gap-3",
|
|
96
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
97
|
+
type: "checkbox",
|
|
98
|
+
defaultChecked: item.defaultChecked,
|
|
99
|
+
className: "border-input h-4 w-4 rounded"
|
|
100
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
101
|
+
className: "text-sm",
|
|
102
|
+
children: item.label
|
|
103
|
+
})]
|
|
104
|
+
}, item.label))
|
|
105
|
+
})]
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ jsxs("div", {
|
|
108
|
+
className: "rounded-xl border border-red-200 bg-red-50 p-6 dark:border-red-900 dark:bg-red-950/20",
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ jsx("h3", {
|
|
111
|
+
className: "mb-2 text-lg font-semibold text-red-700 dark:text-red-400",
|
|
112
|
+
children: "Danger Zone"
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ jsx("p", {
|
|
115
|
+
className: "mb-4 text-sm text-red-600 dark:text-red-300",
|
|
116
|
+
children: "These actions are irreversible. Please proceed with caution."
|
|
117
|
+
}),
|
|
118
|
+
/* @__PURE__ */ jsxs("div", {
|
|
119
|
+
className: "flex gap-3",
|
|
120
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
121
|
+
variant: "secondary",
|
|
122
|
+
size: "sm",
|
|
123
|
+
children: "Export Data"
|
|
124
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
125
|
+
variant: "secondary",
|
|
126
|
+
size: "sm",
|
|
127
|
+
children: "Delete Organization"
|
|
128
|
+
})]
|
|
129
|
+
})
|
|
130
|
+
]
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
//#endregion
|
|
137
|
+
export { SaasSettingsPanel };
|
|
138
|
+
//# sourceMappingURL=SaasSettingsPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SaasSettingsPanel.js","names":[],"sources":["../../src/ui/SaasSettingsPanel.tsx"],"sourcesContent":["'use client';\n\n/**\n * SaaS Settings Panel - Organization and user settings\n */\nimport { useState } from 'react';\nimport { Button } from '@contractspec/lib.design-system';\n\nexport function SaasSettingsPanel() {\n const [orgName, setOrgName] = useState('Demo Organization');\n const [timezone, setTimezone] = useState('UTC');\n\n return (\n <div className=\"space-y-6\">\n <div className=\"border-border bg-card rounded-xl border p-6\">\n <h3 className=\"mb-4 text-lg font-semibold\">Organization Settings</h3>\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"setting-org-name\"\n className=\"block text-sm font-medium\"\n >\n Organization Name\n </label>\n <input\n id=\"setting-org-name\"\n type=\"text\"\n value={orgName}\n onChange={(e) => setOrgName(e.target.value)}\n className=\"border-input bg-background mt-1 block w-full rounded-md border px-3 py-2\"\n />\n </div>\n <div>\n <label\n htmlFor=\"setting-timezone\"\n className=\"block text-sm font-medium\"\n >\n Default Timezone\n </label>\n <select\n id=\"setting-timezone\"\n value={timezone}\n onChange={(e) => setTimezone(e.target.value)}\n className=\"border-input bg-background mt-1 block w-full rounded-md border px-3 py-2\"\n >\n <option value=\"UTC\">UTC</option>\n <option value=\"America/New_York\">America/New_York</option>\n <option value=\"Europe/London\">Europe/London</option>\n <option value=\"Asia/Tokyo\">Asia/Tokyo</option>\n </select>\n </div>\n </div>\n <div className=\"mt-6\">\n <Button variant=\"default\">Save Changes</Button>\n </div>\n </div>\n\n <div className=\"border-border bg-card rounded-xl border p-6\">\n <h3 className=\"mb-4 text-lg font-semibold\">Notifications</h3>\n <div className=\"space-y-3\">\n {[\n { label: 'Email notifications', defaultChecked: true },\n { label: 'Usage alerts', defaultChecked: true },\n { label: 'Weekly digest', defaultChecked: false },\n ].map((item) => (\n <label key={item.label} className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n defaultChecked={item.defaultChecked}\n className=\"border-input h-4 w-4 rounded\"\n />\n <span className=\"text-sm\">{item.label}</span>\n </label>\n ))}\n </div>\n </div>\n\n <div className=\"rounded-xl border border-red-200 bg-red-50 p-6 dark:border-red-900 dark:bg-red-950/20\">\n <h3 className=\"mb-2 text-lg font-semibold text-red-700 dark:text-red-400\">\n Danger Zone\n </h3>\n <p className=\"mb-4 text-sm text-red-600 dark:text-red-300\">\n These actions are irreversible. Please proceed with caution.\n </p>\n <div className=\"flex gap-3\">\n <Button variant=\"secondary\" size=\"sm\">\n Export Data\n </Button>\n <Button variant=\"secondary\" size=\"sm\">\n Delete Organization\n </Button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAQA,SAAgB,oBAAoB;CAClC,MAAM,CAAC,SAAS,cAAc,SAAS,oBAAoB;CAC3D,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;AAE/C,QACE,qBAAC;EAAI,WAAU;;GACb,qBAAC;IAAI,WAAU;;KACb,oBAAC;MAAG,WAAU;gBAA6B;OAA0B;KACrE,qBAAC;MAAI,WAAU;iBACb,qBAAC,oBACC,oBAAC;OACC,SAAQ;OACR,WAAU;iBACX;QAEO,EACR,oBAAC;OACC,IAAG;OACH,MAAK;OACL,OAAO;OACP,WAAW,MAAM,WAAW,EAAE,OAAO,MAAM;OAC3C,WAAU;QACV,IACE,EACN,qBAAC,oBACC,oBAAC;OACC,SAAQ;OACR,WAAU;iBACX;QAEO,EACR,qBAAC;OACC,IAAG;OACH,OAAO;OACP,WAAW,MAAM,YAAY,EAAE,OAAO,MAAM;OAC5C,WAAU;;QAEV,oBAAC;SAAO,OAAM;mBAAM;UAAY;QAChC,oBAAC;SAAO,OAAM;mBAAmB;UAAyB;QAC1D,oBAAC;SAAO,OAAM;mBAAgB;UAAsB;QACpD,oBAAC;SAAO,OAAM;mBAAa;UAAmB;;QACvC,IACL;OACF;KACN,oBAAC;MAAI,WAAU;gBACb,oBAAC;OAAO,SAAQ;iBAAU;QAAqB;OAC3C;;KACF;GAEN,qBAAC;IAAI,WAAU;eACb,oBAAC;KAAG,WAAU;eAA6B;MAAkB,EAC7D,oBAAC;KAAI,WAAU;eACZ;MACC;OAAE,OAAO;OAAuB,gBAAgB;OAAM;MACtD;OAAE,OAAO;OAAgB,gBAAgB;OAAM;MAC/C;OAAE,OAAO;OAAiB,gBAAgB;OAAO;MAClD,CAAC,KAAK,SACL,qBAAC;MAAuB,WAAU;iBAChC,oBAAC;OACC,MAAK;OACL,gBAAgB,KAAK;OACrB,WAAU;QACV,EACF,oBAAC;OAAK,WAAU;iBAAW,KAAK;QAAa;QANnC,KAAK,MAOT,CACR;MACE;KACF;GAEN,qBAAC;IAAI,WAAU;;KACb,oBAAC;MAAG,WAAU;gBAA4D;OAErE;KACL,oBAAC;MAAE,WAAU;gBAA8C;OAEvD;KACJ,qBAAC;MAAI,WAAU;iBACb,oBAAC;OAAO,SAAQ;OAAY,MAAK;iBAAK;QAE7B,EACT,oBAAC;OAAO,SAAQ;OAAY,MAAK;iBAAK;QAE7B;OACL;;KACF;;GACF"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { UseProjectListOptions, useProjectList } from "./useProjectList.js";
|
|
2
|
+
import { UseProjectMutationsOptions, useProjectMutations } from "./useProjectMutations.js";
|
|
3
|
+
export { type UseProjectListOptions, type UseProjectMutationsOptions, useProjectList, useProjectMutations };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Project as Project$1, Subscription as Subscription$1 } from "../../handlers/saas.handlers.js";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/hooks/useProjectList.d.ts
|
|
4
|
+
type Project = Project$1;
|
|
5
|
+
type Subscription = Subscription$1;
|
|
6
|
+
interface ListProjectsOutput {
|
|
7
|
+
items: Project[];
|
|
8
|
+
total: number;
|
|
9
|
+
}
|
|
10
|
+
interface UseProjectListOptions {
|
|
11
|
+
status?: 'DRAFT' | 'ACTIVE' | 'ARCHIVED' | 'all';
|
|
12
|
+
search?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
}
|
|
15
|
+
declare function useProjectList(options?: UseProjectListOptions): {
|
|
16
|
+
data: ListProjectsOutput | null;
|
|
17
|
+
subscription: Subscription$1 | null;
|
|
18
|
+
loading: boolean;
|
|
19
|
+
error: Error | null;
|
|
20
|
+
stats: {
|
|
21
|
+
total: number;
|
|
22
|
+
activeCount: number;
|
|
23
|
+
draftCount: number;
|
|
24
|
+
projectLimit: number;
|
|
25
|
+
usagePercent: number;
|
|
26
|
+
} | null;
|
|
27
|
+
page: number;
|
|
28
|
+
refetch: () => Promise<void>;
|
|
29
|
+
nextPage: () => void;
|
|
30
|
+
prevPage: () => false | void;
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { ListProjectsOutput, Project, Subscription, UseProjectListOptions, useProjectList };
|
|
34
|
+
//# sourceMappingURL=useProjectList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProjectList.d.ts","names":[],"sources":["../../../src/ui/hooks/useProjectList.ts"],"sourcesContent":[],"mappings":";;;KAcY,OAAA,GAAU;KACV,YAAA,GAAe;AADf,UAGK,kBAAA,CAHmB;EACxB,KAAA,EAGH,OAHG,EAAY;EAEP,KAAA,EAAA,MAAA;AAKjB;AAMgB,UANC,qBAAA,CAMa;EAAU,MAAA,CAAA,EAAA,OAAA,GAAA,QAAA,GAAA,UAAA,GAAA,KAAA;;;;iBAAxB,cAAA,WAAwB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
3
|
+
|
|
4
|
+
//#region src/ui/hooks/useProjectList.ts
|
|
5
|
+
/**
|
|
6
|
+
* Hook for fetching and managing project list data
|
|
7
|
+
*
|
|
8
|
+
* Uses runtime-local database-backed handlers.
|
|
9
|
+
*/
|
|
10
|
+
function useProjectList(options = {}) {
|
|
11
|
+
const { handlers, projectId } = useTemplateRuntime();
|
|
12
|
+
const { saas } = handlers;
|
|
13
|
+
const [data, setData] = useState(null);
|
|
14
|
+
const [subscription, setSubscription] = useState(null);
|
|
15
|
+
const [loading, setLoading] = useState(true);
|
|
16
|
+
const [error, setError] = useState(null);
|
|
17
|
+
const [page, setPage] = useState(1);
|
|
18
|
+
const fetchData = useCallback(async () => {
|
|
19
|
+
setLoading(true);
|
|
20
|
+
setError(null);
|
|
21
|
+
try {
|
|
22
|
+
const [projectsResult, subscriptionResult] = await Promise.all([saas.listProjects({
|
|
23
|
+
projectId,
|
|
24
|
+
status: options.status === "all" ? void 0 : options.status,
|
|
25
|
+
search: options.search,
|
|
26
|
+
limit: options.limit ?? 20,
|
|
27
|
+
offset: (page - 1) * (options.limit ?? 20)
|
|
28
|
+
}), saas.getSubscription({ projectId })]);
|
|
29
|
+
setData({
|
|
30
|
+
items: projectsResult.items,
|
|
31
|
+
total: projectsResult.total
|
|
32
|
+
});
|
|
33
|
+
setSubscription(subscriptionResult);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
setError(err instanceof Error ? err : /* @__PURE__ */ new Error("Unknown error"));
|
|
36
|
+
} finally {
|
|
37
|
+
setLoading(false);
|
|
38
|
+
}
|
|
39
|
+
}, [
|
|
40
|
+
saas,
|
|
41
|
+
projectId,
|
|
42
|
+
options.status,
|
|
43
|
+
options.search,
|
|
44
|
+
options.limit,
|
|
45
|
+
page
|
|
46
|
+
]);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
fetchData();
|
|
49
|
+
}, [fetchData]);
|
|
50
|
+
return {
|
|
51
|
+
data,
|
|
52
|
+
subscription,
|
|
53
|
+
loading,
|
|
54
|
+
error,
|
|
55
|
+
stats: useMemo(() => {
|
|
56
|
+
if (!data) return null;
|
|
57
|
+
const items = data.items;
|
|
58
|
+
return {
|
|
59
|
+
total: data.total,
|
|
60
|
+
activeCount: items.filter((p) => p.status === "ACTIVE").length,
|
|
61
|
+
draftCount: items.filter((p) => p.status === "DRAFT").length,
|
|
62
|
+
projectLimit: 10,
|
|
63
|
+
usagePercent: Math.min(data.total / 10 * 100, 100)
|
|
64
|
+
};
|
|
65
|
+
}, [data]),
|
|
66
|
+
page,
|
|
67
|
+
refetch: fetchData,
|
|
68
|
+
nextPage: () => setPage((p) => p + 1),
|
|
69
|
+
prevPage: () => page > 1 && setPage((p) => p - 1)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { useProjectList };
|
|
75
|
+
//# sourceMappingURL=useProjectList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProjectList.js","names":[],"sources":["../../../src/ui/hooks/useProjectList.ts"],"sourcesContent":["/**\n * Hook for fetching and managing project list data\n *\n * Uses runtime-local database-backed handlers.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\nimport type {\n Project as RuntimeProject,\n Subscription as RuntimeSubscription,\n SaasHandlers,\n} from '../../handlers/saas.handlers';\n\n// Re-export types for convenience\nexport type Project = RuntimeProject;\nexport type Subscription = RuntimeSubscription;\n\nexport interface ListProjectsOutput {\n items: Project[];\n total: number;\n}\n\nexport interface UseProjectListOptions {\n status?: 'DRAFT' | 'ACTIVE' | 'ARCHIVED' | 'all';\n search?: string;\n limit?: number;\n}\n\nexport function useProjectList(options: UseProjectListOptions = {}) {\n const { handlers, projectId } = useTemplateRuntime<{ saas: SaasHandlers }>();\n const { saas } = handlers;\n\n const [data, setData] = useState<ListProjectsOutput | null>(null);\n const [subscription, setSubscription] = useState<Subscription | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [page, setPage] = useState(1);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n\n try {\n const [projectsResult, subscriptionResult] = await Promise.all([\n saas.listProjects({\n projectId,\n status: options.status === 'all' ? undefined : options.status,\n search: options.search,\n limit: options.limit ?? 20,\n offset: (page - 1) * (options.limit ?? 20),\n }),\n saas.getSubscription({ projectId }),\n ]);\n setData({\n items: projectsResult.items,\n total: projectsResult.total,\n });\n setSubscription(subscriptionResult);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'));\n } finally {\n setLoading(false);\n }\n }, [saas, projectId, options.status, options.search, options.limit, page]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n // Calculate stats\n const stats = useMemo(() => {\n if (!data) return null;\n const items = data.items;\n return {\n total: data.total,\n activeCount: items.filter((p) => p.status === 'ACTIVE').length,\n draftCount: items.filter((p) => p.status === 'DRAFT').length,\n // Subscription stats are optional since they may not be seeded\n projectLimit: 10, // Default limit for demo\n usagePercent: Math.min((data.total / 10) * 100, 100),\n };\n }, [data]);\n\n return {\n data,\n subscription,\n loading,\n error,\n stats,\n page,\n refetch: fetchData,\n nextPage: () => setPage((p) => p + 1),\n prevPage: () => page > 1 && setPage((p) => p - 1),\n };\n}\n"],"mappings":";;;;;;;;;AA4BA,SAAgB,eAAe,UAAiC,EAAE,EAAE;CAClE,MAAM,EAAE,UAAU,cAAc,oBAA4C;CAC5E,MAAM,EAAE,SAAS;CAEjB,MAAM,CAAC,MAAM,WAAW,SAAoC,KAAK;CACjE,MAAM,CAAC,cAAc,mBAAmB,SAA8B,KAAK;CAC3E,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CACtD,MAAM,CAAC,MAAM,WAAW,SAAS,EAAE;CAEnC,MAAM,YAAY,YAAY,YAAY;AACxC,aAAW,KAAK;AAChB,WAAS,KAAK;AAEd,MAAI;GACF,MAAM,CAAC,gBAAgB,sBAAsB,MAAM,QAAQ,IAAI,CAC7D,KAAK,aAAa;IAChB;IACA,QAAQ,QAAQ,WAAW,QAAQ,SAAY,QAAQ;IACvD,QAAQ,QAAQ;IAChB,OAAO,QAAQ,SAAS;IACxB,SAAS,OAAO,MAAM,QAAQ,SAAS;IACxC,CAAC,EACF,KAAK,gBAAgB,EAAE,WAAW,CAAC,CACpC,CAAC;AACF,WAAQ;IACN,OAAO,eAAe;IACtB,OAAO,eAAe;IACvB,CAAC;AACF,mBAAgB,mBAAmB;WAC5B,KAAK;AACZ,YAAS,eAAe,QAAQ,sBAAM,IAAI,MAAM,gBAAgB,CAAC;YACzD;AACR,cAAW,MAAM;;IAElB;EAAC;EAAM;EAAW,QAAQ;EAAQ,QAAQ;EAAQ,QAAQ;EAAO;EAAK,CAAC;AAE1E,iBAAgB;AACd,aAAW;IACV,CAAC,UAAU,CAAC;AAgBf,QAAO;EACL;EACA;EACA;EACA;EACA,OAlBY,cAAc;AAC1B,OAAI,CAAC,KAAM,QAAO;GAClB,MAAM,QAAQ,KAAK;AACnB,UAAO;IACL,OAAO,KAAK;IACZ,aAAa,MAAM,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;IACxD,YAAY,MAAM,QAAQ,MAAM,EAAE,WAAW,QAAQ,CAAC;IAEtD,cAAc;IACd,cAAc,KAAK,IAAK,KAAK,QAAQ,KAAM,KAAK,IAAI;IACrD;KACA,CAAC,KAAK,CAAC;EAQR;EACA,SAAS;EACT,gBAAgB,SAAS,MAAM,IAAI,EAAE;EACrC,gBAAgB,OAAO,KAAK,SAAS,MAAM,IAAI,EAAE;EAClD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CreateProjectInput, Project, UpdateProjectInput } from "../../handlers/saas.handlers.js";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/hooks/useProjectMutations.d.ts
|
|
4
|
+
interface MutationState<T> {
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: Error | null;
|
|
7
|
+
data: T | null;
|
|
8
|
+
}
|
|
9
|
+
interface UseProjectMutationsOptions {
|
|
10
|
+
onSuccess?: () => void;
|
|
11
|
+
onError?: (error: Error) => void;
|
|
12
|
+
}
|
|
13
|
+
declare function useProjectMutations(options?: UseProjectMutationsOptions): {
|
|
14
|
+
createProject: (input: CreateProjectInput) => Promise<Project | null>;
|
|
15
|
+
updateProject: (input: UpdateProjectInput) => Promise<Project | null>;
|
|
16
|
+
deleteProject: (id: string) => Promise<boolean>;
|
|
17
|
+
archiveProject: (id: string) => Promise<Project | null>;
|
|
18
|
+
activateProject: (id: string) => Promise<Project | null>;
|
|
19
|
+
createState: MutationState<Project>;
|
|
20
|
+
updateState: MutationState<Project>;
|
|
21
|
+
deleteState: MutationState<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { MutationState, UseProjectMutationsOptions, useProjectMutations };
|
|
28
|
+
//# sourceMappingURL=useProjectMutations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProjectMutations.d.ts","names":[],"sources":["../../../src/ui/hooks/useProjectMutations.ts"],"sourcesContent":[],"mappings":";;;UAiBiB;;EAAA,KAAA,EAER,KAFQ,GAAA,IAAa;EAMb,IAAA,EAHT,CAGS,GAAA,IAAA;AAKjB;AAA6C,UAL5B,0BAAA,CAK4B;EA4B3B,SAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAA6B,OAAA,CAAA,EAAA,CAAA,KAAA,EA/B3B,KA+B2B,EAAA,GAAA,IAAA;;AAyB7B,iBArDF,mBAAA,CAqDE,OAAA,CAAA,EArD2B,0BAqD3B,CAAA,EAAA;EAA6B,aAAA,EAAA,CAAA,KAAA,EAzB7B,kBAyB6B,EAAA,GAzBR,OAyBQ,CAzBA,OAyBA,GAAA,IAAA,CAAA;EAAR,aAAA,EAAA,CAAA,KAAA,EAArB,kBAAqB,EAAA,GAAA,OAAA,CAAQ,OAAR,GAAA,IAAA,CAAA;EAsBf,aAAA,EAAA,CAAA,EAAA,EAAA,MAAA,EAAA,GAAA,OAAA,CAAA,OAAA,CAAA;EA0BQ,cAAA,EAAA,CAAA,EAAA,EAAA,MAAA,EAAA,GAAR,OAAQ,CAAA,OAAA,GAAA,IAAA,CAAA;EAAR,eAAA,EAAA,CAAA,EAAA,EAAA,MAAA,EAAA,GAUA,OAVA,CAUQ,OAVR,GAAA,IAAA,CAAA;EAUQ,WAAA,eAAA,QAAA,CAAA;EAAR,WAAA,eAAA,QAAA,CAAA"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
3
|
+
|
|
4
|
+
//#region src/ui/hooks/useProjectMutations.ts
|
|
5
|
+
/**
|
|
6
|
+
* Hook for SaaS project mutations (commands)
|
|
7
|
+
*
|
|
8
|
+
* Uses runtime-local database-backed handlers for:
|
|
9
|
+
* - CreateProjectContract
|
|
10
|
+
* - UpdateProjectContract
|
|
11
|
+
* - DeleteProjectContract
|
|
12
|
+
*/
|
|
13
|
+
function useProjectMutations(options = {}) {
|
|
14
|
+
const { handlers, projectId } = useTemplateRuntime();
|
|
15
|
+
const { saas } = handlers;
|
|
16
|
+
const [createState, setCreateState] = useState({
|
|
17
|
+
loading: false,
|
|
18
|
+
error: null,
|
|
19
|
+
data: null
|
|
20
|
+
});
|
|
21
|
+
const [updateState, setUpdateState] = useState({
|
|
22
|
+
loading: false,
|
|
23
|
+
error: null,
|
|
24
|
+
data: null
|
|
25
|
+
});
|
|
26
|
+
const [deleteState, setDeleteState] = useState({
|
|
27
|
+
loading: false,
|
|
28
|
+
error: null,
|
|
29
|
+
data: null
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Create a new project
|
|
33
|
+
*/
|
|
34
|
+
const createProject = useCallback(async (input) => {
|
|
35
|
+
setCreateState({
|
|
36
|
+
loading: true,
|
|
37
|
+
error: null,
|
|
38
|
+
data: null
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
const result = await saas.createProject(input, {
|
|
42
|
+
projectId,
|
|
43
|
+
organizationId: "demo-org"
|
|
44
|
+
});
|
|
45
|
+
setCreateState({
|
|
46
|
+
loading: false,
|
|
47
|
+
error: null,
|
|
48
|
+
data: result
|
|
49
|
+
});
|
|
50
|
+
options.onSuccess?.();
|
|
51
|
+
return result;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const error = err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to create project");
|
|
54
|
+
setCreateState({
|
|
55
|
+
loading: false,
|
|
56
|
+
error,
|
|
57
|
+
data: null
|
|
58
|
+
});
|
|
59
|
+
options.onError?.(error);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}, [
|
|
63
|
+
saas,
|
|
64
|
+
projectId,
|
|
65
|
+
options
|
|
66
|
+
]);
|
|
67
|
+
/**
|
|
68
|
+
* Update a project
|
|
69
|
+
*/
|
|
70
|
+
const updateProject = useCallback(async (input) => {
|
|
71
|
+
setUpdateState({
|
|
72
|
+
loading: true,
|
|
73
|
+
error: null,
|
|
74
|
+
data: null
|
|
75
|
+
});
|
|
76
|
+
try {
|
|
77
|
+
const result = await saas.updateProject(input);
|
|
78
|
+
setUpdateState({
|
|
79
|
+
loading: false,
|
|
80
|
+
error: null,
|
|
81
|
+
data: result
|
|
82
|
+
});
|
|
83
|
+
options.onSuccess?.();
|
|
84
|
+
return result;
|
|
85
|
+
} catch (err) {
|
|
86
|
+
const error = err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to update project");
|
|
87
|
+
setUpdateState({
|
|
88
|
+
loading: false,
|
|
89
|
+
error,
|
|
90
|
+
data: null
|
|
91
|
+
});
|
|
92
|
+
options.onError?.(error);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}, [saas, options]);
|
|
96
|
+
return {
|
|
97
|
+
createProject,
|
|
98
|
+
updateProject,
|
|
99
|
+
deleteProject: useCallback(async (id) => {
|
|
100
|
+
setDeleteState({
|
|
101
|
+
loading: true,
|
|
102
|
+
error: null,
|
|
103
|
+
data: null
|
|
104
|
+
});
|
|
105
|
+
try {
|
|
106
|
+
await saas.deleteProject(id);
|
|
107
|
+
setDeleteState({
|
|
108
|
+
loading: false,
|
|
109
|
+
error: null,
|
|
110
|
+
data: { success: true }
|
|
111
|
+
});
|
|
112
|
+
options.onSuccess?.();
|
|
113
|
+
return true;
|
|
114
|
+
} catch (err) {
|
|
115
|
+
const error = err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to delete project");
|
|
116
|
+
setDeleteState({
|
|
117
|
+
loading: false,
|
|
118
|
+
error,
|
|
119
|
+
data: null
|
|
120
|
+
});
|
|
121
|
+
options.onError?.(error);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}, [saas, options]),
|
|
125
|
+
archiveProject: useCallback(async (id) => {
|
|
126
|
+
return updateProject({
|
|
127
|
+
id,
|
|
128
|
+
status: "ARCHIVED"
|
|
129
|
+
});
|
|
130
|
+
}, [updateProject]),
|
|
131
|
+
activateProject: useCallback(async (id) => {
|
|
132
|
+
return updateProject({
|
|
133
|
+
id,
|
|
134
|
+
status: "ACTIVE"
|
|
135
|
+
});
|
|
136
|
+
}, [updateProject]),
|
|
137
|
+
createState,
|
|
138
|
+
updateState,
|
|
139
|
+
deleteState,
|
|
140
|
+
isLoading: createState.loading || updateState.loading || deleteState.loading
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//#endregion
|
|
145
|
+
export { useProjectMutations };
|
|
146
|
+
//# sourceMappingURL=useProjectMutations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProjectMutations.js","names":[],"sources":["../../../src/ui/hooks/useProjectMutations.ts"],"sourcesContent":["/**\n * Hook for SaaS project mutations (commands)\n *\n * Uses runtime-local database-backed handlers for:\n * - CreateProjectContract\n * - UpdateProjectContract\n * - DeleteProjectContract\n */\nimport { useCallback, useState } from 'react';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\nimport type {\n CreateProjectInput,\n Project,\n UpdateProjectInput,\n SaasHandlers,\n} from '../../handlers/saas.handlers';\n\nexport interface MutationState<T> {\n loading: boolean;\n error: Error | null;\n data: T | null;\n}\n\nexport interface UseProjectMutationsOptions {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport function useProjectMutations(options: UseProjectMutationsOptions = {}) {\n const { handlers, projectId } = useTemplateRuntime<{ saas: SaasHandlers }>();\n const { saas } = handlers;\n\n const [createState, setCreateState] = useState<MutationState<Project>>({\n loading: false,\n error: null,\n data: null,\n });\n\n const [updateState, setUpdateState] = useState<MutationState<Project>>({\n loading: false,\n error: null,\n data: null,\n });\n\n const [deleteState, setDeleteState] = useState<\n MutationState<{ success: boolean }>\n >({\n loading: false,\n error: null,\n data: null,\n });\n\n /**\n * Create a new project\n */\n const createProject = useCallback(\n async (input: CreateProjectInput): Promise<Project | null> => {\n setCreateState({ loading: true, error: null, data: null });\n try {\n const result = await saas.createProject(input, {\n projectId,\n organizationId: 'demo-org',\n });\n setCreateState({ loading: false, error: null, data: result });\n options.onSuccess?.();\n return result;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to create project');\n setCreateState({ loading: false, error, data: null });\n options.onError?.(error);\n return null;\n }\n },\n [saas, projectId, options]\n );\n\n /**\n * Update a project\n */\n const updateProject = useCallback(\n async (input: UpdateProjectInput): Promise<Project | null> => {\n setUpdateState({ loading: true, error: null, data: null });\n try {\n const result = await saas.updateProject(input);\n setUpdateState({ loading: false, error: null, data: result });\n options.onSuccess?.();\n return result;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to update project');\n setUpdateState({ loading: false, error, data: null });\n options.onError?.(error);\n return null;\n }\n },\n [saas, options]\n );\n\n /**\n * Delete a project (soft delete)\n */\n const deleteProject = useCallback(\n async (id: string): Promise<boolean> => {\n setDeleteState({ loading: true, error: null, data: null });\n try {\n await saas.deleteProject(id);\n setDeleteState({\n loading: false,\n error: null,\n data: { success: true },\n });\n options.onSuccess?.();\n return true;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to delete project');\n setDeleteState({ loading: false, error, data: null });\n options.onError?.(error);\n return false;\n }\n },\n [saas, options]\n );\n\n /**\n * Archive a project (status change)\n */\n const archiveProject = useCallback(\n async (id: string): Promise<Project | null> => {\n return updateProject({ id, status: 'ARCHIVED' });\n },\n [updateProject]\n );\n\n /**\n * Activate a project (status change)\n */\n const activateProject = useCallback(\n async (id: string): Promise<Project | null> => {\n return updateProject({ id, status: 'ACTIVE' });\n },\n [updateProject]\n );\n\n return {\n // Mutations\n createProject,\n updateProject,\n deleteProject,\n archiveProject,\n activateProject,\n\n // State\n createState,\n updateState,\n deleteState,\n\n // Convenience\n isLoading:\n createState.loading || updateState.loading || deleteState.loading,\n };\n}\n\n// Note: Types are re-exported from the handlers package\n// Consumers should import types directly from '@contractspec/example.saas-boilerplate/handlers'\n"],"mappings":";;;;;;;;;;;;AA4BA,SAAgB,oBAAoB,UAAsC,EAAE,EAAE;CAC5E,MAAM,EAAE,UAAU,cAAc,oBAA4C;CAC5E,MAAM,EAAE,SAAS;CAEjB,MAAM,CAAC,aAAa,kBAAkB,SAAiC;EACrE,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;CAEF,MAAM,CAAC,aAAa,kBAAkB,SAAiC;EACrE,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;CAEF,MAAM,CAAC,aAAa,kBAAkB,SAEpC;EACA,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;;;;CAKF,MAAM,gBAAgB,YACpB,OAAO,UAAuD;AAC5D,iBAAe;GAAE,SAAS;GAAM,OAAO;GAAM,MAAM;GAAM,CAAC;AAC1D,MAAI;GACF,MAAM,SAAS,MAAM,KAAK,cAAc,OAAO;IAC7C;IACA,gBAAgB;IACjB,CAAC;AACF,kBAAe;IAAE,SAAS;IAAO,OAAO;IAAM,MAAM;IAAQ,CAAC;AAC7D,WAAQ,aAAa;AACrB,UAAO;WACA,KAAK;GACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,2BAA2B;AACpE,kBAAe;IAAE,SAAS;IAAO;IAAO,MAAM;IAAM,CAAC;AACrD,WAAQ,UAAU,MAAM;AACxB,UAAO;;IAGX;EAAC;EAAM;EAAW;EAAQ,CAC3B;;;;CAKD,MAAM,gBAAgB,YACpB,OAAO,UAAuD;AAC5D,iBAAe;GAAE,SAAS;GAAM,OAAO;GAAM,MAAM;GAAM,CAAC;AAC1D,MAAI;GACF,MAAM,SAAS,MAAM,KAAK,cAAc,MAAM;AAC9C,kBAAe;IAAE,SAAS;IAAO,OAAO;IAAM,MAAM;IAAQ,CAAC;AAC7D,WAAQ,aAAa;AACrB,UAAO;WACA,KAAK;GACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,2BAA2B;AACpE,kBAAe;IAAE,SAAS;IAAO;IAAO,MAAM;IAAM,CAAC;AACrD,WAAQ,UAAU,MAAM;AACxB,UAAO;;IAGX,CAAC,MAAM,QAAQ,CAChB;AAgDD,QAAO;EAEL;EACA;EACA,eA/CoB,YACpB,OAAO,OAAiC;AACtC,kBAAe;IAAE,SAAS;IAAM,OAAO;IAAM,MAAM;IAAM,CAAC;AAC1D,OAAI;AACF,UAAM,KAAK,cAAc,GAAG;AAC5B,mBAAe;KACb,SAAS;KACT,OAAO;KACP,MAAM,EAAE,SAAS,MAAM;KACxB,CAAC;AACF,YAAQ,aAAa;AACrB,WAAO;YACA,KAAK;IACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,2BAA2B;AACpE,mBAAe;KAAE,SAAS;KAAO;KAAO,MAAM;KAAM,CAAC;AACrD,YAAQ,UAAU,MAAM;AACxB,WAAO;;KAGX,CAAC,MAAM,QAAQ,CAChB;EA2BC,gBAtBqB,YACrB,OAAO,OAAwC;AAC7C,UAAO,cAAc;IAAE;IAAI,QAAQ;IAAY,CAAC;KAElD,CAAC,cAAc,CAChB;EAkBC,iBAbsB,YACtB,OAAO,OAAwC;AAC7C,UAAO,cAAc;IAAE;IAAI,QAAQ;IAAU,CAAC;KAEhD,CAAC,cAAc,CAChB;EAWC;EACA;EACA;EAGA,WACE,YAAY,WAAW,YAAY,WAAW,YAAY;EAC7D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SaasDashboard } from "./SaasDashboard.js";
|
|
2
|
+
import { SaasProjectList } from "./SaasProjectList.js";
|
|
3
|
+
import { SaasSettingsPanel } from "./SaasSettingsPanel.js";
|
|
4
|
+
import { CreateProjectModal } from "./modals/CreateProjectModal.js";
|
|
5
|
+
import { ProjectActionsModal } from "./modals/ProjectActionsModal.js";
|
|
6
|
+
import "./modals/index.js";
|
|
7
|
+
import { UseProjectListOptions, useProjectList } from "./hooks/useProjectList.js";
|
|
8
|
+
import { UseProjectMutationsOptions, useProjectMutations } from "./hooks/useProjectMutations.js";
|
|
9
|
+
import "./hooks/index.js";
|
|
10
|
+
import { projectListReactRenderer } from "./renderers/project-list.renderer.js";
|
|
11
|
+
import { projectListMarkdownRenderer, saasBillingMarkdownRenderer, saasDashboardMarkdownRenderer } from "./renderers/project-list.markdown.js";
|
|
12
|
+
import "./renderers/index.js";
|
|
13
|
+
import { saasDemoOverlay, saasFreeUserOverlay, saasOverlays } from "./overlays/demo-overlays.js";
|
|
14
|
+
export { CreateProjectModal, ProjectActionsModal, SaasDashboard, SaasProjectList, SaasSettingsPanel, UseProjectListOptions, UseProjectMutationsOptions, projectListMarkdownRenderer, projectListReactRenderer, saasBillingMarkdownRenderer, saasDashboardMarkdownRenderer, saasDemoOverlay, saasFreeUserOverlay, saasOverlays, useProjectList, useProjectMutations };
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useProjectList } from "./hooks/useProjectList.js";
|
|
2
|
+
import { useProjectMutations } from "./hooks/useProjectMutations.js";
|
|
3
|
+
import { CreateProjectModal } from "./modals/CreateProjectModal.js";
|
|
4
|
+
import { ProjectActionsModal } from "./modals/ProjectActionsModal.js";
|
|
5
|
+
import { SaasDashboard } from "./SaasDashboard.js";
|
|
6
|
+
import { SaasProjectList } from "./SaasProjectList.js";
|
|
7
|
+
import { SaasSettingsPanel } from "./SaasSettingsPanel.js";
|
|
8
|
+
import "./modals/index.js";
|
|
9
|
+
import "./hooks/index.js";
|
|
10
|
+
import { projectListReactRenderer } from "./renderers/project-list.renderer.js";
|
|
11
|
+
import { projectListMarkdownRenderer, saasBillingMarkdownRenderer, saasDashboardMarkdownRenderer } from "./renderers/project-list.markdown.js";
|
|
12
|
+
import "./renderers/index.js";
|
|
13
|
+
import { saasDemoOverlay, saasFreeUserOverlay, saasOverlays } from "./overlays/demo-overlays.js";
|
|
14
|
+
|
|
15
|
+
export { CreateProjectModal, ProjectActionsModal, SaasDashboard, SaasProjectList, SaasSettingsPanel, projectListMarkdownRenderer, projectListReactRenderer, saasBillingMarkdownRenderer, saasDashboardMarkdownRenderer, saasDemoOverlay, saasFreeUserOverlay, saasOverlays, useProjectList, useProjectMutations };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime2 from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/modals/CreateProjectModal.d.ts
|
|
4
|
+
interface CreateProjectInput {
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
tier: 'FREE' | 'PRO' | 'ENTERPRISE';
|
|
8
|
+
}
|
|
9
|
+
interface CreateProjectModalProps {
|
|
10
|
+
isOpen: boolean;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
onSubmit: (input: CreateProjectInput) => Promise<void>;
|
|
13
|
+
isLoading?: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare function CreateProjectModal({
|
|
16
|
+
isOpen,
|
|
17
|
+
onClose,
|
|
18
|
+
onSubmit,
|
|
19
|
+
isLoading
|
|
20
|
+
}: CreateProjectModalProps): react_jsx_runtime2.JSX.Element | null;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { CreateProjectInput, CreateProjectModal };
|
|
23
|
+
//# sourceMappingURL=CreateProjectModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CreateProjectModal.d.ts","names":[],"sources":["../../../src/ui/modals/CreateProjectModal.tsx"],"sourcesContent":[],"mappings":";;;UAWiB,kBAAA;;;EAAA,IAAA,EAAA,MAAA,GAAA,KAAA,GAAkB,YAAA;AAIlC;AAeD,UAbU,uBAAA,CAawB;EAChC,MAAA,EAAA,OAAA;EACA,OAAA,EAAA,GAAA,GAAA,IAAA;EACA,QAAA,EAAA,CAAA,KAAA,EAbkB,kBAalB,EAAA,GAbyC,OAazC,CAAA,IAAA,CAAA;EACA,SAAA,CAAA,EAAA,OAAA;;AACwB,iBALV,kBAAA,CAKU;EAAA,MAAA;EAAA,OAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAAvB,uBAAuB,CAAA,EAAA,kBAAA,CAAA,GAAA,CAAA,OAAA,GAAA,IAAA"}
|