@growflowstudio/growflowbooking-admin-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1569 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BillingPlansPage: () => BillingPlansPage,
34
+ BillingSubscriptionsPage: () => BillingSubscriptionsPage,
35
+ BookingAdminProvider: () => BookingAdminProvider,
36
+ CustomerFormDialog: () => CustomerFormDialog,
37
+ CustomersPage: () => CustomersPage,
38
+ CustomersTable: () => CustomersTable,
39
+ DeleteConfirmDialog: () => DeleteConfirmDialog,
40
+ FilterBar: () => FilterBar,
41
+ Pagination: () => Pagination,
42
+ SettingsPage: () => SettingsPage,
43
+ SkeletonRows: () => SkeletonRows,
44
+ StatusBadge: () => StatusBadge,
45
+ SubscriptionPlanFormDialog: () => SubscriptionPlanFormDialog,
46
+ SubscriptionPlansPage: () => SubscriptionPlansPage,
47
+ SubscriptionPlansTable: () => SubscriptionPlansTable,
48
+ TenantDetailDialog: () => TenantDetailDialog,
49
+ TenantFormDialog: () => TenantFormDialog,
50
+ TenantsPage: () => TenantsPage,
51
+ TenantsTable: () => TenantsTable,
52
+ getBookingNavItems: () => getBookingNavItems,
53
+ useBookingAdminConfig: () => useBookingAdminConfig,
54
+ useEnabledModules: () => useEnabledModules
55
+ });
56
+ module.exports = __toCommonJS(index_exports);
57
+
58
+ // src/provider.tsx
59
+ var import_react = __toESM(require("react"));
60
+ var import_growflowbooking_admin_core = require("@growflowstudio/growflowbooking-admin-core");
61
+ var import_jsx_runtime = require("react/jsx-runtime");
62
+ var DEFAULT_MODULES = {
63
+ tenants: true,
64
+ customers: true,
65
+ subscriptionPlans: true,
66
+ billingPlans: true,
67
+ billingSubscriptions: true,
68
+ settings: true
69
+ };
70
+ var BookingAdminConfigContext = import_react.default.createContext(null);
71
+ function useBookingAdminConfig() {
72
+ const config = import_react.default.useContext(BookingAdminConfigContext);
73
+ if (!config) {
74
+ throw new Error(
75
+ "useBookingAdminConfig must be used within a BookingAdminProvider."
76
+ );
77
+ }
78
+ return config;
79
+ }
80
+ function useEnabledModules() {
81
+ const config = useBookingAdminConfig();
82
+ return { ...DEFAULT_MODULES, ...config.modules };
83
+ }
84
+ function BookingAdminProvider({ config, children }) {
85
+ const client = (0, import_react.useMemo)(
86
+ () => (0, import_growflowbooking_admin_core.createBookingAdminClient)({
87
+ basePath: config.basePath,
88
+ fetcher: config.fetcher
89
+ }),
90
+ [config.basePath, config.fetcher]
91
+ );
92
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BookingAdminConfigContext.Provider, { value: config, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_growflowbooking_admin_core.BookingAdminClientContext.Provider, { value: client, children }) });
93
+ }
94
+
95
+ // src/pages/TenantsPage.tsx
96
+ var import_react3 = require("react");
97
+ var import_sonner = require("sonner");
98
+ var import_lucide_react7 = require("lucide-react");
99
+ var import_growflowbooking_admin_core5 = require("@growflowstudio/growflowbooking-admin-core");
100
+
101
+ // src/components/tenants/TenantsTable.tsx
102
+ var import_lucide_react = require("lucide-react");
103
+
104
+ // src/primitives/utils.ts
105
+ var import_clsx = require("clsx");
106
+ var import_tailwind_merge = require("tailwind-merge");
107
+ function cn(...inputs) {
108
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
109
+ }
110
+
111
+ // src/components/shared/StatusBadge.tsx
112
+ var import_jsx_runtime2 = require("react/jsx-runtime");
113
+ function StatusBadge({ label, colorClass, className }) {
114
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
115
+ "span",
116
+ {
117
+ className: cn(
118
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors",
119
+ colorClass,
120
+ className
121
+ ),
122
+ children: label
123
+ }
124
+ );
125
+ }
126
+
127
+ // src/components/shared/SkeletonRows.tsx
128
+ var import_jsx_runtime3 = require("react/jsx-runtime");
129
+ function SkeletonRows({ rows = 5, columns = 1 }) {
130
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { colSpan: columns, className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "h-10 w-full animate-pulse rounded-md bg-muted" }) }) }, i)) });
131
+ }
132
+
133
+ // src/components/tenants/TenantsTable.tsx
134
+ var import_growflowbooking_admin_core2 = require("@growflowstudio/growflowbooking-admin-core");
135
+ var import_jsx_runtime4 = require("react/jsx-runtime");
136
+ function TenantsTable({ tenants, isLoading, onEdit, onDelete, onView }) {
137
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "w-full", children: [
138
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "border-b", children: [
139
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Nome" }),
140
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Slug" }),
141
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Piano" }),
142
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stato" }),
143
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Email" }),
144
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Creato" }),
145
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
146
+ ] }) }),
147
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SkeletonRows, { rows: 5, columns: 7 }) : tenants.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { colSpan: 7, className: "h-24 text-center text-muted-foreground", children: "Nessun tenant trovato." }) }) : tenants.map((tenant) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "border-b hover:bg-muted/50 cursor-pointer", onClick: () => onView(tenant), children: [
148
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 font-medium", children: tenant.name }),
149
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { className: "text-xs bg-muted px-1.5 py-0.5 rounded", children: tenant.slug }) }),
150
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StatusBadge, { label: import_growflowbooking_admin_core2.tenantPlanLabels[tenant.plan], colorClass: import_growflowbooking_admin_core2.tenantPlanColors[tenant.plan] }) }),
151
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
152
+ StatusBadge,
153
+ {
154
+ label: tenant.is_active ? import_growflowbooking_admin_core2.tenantStatusLabels.active : import_growflowbooking_admin_core2.tenantStatusLabels.inactive,
155
+ colorClass: tenant.is_active ? import_growflowbooking_admin_core2.tenantStatusColors.active : import_growflowbooking_admin_core2.tenantStatusColors.inactive
156
+ }
157
+ ) }),
158
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 text-sm text-muted-foreground", children: tenant.owner_email }),
159
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 text-sm text-muted-foreground", children: (0, import_growflowbooking_admin_core2.formatDate)(tenant.created_at) }),
160
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex justify-end gap-1", onClick: (e) => e.stopPropagation(), children: [
161
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm h-8 w-8 hover:bg-accent", onClick: () => onEdit(tenant), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Pencil, { className: "w-4 h-4" }) }),
162
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm h-8 w-8 hover:bg-accent text-destructive", onClick: () => onDelete(tenant), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Trash2, { className: "w-4 h-4" }) })
163
+ ] }) })
164
+ ] }, tenant.id)) })
165
+ ] });
166
+ }
167
+
168
+ // src/components/tenants/TenantFormDialog.tsx
169
+ var import_react2 = require("react");
170
+ var import_lucide_react2 = require("lucide-react");
171
+ var import_growflowbooking_admin_core3 = require("@growflowstudio/growflowbooking-admin-core");
172
+ var import_jsx_runtime5 = require("react/jsx-runtime");
173
+ function TenantFormDialog({ isOpen, onOpenChange, tenant, onSubmit, isPending }) {
174
+ const isEdit = !!tenant;
175
+ const [name, setName] = (0, import_react2.useState)("");
176
+ const [slug, setSlug] = (0, import_react2.useState)("");
177
+ const [ownerEmail, setOwnerEmail] = (0, import_react2.useState)("");
178
+ const [plan, setPlan] = (0, import_react2.useState)("free");
179
+ const [domain, setDomain] = (0, import_react2.useState)("");
180
+ const [errors, setErrors] = (0, import_react2.useState)({});
181
+ (0, import_react2.useEffect)(() => {
182
+ if (isOpen) {
183
+ if (tenant) {
184
+ setName(tenant.name);
185
+ setSlug(tenant.slug);
186
+ setOwnerEmail(tenant.owner_email);
187
+ setPlan(tenant.plan);
188
+ setDomain(tenant.domain || "");
189
+ } else {
190
+ setName("");
191
+ setSlug("");
192
+ setOwnerEmail("");
193
+ setPlan("free");
194
+ setDomain("");
195
+ }
196
+ setErrors({});
197
+ }
198
+ }, [isOpen, tenant]);
199
+ const handleSubmit = () => {
200
+ const errs = {};
201
+ const nameErr = (0, import_growflowbooking_admin_core3.validateRequired)(name, "Il nome");
202
+ if (nameErr) errs.name = nameErr;
203
+ if (!isEdit) {
204
+ const slugErr = (0, import_growflowbooking_admin_core3.validateSlug)(slug);
205
+ if (slugErr) errs.slug = slugErr;
206
+ }
207
+ const emailErr = (0, import_growflowbooking_admin_core3.validateEmail)(ownerEmail);
208
+ if (emailErr) errs.ownerEmail = emailErr;
209
+ setErrors(errs);
210
+ if (Object.keys(errs).length > 0) return;
211
+ if (isEdit) {
212
+ onSubmit({ name, owner_email: ownerEmail, domain: domain || void 0 });
213
+ } else {
214
+ onSubmit({ name, slug, owner_email: ownerEmail, plan, domain: domain || void 0 });
215
+ }
216
+ };
217
+ if (!isOpen) return null;
218
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
220
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative z-50 w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-lg border bg-background p-6 shadow-lg", children: [
221
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
222
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { className: "text-lg font-semibold", children: isEdit ? "Modifica Tenant" : "Nuovo Tenant" }),
223
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm text-muted-foreground", children: isEdit ? "Modifica i dati del tenant selezionato" : "Crea un nuovo tenant per la piattaforma di booking" })
224
+ ] }),
225
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid gap-4 py-4", children: [
226
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-2", children: [
227
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-sm font-medium leading-none", children: "Nome *" }),
228
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: name, onChange: (e) => setName(e.target.value), placeholder: "Acme Salon" }),
229
+ errors.name && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-destructive", children: errors.name })
230
+ ] }),
231
+ !isEdit && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-2", children: [
232
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-sm font-medium leading-none", children: "Slug *" }),
233
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: slug, onChange: (e) => setSlug(e.target.value), placeholder: "acme-salon" }),
234
+ errors.slug && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-destructive", children: errors.slug })
235
+ ] }),
236
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-2", children: [
237
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-sm font-medium leading-none", children: "Email Proprietario *" }),
238
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "email", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: ownerEmail, onChange: (e) => setOwnerEmail(e.target.value), placeholder: "owner@example.com" }),
239
+ errors.ownerEmail && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-destructive", children: errors.ownerEmail })
240
+ ] }),
241
+ !isEdit && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-2", children: [
242
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-sm font-medium leading-none", children: "Piano" }),
243
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: plan, onChange: (e) => setPlan(e.target.value), children: [
244
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "free", children: "Free" }),
245
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "starter", children: "Starter" }),
246
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "professional", children: "Professional" }),
247
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "enterprise", children: "Enterprise" })
248
+ ] })
249
+ ] }),
250
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-2", children: [
251
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-sm font-medium leading-none", children: "Dominio" }),
252
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: domain, onChange: (e) => setDomain(e.target.value), placeholder: "salon.example.com" })
253
+ ] })
254
+ ] }),
255
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
256
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 border border-input bg-background hover:bg-accent mt-2 sm:mt-0", onClick: () => onOpenChange(false), children: "Annulla" }),
257
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50", onClick: handleSubmit, disabled: isPending, children: [
258
+ isPending && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
259
+ isEdit ? "Salva Modifiche" : "Crea Tenant"
260
+ ] })
261
+ ] })
262
+ ] })
263
+ ] });
264
+ }
265
+
266
+ // src/components/tenants/TenantDetailDialog.tsx
267
+ var import_lucide_react3 = require("lucide-react");
268
+ var import_growflowbooking_admin_core4 = require("@growflowstudio/growflowbooking-admin-core");
269
+ var import_jsx_runtime6 = require("react/jsx-runtime");
270
+ function TenantDetailDialog({ isOpen, onOpenChange, tenant, isLoading }) {
271
+ if (!isOpen) return null;
272
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
273
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
274
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative z-50 w-full max-w-2xl max-h-[90vh] overflow-y-auto rounded-lg border bg-background p-6 shadow-lg", children: [
275
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between pb-4", children: [
276
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "text-lg font-semibold", children: "Dettaglio Tenant" }),
277
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "rounded-md h-8 w-8 inline-flex items-center justify-center hover:bg-accent", onClick: () => onOpenChange(false), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.X, { className: "w-4 h-4" }) })
278
+ ] }),
279
+ isLoading || !tenant ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "space-y-4", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-6 w-full animate-pulse rounded-md bg-muted" }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-6", children: [
280
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
281
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
282
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Nome" }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "font-medium", children: tenant.name })
284
+ ] }),
285
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
286
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Slug" }),
287
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "text-xs bg-muted px-1.5 py-0.5 rounded", children: tenant.slug }) })
288
+ ] }),
289
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
290
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Piano" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatusBadge, { label: import_growflowbooking_admin_core4.tenantPlanLabels[tenant.plan], colorClass: import_growflowbooking_admin_core4.tenantPlanColors[tenant.plan] }) })
292
+ ] }),
293
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
294
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Stato" }),
295
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatusBadge, { label: tenant.is_active ? import_growflowbooking_admin_core4.tenantStatusLabels.active : import_growflowbooking_admin_core4.tenantStatusLabels.inactive, colorClass: tenant.is_active ? import_growflowbooking_admin_core4.tenantStatusColors.active : import_growflowbooking_admin_core4.tenantStatusColors.inactive }) })
296
+ ] }),
297
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
298
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Email" }),
299
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm", children: tenant.owner_email })
300
+ ] }),
301
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Dominio" }),
303
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm", children: tenant.domain || "-" })
304
+ ] }),
305
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
306
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Creato" }),
307
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm", children: (0, import_growflowbooking_admin_core4.formatDate)(tenant.created_at) })
308
+ ] }),
309
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
310
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-muted-foreground", children: "Aggiornato" }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm", children: (0, import_growflowbooking_admin_core4.formatDate)(tenant.updated_at) })
312
+ ] })
313
+ ] }),
314
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "border-t pt-4", children: [
315
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: "font-medium mb-3", children: "Statistiche" }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-3 gap-4", children: [
317
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-lg border p-3 text-center", children: [
318
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-2xl font-bold", children: tenant.services_count }),
319
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground", children: "Servizi" })
320
+ ] }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-lg border p-3 text-center", children: [
322
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-2xl font-bold", children: tenant.staff_count }),
323
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground", children: "Staff" })
324
+ ] }),
325
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-lg border p-3 text-center", children: [
326
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-2xl font-bold", children: tenant.locations_count }),
327
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground", children: "Sedi" })
328
+ ] }),
329
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-lg border p-3 text-center", children: [
330
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-2xl font-bold", children: tenant.customers_count }),
331
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground", children: "Clienti" })
332
+ ] }),
333
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-lg border p-3 text-center", children: [
334
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-2xl font-bold", children: tenant.bookings_count }),
335
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground", children: "Prenotazioni" })
336
+ ] })
337
+ ] })
338
+ ] }),
339
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "border-t pt-4", children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: "font-medium mb-3", children: "Limiti" }),
341
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-3 gap-4 text-sm", children: [
342
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
343
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-muted-foreground", children: "Max Servizi:" }),
344
+ " ",
345
+ tenant.max_services === -1 ? "Illimitati" : tenant.max_services
346
+ ] }),
347
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
348
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-muted-foreground", children: "Max Staff:" }),
349
+ " ",
350
+ tenant.max_staff === -1 ? "Illimitati" : tenant.max_staff
351
+ ] }),
352
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
353
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-muted-foreground", children: "Max Sedi:" }),
354
+ " ",
355
+ tenant.max_locations === -1 ? "Illimitate" : tenant.max_locations
356
+ ] })
357
+ ] })
358
+ ] })
359
+ ] })
360
+ ] })
361
+ ] });
362
+ }
363
+
364
+ // src/components/shared/DeleteConfirmDialog.tsx
365
+ var import_lucide_react4 = require("lucide-react");
366
+ var import_jsx_runtime7 = require("react/jsx-runtime");
367
+ function DeleteConfirmDialog({
368
+ isOpen,
369
+ onOpenChange,
370
+ title = "Sei sicuro?",
371
+ description,
372
+ onConfirm,
373
+ isDeleting,
374
+ confirmLabel = "Elimina",
375
+ cancelLabel = "Annulla"
376
+ }) {
377
+ if (!isOpen) return null;
378
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
379
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
380
+ "div",
381
+ {
382
+ className: "fixed inset-0 bg-black/80",
383
+ onClick: () => onOpenChange(false)
384
+ }
385
+ ),
386
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
387
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col space-y-2 text-center sm:text-left", children: [
388
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "text-lg font-semibold", children: title }),
389
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-muted-foreground", children: description })
390
+ ] }),
391
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 mt-4", children: [
392
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
393
+ "button",
394
+ {
395
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 border border-input bg-background hover:bg-accent hover:text-accent-foreground mt-2 sm:mt-0",
396
+ onClick: () => onOpenChange(false),
397
+ children: cancelLabel
398
+ }
399
+ ),
400
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
401
+ "button",
402
+ {
403
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-destructive text-destructive-foreground hover:bg-destructive/90",
404
+ onClick: onConfirm,
405
+ disabled: isDeleting,
406
+ children: [
407
+ isDeleting && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
408
+ confirmLabel
409
+ ]
410
+ }
411
+ )
412
+ ] })
413
+ ] })
414
+ ] });
415
+ }
416
+
417
+ // src/components/shared/FilterBar.tsx
418
+ var import_lucide_react5 = require("lucide-react");
419
+ var import_jsx_runtime8 = require("react/jsx-runtime");
420
+ function FilterBar({
421
+ searchPlaceholder = "Cerca...",
422
+ searchValue,
423
+ onSearchChange,
424
+ statusFilter,
425
+ onStatusFilterChange,
426
+ statusOptions,
427
+ onRefresh
428
+ }) {
429
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "p-6 pt-6", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col sm:flex-row gap-4", children: [
430
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative flex-1", children: [
431
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" }),
432
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
433
+ "input",
434
+ {
435
+ className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 pl-9",
436
+ placeholder: searchPlaceholder,
437
+ value: searchValue,
438
+ onChange: (e) => onSearchChange(e.target.value)
439
+ }
440
+ )
441
+ ] }),
442
+ statusOptions && onStatusFilterChange && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
443
+ "select",
444
+ {
445
+ className: "flex h-10 w-[180px] rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
446
+ value: statusFilter || "all",
447
+ onChange: (e) => onStatusFilterChange(e.target.value),
448
+ children: statusOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
449
+ }
450
+ ),
451
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
452
+ "button",
453
+ {
454
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 border border-input bg-background hover:bg-accent hover:text-accent-foreground",
455
+ onClick: onRefresh,
456
+ children: [
457
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.RefreshCw, { className: "w-4 h-4 mr-2" }),
458
+ "Aggiorna"
459
+ ]
460
+ }
461
+ )
462
+ ] }) }) });
463
+ }
464
+
465
+ // src/components/shared/Pagination.tsx
466
+ var import_lucide_react6 = require("lucide-react");
467
+ var import_jsx_runtime9 = require("react/jsx-runtime");
468
+ function Pagination({ page, pageSize, total, onPageChange }) {
469
+ const totalPages = Math.ceil(total / pageSize);
470
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between items-center", children: [
471
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-sm text-muted-foreground", children: total > 0 ? `${(page - 1) * pageSize + 1}-${Math.min(page * pageSize, total)} di ${total}` : "Nessun risultato" }),
472
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
473
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
474
+ "button",
475
+ {
476
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 border border-input bg-background hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:pointer-events-none",
477
+ onClick: () => onPageChange(page - 1),
478
+ disabled: page <= 1,
479
+ children: [
480
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react6.ChevronLeft, { className: "w-4 h-4 mr-1" }),
481
+ "Precedente"
482
+ ]
483
+ }
484
+ ),
485
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
486
+ "button",
487
+ {
488
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 border border-input bg-background hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:pointer-events-none",
489
+ onClick: () => onPageChange(page + 1),
490
+ disabled: page >= totalPages,
491
+ children: [
492
+ "Successiva",
493
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react6.ChevronRight, { className: "w-4 h-4 ml-1" })
494
+ ]
495
+ }
496
+ )
497
+ ] })
498
+ ] });
499
+ }
500
+
501
+ // src/pages/TenantsPage.tsx
502
+ var import_jsx_runtime10 = require("react/jsx-runtime");
503
+ function TenantsPage({ wrapper: Wrapper, header }) {
504
+ const [search, setSearch] = (0, import_react3.useState)("");
505
+ const [planFilter, setPlanFilter] = (0, import_react3.useState)("all");
506
+ const [page, setPage] = (0, import_react3.useState)(1);
507
+ const pageSize = 20;
508
+ const [showForm, setShowForm] = (0, import_react3.useState)(false);
509
+ const [showDelete, setShowDelete] = (0, import_react3.useState)(false);
510
+ const [showDetail, setShowDetail] = (0, import_react3.useState)(false);
511
+ const [selectedTenant, setSelectedTenant] = (0, import_react3.useState)(null);
512
+ const { data, isLoading, refetch } = (0, import_growflowbooking_admin_core5.useAdminTenants)({
513
+ search: search || void 0,
514
+ plan: planFilter !== "all" ? planFilter : void 0,
515
+ page,
516
+ page_size: pageSize
517
+ });
518
+ const { data: tenantDetail, isLoading: isLoadingDetail } = (0, import_growflowbooking_admin_core5.useAdminTenant)(
519
+ showDetail && selectedTenant ? selectedTenant.id : ""
520
+ );
521
+ const createMutation = (0, import_growflowbooking_admin_core5.useCreateTenant)();
522
+ const updateMutation = (0, import_growflowbooking_admin_core5.useUpdateTenant)();
523
+ const deleteMutation = (0, import_growflowbooking_admin_core5.useDeleteTenant)();
524
+ const tenants = data?.items || [];
525
+ const total = data?.total || 0;
526
+ const handleSubmit = (formData) => {
527
+ if (selectedTenant) {
528
+ updateMutation.mutate({ id: selectedTenant.id, data: formData }, {
529
+ onSuccess: () => {
530
+ import_sonner.toast.success("Tenant aggiornato con successo");
531
+ setShowForm(false);
532
+ setSelectedTenant(null);
533
+ },
534
+ onError: (err) => import_sonner.toast.error(`Errore: ${err.message}`)
535
+ });
536
+ } else {
537
+ createMutation.mutate(formData, {
538
+ onSuccess: () => {
539
+ import_sonner.toast.success("Tenant creato con successo");
540
+ setShowForm(false);
541
+ },
542
+ onError: (err) => import_sonner.toast.error(`Errore: ${err.message}`)
543
+ });
544
+ }
545
+ };
546
+ const handleDelete = () => {
547
+ if (selectedTenant) {
548
+ deleteMutation.mutate(selectedTenant.id, {
549
+ onSuccess: () => {
550
+ import_sonner.toast.success("Tenant eliminato con successo");
551
+ setShowDelete(false);
552
+ setSelectedTenant(null);
553
+ },
554
+ onError: (err) => import_sonner.toast.error(`Errore: ${err.message}`)
555
+ });
556
+ }
557
+ };
558
+ const content = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
559
+ header,
560
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-4", children: [
561
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
562
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
563
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.Building2, { className: "w-4 h-4" }),
564
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
565
+ total,
566
+ " tenant"
567
+ ] })
568
+ ] }),
569
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90", onClick: () => {
570
+ setSelectedTenant(null);
571
+ setShowForm(true);
572
+ }, children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.Plus, { className: "w-4 h-4 mr-2" }),
574
+ "Nuovo Tenant"
575
+ ] })
576
+ ] }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
578
+ FilterBar,
579
+ {
580
+ searchPlaceholder: "Cerca tenant...",
581
+ searchValue: search,
582
+ onSearchChange: (v) => {
583
+ setSearch(v);
584
+ setPage(1);
585
+ },
586
+ statusFilter: planFilter,
587
+ onStatusFilterChange: (v) => {
588
+ setPlanFilter(v);
589
+ setPage(1);
590
+ },
591
+ statusOptions: [
592
+ { value: "all", label: "Tutti i piani" },
593
+ { value: "free", label: "Free" },
594
+ { value: "starter", label: "Starter" },
595
+ { value: "professional", label: "Professional" },
596
+ { value: "enterprise", label: "Enterprise" }
597
+ ],
598
+ onRefresh: () => refetch()
599
+ }
600
+ ),
601
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: [
602
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
603
+ TenantsTable,
604
+ {
605
+ tenants,
606
+ isLoading,
607
+ onEdit: (t) => {
608
+ setSelectedTenant(t);
609
+ setShowForm(true);
610
+ },
611
+ onDelete: (t) => {
612
+ setSelectedTenant(t);
613
+ setShowDelete(true);
614
+ },
615
+ onView: (t) => {
616
+ setSelectedTenant(t);
617
+ setShowDetail(true);
618
+ }
619
+ }
620
+ ) }),
621
+ total > pageSize && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-4 border-t", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pagination, { page, pageSize, total, onPageChange: setPage }) })
622
+ ] })
623
+ ] }),
624
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
625
+ TenantFormDialog,
626
+ {
627
+ isOpen: showForm,
628
+ onOpenChange: setShowForm,
629
+ tenant: selectedTenant,
630
+ onSubmit: handleSubmit,
631
+ isPending: createMutation.isPending || updateMutation.isPending
632
+ }
633
+ ),
634
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
635
+ TenantDetailDialog,
636
+ {
637
+ isOpen: showDetail,
638
+ onOpenChange: setShowDetail,
639
+ tenant: tenantDetail,
640
+ isLoading: isLoadingDetail
641
+ }
642
+ ),
643
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
644
+ DeleteConfirmDialog,
645
+ {
646
+ isOpen: showDelete,
647
+ onOpenChange: setShowDelete,
648
+ title: "Eliminare Tenant?",
649
+ description: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
650
+ "Stai per eliminare il tenant ",
651
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: selectedTenant?.name }),
652
+ ". Questa azione non pu\xF2 essere annullata e rimuover\xE0 tutti i dati associati."
653
+ ] }),
654
+ onConfirm: handleDelete,
655
+ isDeleting: deleteMutation.isPending,
656
+ confirmLabel: "Elimina Tenant"
657
+ }
658
+ )
659
+ ] });
660
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Wrapper, { children: content }) : content;
661
+ }
662
+
663
+ // src/pages/CustomersPage.tsx
664
+ var import_react5 = require("react");
665
+ var import_sonner2 = require("sonner");
666
+ var import_lucide_react10 = require("lucide-react");
667
+ var import_growflowbooking_admin_core8 = require("@growflowstudio/growflowbooking-admin-core");
668
+
669
+ // src/components/customers/CustomersTable.tsx
670
+ var import_lucide_react8 = require("lucide-react");
671
+ var import_growflowbooking_admin_core6 = require("@growflowstudio/growflowbooking-admin-core");
672
+ var import_jsx_runtime11 = require("react/jsx-runtime");
673
+ function CustomersTable({ customers, isLoading, onEdit, onDelete }) {
674
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { className: "w-full", children: [
675
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { className: "border-b", children: [
676
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Nome" }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Email" }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Tenant" }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stato" }),
680
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Creato" }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
682
+ ] }) }),
683
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SkeletonRows, { rows: 5, columns: 6 }) : customers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { colSpan: 6, className: "h-24 text-center text-muted-foreground", children: "Nessun cliente trovato." }) }) : customers.map((customer) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { className: "p-4 font-medium", children: [
685
+ customer.first_name,
686
+ " ",
687
+ customer.last_name
688
+ ] }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "p-4 text-sm", children: customer.email }),
690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "p-4 text-sm text-muted-foreground", children: customer.tenant_name }),
691
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
692
+ StatusBadge,
693
+ {
694
+ label: customer.is_active ? "Attivo" : "Inattivo",
695
+ colorClass: customer.is_active ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"
696
+ }
697
+ ) }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "p-4 text-sm text-muted-foreground", children: (0, import_growflowbooking_admin_core6.formatDate)(customer.created_at) }),
699
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-end gap-1", children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm h-8 w-8 hover:bg-accent", onClick: () => onEdit(customer), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.Pencil, { className: "w-4 h-4" }) }),
701
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm h-8 w-8 hover:bg-accent text-destructive", onClick: () => onDelete(customer), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.Trash2, { className: "w-4 h-4" }) })
702
+ ] }) })
703
+ ] }, customer.id)) })
704
+ ] });
705
+ }
706
+
707
+ // src/components/customers/CustomerFormDialog.tsx
708
+ var import_react4 = require("react");
709
+ var import_lucide_react9 = require("lucide-react");
710
+ var import_growflowbooking_admin_core7 = require("@growflowstudio/growflowbooking-admin-core");
711
+ var import_jsx_runtime12 = require("react/jsx-runtime");
712
+ function CustomerFormDialog({ isOpen, onOpenChange, customer, onSubmit, isPending, tenantId }) {
713
+ const isEdit = !!customer;
714
+ const [firstName, setFirstName] = (0, import_react4.useState)("");
715
+ const [lastName, setLastName] = (0, import_react4.useState)("");
716
+ const [email, setEmail] = (0, import_react4.useState)("");
717
+ const [phone, setPhone] = (0, import_react4.useState)("");
718
+ const [notes, setNotes] = (0, import_react4.useState)("");
719
+ const [errors, setErrors] = (0, import_react4.useState)({});
720
+ (0, import_react4.useEffect)(() => {
721
+ if (isOpen) {
722
+ if (customer) {
723
+ setFirstName(customer.first_name);
724
+ setLastName(customer.last_name);
725
+ setEmail(customer.email);
726
+ setPhone(customer.phone || "");
727
+ setNotes(customer.notes || "");
728
+ } else {
729
+ setFirstName("");
730
+ setLastName("");
731
+ setEmail("");
732
+ setPhone("");
733
+ setNotes("");
734
+ }
735
+ setErrors({});
736
+ }
737
+ }, [isOpen, customer]);
738
+ const handleSubmit = () => {
739
+ const errs = {};
740
+ const fnErr = (0, import_growflowbooking_admin_core7.validateRequired)(firstName, "Il nome");
741
+ if (fnErr) errs.firstName = fnErr;
742
+ const lnErr = (0, import_growflowbooking_admin_core7.validateRequired)(lastName, "Il cognome");
743
+ if (lnErr) errs.lastName = lnErr;
744
+ const emailErr = (0, import_growflowbooking_admin_core7.validateEmail)(email);
745
+ if (emailErr) errs.email = emailErr;
746
+ setErrors(errs);
747
+ if (Object.keys(errs).length > 0) return;
748
+ if (isEdit) {
749
+ onSubmit({ first_name: firstName, last_name: lastName, email, phone: phone || void 0, notes: notes || void 0 });
750
+ } else {
751
+ onSubmit({ tenant_id: tenantId || "", first_name: firstName, last_name: lastName, email, phone: phone || void 0, notes: notes || void 0 });
752
+ }
753
+ };
754
+ if (!isOpen) return null;
755
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
756
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
757
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative z-50 w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-lg border bg-background p-6 shadow-lg", children: [
758
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex flex-col space-y-1.5 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "text-lg font-semibold", children: isEdit ? "Modifica Cliente" : "Nuovo Cliente" }) }),
759
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid gap-4 py-4", children: [
760
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
761
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-2", children: [
762
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { className: "text-sm font-medium leading-none", children: "Nome *" }),
763
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: firstName, onChange: (e) => setFirstName(e.target.value), placeholder: "Mario" }),
764
+ errors.firstName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-destructive", children: errors.firstName })
765
+ ] }),
766
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-2", children: [
767
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { className: "text-sm font-medium leading-none", children: "Cognome *" }),
768
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: lastName, onChange: (e) => setLastName(e.target.value), placeholder: "Rossi" }),
769
+ errors.lastName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-destructive", children: errors.lastName })
770
+ ] })
771
+ ] }),
772
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-2", children: [
773
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { className: "text-sm font-medium leading-none", children: "Email *" }),
774
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "email", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: email, onChange: (e) => setEmail(e.target.value), placeholder: "mario@example.com" }),
775
+ errors.email && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-destructive", children: errors.email })
776
+ ] }),
777
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-2", children: [
778
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { className: "text-sm font-medium leading-none", children: "Telefono" }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: phone, onChange: (e) => setPhone(e.target.value), placeholder: "+39 123 456 7890" })
780
+ ] }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-2", children: [
782
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { className: "text-sm font-medium leading-none", children: "Note" }),
783
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("textarea", { className: "flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: notes, onChange: (e) => setNotes(e.target.value), rows: 2 })
784
+ ] })
785
+ ] }),
786
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
787
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 border border-input bg-background hover:bg-accent mt-2 sm:mt-0", onClick: () => onOpenChange(false), children: "Annulla" }),
788
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50", onClick: handleSubmit, disabled: isPending, children: [
789
+ isPending && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react9.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
790
+ isEdit ? "Salva Modifiche" : "Crea Cliente"
791
+ ] })
792
+ ] })
793
+ ] })
794
+ ] });
795
+ }
796
+
797
+ // src/pages/CustomersPage.tsx
798
+ var import_jsx_runtime13 = require("react/jsx-runtime");
799
+ function CustomersPage({ wrapper: Wrapper, header }) {
800
+ const [search, setSearch] = (0, import_react5.useState)("");
801
+ const [page, setPage] = (0, import_react5.useState)(1);
802
+ const pageSize = 20;
803
+ const [showForm, setShowForm] = (0, import_react5.useState)(false);
804
+ const [showDelete, setShowDelete] = (0, import_react5.useState)(false);
805
+ const [selectedCustomer, setSelectedCustomer] = (0, import_react5.useState)(null);
806
+ const { data, isLoading, refetch } = (0, import_growflowbooking_admin_core8.useAdminCustomers)({
807
+ search: search || void 0,
808
+ page,
809
+ page_size: pageSize
810
+ });
811
+ const createMutation = (0, import_growflowbooking_admin_core8.useCreateCustomer)();
812
+ const updateMutation = (0, import_growflowbooking_admin_core8.useUpdateCustomer)();
813
+ const deleteMutation = (0, import_growflowbooking_admin_core8.useDeleteCustomer)();
814
+ const customers = data?.items || [];
815
+ const total = data?.total || 0;
816
+ const handleSubmit = (formData) => {
817
+ if (selectedCustomer) {
818
+ updateMutation.mutate({ id: selectedCustomer.id, data: formData }, {
819
+ onSuccess: () => {
820
+ import_sonner2.toast.success("Cliente aggiornato con successo");
821
+ setShowForm(false);
822
+ setSelectedCustomer(null);
823
+ },
824
+ onError: (err) => import_sonner2.toast.error(`Errore: ${err.message}`)
825
+ });
826
+ } else {
827
+ createMutation.mutate(formData, {
828
+ onSuccess: () => {
829
+ import_sonner2.toast.success("Cliente creato con successo");
830
+ setShowForm(false);
831
+ },
832
+ onError: (err) => import_sonner2.toast.error(`Errore: ${err.message}`)
833
+ });
834
+ }
835
+ };
836
+ const handleDelete = () => {
837
+ if (selectedCustomer) {
838
+ deleteMutation.mutate(selectedCustomer.id, {
839
+ onSuccess: () => {
840
+ import_sonner2.toast.success("Cliente eliminato con successo");
841
+ setShowDelete(false);
842
+ setSelectedCustomer(null);
843
+ },
844
+ onError: (err) => import_sonner2.toast.error(`Errore: ${err.message}`)
845
+ });
846
+ }
847
+ };
848
+ const content = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
849
+ header,
850
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-4", children: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
852
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
853
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react10.Users, { className: "w-4 h-4" }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
855
+ total,
856
+ " clienti"
857
+ ] })
858
+ ] }),
859
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90", onClick: () => {
860
+ setSelectedCustomer(null);
861
+ setShowForm(true);
862
+ }, children: [
863
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react10.Plus, { className: "w-4 h-4 mr-2" }),
864
+ "Nuovo Cliente"
865
+ ] })
866
+ ] }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
868
+ FilterBar,
869
+ {
870
+ searchPlaceholder: "Cerca clienti...",
871
+ searchValue: search,
872
+ onSearchChange: (v) => {
873
+ setSearch(v);
874
+ setPage(1);
875
+ },
876
+ onRefresh: () => refetch()
877
+ }
878
+ ),
879
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: [
880
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
881
+ CustomersTable,
882
+ {
883
+ customers,
884
+ isLoading,
885
+ onEdit: (c) => {
886
+ setSelectedCustomer(c);
887
+ setShowForm(true);
888
+ },
889
+ onDelete: (c) => {
890
+ setSelectedCustomer(c);
891
+ setShowDelete(true);
892
+ }
893
+ }
894
+ ) }),
895
+ total > pageSize && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-4 border-t", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Pagination, { page, pageSize, total, onPageChange: setPage }) })
896
+ ] })
897
+ ] }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
899
+ CustomerFormDialog,
900
+ {
901
+ isOpen: showForm,
902
+ onOpenChange: setShowForm,
903
+ customer: selectedCustomer,
904
+ onSubmit: handleSubmit,
905
+ isPending: createMutation.isPending || updateMutation.isPending
906
+ }
907
+ ),
908
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
909
+ DeleteConfirmDialog,
910
+ {
911
+ isOpen: showDelete,
912
+ onOpenChange: setShowDelete,
913
+ title: "Eliminare Cliente?",
914
+ description: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
915
+ "Stai per eliminare il cliente ",
916
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("strong", { children: [
917
+ selectedCustomer?.first_name,
918
+ " ",
919
+ selectedCustomer?.last_name
920
+ ] }),
921
+ ". Questa azione non pu\xF2 essere annullata."
922
+ ] }),
923
+ onConfirm: handleDelete,
924
+ isDeleting: deleteMutation.isPending,
925
+ confirmLabel: "Elimina Cliente"
926
+ }
927
+ )
928
+ ] });
929
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Wrapper, { children: content }) : content;
930
+ }
931
+
932
+ // src/pages/SubscriptionPlansPage.tsx
933
+ var import_react7 = require("react");
934
+ var import_sonner3 = require("sonner");
935
+ var import_lucide_react13 = require("lucide-react");
936
+ var import_growflowbooking_admin_core11 = require("@growflowstudio/growflowbooking-admin-core");
937
+
938
+ // src/components/subscription-plans/SubscriptionPlansTable.tsx
939
+ var import_lucide_react11 = require("lucide-react");
940
+ var import_growflowbooking_admin_core9 = require("@growflowstudio/growflowbooking-admin-core");
941
+ var import_jsx_runtime14 = require("react/jsx-runtime");
942
+ function SubscriptionPlansTable({ plans, isLoading, onEdit, onDelete }) {
943
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("table", { className: "w-full", children: [
944
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b", children: [
945
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Nome" }),
946
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Slug" }),
947
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Mensile" }),
948
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Annuale" }),
949
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stato" }),
950
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Trial" }),
951
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
952
+ ] }) }),
953
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SkeletonRows, { rows: 5, columns: 7 }) : plans.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { colSpan: 7, className: "h-24 text-center text-muted-foreground", children: "Nessun piano trovato." }) }) : plans.map((plan) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
954
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 font-medium", children: plan.name }),
955
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("code", { className: "text-xs bg-muted px-1.5 py-0.5 rounded", children: plan.slug }) }),
956
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 text-sm", children: (0, import_growflowbooking_admin_core9.formatPrice)(plan.price_monthly, plan.currency) }),
957
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 text-sm", children: (0, import_growflowbooking_admin_core9.formatPrice)(plan.price_yearly, plan.currency) }),
958
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
959
+ StatusBadge,
960
+ {
961
+ label: plan.is_active ? "Attivo" : "Inattivo",
962
+ colorClass: plan.is_active ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"
963
+ }
964
+ ) }),
965
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("td", { className: "p-4 text-sm text-muted-foreground", children: [
966
+ plan.trial_days,
967
+ " giorni"
968
+ ] }),
969
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-end gap-1", children: [
970
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm h-8 w-8 hover:bg-accent", onClick: () => onEdit(plan), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react11.Pencil, { className: "w-4 h-4" }) }),
971
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm h-8 w-8 hover:bg-accent text-destructive", onClick: () => onDelete(plan), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react11.Trash2, { className: "w-4 h-4" }) })
972
+ ] }) })
973
+ ] }, plan.id)) })
974
+ ] });
975
+ }
976
+
977
+ // src/components/subscription-plans/SubscriptionPlanFormDialog.tsx
978
+ var import_react6 = require("react");
979
+ var import_lucide_react12 = require("lucide-react");
980
+ var import_growflowbooking_admin_core10 = require("@growflowstudio/growflowbooking-admin-core");
981
+ var import_jsx_runtime15 = require("react/jsx-runtime");
982
+ function SubscriptionPlanFormDialog({ isOpen, onOpenChange, plan, onSubmit, isPending }) {
983
+ const isEdit = !!plan;
984
+ const [slug, setSlug] = (0, import_react6.useState)("");
985
+ const [name, setName] = (0, import_react6.useState)("");
986
+ const [description, setDescription] = (0, import_react6.useState)("");
987
+ const [pricingModel, setPricingModel] = (0, import_react6.useState)("flat");
988
+ const [priceMonthly, setPriceMonthly] = (0, import_react6.useState)("");
989
+ const [priceYearly, setPriceYearly] = (0, import_react6.useState)("");
990
+ const [currency, setCurrency] = (0, import_react6.useState)("eur");
991
+ const [trialDays, setTrialDays] = (0, import_react6.useState)(14);
992
+ const [isActive, setIsActive] = (0, import_react6.useState)(true);
993
+ const [errors, setErrors] = (0, import_react6.useState)({});
994
+ (0, import_react6.useEffect)(() => {
995
+ if (isOpen) {
996
+ if (plan) {
997
+ setSlug(plan.slug);
998
+ setName(plan.name);
999
+ setDescription(plan.description || "");
1000
+ setPricingModel(plan.pricing_model);
1001
+ setPriceMonthly(plan.price_monthly?.toString() || "");
1002
+ setPriceYearly(plan.price_yearly?.toString() || "");
1003
+ setCurrency(plan.currency);
1004
+ setTrialDays(plan.trial_days);
1005
+ setIsActive(plan.is_active);
1006
+ } else {
1007
+ setSlug("");
1008
+ setName("");
1009
+ setDescription("");
1010
+ setPricingModel("flat");
1011
+ setPriceMonthly("");
1012
+ setPriceYearly("");
1013
+ setCurrency("eur");
1014
+ setTrialDays(14);
1015
+ setIsActive(true);
1016
+ }
1017
+ setErrors({});
1018
+ }
1019
+ }, [isOpen, plan]);
1020
+ const handleSubmit = () => {
1021
+ const errs = {};
1022
+ if (!isEdit) {
1023
+ const slugErr = (0, import_growflowbooking_admin_core10.validateSlug)(slug);
1024
+ if (slugErr) errs.slug = slugErr;
1025
+ }
1026
+ const nameErr = (0, import_growflowbooking_admin_core10.validateRequired)(name, "Il nome");
1027
+ if (nameErr) errs.name = nameErr;
1028
+ setErrors(errs);
1029
+ if (Object.keys(errs).length > 0) return;
1030
+ const data = {
1031
+ ...isEdit ? {} : { slug },
1032
+ name,
1033
+ description: description || void 0,
1034
+ pricing_model: pricingModel,
1035
+ price_monthly: priceMonthly ? parseFloat(priceMonthly) : void 0,
1036
+ price_yearly: priceYearly ? parseFloat(priceYearly) : void 0,
1037
+ currency,
1038
+ trial_days: trialDays,
1039
+ is_active: isActive
1040
+ };
1041
+ onSubmit(data);
1042
+ };
1043
+ if (!isOpen) return null;
1044
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1045
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
1046
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative z-50 w-full max-w-xl max-h-[90vh] overflow-y-auto rounded-lg border bg-background p-6 shadow-lg", children: [
1047
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col space-y-1.5 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: "text-lg font-semibold", children: isEdit ? "Modifica Piano" : "Nuovo Piano" }) }),
1048
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid gap-4 py-4", children: [
1049
+ !isEdit && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1050
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Slug *" }),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: slug, onChange: (e) => setSlug(e.target.value), placeholder: "pro-monthly" }),
1052
+ errors.slug && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-xs text-destructive", children: errors.slug })
1053
+ ] }),
1054
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1055
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Nome *" }),
1056
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: name, onChange: (e) => setName(e.target.value), placeholder: "Professional" }),
1057
+ errors.name && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-xs text-destructive", children: errors.name })
1058
+ ] }),
1059
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1060
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Descrizione" }),
1061
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("textarea", { className: "flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: description, onChange: (e) => setDescription(e.target.value), rows: 2 })
1062
+ ] }),
1063
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1064
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1065
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Prezzo Mensile" }),
1066
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "number", step: "0.01", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: priceMonthly, onChange: (e) => setPriceMonthly(e.target.value), placeholder: "29.00" })
1067
+ ] }),
1068
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1069
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Prezzo Annuale" }),
1070
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "number", step: "0.01", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: priceYearly, onChange: (e) => setPriceYearly(e.target.value), placeholder: "290.00" })
1071
+ ] })
1072
+ ] }),
1073
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1074
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1075
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Valuta" }),
1076
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("select", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: currency, onChange: (e) => setCurrency(e.target.value), children: [
1077
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "eur", children: "EUR" }),
1078
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "usd", children: "USD" }),
1079
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "gbp", children: "GBP" })
1080
+ ] })
1081
+ ] }),
1082
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-2", children: [
1083
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-sm font-medium leading-none", children: "Giorni Prova" }),
1084
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "number", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: trialDays, onChange: (e) => setTrialDays(parseInt(e.target.value) || 0) })
1085
+ ] })
1086
+ ] }),
1087
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
1088
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1089
+ "button",
1090
+ {
1091
+ type: "button",
1092
+ role: "switch",
1093
+ "aria-checked": isActive,
1094
+ onClick: () => setIsActive(!isActive),
1095
+ className: `inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${isActive ? "bg-primary" : "bg-input"}`,
1096
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg transition-transform ${isActive ? "translate-x-4" : "translate-x-0"}` })
1097
+ }
1098
+ ),
1099
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-sm font-medium leading-none", children: "Piano Attivo" })
1100
+ ] })
1101
+ ] }),
1102
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
1103
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 border border-input bg-background hover:bg-accent mt-2 sm:mt-0", onClick: () => onOpenChange(false), children: "Annulla" }),
1104
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50", onClick: handleSubmit, disabled: isPending, children: [
1105
+ isPending && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react12.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
1106
+ isEdit ? "Salva Modifiche" : "Crea Piano"
1107
+ ] })
1108
+ ] })
1109
+ ] })
1110
+ ] });
1111
+ }
1112
+
1113
+ // src/pages/SubscriptionPlansPage.tsx
1114
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1115
+ function SubscriptionPlansPage({ wrapper: Wrapper, header }) {
1116
+ const [showForm, setShowForm] = (0, import_react7.useState)(false);
1117
+ const [showDelete, setShowDelete] = (0, import_react7.useState)(false);
1118
+ const [selectedPlan, setSelectedPlan] = (0, import_react7.useState)(null);
1119
+ const { data, isLoading, refetch } = (0, import_growflowbooking_admin_core11.useSubscriptionPlans)(true);
1120
+ const createMutation = (0, import_growflowbooking_admin_core11.useCreateSubscriptionPlan)();
1121
+ const updateMutation = (0, import_growflowbooking_admin_core11.useUpdateSubscriptionPlan)();
1122
+ const deleteMutation = (0, import_growflowbooking_admin_core11.useDeleteSubscriptionPlan)();
1123
+ const plans = data?.items || [];
1124
+ const handleSubmit = (formData) => {
1125
+ if (selectedPlan) {
1126
+ updateMutation.mutate({ id: selectedPlan.id, data: formData }, {
1127
+ onSuccess: () => {
1128
+ import_sonner3.toast.success("Piano aggiornato con successo");
1129
+ setShowForm(false);
1130
+ setSelectedPlan(null);
1131
+ },
1132
+ onError: (err) => import_sonner3.toast.error(`Errore: ${err.message}`)
1133
+ });
1134
+ } else {
1135
+ createMutation.mutate(formData, {
1136
+ onSuccess: () => {
1137
+ import_sonner3.toast.success("Piano creato con successo");
1138
+ setShowForm(false);
1139
+ },
1140
+ onError: (err) => import_sonner3.toast.error(`Errore: ${err.message}`)
1141
+ });
1142
+ }
1143
+ };
1144
+ const handleDelete = () => {
1145
+ if (selectedPlan) {
1146
+ deleteMutation.mutate(selectedPlan.id, {
1147
+ onSuccess: () => {
1148
+ import_sonner3.toast.success("Piano eliminato con successo");
1149
+ setShowDelete(false);
1150
+ setSelectedPlan(null);
1151
+ },
1152
+ onError: (err) => import_sonner3.toast.error(`Errore: ${err.message}`)
1153
+ });
1154
+ }
1155
+ };
1156
+ const content = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1157
+ header,
1158
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-4", children: [
1159
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between", children: [
1160
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1161
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react13.LayoutGrid, { className: "w-4 h-4" }),
1162
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { children: [
1163
+ plans.length,
1164
+ " piani configurati"
1165
+ ] })
1166
+ ] }),
1167
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex gap-2", children: [
1168
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 border border-input bg-background hover:bg-accent", onClick: () => refetch(), children: "Aggiorna" }),
1169
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90", onClick: () => {
1170
+ setSelectedPlan(null);
1171
+ setShowForm(true);
1172
+ }, children: [
1173
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react13.Plus, { className: "w-4 h-4 mr-2" }),
1174
+ "Nuovo Piano"
1175
+ ] })
1176
+ ] })
1177
+ ] }),
1178
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1179
+ SubscriptionPlansTable,
1180
+ {
1181
+ plans,
1182
+ isLoading,
1183
+ onEdit: (p) => {
1184
+ setSelectedPlan(p);
1185
+ setShowForm(true);
1186
+ },
1187
+ onDelete: (p) => {
1188
+ setSelectedPlan(p);
1189
+ setShowDelete(true);
1190
+ }
1191
+ }
1192
+ ) }) })
1193
+ ] }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1195
+ SubscriptionPlanFormDialog,
1196
+ {
1197
+ isOpen: showForm,
1198
+ onOpenChange: setShowForm,
1199
+ plan: selectedPlan,
1200
+ onSubmit: handleSubmit,
1201
+ isPending: createMutation.isPending || updateMutation.isPending
1202
+ }
1203
+ ),
1204
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1205
+ DeleteConfirmDialog,
1206
+ {
1207
+ isOpen: showDelete,
1208
+ onOpenChange: setShowDelete,
1209
+ title: "Eliminare Piano?",
1210
+ description: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1211
+ "Stai per eliminare il piano ",
1212
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: selectedPlan?.name }),
1213
+ " (",
1214
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("code", { children: selectedPlan?.slug }),
1215
+ "). Questa azione non pu\xF2 essere annullata."
1216
+ ] }),
1217
+ onConfirm: handleDelete,
1218
+ isDeleting: deleteMutation.isPending,
1219
+ confirmLabel: "Elimina Piano"
1220
+ }
1221
+ )
1222
+ ] });
1223
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Wrapper, { children: content }) : content;
1224
+ }
1225
+
1226
+ // src/pages/BillingPlansPage.tsx
1227
+ var import_sonner4 = require("sonner");
1228
+ var import_lucide_react14 = require("lucide-react");
1229
+ var import_growflowbooking_admin_core12 = require("@growflowstudio/growflowbooking-admin-core");
1230
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1231
+ function BillingPlansPage({ wrapper: Wrapper, header }) {
1232
+ const { data, isLoading, refetch } = (0, import_growflowbooking_admin_core12.useBillingPlans)();
1233
+ const syncMutation = (0, import_growflowbooking_admin_core12.useSyncBillingPlanToStripe)();
1234
+ const plans = data?.items || [];
1235
+ const content = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1236
+ header,
1237
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-4", children: [
1238
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between", children: [
1239
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react14.CreditCard, { className: "w-4 h-4" }),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
1242
+ plans.length,
1243
+ " piani billing (GrowFlow)"
1244
+ ] })
1245
+ ] }),
1246
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 border border-input bg-background hover:bg-accent", onClick: () => refetch(), children: [
1247
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react14.RefreshCw, { className: "w-4 h-4 mr-2" }),
1248
+ "Aggiorna"
1249
+ ] })
1250
+ ] }),
1251
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("table", { className: "w-full", children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("tr", { className: "border-b", children: [
1253
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Nome" }),
1254
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Slug" }),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Mensile" }),
1256
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Annuale" }),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stato" }),
1258
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
1259
+ ] }) }),
1260
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SkeletonRows, { rows: 5, columns: 6 }) : plans.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { colSpan: 6, className: "h-24 text-center text-muted-foreground", children: "Nessun piano billing configurato." }) }) : plans.map((plan) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1261
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4 font-medium", children: plan.name }),
1262
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { className: "text-xs bg-muted px-1.5 py-0.5 rounded", children: plan.slug }) }),
1263
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4 text-sm", children: (0, import_growflowbooking_admin_core12.formatPrice)(plan.priceMonthly, plan.currency) }),
1264
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4 text-sm", children: (0, import_growflowbooking_admin_core12.formatPrice)(plan.priceYearly, plan.currency) }),
1265
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1266
+ StatusBadge,
1267
+ {
1268
+ label: plan.isActive ? "Attivo" : "Inattivo",
1269
+ colorClass: plan.isActive ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400"
1270
+ }
1271
+ ) }),
1272
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1273
+ "button",
1274
+ {
1275
+ className: "inline-flex items-center justify-center rounded-md text-sm h-8 px-2 hover:bg-accent disabled:opacity-50",
1276
+ onClick: () => syncMutation.mutate(plan.id, {
1277
+ onSuccess: () => import_sonner4.toast.success("Piano sincronizzato con Stripe"),
1278
+ onError: (err) => import_sonner4.toast.error(`Errore sync: ${err.message}`)
1279
+ }),
1280
+ disabled: syncMutation.isPending,
1281
+ children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react14.CloudUpload, { className: "w-4 h-4 mr-1" }),
1283
+ "Sync"
1284
+ ]
1285
+ }
1286
+ ) })
1287
+ ] }, plan.id)) })
1288
+ ] }) }) })
1289
+ ] })
1290
+ ] });
1291
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Wrapper, { children: content }) : content;
1292
+ }
1293
+
1294
+ // src/pages/BillingSubscriptionsPage.tsx
1295
+ var import_react8 = require("react");
1296
+ var import_sonner5 = require("sonner");
1297
+ var import_lucide_react15 = require("lucide-react");
1298
+ var import_growflowbooking_admin_core13 = require("@growflowstudio/growflowbooking-admin-core");
1299
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1300
+ function BillingSubscriptionsPage({ wrapper: Wrapper, header }) {
1301
+ const [search, setSearch] = (0, import_react8.useState)("");
1302
+ const [statusFilter, setStatusFilter] = (0, import_react8.useState)("all");
1303
+ const { data, isLoading, refetch } = (0, import_growflowbooking_admin_core13.useBillingSubscriptions)({
1304
+ search: search || void 0,
1305
+ status: statusFilter !== "all" ? statusFilter : void 0
1306
+ });
1307
+ const cancelMutation = (0, import_growflowbooking_admin_core13.useCancelBillingSubscription)();
1308
+ const subscriptions = data?.items || [];
1309
+ const content = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1310
+ header,
1311
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-4", children: [
1312
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1313
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react15.CreditCard, { className: "w-4 h-4" }),
1314
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { children: [
1315
+ data?.total || 0,
1316
+ " abbonamenti billing"
1317
+ ] })
1318
+ ] }),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1320
+ FilterBar,
1321
+ {
1322
+ searchPlaceholder: "Cerca abbonamenti...",
1323
+ searchValue: search,
1324
+ onSearchChange: setSearch,
1325
+ statusFilter,
1326
+ onStatusFilterChange: setStatusFilter,
1327
+ statusOptions: [
1328
+ { value: "all", label: "Tutti gli stati" },
1329
+ { value: "active", label: "Attivi" },
1330
+ { value: "trialing", label: "In Prova" },
1331
+ { value: "past_due", label: "Scaduti" },
1332
+ { value: "canceled", label: "Cancellati" }
1333
+ ],
1334
+ onRefresh: () => refetch()
1335
+ }
1336
+ ),
1337
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("table", { className: "w-full", children: [
1338
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("tr", { className: "border-b", children: [
1339
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Subscriber" }),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Piano" }),
1341
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Ciclo" }),
1342
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stato" }),
1343
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Periodo Corrente" }),
1344
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
1345
+ ] }) }),
1346
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SkeletonRows, { rows: 5, columns: 6 }) : subscriptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("td", { colSpan: 6, className: "h-24 text-center text-muted-foreground", children: "Nessun abbonamento trovato." }) }) : subscriptions.map((sub) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1347
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("td", { className: "p-4", children: [
1348
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "font-medium", children: sub.subscriberName || sub.subscriberEmail }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-xs text-muted-foreground", children: sub.subscriberEmail })
1350
+ ] }),
1351
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { className: "text-xs bg-muted px-1.5 py-0.5 rounded", children: sub.planSlug }) }),
1352
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("td", { className: "p-4 text-sm capitalize", children: sub.billingCycle }),
1353
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1354
+ StatusBadge,
1355
+ {
1356
+ label: import_growflowbooking_admin_core13.billingSubscriptionStatusLabels[sub.status],
1357
+ colorClass: import_growflowbooking_admin_core13.billingSubscriptionStatusColors[sub.status]
1358
+ }
1359
+ ) }),
1360
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("td", { className: "p-4 text-sm text-muted-foreground", children: sub.currentPeriodStart && sub.currentPeriodEnd ? `${(0, import_growflowbooking_admin_core13.formatDate)(sub.currentPeriodStart)} - ${(0, import_growflowbooking_admin_core13.formatDate)(sub.currentPeriodEnd)}` : "-" }),
1361
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("td", { className: "p-4 text-right", children: sub.status === "active" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1362
+ "button",
1363
+ {
1364
+ className: "inline-flex items-center justify-center rounded-md text-sm h-8 px-2 hover:bg-accent text-destructive disabled:opacity-50",
1365
+ onClick: () => cancelMutation.mutate({ id: sub.id, atPeriodEnd: true }, {
1366
+ onSuccess: () => import_sonner5.toast.success("Abbonamento cancellato a fine periodo"),
1367
+ onError: (err) => import_sonner5.toast.error(`Errore: ${err.message}`)
1368
+ }),
1369
+ disabled: cancelMutation.isPending,
1370
+ children: "Cancella"
1371
+ }
1372
+ ) })
1373
+ ] }, sub.id)) })
1374
+ ] }) }) })
1375
+ ] })
1376
+ ] });
1377
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Wrapper, { children: content }) : content;
1378
+ }
1379
+
1380
+ // src/pages/SettingsPage.tsx
1381
+ var import_react9 = require("react");
1382
+ var import_sonner6 = require("sonner");
1383
+ var import_lucide_react16 = require("lucide-react");
1384
+ var import_growflowbooking_admin_core14 = require("@growflowstudio/growflowbooking-admin-core");
1385
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1386
+ function SettingsPage({ wrapper: Wrapper, header }) {
1387
+ const { data: settings, isLoading } = (0, import_growflowbooking_admin_core14.useBillingSettings)();
1388
+ const updateMutation = (0, import_growflowbooking_admin_core14.useUpdateBillingSettings)();
1389
+ const testMutation = (0, import_growflowbooking_admin_core14.useTestBillingConnection)();
1390
+ const [apiKey, setApiKey] = (0, import_react9.useState)("");
1391
+ const [webhookSecret, setWebhookSecret] = (0, import_react9.useState)("");
1392
+ const [mode, setMode] = (0, import_react9.useState)("test");
1393
+ const [billingUrlTest, setBillingUrlTest] = (0, import_react9.useState)("");
1394
+ const [billingUrlProduction, setBillingUrlProduction] = (0, import_react9.useState)("");
1395
+ const handleSave = () => {
1396
+ const data = {};
1397
+ if (apiKey) data.apiKey = apiKey;
1398
+ if (webhookSecret) data.webhookSecret = webhookSecret;
1399
+ if (mode) data.mode = mode;
1400
+ if (billingUrlTest) data.billingUrlTest = billingUrlTest;
1401
+ if (billingUrlProduction) data.billingUrlProduction = billingUrlProduction;
1402
+ updateMutation.mutate(data, {
1403
+ onSuccess: () => {
1404
+ import_sonner6.toast.success("Impostazioni salvate");
1405
+ setApiKey("");
1406
+ setWebhookSecret("");
1407
+ },
1408
+ onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
1409
+ });
1410
+ };
1411
+ const handleTest = () => {
1412
+ testMutation.mutate(void 0, {
1413
+ onSuccess: (result) => {
1414
+ if (result.success) {
1415
+ import_sonner6.toast.success(`Connessione OK \u2014 ${result.plansCount} piani trovati`);
1416
+ } else {
1417
+ import_sonner6.toast.error(`Connessione fallita: ${result.message}`);
1418
+ }
1419
+ },
1420
+ onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
1421
+ });
1422
+ };
1423
+ const content = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1424
+ header,
1425
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-6", children: [
1426
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1427
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.Settings, { className: "w-4 h-4" }),
1428
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Impostazioni GrowFlow Billing" })
1429
+ ] }),
1430
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "space-y-4", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "h-12 w-full animate-pulse rounded-md bg-muted" }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-6", children: [
1431
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "rounded-lg border bg-card p-6 space-y-4", children: [
1432
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "font-medium", children: "Stato Connessione" }),
1433
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-2 gap-4 text-sm", children: [
1434
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
1435
+ settings?.apiKeyConfigured ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.CheckCircle2, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.XCircle, { className: "w-4 h-4 text-red-500" }),
1436
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
1437
+ "API Key: ",
1438
+ settings?.apiKeyMasked || "Non configurata"
1439
+ ] })
1440
+ ] }),
1441
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
1442
+ settings?.webhookSecretConfigured ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.CheckCircle2, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.XCircle, { className: "w-4 h-4 text-red-500" }),
1443
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
1444
+ "Webhook: ",
1445
+ settings?.webhookSecretMasked || "Non configurato"
1446
+ ] })
1447
+ ] }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: "Modalit\xE0:" }),
1450
+ " ",
1451
+ settings?.mode || "-"
1452
+ ] }),
1453
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1454
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: "Client ID:" }),
1455
+ " ",
1456
+ settings?.clientId || "-"
1457
+ ] })
1458
+ ] }),
1459
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1460
+ "button",
1461
+ {
1462
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 border border-input bg-background hover:bg-accent disabled:opacity-50",
1463
+ onClick: handleTest,
1464
+ disabled: testMutation.isPending,
1465
+ children: [
1466
+ testMutation.isPending && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
1467
+ "Testa Connessione"
1468
+ ]
1469
+ }
1470
+ )
1471
+ ] }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "rounded-lg border bg-card p-6 space-y-4", children: [
1473
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "font-medium", children: "Aggiorna Impostazioni" }),
1474
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid gap-4", children: [
1475
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-2", children: [
1476
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "text-sm font-medium", children: "API Key" }),
1477
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "password", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: apiKey, onChange: (e) => setApiKey(e.target.value), placeholder: "sk_live_..." })
1478
+ ] }),
1479
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-2", children: [
1480
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "text-sm font-medium", children: "Webhook Secret" }),
1481
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "password", className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: webhookSecret, onChange: (e) => setWebhookSecret(e.target.value), placeholder: "whsec_..." })
1482
+ ] }),
1483
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1484
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-2", children: [
1485
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "text-sm font-medium", children: "URL Test" }),
1486
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: billingUrlTest, onChange: (e) => setBillingUrlTest(e.target.value), placeholder: "http://localhost:8008" })
1487
+ ] }),
1488
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-2", children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "text-sm font-medium", children: "URL Produzione" }),
1490
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: billingUrlProduction, onChange: (e) => setBillingUrlProduction(e.target.value), placeholder: "https://billing.growflow.studio" })
1491
+ ] })
1492
+ ] }),
1493
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-2", children: [
1494
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "text-sm font-medium", children: "Modalit\xE0" }),
1495
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: mode, onChange: (e) => setMode(e.target.value), children: [
1496
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "test", children: "Test" }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "production", children: "Produzione" })
1498
+ ] })
1499
+ ] })
1500
+ ] }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1502
+ "button",
1503
+ {
1504
+ className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50",
1505
+ onClick: handleSave,
1506
+ disabled: updateMutation.isPending,
1507
+ children: [
1508
+ updateMutation.isPending && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react16.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
1509
+ "Salva Impostazioni"
1510
+ ]
1511
+ }
1512
+ )
1513
+ ] })
1514
+ ] })
1515
+ ] })
1516
+ ] });
1517
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Wrapper, { children: content }) : content;
1518
+ }
1519
+
1520
+ // src/nav/bookingNavItems.ts
1521
+ var ALL_NAV_ITEMS = [
1522
+ { key: "tenants", label: "Tenant", icon: "Building2", href: "/admin/tenants" },
1523
+ { key: "customers", label: "Clienti", icon: "Users", href: "/admin/customers" },
1524
+ { key: "subscriptionPlans", label: "Piani", icon: "LayoutGrid", href: "/admin/subscription-plans" },
1525
+ { key: "billingPlans", label: "Billing Piani", icon: "CreditCard", href: "/admin/billing-plans" },
1526
+ { key: "billingSubscriptions", label: "Abbonamenti", icon: "Receipt", href: "/admin/billing-subscriptions" },
1527
+ { key: "settings", label: "Impostazioni", icon: "Settings", href: "/admin/settings" }
1528
+ ];
1529
+ function getBookingNavItems(modules, basePath) {
1530
+ const enabled = {
1531
+ tenants: true,
1532
+ customers: true,
1533
+ subscriptionPlans: true,
1534
+ billingPlans: true,
1535
+ billingSubscriptions: true,
1536
+ settings: true,
1537
+ ...modules
1538
+ };
1539
+ return ALL_NAV_ITEMS.filter((item) => enabled[item.key] !== false).map((item) => ({
1540
+ ...item,
1541
+ href: basePath ? `${basePath}${item.href}` : item.href
1542
+ }));
1543
+ }
1544
+ // Annotate the CommonJS export names for ESM import in node:
1545
+ 0 && (module.exports = {
1546
+ BillingPlansPage,
1547
+ BillingSubscriptionsPage,
1548
+ BookingAdminProvider,
1549
+ CustomerFormDialog,
1550
+ CustomersPage,
1551
+ CustomersTable,
1552
+ DeleteConfirmDialog,
1553
+ FilterBar,
1554
+ Pagination,
1555
+ SettingsPage,
1556
+ SkeletonRows,
1557
+ StatusBadge,
1558
+ SubscriptionPlanFormDialog,
1559
+ SubscriptionPlansPage,
1560
+ SubscriptionPlansTable,
1561
+ TenantDetailDialog,
1562
+ TenantFormDialog,
1563
+ TenantsPage,
1564
+ TenantsTable,
1565
+ getBookingNavItems,
1566
+ useBookingAdminConfig,
1567
+ useEnabledModules
1568
+ });
1569
+ //# sourceMappingURL=index.js.map