@growflowstudio/growflowbilling-admin-ui 2.0.0 → 2.1.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 CHANGED
@@ -33,6 +33,8 @@ __export(index_exports, {
33
33
  BillingAdminProvider: () => BillingAdminProvider,
34
34
  CursorPagination: () => CursorPagination,
35
35
  DeleteConfirmDialog: () => DeleteConfirmDialog,
36
+ FeatureFormModal: () => FeatureFormModal,
37
+ FeatureListItem: () => FeatureListItem,
36
38
  FeaturesPage: () => FeaturesPage,
37
39
  FilterBar: () => FilterBar,
38
40
  InvoiceDetailsDialog: () => InvoiceDetailsDialog,
@@ -40,7 +42,11 @@ __export(index_exports, {
40
42
  LimitInput: () => LimitInput,
41
43
  PLAN_COLORS: () => PLAN_COLORS,
42
44
  PaymentsPage: () => PaymentsPage,
45
+ PlanDetailsSection: () => PlanDetailsSection,
46
+ PlanFeaturesSection: () => PlanFeaturesSection,
43
47
  PlanFormDialog: () => PlanFormDialog,
48
+ PlanLimitsSection: () => PlanLimitsSection,
49
+ PlanPricingSection: () => PlanPricingSection,
44
50
  PlansPage: () => PlansPage,
45
51
  PlansTable: () => PlansTable,
46
52
  ProductFormDialog: () => ProductFormDialog,
@@ -48,6 +54,7 @@ __export(index_exports, {
48
54
  SkeletonRows: () => SkeletonRows,
49
55
  StatusBadge: () => StatusBadge,
50
56
  SubscriptionsPage: () => SubscriptionsPage,
57
+ ToggleSwitch: () => ToggleSwitch,
51
58
  createDefaultPlanFormData: () => createDefaultPlanFormData,
52
59
  defaultProductFormData: () => defaultProductFormData,
53
60
  getBillingNavItems: () => getBillingNavItems,
@@ -58,9 +65,43 @@ __export(index_exports, {
58
65
  module.exports = __toCommonJS(index_exports);
59
66
 
60
67
  // src/provider.tsx
61
- var import_react = __toESM(require("react"));
68
+ var import_react2 = __toESM(require("react"));
62
69
  var import_growflowbilling_admin_core = require("@growflowstudio/growflowbilling-admin-core");
70
+
71
+ // src/components/shared/ErrorBoundary.tsx
72
+ var import_react = require("react");
63
73
  var import_jsx_runtime = require("react/jsx-runtime");
74
+ var ErrorBoundary = class extends import_react.Component {
75
+ constructor(props) {
76
+ super(props);
77
+ this.state = { hasError: false, error: null };
78
+ }
79
+ static getDerivedStateFromError(error) {
80
+ return { hasError: true, error };
81
+ }
82
+ componentDidCatch(error, errorInfo) {
83
+ console.error("[BillingSDK] Error caught by boundary:", error, errorInfo);
84
+ }
85
+ render() {
86
+ if (this.state.hasError) {
87
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "1rem", textAlign: "center", color: "#666" }, children: [
88
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Something went wrong in the billing module." }),
89
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
90
+ "button",
91
+ {
92
+ onClick: () => this.setState({ hasError: false, error: null }),
93
+ style: { marginTop: "0.5rem", cursor: "pointer" },
94
+ children: "Try again"
95
+ }
96
+ )
97
+ ] });
98
+ }
99
+ return this.props.children;
100
+ }
101
+ };
102
+
103
+ // src/provider.tsx
104
+ var import_jsx_runtime2 = require("react/jsx-runtime");
64
105
  var DEFAULT_MODULES = {
65
106
  plans: true,
66
107
  subscriptions: true,
@@ -69,9 +110,9 @@ var DEFAULT_MODULES = {
69
110
  invoices: true,
70
111
  features: true
71
112
  };
72
- var BillingAdminConfigContext = import_react.default.createContext(null);
113
+ var BillingAdminConfigContext = import_react2.default.createContext(null);
73
114
  function useBillingAdminConfig() {
74
- const config = import_react.default.useContext(BillingAdminConfigContext);
115
+ const config = import_react2.default.useContext(BillingAdminConfigContext);
75
116
  if (!config) {
76
117
  throw new Error(
77
118
  "useBillingAdminConfig must be used within a BillingAdminProvider."
@@ -84,20 +125,20 @@ function useEnabledModules() {
84
125
  return { ...DEFAULT_MODULES, ...config.modules };
85
126
  }
86
127
  function BillingAdminProvider({ config, children }) {
87
- const client = (0, import_react.useMemo)(
128
+ const client = (0, import_react2.useMemo)(
88
129
  () => (0, import_growflowbilling_admin_core.createBillingAdminClient)({
89
130
  basePath: config.basePath,
90
131
  fetcher: config.fetcher
91
132
  }),
92
133
  [config.basePath, config.fetcher]
93
134
  );
94
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BillingAdminConfigContext.Provider, { value: config, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_growflowbilling_admin_core.BillingAdminClientContext.Provider, { value: client, children }) });
135
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BillingAdminConfigContext.Provider, { value: config, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_growflowbilling_admin_core.BillingAdminClientContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ErrorBoundary, { children }) }) });
95
136
  }
96
137
 
97
138
  // src/pages/PlansPage.tsx
98
- var import_react3 = require("react");
139
+ var import_react5 = require("react");
99
140
  var import_sonner = require("sonner");
100
- var import_lucide_react4 = require("lucide-react");
141
+ var import_lucide_react5 = require("lucide-react");
101
142
  var import_growflowbilling_admin_core3 = require("@growflowstudio/growflowbilling-admin-core");
102
143
 
103
144
  // src/components/plans/PlansTable.tsx
@@ -128,9 +169,9 @@ function cn(...inputs) {
128
169
  }
129
170
 
130
171
  // src/components/shared/StatusBadge.tsx
131
- var import_jsx_runtime2 = require("react/jsx-runtime");
172
+ var import_jsx_runtime3 = require("react/jsx-runtime");
132
173
  function StatusBadge({ label, colorClass, className }) {
133
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
174
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
134
175
  "span",
135
176
  {
136
177
  className: cn(
@@ -144,13 +185,13 @@ function StatusBadge({ label, colorClass, className }) {
144
185
  }
145
186
 
146
187
  // src/components/shared/SkeletonRows.tsx
147
- var import_jsx_runtime3 = require("react/jsx-runtime");
188
+ var import_jsx_runtime4 = require("react/jsx-runtime");
148
189
  function SkeletonRows({ rows = 5, columns = 1 }) {
149
- 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)) });
190
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { colSpan: columns, className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-10 w-full animate-pulse rounded-md bg-muted" }) }) }, i)) });
150
191
  }
151
192
 
152
193
  // src/components/plans/PlansTable.tsx
153
- var import_jsx_runtime4 = require("react/jsx-runtime");
194
+ var import_jsx_runtime5 = require("react/jsx-runtime");
154
195
  var pricingModelLabels = {
155
196
  flat: "Fisso",
156
197
  tiered: "A Scaglioni",
@@ -165,55 +206,55 @@ function PlansTable({
165
206
  onSync,
166
207
  isSyncing
167
208
  }) {
168
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
169
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "border-b transition-colors hover:bg-muted/50", children: [
170
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Slug" }),
171
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Nome" }),
172
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Colore" }),
173
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Modello" }),
174
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Mensile" }),
175
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Annuale" }),
176
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Trial" }),
177
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Attivo" }),
178
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stripe" }),
179
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
209
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
210
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "border-b transition-colors hover:bg-muted/50", children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Slug" }),
212
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Nome" }),
213
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Colore" }),
214
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Modello" }),
215
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Mensile" }),
216
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Annuale" }),
217
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Trial" }),
218
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Attivo" }),
219
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stripe" }),
220
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
180
221
  ] }) }),
181
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { className: "[&_tr:last-child]:border-0", children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SkeletonRows, { rows: 3, columns: 10 }) : plans.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { colSpan: 10, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun piano configurato" }) }) : plans.map((plan) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "border-b transition-colors hover:bg-muted/50", children: [
182
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { className: "text-sm bg-muted px-2 py-0.5 rounded", children: plan.slug }) }),
183
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle font-medium", children: plan.name }),
184
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StatusBadge, { label: plan.color, colorClass: getPlanColorClass(plan.color) }) }),
185
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StatusBadge, { label: pricingModelLabels[plan.pricing_model], colorClass: "border" }) }),
186
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: plan.contact_sales ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-muted-foreground", children: "Contattaci" }) : (0, import_growflowbilling_admin_core2.formatCurrency)(plan.price_monthly ?? 0, plan.currency) }),
187
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: plan.contact_sales ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-muted-foreground", children: "Contattaci" }) : (0, import_growflowbilling_admin_core2.formatCurrency)(plan.price_yearly ?? 0, plan.currency) }),
188
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("td", { className: "p-4 align-middle", children: [
222
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { className: "[&_tr:last-child]:border-0", children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SkeletonRows, { rows: 3, columns: 10 }) : plans.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: 10, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun piano configurato" }) }) : plans.map((plan) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "border-b transition-colors hover:bg-muted/50", children: [
223
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "text-sm bg-muted px-2 py-0.5 rounded", children: plan.slug }) }),
224
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle font-medium", children: plan.name }),
225
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatusBadge, { label: plan.color, colorClass: getPlanColorClass(plan.color) }) }),
226
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatusBadge, { label: pricingModelLabels[plan.pricing_model], colorClass: "border" }) }),
227
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: plan.contact_sales ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-muted-foreground", children: "Contattaci" }) : (0, import_growflowbilling_admin_core2.formatCurrency)(plan.price_monthly ?? 0, plan.currency) }),
228
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: plan.contact_sales ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-muted-foreground", children: "Contattaci" }) : (0, import_growflowbilling_admin_core2.formatCurrency)(plan.price_yearly ?? 0, plan.currency) }),
229
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("td", { className: "p-4 align-middle", children: [
189
230
  plan.trial_days,
190
231
  " giorni"
191
232
  ] }),
192
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: plan.is_active ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Check, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.X, { className: "w-4 h-4 text-muted-foreground" }) }),
193
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle", children: plan.stripe_price_id_monthly ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StatusBadge, { label: "Synced", colorClass: "bg-green-50 text-green-700 border-green-200" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
233
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: plan.is_active ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Check, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.X, { className: "w-4 h-4 text-muted-foreground" }) }),
234
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle", children: plan.stripe_price_id_monthly ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatusBadge, { label: "Synced", colorClass: "bg-green-50 text-green-700 border-green-200" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
194
235
  "button",
195
236
  {
196
237
  className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 w-9 hover:bg-accent hover:text-accent-foreground",
197
238
  onClick: () => onSync(plan.id),
198
239
  disabled: isSyncing,
199
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Upload, { className: "w-4 h-4" })
240
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Upload, { className: "w-4 h-4" })
200
241
  }
201
242
  ) }),
202
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "p-4 align-middle text-right", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex justify-end gap-1", children: [
203
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
243
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "p-4 align-middle text-right", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-end gap-1", children: [
244
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
204
245
  "button",
205
246
  {
206
247
  className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 w-9 hover:bg-accent hover:text-accent-foreground",
207
248
  onClick: () => onEdit(plan),
208
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Pencil, { className: "w-4 h-4" })
249
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Pencil, { className: "w-4 h-4" })
209
250
  }
210
251
  ),
211
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
252
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
212
253
  "button",
213
254
  {
214
255
  className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 w-9 text-destructive hover:bg-accent hover:text-destructive",
215
256
  onClick: () => onDelete(plan),
216
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Trash2, { className: "w-4 h-4" })
257
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Trash2, { className: "w-4 h-4" })
217
258
  }
218
259
  )
219
260
  ] }) })
@@ -222,12 +263,200 @@ function PlansTable({
222
263
  }
223
264
 
224
265
  // src/components/plans/PlanFormDialog.tsx
225
- var import_react2 = require("react");
266
+ var import_react4 = require("react");
226
267
  var import_react_query = require("@tanstack/react-query");
227
- var import_lucide_react2 = require("lucide-react");
268
+ var import_lucide_react3 = require("lucide-react");
269
+
270
+ // src/components/shared/ToggleSwitch.tsx
271
+ var import_jsx_runtime6 = require("react/jsx-runtime");
272
+ function ToggleSwitch({ label, checked, onChange }) {
273
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", children: [
274
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
275
+ "button",
276
+ {
277
+ type: "button",
278
+ role: "switch",
279
+ "aria-checked": checked,
280
+ onClick: () => onChange(!checked),
281
+ className: `peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${checked ? "bg-primary" : "bg-input"}`,
282
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
283
+ "span",
284
+ {
285
+ className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${checked ? "translate-x-4" : "translate-x-0"}`
286
+ }
287
+ )
288
+ }
289
+ ),
290
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium leading-none", children: label })
291
+ ] });
292
+ }
293
+
294
+ // src/components/plans/PlanDetailsSection.tsx
295
+ var import_jsx_runtime7 = require("react/jsx-runtime");
296
+ function PlanDetailsSection({
297
+ formData,
298
+ formErrors,
299
+ onFormDataChange,
300
+ onNameChange
301
+ }) {
302
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
303
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
304
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "name", children: "Nome *" }),
305
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
306
+ "input",
307
+ {
308
+ id: "name",
309
+ 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",
310
+ value: formData.name,
311
+ onChange: (e) => onNameChange(e.target.value),
312
+ placeholder: "es. Piano Pro"
313
+ }
314
+ ),
315
+ formErrors.name && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-xs text-destructive", children: formErrors.name })
316
+ ] }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
318
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "description", children: "Descrizione" }),
319
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
320
+ "textarea",
321
+ {
322
+ id: "description",
323
+ 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",
324
+ value: formData.description,
325
+ onChange: (e) => onFormDataChange({ description: e.target.value }),
326
+ placeholder: "Descrizione del piano...",
327
+ rows: 2
328
+ }
329
+ )
330
+ ] }),
331
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
332
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
333
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "text-sm font-medium leading-none", children: "Colore Badge" }),
334
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
335
+ "select",
336
+ {
337
+ 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",
338
+ value: formData.color,
339
+ onChange: (e) => onFormDataChange({ color: e.target.value }),
340
+ children: PLAN_COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: color.value, children: color.label }, color.value))
341
+ }
342
+ ),
343
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
344
+ "Anteprima:",
345
+ " ",
346
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: `inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${getPlanColorClass(formData.color)}`, children: formData.name || "Piano" })
347
+ ] })
348
+ ] }),
349
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-4 pt-6", children: [
350
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleSwitch, { label: "Piano Attivo", checked: formData.is_active, onChange: (v) => onFormDataChange({ is_active: v }) }),
351
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleSwitch, { label: "Contattaci per Prezzi", checked: formData.contact_sales, onChange: (v) => onFormDataChange({ contact_sales: v }) }),
352
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleSwitch, { label: "Visibile in Homepage", checked: formData.is_public, onChange: (v) => onFormDataChange({ is_public: v }) })
353
+ ] })
354
+ ] })
355
+ ] });
356
+ }
357
+
358
+ // src/components/plans/PlanPricingSection.tsx
359
+ var import_jsx_runtime8 = require("react/jsx-runtime");
360
+ function PlanPricingSection({ formData, onFormDataChange }) {
361
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
362
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "grid grid-cols-3 gap-4", children: [
363
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
364
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "text-sm font-medium leading-none", children: "Modello Pricing" }),
365
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
366
+ "select",
367
+ {
368
+ 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",
369
+ value: formData.pricing_model,
370
+ onChange: (e) => onFormDataChange({ pricing_model: e.target.value }),
371
+ children: [
372
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "flat", children: "Fisso" }),
373
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "tiered", children: "A Scaglioni" }),
374
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "per_unit", children: "Per Unit\xE0" }),
375
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "usage_based", children: "A Consumo" })
376
+ ]
377
+ }
378
+ )
379
+ ] }),
380
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
381
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "price_monthly", children: "Prezzo Mensile" }),
382
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
383
+ "input",
384
+ {
385
+ id: "price_monthly",
386
+ type: "number",
387
+ step: "0.01",
388
+ 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",
389
+ value: formData.price_monthly,
390
+ onChange: (e) => onFormDataChange({ price_monthly: e.target.value }),
391
+ placeholder: "0.00"
392
+ }
393
+ )
394
+ ] }),
395
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
396
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "price_yearly", children: "Prezzo Annuale" }),
397
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
398
+ "input",
399
+ {
400
+ id: "price_yearly",
401
+ type: "number",
402
+ step: "0.01",
403
+ 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",
404
+ value: formData.price_yearly,
405
+ onChange: (e) => onFormDataChange({ price_yearly: e.target.value }),
406
+ placeholder: "0.00"
407
+ }
408
+ )
409
+ ] })
410
+ ] }),
411
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "grid grid-cols-3 gap-4", children: [
412
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
413
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "text-sm font-medium leading-none", children: "Valuta" }),
414
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
415
+ "select",
416
+ {
417
+ 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",
418
+ value: formData.currency,
419
+ onChange: (e) => onFormDataChange({ currency: e.target.value }),
420
+ children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "eur", children: "EUR" }),
422
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "usd", children: "USD" }),
423
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "gbp", children: "GBP" })
424
+ ]
425
+ }
426
+ )
427
+ ] }),
428
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
429
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "trial_days", children: "Giorni Trial" }),
430
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
431
+ "input",
432
+ {
433
+ id: "trial_days",
434
+ type: "number",
435
+ 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",
436
+ value: formData.trial_days,
437
+ onChange: (e) => onFormDataChange({ trial_days: parseInt(e.target.value) || 0 })
438
+ }
439
+ )
440
+ ] }),
441
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
442
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "sort_order", children: "Ordine" }),
443
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
444
+ "input",
445
+ {
446
+ id: "sort_order",
447
+ type: "number",
448
+ 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",
449
+ value: formData.sort_order,
450
+ onChange: (e) => onFormDataChange({ sort_order: parseInt(e.target.value) || 0 })
451
+ }
452
+ )
453
+ ] })
454
+ ] })
455
+ ] });
456
+ }
228
457
 
229
458
  // src/components/plans/LimitInput.tsx
230
- var import_jsx_runtime5 = require("react/jsx-runtime");
459
+ var import_jsx_runtime9 = require("react/jsx-runtime");
231
460
  function LimitInput({
232
461
  id,
233
462
  label,
@@ -237,11 +466,11 @@ function LimitInput({
237
466
  onUnlimitedChange,
238
467
  min = 1
239
468
  }) {
240
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-2 p-3 border rounded-lg", children: [
241
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
242
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: id, className: "text-sm font-medium leading-none", children: label }),
243
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
244
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
469
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2 p-3 border rounded-lg", children: [
470
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
471
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { htmlFor: id, className: "text-sm font-medium leading-none", children: label }),
472
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
473
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
245
474
  "button",
246
475
  {
247
476
  type: "button",
@@ -249,7 +478,7 @@ function LimitInput({
249
478
  "aria-checked": isUnlimited,
250
479
  onClick: () => onUnlimitedChange(!isUnlimited),
251
480
  className: `peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${isUnlimited ? "bg-primary" : "bg-input"}`,
252
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
481
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
253
482
  "span",
254
483
  {
255
484
  className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${isUnlimited ? "translate-x-4" : "translate-x-0"}`
@@ -257,10 +486,10 @@ function LimitInput({
257
486
  )
258
487
  }
259
488
  ),
260
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs text-muted-foreground", children: "Illimitati" })
489
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs text-muted-foreground", children: "Illimitati" })
261
490
  ] })
262
491
  ] }),
263
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
492
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
264
493
  "input",
265
494
  {
266
495
  id,
@@ -275,8 +504,275 @@ function LimitInput({
275
504
  ] });
276
505
  }
277
506
 
507
+ // src/components/plans/PlanLimitsSection.tsx
508
+ var import_jsx_runtime10 = require("react/jsx-runtime");
509
+ function PlanLimitsSection({ limitFields, formData, onFormDataChange }) {
510
+ if (limitFields.length === 0) return null;
511
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-3", children: [
512
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "text-sm font-medium leading-none", children: "Limiti Piano" }),
513
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid grid-cols-2 gap-3", children: limitFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
514
+ LimitInput,
515
+ {
516
+ id: `limit_${field.key}`,
517
+ label: field.label,
518
+ value: formData.limits[field.key] ?? field.defaultValue ?? 1,
519
+ isUnlimited: formData.limits_unlimited[field.key] ?? false,
520
+ onValueChange: (v) => onFormDataChange({ limits: { ...formData.limits, [field.key]: v } }),
521
+ onUnlimitedChange: (v) => onFormDataChange({ limits_unlimited: { ...formData.limits_unlimited, [field.key]: v } })
522
+ },
523
+ field.key
524
+ )) })
525
+ ] });
526
+ }
527
+
528
+ // src/components/plans/PlanFeaturesSection.tsx
529
+ var import_react3 = require("react");
530
+
531
+ // src/lib/plan-feature-state.ts
532
+ var FEATURE_STATE_DESCRIPTIONS = {
533
+ off: "Non disponibile per gli utenti di questo piano (default).",
534
+ teaser: "Mostrata in sidebar come locked con CTA upgrade. Non attivata funzionalmente.",
535
+ on: "Inclusa nel piano e pienamente accessibile.",
536
+ sunset: "Tecnicamente nel piano ma nascosta. Uso raro (deprecazioni / incidenti)."
537
+ };
538
+ function featureStateFromPlan(slug, features, uiVisibility) {
539
+ const inPlan = (features ?? []).includes(slug);
540
+ const ui = (uiVisibility ?? {})[slug];
541
+ if (inPlan) {
542
+ if (ui === "hidden") return "sunset";
543
+ return "on";
544
+ }
545
+ if (ui === "teaser") return "teaser";
546
+ return "off";
547
+ }
548
+ function applyFeatureState(slug, state, features, uiVisibility) {
549
+ const nextFeaturesSet = new Set(features ?? []);
550
+ const nextUi = { ...uiVisibility ?? {} };
551
+ switch (state) {
552
+ case "off":
553
+ nextFeaturesSet.delete(slug);
554
+ delete nextUi[slug];
555
+ break;
556
+ case "teaser":
557
+ nextFeaturesSet.delete(slug);
558
+ nextUi[slug] = "teaser";
559
+ break;
560
+ case "on":
561
+ nextFeaturesSet.add(slug);
562
+ delete nextUi[slug];
563
+ break;
564
+ case "sunset":
565
+ nextFeaturesSet.add(slug);
566
+ nextUi[slug] = "hidden";
567
+ break;
568
+ }
569
+ return {
570
+ features: Array.from(nextFeaturesSet),
571
+ uiVisibility: nextUi
572
+ };
573
+ }
574
+ function summarizeFeatureStates(features, uiVisibility) {
575
+ const counts = {
576
+ off: 0,
577
+ teaser: 0,
578
+ on: 0,
579
+ sunset: 0
580
+ };
581
+ const slugs = /* @__PURE__ */ new Set([
582
+ ...features ?? [],
583
+ ...Object.keys(uiVisibility ?? {})
584
+ ]);
585
+ for (const slug of slugs) {
586
+ const state = featureStateFromPlan(slug, features, uiVisibility);
587
+ counts[state] += 1;
588
+ }
589
+ return counts;
590
+ }
591
+
592
+ // src/components/plans/PlanFeatureRow.tsx
593
+ var import_lucide_react2 = require("lucide-react");
594
+ var import_jsx_runtime11 = require("react/jsx-runtime");
595
+ var STATE_VISUAL = {
596
+ off: {
597
+ label: "Non inclusa",
598
+ Icon: import_lucide_react2.CircleSlash,
599
+ classes: "bg-muted text-muted-foreground border-muted-foreground/20"
600
+ },
601
+ teaser: {
602
+ label: "Teaser",
603
+ Icon: import_lucide_react2.Lock,
604
+ classes: "bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-700"
605
+ },
606
+ on: {
607
+ label: "Inclusa",
608
+ Icon: import_lucide_react2.Check,
609
+ classes: "bg-green-100 text-green-800 border-green-300 dark:bg-green-900/30 dark:text-green-400 dark:border-green-700"
610
+ },
611
+ sunset: {
612
+ label: "Sunset",
613
+ Icon: import_lucide_react2.Archive,
614
+ classes: "bg-rose-100 text-rose-800 border-rose-300 dark:bg-rose-900/30 dark:text-rose-400 dark:border-rose-700"
615
+ }
616
+ };
617
+ function PlanFeatureRow({
618
+ slug,
619
+ name,
620
+ description,
621
+ state,
622
+ showSunset = false,
623
+ onChange,
624
+ onRemove
625
+ }) {
626
+ const visual = STATE_VISUAL[state];
627
+ const Icon = visual.Icon;
628
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-start gap-3 p-2 rounded-md hover:bg-muted/50 transition-colors", children: [
629
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 min-w-0", children: [
630
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 flex-wrap", children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-sm font-medium truncate", children: name || slug }),
632
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
633
+ "span",
634
+ {
635
+ className: `inline-flex items-center h-5 text-[10px] px-1.5 gap-1 rounded-md border ${visual.classes}`,
636
+ children: [
637
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { className: "h-3 w-3 mr-1" }),
638
+ visual.label
639
+ ]
640
+ }
641
+ )
642
+ ] }),
643
+ description && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-1", children: description }),
644
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { className: "text-[10px] text-muted-foreground bg-muted px-1.5 py-0.5 rounded mt-1 inline-block", children: slug })
645
+ ] }),
646
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
647
+ "select",
648
+ {
649
+ value: state,
650
+ onChange: (e) => onChange(slug, e.target.value),
651
+ "aria-label": `Stato per ${slug}`,
652
+ className: "h-8 w-[140px] text-xs flex-shrink-0 rounded-md border border-input bg-background px-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
653
+ children: [
654
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "off", title: FEATURE_STATE_DESCRIPTIONS.off, children: "Non inclusa" }),
655
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "teaser", title: FEATURE_STATE_DESCRIPTIONS.teaser, children: "Teaser" }),
656
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "on", title: FEATURE_STATE_DESCRIPTIONS.on, children: "Inclusa" }),
657
+ showSunset && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "sunset", title: FEATURE_STATE_DESCRIPTIONS.sunset, children: "Sunset (admin)" })
658
+ ]
659
+ }
660
+ ),
661
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
662
+ "button",
663
+ {
664
+ type: "button",
665
+ onClick: onRemove,
666
+ className: "text-muted-foreground hover:text-destructive text-xs mt-1",
667
+ "aria-label": `Rimuovi override ${slug}`,
668
+ children: "\u2715"
669
+ }
670
+ )
671
+ ] });
672
+ }
673
+
674
+ // src/components/plans/PlanFeaturesSection.tsx
675
+ var import_jsx_runtime12 = require("react/jsx-runtime");
676
+ function PlanFeaturesSection({
677
+ availableFeatures,
678
+ selectedFeatureSlugs,
679
+ uiVisibility,
680
+ onFeatureStateChange
681
+ }) {
682
+ const [showSunset, setShowSunset] = (0, import_react3.useState)(false);
683
+ const rowSlugs = (0, import_react3.useMemo)(() => {
684
+ const out = new Set(availableFeatures.map((f) => f.slug));
685
+ for (const slug of selectedFeatureSlugs) out.add(slug);
686
+ for (const slug of Object.keys(uiVisibility)) out.add(slug);
687
+ return Array.from(out).sort();
688
+ }, [availableFeatures, selectedFeatureSlugs, uiVisibility]);
689
+ const stateCounts = (0, import_react3.useMemo)(
690
+ () => summarizeFeatureStates(selectedFeatureSlugs, uiVisibility),
691
+ [selectedFeatureSlugs, uiVisibility]
692
+ );
693
+ const handleChange = (slug, next) => {
694
+ const result = applyFeatureState(
695
+ slug,
696
+ next,
697
+ selectedFeatureSlugs,
698
+ uiVisibility
699
+ );
700
+ onFeatureStateChange(result);
701
+ };
702
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-2", children: [
703
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [
704
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { className: "text-sm font-medium leading-none", children: "Funzionalit\xE0 del piano" }),
705
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1 text-xs", children: [
706
+ stateCounts.on > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex items-center rounded-md border px-1.5 py-0.5 bg-green-100 text-green-800 border-green-300 dark:bg-green-900/30 dark:text-green-400 dark:border-green-700", children: [
707
+ stateCounts.on,
708
+ " inclusa",
709
+ stateCounts.on !== 1 ? "e" : ""
710
+ ] }),
711
+ stateCounts.teaser > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex items-center rounded-md border px-1.5 py-0.5 bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-700", children: [
712
+ stateCounts.teaser,
713
+ " teaser"
714
+ ] }),
715
+ stateCounts.sunset > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex items-center rounded-md border px-1.5 py-0.5 bg-rose-100 text-rose-800 border-rose-300 dark:bg-rose-900/30 dark:text-rose-400 dark:border-rose-700", children: [
716
+ stateCounts.sunset,
717
+ " sunset"
718
+ ] })
719
+ ] })
720
+ ] }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
722
+ "Per ogni funzionalit\xE0 scegli lo stato: ",
723
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Non inclusa" }),
724
+ " ",
725
+ "(default), ",
726
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Teaser" }),
727
+ " (mostrata come locked con CTA upgrade), o ",
728
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Inclusa" }),
729
+ " (attiva). Lo stato scrive automaticamente le feature del piano e la visibility UI."
730
+ ] }),
731
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "border rounded-lg p-2 space-y-1 max-h-[320px] overflow-y-auto", children: rowSlugs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground text-center py-4", children: "Nessuna funzionalit\xE0 disponibile nel catalogo." }) : rowSlugs.map((slug) => {
732
+ const feature = availableFeatures.find((f) => f.slug === slug);
733
+ const state = featureStateFromPlan(
734
+ slug,
735
+ selectedFeatureSlugs,
736
+ uiVisibility
737
+ );
738
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
739
+ PlanFeatureRow,
740
+ {
741
+ slug,
742
+ name: feature?.name,
743
+ description: feature?.description,
744
+ state,
745
+ showSunset,
746
+ onChange: handleChange
747
+ },
748
+ slug
749
+ );
750
+ }) }),
751
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2 pt-1", children: [
752
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
753
+ "input",
754
+ {
755
+ id: "show-advanced-state",
756
+ type: "checkbox",
757
+ checked: showSunset,
758
+ onChange: (e) => setShowSunset(e.target.checked),
759
+ className: "h-4 w-4 rounded border-input cursor-pointer"
760
+ }
761
+ ),
762
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
763
+ "label",
764
+ {
765
+ htmlFor: "show-advanced-state",
766
+ className: "text-xs text-muted-foreground cursor-pointer",
767
+ children: 'Mostra stato avanzato "Sunset" (feature deprecate)'
768
+ }
769
+ )
770
+ ] })
771
+ ] });
772
+ }
773
+
278
774
  // src/components/plans/PlanFormDialog.tsx
279
- var import_jsx_runtime6 = require("react/jsx-runtime");
775
+ var import_jsx_runtime13 = require("react/jsx-runtime");
280
776
  function createDefaultPlanFormData(limitFields = []) {
281
777
  const limits = {};
282
778
  const limitsUnlimited = {};
@@ -300,9 +796,13 @@ function createDefaultPlanFormData(limitFields = []) {
300
796
  limits,
301
797
  limits_unlimited: limitsUnlimited,
302
798
  features: "",
799
+ ui_visibility: {},
303
800
  sort_order: 0
304
801
  };
305
802
  }
803
+ function generateSlug(name) {
804
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
805
+ }
306
806
  function PlanFormDialog({
307
807
  open,
308
808
  onOpenChange,
@@ -316,221 +816,74 @@ function PlanFormDialog({
316
816
  const config = useBillingAdminConfig();
317
817
  const limitFields = config.plans?.limitFields || [];
318
818
  const featuresConfig = config.plans?.features;
819
+ const isCreating = !selectedPlan;
319
820
  const { data: featuresData } = (0, import_react_query.useQuery)({
320
821
  queryKey: ["billing-admin-available-features"],
321
822
  queryFn: () => featuresConfig?.fetchFn?.() ?? Promise.resolve({ features: [] }),
322
823
  enabled: !!featuresConfig?.enabled && !!featuresConfig?.fetchFn
323
824
  });
324
825
  const availableFeatures = featuresData?.features || [];
325
- const [selectedFeatureSlugs, setSelectedFeatureSlugs] = (0, import_react2.useState)([]);
326
- (0, import_react2.useEffect)(() => {
327
- if (formData.features) {
328
- const slugs = formData.features.split("\n").map((line) => line.trim()).filter(Boolean);
329
- setSelectedFeatureSlugs(slugs);
826
+ const selectedFeatureSlugs = (0, import_react4.useMemo)(
827
+ () => formData.features ? formData.features.split("\n").map((line) => line.trim()).filter(Boolean) : [],
828
+ [formData.features]
829
+ );
830
+ const uiVisibility = (0, import_react4.useMemo)(
831
+ () => formData.ui_visibility ?? {},
832
+ [formData.ui_visibility]
833
+ );
834
+ const handleNameChange = (name) => {
835
+ if (isCreating) {
836
+ onFormDataChange({ name, slug: generateSlug(name) });
837
+ } else {
838
+ onFormDataChange({ name });
330
839
  }
331
- }, [formData.features]);
332
- const handleFeatureToggle = (slug, checked) => {
333
- const updated = checked ? [...selectedFeatureSlugs, slug] : selectedFeatureSlugs.filter((s) => s !== slug);
334
- setSelectedFeatureSlugs(updated);
335
- onFormDataChange({ features: updated.join("\n") });
840
+ };
841
+ const handleFeatureStateChange = (next) => {
842
+ onFormDataChange({
843
+ features: next.features.join("\n"),
844
+ ui_visibility: next.uiVisibility
845
+ });
336
846
  };
337
847
  if (!open) return null;
338
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
339
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
340
- /* @__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: [
341
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
342
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "text-lg font-semibold leading-none tracking-tight", children: selectedPlan ? "Modifica Piano" : "Nuovo Piano" }),
343
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm text-muted-foreground", children: selectedPlan ? "Modifica le impostazioni del piano selezionato" : "Crea un nuovo piano di abbonamento" })
848
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
849
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
850
+ /* @__PURE__ */ (0, import_jsx_runtime13.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: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
852
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-lg font-semibold leading-none tracking-tight", children: selectedPlan ? "Modifica Piano" : "Nuovo Piano" }),
853
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-muted-foreground", children: selectedPlan ? "Modifica le impostazioni del piano selezionato" : "Crea un nuovo piano di abbonamento" })
344
854
  ] }),
345
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid gap-4 py-4", children: [
346
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
347
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
348
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "slug", children: "Slug *" }),
349
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
350
- "input",
351
- {
352
- id: "slug",
353
- 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 disabled:opacity-50",
354
- value: formData.slug,
355
- onChange: (e) => onFormDataChange({ slug: e.target.value }),
356
- placeholder: "es. pro, enterprise",
357
- disabled: !!selectedPlan
358
- }
359
- ),
360
- formErrors.slug && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-destructive", children: formErrors.slug })
361
- ] }),
362
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
363
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "name", children: "Nome *" }),
364
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
365
- "input",
366
- {
367
- id: "name",
368
- 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",
369
- value: formData.name,
370
- onChange: (e) => onFormDataChange({ name: e.target.value }),
371
- placeholder: "es. Piano Pro"
372
- }
373
- ),
374
- formErrors.name && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-destructive", children: formErrors.name })
375
- ] })
376
- ] }),
377
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
378
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "description", children: "Descrizione" }),
379
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
380
- "textarea",
381
- {
382
- id: "description",
383
- 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",
384
- value: formData.description,
385
- onChange: (e) => onFormDataChange({ description: e.target.value }),
386
- placeholder: "Descrizione del piano...",
387
- rows: 2
388
- }
389
- )
390
- ] }),
391
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-3 gap-4", children: [
392
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
393
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", children: "Modello Pricing" }),
394
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
395
- "select",
396
- {
397
- 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",
398
- value: formData.pricing_model,
399
- onChange: (e) => onFormDataChange({ pricing_model: e.target.value }),
400
- children: [
401
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "flat", children: "Fisso" }),
402
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "tiered", children: "A Scaglioni" }),
403
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "per_unit", children: "Per Unit\xE0" }),
404
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "usage_based", children: "A Consumo" })
405
- ]
406
- }
407
- )
408
- ] }),
409
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
410
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "price_monthly", children: "Prezzo Mensile" }),
411
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
412
- "input",
413
- {
414
- id: "price_monthly",
415
- type: "number",
416
- step: "0.01",
417
- 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",
418
- value: formData.price_monthly,
419
- onChange: (e) => onFormDataChange({ price_monthly: e.target.value }),
420
- placeholder: "0.00"
421
- }
422
- )
423
- ] }),
424
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
425
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "price_yearly", children: "Prezzo Annuale" }),
426
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
427
- "input",
428
- {
429
- id: "price_yearly",
430
- type: "number",
431
- step: "0.01",
432
- 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",
433
- value: formData.price_yearly,
434
- onChange: (e) => onFormDataChange({ price_yearly: e.target.value }),
435
- placeholder: "0.00"
436
- }
437
- )
438
- ] })
439
- ] }),
440
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-3 gap-4", children: [
441
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
442
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", children: "Valuta" }),
443
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
444
- "select",
445
- {
446
- 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",
447
- value: formData.currency,
448
- onChange: (e) => onFormDataChange({ currency: e.target.value }),
449
- children: [
450
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "eur", children: "EUR" }),
451
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "usd", children: "USD" }),
452
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "gbp", children: "GBP" })
453
- ]
454
- }
455
- )
456
- ] }),
457
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
458
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "trial_days", children: "Giorni Trial" }),
459
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { id: "trial_days", 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: formData.trial_days, onChange: (e) => onFormDataChange({ trial_days: parseInt(e.target.value) || 0 }) })
460
- ] }),
461
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
462
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "sort_order", children: "Ordine" }),
463
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { id: "sort_order", 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: formData.sort_order, onChange: (e) => onFormDataChange({ sort_order: parseInt(e.target.value) || 0 }) })
464
- ] })
465
- ] }),
466
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
467
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
468
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", children: "Colore Badge" }),
469
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
470
- "select",
471
- {
472
- 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",
473
- value: formData.color,
474
- onChange: (e) => onFormDataChange({ color: e.target.value }),
475
- children: PLAN_COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: color.value, children: color.label }, color.value))
476
- }
477
- ),
478
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
479
- "Anteprima: ",
480
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${getPlanColorClass(formData.color)}`, children: formData.name || "Piano" })
481
- ] })
482
- ] }),
483
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-4 pt-6", children: [
484
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleSwitch, { label: "Piano Attivo", checked: formData.is_active, onChange: (v) => onFormDataChange({ is_active: v }) }),
485
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleSwitch, { label: "Contattaci per Prezzi", checked: formData.contact_sales, onChange: (v) => onFormDataChange({ contact_sales: v }) }),
486
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleSwitch, { label: "Visibile in Homepage", checked: formData.is_public, onChange: (v) => onFormDataChange({ is_public: v }) })
487
- ] })
488
- ] }),
489
- limitFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-3", children: [
490
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", children: "Limiti Piano" }),
491
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "grid grid-cols-2 gap-3", children: limitFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
492
- LimitInput,
493
- {
494
- id: `limit_${field.key}`,
495
- label: field.label,
496
- value: formData.limits[field.key] ?? field.defaultValue ?? 1,
497
- isUnlimited: formData.limits_unlimited[field.key] ?? false,
498
- onValueChange: (v) => onFormDataChange({ limits: { ...formData.limits, [field.key]: v } }),
499
- onUnlimitedChange: (v) => onFormDataChange({ limits_unlimited: { ...formData.limits_unlimited, [field.key]: v } })
500
- },
501
- field.key
502
- )) })
503
- ] }),
504
- featuresConfig?.enabled && availableFeatures.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
505
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "text-sm font-medium leading-none", children: "Features Incluse nel Piano" }),
506
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "border rounded-lg p-3 space-y-2 max-h-64 overflow-y-auto", children: availableFeatures.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-3 p-2 hover:bg-muted/50 rounded", children: [
507
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
508
- "input",
509
- {
510
- type: "checkbox",
511
- id: `feature-${feature.slug}`,
512
- checked: selectedFeatureSlugs.includes(feature.slug),
513
- onChange: (e) => handleFeatureToggle(feature.slug, e.target.checked),
514
- className: "h-4 w-4 rounded border-input"
515
- }
516
- ),
517
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex-1", children: [
518
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { htmlFor: `feature-${feature.slug}`, className: "text-sm font-medium cursor-pointer", children: feature.name }),
519
- feature.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-muted-foreground", children: feature.description })
520
- ] }),
521
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded", children: feature.slug })
522
- ] }, feature.slug)) }),
523
- selectedFeatureSlugs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-wrap gap-2 pt-2", children: selectedFeatureSlugs.map((slug) => {
524
- const feature = availableFeatures.find((f) => f.slug === slug);
525
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-secondary text-secondary-foreground gap-1", children: [
526
- feature?.name || slug,
527
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: () => handleFeatureToggle(slug, false), className: "ml-1 hover:bg-destructive/20 rounded-full", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.X, { className: "h-3 w-3" }) })
528
- ] }, slug);
529
- }) })
530
- ] })
855
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid gap-4 py-4", children: [
856
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
857
+ PlanDetailsSection,
858
+ {
859
+ formData,
860
+ formErrors,
861
+ isCreating,
862
+ onFormDataChange,
863
+ onNameChange: handleNameChange
864
+ }
865
+ ),
866
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PlanPricingSection, { formData, onFormDataChange }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
868
+ PlanLimitsSection,
869
+ {
870
+ limitFields,
871
+ formData,
872
+ onFormDataChange
873
+ }
874
+ ),
875
+ featuresConfig?.enabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
876
+ PlanFeaturesSection,
877
+ {
878
+ availableFeatures,
879
+ selectedFeatureSlugs,
880
+ uiVisibility,
881
+ onFeatureStateChange: handleFeatureStateChange
882
+ }
883
+ )
531
884
  ] }),
532
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
533
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
885
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
886
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
534
887
  "button",
535
888
  {
536
889
  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",
@@ -538,14 +891,14 @@ function PlanFormDialog({
538
891
  children: "Annulla"
539
892
  }
540
893
  ),
541
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
894
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
542
895
  "button",
543
896
  {
544
897
  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",
545
898
  onClick: onSubmit,
546
899
  disabled: isPending,
547
900
  children: [
548
- isPending && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
901
+ isPending && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
549
902
  selectedPlan ? "Salva Modifiche" : "Crea Piano"
550
903
  ]
551
904
  }
@@ -554,26 +907,10 @@ function PlanFormDialog({
554
907
  ] })
555
908
  ] });
556
909
  }
557
- function ToggleSwitch({ label, checked, onChange }) {
558
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", children: [
559
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
560
- "button",
561
- {
562
- type: "button",
563
- role: "switch",
564
- "aria-checked": checked,
565
- onClick: () => onChange(!checked),
566
- className: `peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${checked ? "bg-primary" : "bg-input"}`,
567
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${checked ? "translate-x-4" : "translate-x-0"}` })
568
- }
569
- ),
570
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium leading-none", children: label })
571
- ] });
572
- }
573
910
 
574
911
  // src/components/shared/DeleteConfirmDialog.tsx
575
- var import_lucide_react3 = require("lucide-react");
576
- var import_jsx_runtime7 = require("react/jsx-runtime");
912
+ var import_lucide_react4 = require("lucide-react");
913
+ var import_jsx_runtime14 = require("react/jsx-runtime");
577
914
  function DeleteConfirmDialog({
578
915
  isOpen,
579
916
  onOpenChange,
@@ -585,21 +922,21 @@ function DeleteConfirmDialog({
585
922
  cancelLabel = "Annulla"
586
923
  }) {
587
924
  if (!isOpen) return null;
588
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
589
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
925
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
590
927
  "div",
591
928
  {
592
929
  className: "fixed inset-0 bg-black/80",
593
930
  onClick: () => onOpenChange(false)
594
931
  }
595
932
  ),
596
- /* @__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: [
597
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col space-y-2 text-center sm:text-left", children: [
598
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "text-lg font-semibold", children: title }),
599
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-muted-foreground", children: description })
933
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
934
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col space-y-2 text-center sm:text-left", children: [
935
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h2", { className: "text-lg font-semibold", children: title }),
936
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "text-sm text-muted-foreground", children: description })
600
937
  ] }),
601
- /* @__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: [
602
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
938
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 mt-4", children: [
939
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
603
940
  "button",
604
941
  {
605
942
  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",
@@ -607,14 +944,14 @@ function DeleteConfirmDialog({
607
944
  children: cancelLabel
608
945
  }
609
946
  ),
610
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
947
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
611
948
  "button",
612
949
  {
613
950
  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",
614
951
  onClick: onConfirm,
615
952
  disabled: isDeleting,
616
953
  children: [
617
- isDeleting && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
954
+ isDeleting && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
618
955
  confirmLabel
619
956
  ]
620
957
  }
@@ -625,23 +962,22 @@ function DeleteConfirmDialog({
625
962
  }
626
963
 
627
964
  // src/pages/PlansPage.tsx
628
- var import_jsx_runtime8 = require("react/jsx-runtime");
965
+ var import_jsx_runtime15 = require("react/jsx-runtime");
629
966
  function PlansPage({ wrapper: Wrapper, header }) {
630
967
  const config = useBillingAdminConfig();
631
968
  const limitFields = config.plans?.limitFields || [];
632
969
  const publicPlansConfig = config.plans?.publicPlans;
633
- const [showForm, setShowForm] = (0, import_react3.useState)(false);
634
- const [showDeleteDialog, setShowDeleteDialog] = (0, import_react3.useState)(false);
635
- const [selectedPlan, setSelectedPlan] = (0, import_react3.useState)(null);
636
- const [formData, setFormData] = (0, import_react3.useState)(createDefaultPlanFormData(limitFields));
637
- const [formErrors, setFormErrors] = (0, import_react3.useState)({});
970
+ const formDialog = (0, import_growflowbilling_admin_core3.useDialogState)();
971
+ const deleteDialog = (0, import_growflowbilling_admin_core3.useDialogState)();
972
+ const [formData, setFormData] = (0, import_react5.useState)(createDefaultPlanFormData(limitFields));
973
+ const [formErrors, setFormErrors] = (0, import_react5.useState)({});
638
974
  const { data, isLoading, refetch } = (0, import_growflowbilling_admin_core3.useAdminPlans)();
639
975
  const createMutation = (0, import_growflowbilling_admin_core3.useCreatePlan)();
640
976
  const updateMutation = (0, import_growflowbilling_admin_core3.useUpdatePlan)();
641
977
  const deleteMutation = (0, import_growflowbilling_admin_core3.useDeletePlan)();
642
978
  const syncMutation = (0, import_growflowbilling_admin_core3.useSyncPlanToStripe)();
643
- const [publicPlanSlugs, setPublicPlanSlugs] = (0, import_react3.useState)([]);
644
- (0, import_react3.useState)(() => {
979
+ const [publicPlanSlugs, setPublicPlanSlugs] = (0, import_react5.useState)([]);
980
+ (0, import_react5.useState)(() => {
645
981
  if (publicPlansConfig?.enabled && publicPlansConfig.fetchFn) {
646
982
  publicPlansConfig.fetchFn().then((r) => setPublicPlanSlugs(r.public_plan_slugs));
647
983
  }
@@ -649,15 +985,13 @@ function PlansPage({ wrapper: Wrapper, header }) {
649
985
  const plans = data?.items || [];
650
986
  const resetForm = () => {
651
987
  setFormData(createDefaultPlanFormData(limitFields));
652
- setSelectedPlan(null);
653
988
  setFormErrors({});
654
989
  };
655
990
  const openCreateForm = () => {
656
991
  resetForm();
657
- setShowForm(true);
992
+ formDialog.open(void 0);
658
993
  };
659
994
  const openEditForm = (plan) => {
660
- setSelectedPlan(plan);
661
995
  const planLimits = plan.limits || {};
662
996
  const limits = {};
663
997
  const limitsUnlimited = {};
@@ -682,27 +1016,28 @@ function PlansPage({ wrapper: Wrapper, header }) {
682
1016
  limits,
683
1017
  limits_unlimited: limitsUnlimited,
684
1018
  features: plan.features?.join("\n") || "",
1019
+ ui_visibility: plan.ui_visibility ?? {},
685
1020
  sort_order: plan.sort_order
686
1021
  });
687
- setShowForm(true);
1022
+ formDialog.open(plan);
688
1023
  };
689
1024
  const handleValidate = () => {
690
1025
  const errors = {};
691
- const slugErr = (0, import_growflowbilling_admin_core3.validateSlug)(formData.slug);
692
- if (slugErr) errors.slug = slugErr;
693
1026
  const nameErr = (0, import_growflowbilling_admin_core3.validateRequired)(formData.name, "Il nome");
694
1027
  if (nameErr) errors.name = nameErr;
695
1028
  setFormErrors(errors);
696
1029
  return Object.keys(errors).length === 0;
697
1030
  };
698
1031
  const handleSubmit = async () => {
1032
+ const resolvedSlug = formData.slug.trim() || formData.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
1033
+ const finalFormData = { ...formData, slug: resolvedSlug };
699
1034
  if (!handleValidate()) return;
700
1035
  const limits = {};
701
1036
  for (const field of limitFields) {
702
- limits[field.key] = formData.limits_unlimited[field.key] ? -1 : formData.limits[field.key] ?? 1;
1037
+ limits[field.key] = finalFormData.limits_unlimited[field.key] ? -1 : finalFormData.limits[field.key] ?? 1;
703
1038
  }
704
1039
  const planData = {
705
- slug: formData.slug,
1040
+ slug: finalFormData.slug,
706
1041
  name: formData.name,
707
1042
  description: formData.description || void 0,
708
1043
  pricing_model: formData.pricing_model,
@@ -715,13 +1050,16 @@ function PlansPage({ wrapper: Wrapper, header }) {
715
1050
  color: formData.color,
716
1051
  limits: Object.keys(limits).length > 0 ? limits : void 0,
717
1052
  features: formData.features.split("\n").filter((f) => f.trim()),
1053
+ // Send the full map — empty ``{}`` is meaningful (clears any
1054
+ // lingering overrides) so we never fall back to ``undefined``.
1055
+ ui_visibility: formData.ui_visibility ?? {},
718
1056
  sort_order: formData.sort_order
719
1057
  };
720
1058
  if (publicPlansConfig?.enabled && publicPlansConfig.updateFn) {
721
- const isCurrentlyPublic = publicPlanSlugs.includes(formData.slug);
722
- if (formData.is_public !== isCurrentlyPublic) {
1059
+ const isCurrentlyPublic = publicPlanSlugs.includes(finalFormData.slug);
1060
+ if (finalFormData.is_public !== isCurrentlyPublic) {
723
1061
  try {
724
- const newSlugs = formData.is_public ? [...publicPlanSlugs, formData.slug] : publicPlanSlugs.filter((s) => s !== formData.slug);
1062
+ const newSlugs = finalFormData.is_public ? [...publicPlanSlugs, finalFormData.slug] : publicPlanSlugs.filter((s) => s !== finalFormData.slug);
725
1063
  await publicPlansConfig.updateFn(newSlugs);
726
1064
  setPublicPlanSlugs(newSlugs);
727
1065
  } catch {
@@ -729,11 +1067,11 @@ function PlansPage({ wrapper: Wrapper, header }) {
729
1067
  }
730
1068
  }
731
1069
  }
732
- if (selectedPlan) {
733
- updateMutation.mutate({ id: selectedPlan.id, data: planData }, {
1070
+ if (formDialog.data) {
1071
+ updateMutation.mutate({ id: formDialog.data.id, data: planData }, {
734
1072
  onSuccess: () => {
735
1073
  import_sonner.toast.success("Piano aggiornato con successo");
736
- setShowForm(false);
1074
+ formDialog.close();
737
1075
  resetForm();
738
1076
  },
739
1077
  onError: (err) => import_sonner.toast.error(`Errore: ${err.message}`)
@@ -742,7 +1080,7 @@ function PlansPage({ wrapper: Wrapper, header }) {
742
1080
  createMutation.mutate(planData, {
743
1081
  onSuccess: () => {
744
1082
  import_sonner.toast.success("Piano creato con successo");
745
- setShowForm(false);
1083
+ formDialog.close();
746
1084
  resetForm();
747
1085
  },
748
1086
  onError: (err) => import_sonner.toast.error(`Errore: ${err.message}`)
@@ -750,49 +1088,45 @@ function PlansPage({ wrapper: Wrapper, header }) {
750
1088
  }
751
1089
  };
752
1090
  const handleDelete = () => {
753
- if (selectedPlan) {
754
- deleteMutation.mutate(selectedPlan.id, {
1091
+ if (deleteDialog.data) {
1092
+ deleteMutation.mutate(deleteDialog.data.id, {
755
1093
  onSuccess: () => {
756
1094
  import_sonner.toast.success("Piano eliminato con successo");
757
- setShowDeleteDialog(false);
758
- setSelectedPlan(null);
1095
+ deleteDialog.close();
759
1096
  },
760
1097
  onError: (err) => import_sonner.toast.error(`Errore: ${err.message}`)
761
1098
  });
762
1099
  }
763
1100
  };
764
- const content = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1101
+ const content = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
765
1102
  header,
766
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-4", children: [
767
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between", children: [
768
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
769
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.LayoutGrid, { className: "w-4 h-4" }),
770
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1103
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-4", children: [
1104
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
1105
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1106
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.LayoutGrid, { className: "w-4 h-4" }),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
771
1108
  plans.length,
772
1109
  " piani configurati"
773
1110
  ] })
774
1111
  ] }),
775
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-2", children: [
776
- /* @__PURE__ */ (0, import_jsx_runtime8.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: [
777
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.RefreshCw, { className: "w-4 h-4 mr-2" }),
1112
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-2", children: [
1113
+ /* @__PURE__ */ (0, import_jsx_runtime15.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: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.RefreshCw, { className: "w-4 h-4 mr-2" }),
778
1115
  "Aggiorna"
779
1116
  ] }),
780
- /* @__PURE__ */ (0, import_jsx_runtime8.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: openCreateForm, children: [
781
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.Plus, { className: "w-4 h-4 mr-2" }),
1117
+ /* @__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", onClick: openCreateForm, children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Plus, { className: "w-4 h-4 mr-2" }),
782
1119
  "Nuovo Piano"
783
1120
  ] })
784
1121
  ] })
785
1122
  ] }),
786
- /* @__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-0", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1123
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
787
1124
  PlansTable,
788
1125
  {
789
1126
  plans,
790
1127
  isLoading,
791
1128
  onEdit: openEditForm,
792
- onDelete: (plan) => {
793
- setSelectedPlan(plan);
794
- setShowDeleteDialog(true);
795
- },
1129
+ onDelete: (plan) => deleteDialog.open(plan),
796
1130
  onSync: (id) => syncMutation.mutate(id, {
797
1131
  onSuccess: () => import_sonner.toast.success("Piano sincronizzato con Stripe"),
798
1132
  onError: (err) => import_sonner.toast.error(`Errore sync: ${err.message}`)
@@ -801,30 +1135,37 @@ function PlansPage({ wrapper: Wrapper, header }) {
801
1135
  }
802
1136
  ) }) })
803
1137
  ] }),
804
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1138
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
805
1139
  PlanFormDialog,
806
1140
  {
807
- open: showForm,
808
- onOpenChange: setShowForm,
1141
+ open: formDialog.isOpen,
1142
+ onOpenChange: (open) => {
1143
+ if (!open) {
1144
+ formDialog.close();
1145
+ resetForm();
1146
+ }
1147
+ },
809
1148
  formData,
810
1149
  onFormDataChange: (data2) => setFormData((prev) => ({ ...prev, ...data2 })),
811
1150
  formErrors,
812
- selectedPlan,
1151
+ selectedPlan: formDialog.data ?? null,
813
1152
  onSubmit: handleSubmit,
814
1153
  isPending: createMutation.isPending || updateMutation.isPending
815
1154
  }
816
1155
  ),
817
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1156
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
818
1157
  DeleteConfirmDialog,
819
1158
  {
820
- isOpen: showDeleteDialog,
821
- onOpenChange: setShowDeleteDialog,
1159
+ isOpen: deleteDialog.isOpen,
1160
+ onOpenChange: (open) => {
1161
+ if (!open) deleteDialog.close();
1162
+ },
822
1163
  title: "Eliminare Piano?",
823
- description: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1164
+ description: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
824
1165
  "Stai per eliminare il piano ",
825
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: selectedPlan?.name }),
1166
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: deleteDialog.data?.name }),
826
1167
  " (",
827
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: selectedPlan?.slug }),
1168
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("code", { children: deleteDialog.data?.slug }),
828
1169
  "). Questa azione non pu\xF2 essere annullata."
829
1170
  ] }),
830
1171
  onConfirm: handleDelete,
@@ -833,19 +1174,27 @@ function PlansPage({ wrapper: Wrapper, header }) {
833
1174
  }
834
1175
  )
835
1176
  ] });
836
- return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Wrapper, { children: content }) : content;
1177
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Wrapper, { children: content }) : content;
837
1178
  }
838
1179
 
839
1180
  // src/pages/ProductsPage.tsx
840
1181
  var import_sonner2 = require("sonner");
841
- var import_lucide_react6 = require("lucide-react");
1182
+ var import_lucide_react7 = require("lucide-react");
842
1183
  var import_react_query2 = require("@tanstack/react-query");
843
1184
  var import_growflowbilling_admin_core4 = require("@growflowstudio/growflowbilling-admin-core");
844
1185
 
845
1186
  // src/components/products/ProductFormDialog.tsx
846
- var import_react4 = require("react");
847
- var import_lucide_react5 = require("lucide-react");
848
- var import_jsx_runtime9 = require("react/jsx-runtime");
1187
+ var import_react6 = require("react");
1188
+ var import_lucide_react6 = require("lucide-react");
1189
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1190
+ var safeJsonParse = (str, fallback = {}) => {
1191
+ try {
1192
+ const parsed = JSON.parse(str);
1193
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : fallback;
1194
+ } catch {
1195
+ return fallback;
1196
+ }
1197
+ };
849
1198
  var defaultProductFormData = {
850
1199
  name: "",
851
1200
  description: "",
@@ -867,9 +1216,9 @@ function ProductFormDialog({
867
1216
  onSubmit,
868
1217
  isSubmitting
869
1218
  }) {
870
- const [formData, setFormData] = (0, import_react4.useState)(defaultProductFormData);
871
- const [formErrors, setFormErrors] = (0, import_react4.useState)({});
872
- (0, import_react4.useEffect)(() => {
1219
+ const [formData, setFormData] = (0, import_react6.useState)(defaultProductFormData);
1220
+ const [formErrors, setFormErrors] = (0, import_react6.useState)({});
1221
+ (0, import_react6.useEffect)(() => {
873
1222
  if (isOpen) {
874
1223
  if (mode === "edit" && product) {
875
1224
  const featureSlug = product.extra_data?.feature_slug || "";
@@ -891,16 +1240,12 @@ function ProductFormDialog({
891
1240
  setFormErrors({});
892
1241
  }
893
1242
  }, [isOpen, mode, product]);
894
- (0, import_react4.useEffect)(() => {
1243
+ (0, import_react6.useEffect)(() => {
895
1244
  if (formData.feature_slug) {
896
1245
  setFormData((prev) => {
897
- try {
898
- const parsedData = JSON.parse(prev.extra_data);
899
- const updated = { ...parsedData, feature_slug: formData.feature_slug };
900
- return { ...prev, extra_data: JSON.stringify(updated, null, 2) };
901
- } catch {
902
- return { ...prev, extra_data: JSON.stringify({ feature_slug: formData.feature_slug }, null, 2) };
903
- }
1246
+ const parsedData = safeJsonParse(prev.extra_data);
1247
+ const updated = { ...parsedData, feature_slug: formData.feature_slug };
1248
+ return { ...prev, extra_data: JSON.stringify(updated, null, 2) };
904
1249
  });
905
1250
  }
906
1251
  }, [formData.feature_slug]);
@@ -920,72 +1265,72 @@ function ProductFormDialog({
920
1265
  if (validateForm()) onSubmit(formData);
921
1266
  };
922
1267
  if (!isOpen) return null;
923
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
924
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
925
- /* @__PURE__ */ (0, import_jsx_runtime9.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: [
926
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
927
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "text-lg font-semibold", children: mode === "create" ? "Nuovo Prodotto" : "Modifica Prodotto" }),
928
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-muted-foreground", children: mode === "create" ? "Crea un nuovo prodotto / feature acquistabile" : "Modifica le impostazioni del prodotto selezionato" })
1268
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1269
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
1270
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: [
1271
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
1272
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { className: "text-lg font-semibold", children: mode === "create" ? "Nuovo Prodotto" : "Modifica Prodotto" }),
1273
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-sm text-muted-foreground", children: mode === "create" ? "Crea un nuovo prodotto / feature acquistabile" : "Modifica le impostazioni del prodotto selezionato" })
929
1274
  ] }),
930
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid gap-4 py-4", children: [
931
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
932
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Nome *" }),
933
- /* @__PURE__ */ (0, import_jsx_runtime9.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: formData.name, onChange: (e) => setFormData({ ...formData, name: e.target.value }), placeholder: "es. Ottimizza Dati Prodotti" }),
934
- formErrors.name && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xs text-destructive", children: formErrors.name })
1275
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "grid gap-4 py-4", children: [
1276
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Nome *" }),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: formData.name, onChange: (e) => setFormData({ ...formData, name: e.target.value }), placeholder: "es. Ottimizza Dati Prodotti" }),
1279
+ formErrors.name && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-destructive", children: formErrors.name })
935
1280
  ] }),
936
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
937
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Descrizione" }),
938
- /* @__PURE__ */ (0, import_jsx_runtime9.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: formData.description, onChange: (e) => setFormData({ ...formData, description: e.target.value }), rows: 2 })
1281
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Descrizione" }),
1283
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: formData.description, onChange: (e) => setFormData({ ...formData, description: e.target.value }), rows: 2 })
939
1284
  ] }),
940
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
941
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
942
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Prezzo" }),
943
- /* @__PURE__ */ (0, import_jsx_runtime9.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: formData.price_cents, onChange: (e) => setFormData({ ...formData, price_cents: e.target.value }), placeholder: "49.00" }),
944
- formErrors.price_cents && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xs text-destructive", children: formErrors.price_cents })
1285
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1286
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1287
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Prezzo" }),
1288
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: formData.price_cents, onChange: (e) => setFormData({ ...formData, price_cents: e.target.value }), placeholder: "49.00" }),
1289
+ formErrors.price_cents && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-destructive", children: formErrors.price_cents })
945
1290
  ] }),
946
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
947
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Valuta" }),
948
- /* @__PURE__ */ (0, import_jsx_runtime9.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: formData.currency, onChange: (e) => setFormData({ ...formData, currency: e.target.value }), children: [
949
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "eur", children: "EUR" }),
950
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "usd", children: "USD" }),
951
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "gbp", children: "GBP" })
1291
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1292
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Valuta" }),
1293
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: formData.currency, onChange: (e) => setFormData({ ...formData, currency: e.target.value }), children: [
1294
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "eur", children: "EUR" }),
1295
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "usd", children: "USD" }),
1296
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "gbp", children: "GBP" })
952
1297
  ] })
953
1298
  ] })
954
1299
  ] }),
955
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
956
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
957
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Ricorrenza" }),
958
- /* @__PURE__ */ (0, import_jsx_runtime9.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: formData.recurring_interval || "one_time", onChange: (e) => setFormData({ ...formData, recurring_interval: e.target.value === "one_time" ? "" : e.target.value }), children: [
959
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "one_time", children: "Una tantum" }),
960
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "month", children: "Mensile" }),
961
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "year", children: "Annuale" })
1300
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1302
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Ricorrenza" }),
1303
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: formData.recurring_interval || "one_time", onChange: (e) => setFormData({ ...formData, recurring_interval: e.target.value === "one_time" ? "" : e.target.value }), children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "one_time", children: "Una tantum" }),
1305
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "month", children: "Mensile" }),
1306
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "year", children: "Annuale" })
962
1307
  ] })
963
1308
  ] }),
964
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
965
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Categoria" }),
966
- /* @__PURE__ */ (0, import_jsx_runtime9.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: formData.category, onChange: (e) => setFormData({ ...formData, category: e.target.value }), children: [
967
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "feature", children: "Feature" }),
968
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "addon", children: "Add-on" }),
969
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "service", children: "Servizio" }),
970
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "credits", children: "Crediti" })
1309
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1310
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Categoria" }),
1311
+ /* @__PURE__ */ (0, import_jsx_runtime16.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: formData.category, onChange: (e) => setFormData({ ...formData, category: e.target.value }), children: [
1312
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "feature", children: "Feature" }),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "addon", children: "Add-on" }),
1314
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "service", children: "Servizio" }),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "credits", children: "Crediti" })
971
1316
  ] })
972
1317
  ] })
973
1318
  ] }),
974
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-4", children: [
975
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToggleRow, { label: "Prodotto Attivo", checked: formData.is_active, onChange: (v) => setFormData({ ...formData, is_active: v }) }),
976
- mode === "create" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToggleRow, { label: "Sincronizza su Stripe", checked: formData.sync_stripe, onChange: (v) => setFormData({ ...formData, sync_stripe: v }) })
1319
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-4", children: [
1320
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleRow, { label: "Prodotto Attivo", checked: formData.is_active, onChange: (v) => setFormData({ ...formData, is_active: v }) }),
1321
+ mode === "create" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleRow, { label: "Sincronizza su Stripe", checked: formData.sync_stripe, onChange: (v) => setFormData({ ...formData, sync_stripe: v }) })
977
1322
  ] }),
978
- features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
979
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Collega a Feature" }),
980
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1323
+ features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1324
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Collega a Feature" }),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
981
1326
  "select",
982
1327
  {
983
1328
  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",
984
1329
  value: formData.feature_slug || "none",
985
1330
  onChange: (e) => setFormData({ ...formData, feature_slug: e.target.value === "none" ? "" : e.target.value }),
986
1331
  children: [
987
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "none", children: "Nessuna feature" }),
988
- features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("option", { value: f.slug, children: [
1332
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "none", children: "Nessuna feature" }),
1333
+ features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("option", { value: f.slug, children: [
989
1334
  f.name,
990
1335
  " (",
991
1336
  f.slug,
@@ -994,24 +1339,24 @@ function ProductFormDialog({
994
1339
  ]
995
1340
  }
996
1341
  ),
997
- formData.feature_slug && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 p-2 bg-blue-50 border border-blue-200 rounded text-sm", children: [
998
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react5.Link, { className: "w-4 h-4 text-blue-600" }),
999
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "text-blue-900", children: [
1342
+ formData.feature_slug && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2 p-2 bg-blue-50 border border-blue-200 rounded text-sm", children: [
1343
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.Link, { className: "w-4 h-4 text-blue-600" }),
1344
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-blue-900", children: [
1000
1345
  "Collegato a: ",
1001
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: formData.feature_slug })
1346
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: formData.feature_slug })
1002
1347
  ] })
1003
1348
  ] })
1004
1349
  ] }),
1005
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
1006
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-sm font-medium leading-none", children: "Extra Data (JSON)" }),
1007
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("textarea", { className: "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-mono focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: formData.extra_data, onChange: (e) => setFormData({ ...formData, extra_data: e.target.value }), rows: 3 }),
1008
- formErrors.extra_data && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xs text-destructive", children: formErrors.extra_data })
1350
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-2", children: [
1351
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "text-sm font-medium leading-none", children: "Extra Data (JSON)" }),
1352
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("textarea", { className: "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-mono focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", value: formData.extra_data, onChange: (e) => setFormData({ ...formData, extra_data: e.target.value }), rows: 3 }),
1353
+ formErrors.extra_data && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-destructive", children: formErrors.extra_data })
1009
1354
  ] })
1010
1355
  ] }),
1011
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
1012
- /* @__PURE__ */ (0, import_jsx_runtime9.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" }),
1013
- /* @__PURE__ */ (0, import_jsx_runtime9.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: isSubmitting, children: [
1014
- isSubmitting && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react5.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
1356
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4", children: [
1357
+ /* @__PURE__ */ (0, import_jsx_runtime16.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" }),
1358
+ /* @__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 disabled:opacity-50", onClick: handleSubmit, disabled: isSubmitting, children: [
1359
+ isSubmitting && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.Loader2, { className: "w-4 h-4 animate-spin mr-2" }),
1015
1360
  mode === "create" ? "Crea Prodotto" : "Salva Modifiche"
1016
1361
  ] })
1017
1362
  ] })
@@ -1019,8 +1364,8 @@ function ProductFormDialog({
1019
1364
  ] });
1020
1365
  }
1021
1366
  function ToggleRow({ label, checked, onChange }) {
1022
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
1023
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1367
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", children: [
1368
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1024
1369
  "button",
1025
1370
  {
1026
1371
  type: "button",
@@ -1028,15 +1373,15 @@ function ToggleRow({ label, checked, onChange }) {
1028
1373
  "aria-checked": checked,
1029
1374
  onClick: () => onChange(!checked),
1030
1375
  className: `inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${checked ? "bg-primary" : "bg-input"}`,
1031
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg transition-transform ${checked ? "translate-x-4" : "translate-x-0"}` })
1376
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg transition-transform ${checked ? "translate-x-4" : "translate-x-0"}` })
1032
1377
  }
1033
1378
  ),
1034
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-sm font-medium leading-none", children: label })
1379
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-sm font-medium leading-none", children: label })
1035
1380
  ] });
1036
1381
  }
1037
1382
 
1038
1383
  // src/pages/ProductsPage.tsx
1039
- var import_jsx_runtime10 = require("react/jsx-runtime");
1384
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1040
1385
  function ProductsPage({ wrapper: Wrapper, header }) {
1041
1386
  const config = useBillingAdminConfig();
1042
1387
  const featuresConfig = config.products?.features;
@@ -1108,81 +1453,81 @@ function ProductsPage({ wrapper: Wrapper, header }) {
1108
1453
  });
1109
1454
  }
1110
1455
  };
1111
- const content = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1456
+ const content = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1112
1457
  header,
1113
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-4", children: [
1114
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
1115
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1116
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Package, { className: "w-4 h-4" }),
1117
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
1458
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-4", children: [
1459
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between", children: [
1460
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1461
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Package, { className: "w-4 h-4" }),
1462
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
1118
1463
  products.length,
1119
1464
  " prodotti configurati"
1120
1465
  ] })
1121
1466
  ] }),
1122
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-2", children: [
1123
- /* @__PURE__ */ (0, import_jsx_runtime10.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: [
1124
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.RefreshCw, { className: "w-4 h-4 mr-2" }),
1467
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2", children: [
1468
+ /* @__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: [
1469
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.RefreshCw, { className: "w-4 h-4 mr-2" }),
1125
1470
  "Aggiorna"
1126
1471
  ] }),
1127
- /* @__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: () => createDialog.open(), children: [
1128
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Plus, { className: "w-4 h-4 mr-2" }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime17.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: () => createDialog.open(), children: [
1473
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Plus, { className: "w-4 h-4 mr-2" }),
1129
1474
  "Nuovo Prodotto"
1130
1475
  ] })
1131
1476
  ] })
1132
1477
  ] }),
1133
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1134
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1135
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Nome" }),
1136
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Categoria" }),
1137
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Prezzo" }),
1138
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Ricorrenza" }),
1139
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Attivo" }),
1140
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stripe" }),
1141
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1478
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1479
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1480
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Nome" }),
1481
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Categoria" }),
1482
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Prezzo" }),
1483
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Ricorrenza" }),
1484
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Attivo" }),
1485
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stripe" }),
1486
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1142
1487
  ] }) }),
1143
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SkeletonRows, { rows: 3, columns: 7 }) : products.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { colSpan: 7, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun prodotto configurato" }) }) : products.map((product) => {
1488
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SkeletonRows, { rows: 3, columns: 7 }) : products.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { colSpan: 7, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun prodotto configurato" }) }) : products.map((product) => {
1144
1489
  const hasFeature = !!product.extra_data?.feature_slug;
1145
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1146
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
1148
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium", children: product.name }),
1149
- hasFeature && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBadge, { label: "Feature", colorClass: "bg-blue-50 text-blue-700 border-blue-200" })
1490
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1491
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
1492
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
1493
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium", children: product.name }),
1494
+ hasFeature && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { label: "Feature", colorClass: "bg-blue-50 text-blue-700 border-blue-200" })
1150
1495
  ] }),
1151
- product.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-sm text-muted-foreground truncate max-w-xs", children: product.description })
1496
+ product.description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-sm text-muted-foreground truncate max-w-xs", children: product.description })
1152
1497
  ] }) }),
1153
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBadge, { label: product.category || "feature", colorClass: "border" }) }),
1154
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core4.formatCurrencyFromCents)(product.price_cents, product.currency) }),
1155
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4", children: product.recurring_interval ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBadge, { label: product.recurring_interval === "month" ? "Mensile" : product.recurring_interval === "year" ? "Annuale" : product.recurring_interval, colorClass: "bg-secondary text-secondary-foreground border-transparent" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-muted-foreground", children: "Una tantum" }) }),
1156
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4", children: product.is_active ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Check, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.X, { className: "w-4 h-4 text-muted-foreground" }) }),
1157
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4", children: product.stripe_product_id ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBadge, { label: "Synced", colorClass: "bg-green-50 text-green-700 border-green-200" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => syncMutation.mutate(product.id, { onSuccess: () => import_sonner2.toast.success("Sincronizzato"), onError: (err) => import_sonner2.toast.error(`Errore: ${err.message}`) }), disabled: syncMutation.isPending, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Upload, { className: "w-4 h-4" }) }) }),
1158
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-end gap-1", children: [
1159
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => editDialog.open(product), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Pencil, { className: "w-4 h-4" }) }),
1160
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent", onClick: () => deleteDialog.open(product), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Trash2, { className: "w-4 h-4" }) })
1498
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { label: product.category || "feature", colorClass: "border" }) }),
1499
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core4.formatCurrencyFromCents)(product.price_cents, product.currency) }),
1500
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: product.recurring_interval ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { label: product.recurring_interval === "month" ? "Mensile" : product.recurring_interval === "year" ? "Annuale" : product.recurring_interval, colorClass: "bg-secondary text-secondary-foreground border-transparent" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-muted-foreground", children: "Una tantum" }) }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: product.is_active ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Check, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { className: "w-4 h-4 text-muted-foreground" }) }),
1502
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4", children: product.stripe_product_id ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { label: "Synced", colorClass: "bg-green-50 text-green-700 border-green-200" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => syncMutation.mutate(product.id, { onSuccess: () => import_sonner2.toast.success("Sincronizzato"), onError: (err) => import_sonner2.toast.error(`Errore: ${err.message}`) }), disabled: syncMutation.isPending, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Upload, { className: "w-4 h-4" }) }) }),
1503
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex justify-end gap-1", children: [
1504
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => editDialog.open(product), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Pencil, { className: "w-4 h-4" }) }),
1505
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent", onClick: () => deleteDialog.open(product), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Trash2, { className: "w-4 h-4" }) })
1161
1506
  ] }) })
1162
1507
  ] }, product.id);
1163
1508
  }) })
1164
1509
  ] }) }) })
1165
1510
  ] }),
1166
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ProductFormDialog, { isOpen: createDialog.isOpen, onOpenChange: (open) => open ? createDialog.open() : createDialog.close(), mode: "create", features, onSubmit: handleCreateSubmit, isSubmitting: createMutation.isPending }),
1167
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ProductFormDialog, { isOpen: editDialog.isOpen, onOpenChange: (open) => open ? editDialog.open(editDialog.data) : editDialog.close(), mode: "edit", product: editDialog.data, features, onSubmit: handleEditSubmit, isSubmitting: updateMutation.isPending }),
1168
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DeleteConfirmDialog, { isOpen: deleteDialog.isOpen, onOpenChange: (open) => !open && deleteDialog.close(), title: "Disattivare Prodotto?", description: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1511
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ProductFormDialog, { isOpen: createDialog.isOpen, onOpenChange: (open) => open ? createDialog.open() : createDialog.close(), mode: "create", features, onSubmit: handleCreateSubmit, isSubmitting: createMutation.isPending }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ProductFormDialog, { isOpen: editDialog.isOpen, onOpenChange: (open) => open ? editDialog.open(editDialog.data) : editDialog.close(), mode: "edit", product: editDialog.data, features, onSubmit: handleEditSubmit, isSubmitting: updateMutation.isPending }),
1513
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DeleteConfirmDialog, { isOpen: deleteDialog.isOpen, onOpenChange: (open) => !open && deleteDialog.close(), title: "Disattivare Prodotto?", description: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1169
1514
  "Stai per disattivare il prodotto ",
1170
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: deleteDialog.data?.name }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: deleteDialog.data?.name }),
1171
1516
  ". Il prodotto non sar\xE0 pi\xF9 acquistabile."
1172
1517
  ] }), onConfirm: handleDeleteConfirm, isDeleting: deleteMutation.isPending, confirmLabel: "Disattiva Prodotto" })
1173
1518
  ] });
1174
- return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Wrapper, { children: content }) : content;
1519
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Wrapper, { children: content }) : content;
1175
1520
  }
1176
1521
 
1177
1522
  // src/pages/SubscriptionsPage.tsx
1178
- var import_react5 = require("react");
1523
+ var import_react7 = require("react");
1179
1524
  var import_sonner3 = require("sonner");
1180
- var import_lucide_react8 = require("lucide-react");
1525
+ var import_lucide_react9 = require("lucide-react");
1181
1526
  var import_growflowbilling_admin_core5 = require("@growflowstudio/growflowbilling-admin-core");
1182
1527
 
1183
1528
  // src/components/shared/FilterBar.tsx
1184
- var import_lucide_react7 = require("lucide-react");
1185
- var import_jsx_runtime11 = require("react/jsx-runtime");
1529
+ var import_lucide_react8 = require("lucide-react");
1530
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1186
1531
  function FilterBar({
1187
1532
  searchPlaceholder = "Cerca...",
1188
1533
  searchValue,
@@ -1192,10 +1537,10 @@ function FilterBar({
1192
1537
  statusOptions,
1193
1538
  onRefresh
1194
1539
  }) {
1195
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-6 pt-6", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col sm:flex-row gap-4", children: [
1196
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "relative flex-1", children: [
1197
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react7.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" }),
1198
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1540
+ return /* @__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-6 pt-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col sm:flex-row gap-4", children: [
1541
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "relative flex-1", children: [
1542
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" }),
1543
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1199
1544
  "input",
1200
1545
  {
1201
1546
  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",
@@ -1205,22 +1550,22 @@ function FilterBar({
1205
1550
  }
1206
1551
  )
1207
1552
  ] }),
1208
- statusOptions && onStatusFilterChange && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1553
+ statusOptions && onStatusFilterChange && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1209
1554
  "select",
1210
1555
  {
1211
1556
  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",
1212
1557
  value: statusFilter || "all",
1213
1558
  onChange: (e) => onStatusFilterChange(e.target.value),
1214
- children: statusOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1559
+ children: statusOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1215
1560
  }
1216
1561
  ),
1217
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1562
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1218
1563
  "button",
1219
1564
  {
1220
1565
  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",
1221
1566
  onClick: onRefresh,
1222
1567
  children: [
1223
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react7.RefreshCw, { className: "w-4 h-4 mr-2" }),
1568
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.RefreshCw, { className: "w-4 h-4 mr-2" }),
1224
1569
  "Aggiorna"
1225
1570
  ]
1226
1571
  }
@@ -1229,7 +1574,7 @@ function FilterBar({
1229
1574
  }
1230
1575
 
1231
1576
  // src/pages/SubscriptionsPage.tsx
1232
- var import_jsx_runtime12 = require("react/jsx-runtime");
1577
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1233
1578
  var statusFilterOptions = [
1234
1579
  { value: "all", label: "Tutti gli stati" },
1235
1580
  { value: "active", label: "Attivi" },
@@ -1239,12 +1584,12 @@ var statusFilterOptions = [
1239
1584
  { value: "unpaid", label: "Non Pagati" }
1240
1585
  ];
1241
1586
  function SubscriptionsPage({ wrapper: Wrapper, header }) {
1242
- const [search, setSearch] = (0, import_react5.useState)("");
1243
- const [statusFilter, setStatusFilter] = (0, import_react5.useState)("all");
1244
- const [selectedSub, setSelectedSub] = (0, import_react5.useState)(null);
1245
- const [showDetails, setShowDetails] = (0, import_react5.useState)(false);
1246
- const [showCancelDialog, setShowCancelDialog] = (0, import_react5.useState)(false);
1247
- const [cancelAtPeriodEnd, setCancelAtPeriodEnd] = (0, import_react5.useState)(true);
1587
+ const [search, setSearch] = (0, import_react7.useState)("");
1588
+ const [statusFilter, setStatusFilter] = (0, import_react7.useState)("all");
1589
+ const [selectedSub, setSelectedSub] = (0, import_react7.useState)(null);
1590
+ const [showDetails, setShowDetails] = (0, import_react7.useState)(false);
1591
+ const [showCancelDialog, setShowCancelDialog] = (0, import_react7.useState)(false);
1592
+ const [cancelAtPeriodEnd, setCancelAtPeriodEnd] = (0, import_react7.useState)(true);
1248
1593
  const { data, isLoading, refetch } = (0, import_growflowbilling_admin_core5.useAdminSubscriptions)({
1249
1594
  search: search || void 0,
1250
1595
  status: statusFilter !== "all" ? statusFilter : void 0,
@@ -1265,10 +1610,10 @@ function SubscriptionsPage({ wrapper: Wrapper, header }) {
1265
1610
  });
1266
1611
  }
1267
1612
  };
1268
- const content = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1613
+ const content = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1269
1614
  header,
1270
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-4", children: [
1271
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1615
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-4", children: [
1616
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1272
1617
  FilterBar,
1273
1618
  {
1274
1619
  searchPlaceholder: "Cerca per email o ID esterno...",
@@ -1280,167 +1625,167 @@ function SubscriptionsPage({ wrapper: Wrapper, header }) {
1280
1625
  onRefresh: refetch
1281
1626
  }
1282
1627
  ),
1283
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1284
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.CreditCard, { className: "w-4 h-4" }),
1285
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
1628
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1629
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.CreditCard, { className: "w-4 h-4" }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
1286
1631
  total,
1287
1632
  " abbonament",
1288
1633
  total === 1 ? "o" : "i",
1289
1634
  " trovati"
1290
1635
  ] })
1291
1636
  ] }),
1292
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1293
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1294
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Subscriber" }),
1295
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Piano" }),
1296
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stato" }),
1297
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Ciclo" }),
1298
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Periodo" }),
1299
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Trial End" }),
1300
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Creato" }),
1301
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1637
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1638
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1639
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Subscriber" }),
1640
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Piano" }),
1641
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stato" }),
1642
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Ciclo" }),
1643
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Periodo" }),
1644
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Trial End" }),
1645
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Creato" }),
1646
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1302
1647
  ] }) }),
1303
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SkeletonRows, { rows: 5, columns: 8 }) : subscriptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { colSpan: 8, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun abbonamento trovato" }) }) : subscriptions.map((sub) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1304
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col", children: [
1305
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "font-medium", children: sub.subscriber_email }),
1306
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-xs text-muted-foreground", children: sub.subscriber_external_id })
1648
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SkeletonRows, { rows: 5, columns: 8 }) : subscriptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { colSpan: 8, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun abbonamento trovato" }) }) : subscriptions.map((sub) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1649
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-medium", children: sub.subscriber_email }),
1651
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-xs text-muted-foreground", children: sub.subscriber_external_id })
1307
1652
  ] }) }),
1308
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { className: "p-4", children: [
1309
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "font-medium", children: sub.plan_name }),
1310
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "text-xs text-muted-foreground ml-1", children: [
1653
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("td", { className: "p-4", children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-medium", children: sub.plan_name }),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "text-xs text-muted-foreground ml-1", children: [
1311
1656
  "(",
1312
1657
  sub.plan_slug,
1313
1658
  ")"
1314
1659
  ] })
1315
1660
  ] }),
1316
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(StatusBadge, { label: import_growflowbilling_admin_core5.subscriptionStatusLabels[sub.status], colorClass: import_growflowbilling_admin_core5.subscriptionStatusColors[sub.status] }) }),
1317
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "p-4 capitalize", children: sub.billing_cycle }),
1318
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { className: "p-4 text-sm", children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusBadge, { label: import_growflowbilling_admin_core5.subscriptionStatusLabels[sub.status], colorClass: import_growflowbilling_admin_core5.subscriptionStatusColors[sub.status] }) }),
1662
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "p-4 capitalize", children: sub.billing_cycle }),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("td", { className: "p-4 text-sm", children: [
1319
1664
  (0, import_growflowbilling_admin_core5.formatDate)(sub.current_period_start),
1320
1665
  " - ",
1321
1666
  (0, import_growflowbilling_admin_core5.formatDate)(sub.current_period_end)
1322
1667
  ] }),
1323
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core5.formatDate)(sub.trial_end) }),
1324
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core5.formatDate)(sub.created_at) }),
1325
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex justify-end gap-1", children: [
1326
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => {
1668
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core5.formatDate)(sub.trial_end) }),
1669
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core5.formatDate)(sub.created_at) }),
1670
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-end gap-1", children: [
1671
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => {
1327
1672
  setSelectedSub(sub);
1328
1673
  setShowDetails(true);
1329
- }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.Eye, { className: "w-4 h-4" }) }),
1330
- sub.status !== "canceled" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent", onClick: () => {
1674
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Eye, { className: "w-4 h-4" }) }),
1675
+ sub.status !== "canceled" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent", onClick: () => {
1331
1676
  setSelectedSub(sub);
1332
1677
  setShowCancelDialog(true);
1333
- }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.XCircle, { className: "w-4 h-4" }) })
1678
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.XCircle, { className: "w-4 h-4" }) })
1334
1679
  ] }) })
1335
1680
  ] }, sub.id)) })
1336
1681
  ] }) }) })
1337
1682
  ] }),
1338
- showDetails && selectedSub && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1339
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setShowDetails(false) }),
1340
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
1341
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "text-lg font-semibold mb-1", children: "Dettagli Abbonamento" }),
1342
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground mb-4", children: "Informazioni complete" }),
1343
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-4", children: [
1344
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1345
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1346
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Subscriber" }),
1347
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [
1348
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.User, { className: "w-4 h-4 text-muted-foreground" }),
1349
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "font-medium", children: selectedSub.subscriber_email })
1683
+ showDetails && selectedSub && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1684
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setShowDetails(false) }),
1685
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
1686
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { className: "text-lg font-semibold mb-1", children: "Dettagli Abbonamento" }),
1687
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground mb-4", children: "Informazioni complete" }),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-4", children: [
1689
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1690
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1691
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Subscriber" }),
1692
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [
1693
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.User, { className: "w-4 h-4 text-muted-foreground" }),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-medium", children: selectedSub.subscriber_email })
1350
1695
  ] }),
1351
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-xs text-muted-foreground mt-1", children: [
1696
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "text-xs text-muted-foreground mt-1", children: [
1352
1697
  "ID: ",
1353
1698
  selectedSub.subscriber_external_id
1354
1699
  ] })
1355
1700
  ] }),
1356
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1357
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Piano" }),
1358
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [
1359
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.CreditCard, { className: "w-4 h-4 text-muted-foreground" }),
1360
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "font-medium", children: selectedSub.plan_name })
1701
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1702
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Piano" }),
1703
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.CreditCard, { className: "w-4 h-4 text-muted-foreground" }),
1705
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-medium", children: selectedSub.plan_name })
1361
1706
  ] })
1362
1707
  ] })
1363
1708
  ] }),
1364
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1365
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1366
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Stato" }),
1367
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(StatusBadge, { label: import_growflowbilling_admin_core5.subscriptionStatusLabels[selectedSub.status], colorClass: import_growflowbilling_admin_core5.subscriptionStatusColors[selectedSub.status], className: "mt-1" })
1709
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1710
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1711
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Stato" }),
1712
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusBadge, { label: import_growflowbilling_admin_core5.subscriptionStatusLabels[selectedSub.status], colorClass: import_growflowbilling_admin_core5.subscriptionStatusColors[selectedSub.status], className: "mt-1" })
1368
1713
  ] }),
1369
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1370
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Ciclo" }),
1371
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "font-medium capitalize mt-1", children: selectedSub.billing_cycle })
1714
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1715
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Ciclo" }),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "font-medium capitalize mt-1", children: selectedSub.billing_cycle })
1372
1717
  ] })
1373
1718
  ] }),
1374
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1376
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Periodo" }),
1377
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [
1378
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.Calendar, { className: "w-4 h-4 text-muted-foreground" }),
1379
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
1719
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1720
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1721
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Periodo" }),
1722
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [
1723
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Calendar, { className: "w-4 h-4 text-muted-foreground" }),
1724
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
1380
1725
  (0, import_growflowbilling_admin_core5.formatDate)(selectedSub.current_period_start),
1381
1726
  " - ",
1382
1727
  (0, import_growflowbilling_admin_core5.formatDate)(selectedSub.current_period_end)
1383
1728
  ] })
1384
1729
  ] })
1385
1730
  ] }),
1386
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1387
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Fine Trial" }),
1388
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "mt-1", children: (0, import_growflowbilling_admin_core5.formatDate)(selectedSub.trial_end) })
1731
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1732
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Fine Trial" }),
1733
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-1", children: (0, import_growflowbilling_admin_core5.formatDate)(selectedSub.trial_end) })
1389
1734
  ] })
1390
1735
  ] }),
1391
- selectedSub.canceled_at && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "p-3 bg-destructive/10 rounded-lg", children: [
1392
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-sm text-destructive font-medium", children: [
1736
+ selectedSub.canceled_at && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "p-3 bg-destructive/10 rounded-lg", children: [
1737
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "text-sm text-destructive font-medium", children: [
1393
1738
  "Cancellato il ",
1394
1739
  (0, import_growflowbilling_admin_core5.formatDate)(selectedSub.canceled_at)
1395
1740
  ] }),
1396
- selectedSub.cancel_at && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-xs text-destructive/80 mt-1", children: [
1741
+ selectedSub.cancel_at && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "text-xs text-destructive/80 mt-1", children: [
1397
1742
  "Termina il ",
1398
1743
  (0, import_growflowbilling_admin_core5.formatDate)(selectedSub.cancel_at)
1399
1744
  ] })
1400
1745
  ] }),
1401
- selectedSub.stripe_subscription_id && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1402
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: "Stripe ID" }),
1403
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { className: "text-xs bg-muted px-2 py-1 rounded mt-1 inline-block", children: selectedSub.stripe_subscription_id })
1746
+ selectedSub.stripe_subscription_id && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1747
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "Stripe ID" }),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("code", { className: "text-xs bg-muted px-2 py-1 rounded mt-1 inline-block", children: selectedSub.stripe_subscription_id })
1404
1749
  ] })
1405
1750
  ] }),
1406
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex justify-end pt-4", children: /* @__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", onClick: () => setShowDetails(false), children: "Chiudi" }) })
1751
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex justify-end pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime19.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", onClick: () => setShowDetails(false), children: "Chiudi" }) })
1407
1752
  ] })
1408
1753
  ] }),
1409
- showCancelDialog && selectedSub && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1410
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setShowCancelDialog(false) }),
1411
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
1412
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "text-lg font-semibold", children: "Cancellare Abbonamento?" }),
1413
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-sm text-muted-foreground mt-1", children: [
1754
+ showCancelDialog && selectedSub && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1755
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setShowCancelDialog(false) }),
1756
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
1757
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { className: "text-lg font-semibold", children: "Cancellare Abbonamento?" }),
1758
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "text-sm text-muted-foreground mt-1", children: [
1414
1759
  "Stai per cancellare l'abbonamento di ",
1415
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: selectedSub.subscriber_email }),
1760
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { children: selectedSub.subscriber_email }),
1416
1761
  "."
1417
1762
  ] }),
1418
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "py-4", children: [
1419
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [
1420
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "checkbox", checked: cancelAtPeriodEnd, onChange: (e) => setCancelAtPeriodEnd(e.target.checked), className: "rounded border-input" }),
1421
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-sm", children: "Cancella alla fine del periodo corrente (consigliato)" })
1763
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "py-4", children: [
1764
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [
1765
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "checkbox", checked: cancelAtPeriodEnd, onChange: (e) => setCancelAtPeriodEnd(e.target.checked), className: "rounded border-input" }),
1766
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-sm", children: "Cancella alla fine del periodo corrente (consigliato)" })
1422
1767
  ] }),
1423
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground mt-2", children: cancelAtPeriodEnd ? "L'abbonamento rimarr\xE0 attivo fino alla fine del periodo." : "L'abbonamento verr\xE0 cancellato immediatamente." })
1768
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-xs text-muted-foreground mt-2", children: cancelAtPeriodEnd ? "L'abbonamento rimarr\xE0 attivo fino alla fine del periodo." : "L'abbonamento verr\xE0 cancellato immediatamente." })
1424
1769
  ] }),
1425
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex justify-end gap-2", children: [
1426
- /* @__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", onClick: () => setShowCancelDialog(false), children: "Annulla" }),
1427
- /* @__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 bg-destructive text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50", onClick: handleCancel, disabled: cancelMutation.isPending, children: cancelMutation.isPending ? "Cancellazione..." : "Conferma Cancellazione" })
1770
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-end gap-2", children: [
1771
+ /* @__PURE__ */ (0, import_jsx_runtime19.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", onClick: () => setShowCancelDialog(false), children: "Annulla" }),
1772
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { 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 disabled:opacity-50", onClick: handleCancel, disabled: cancelMutation.isPending, children: cancelMutation.isPending ? "Cancellazione..." : "Conferma Cancellazione" })
1428
1773
  ] })
1429
1774
  ] })
1430
1775
  ] })
1431
1776
  ] });
1432
- return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Wrapper, { children: content }) : content;
1777
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Wrapper, { children: content }) : content;
1433
1778
  }
1434
1779
 
1435
1780
  // src/pages/PaymentsPage.tsx
1436
- var import_react6 = require("react");
1781
+ var import_react8 = require("react");
1437
1782
  var import_sonner4 = require("sonner");
1438
- var import_lucide_react10 = require("lucide-react");
1783
+ var import_lucide_react11 = require("lucide-react");
1439
1784
  var import_growflowbilling_admin_core6 = require("@growflowstudio/growflowbilling-admin-core");
1440
1785
 
1441
1786
  // src/components/shared/CursorPagination.tsx
1442
- var import_lucide_react9 = require("lucide-react");
1443
- var import_jsx_runtime13 = require("react/jsx-runtime");
1787
+ var import_lucide_react10 = require("lucide-react");
1788
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1444
1789
  function CursorPagination({
1445
1790
  cursor,
1446
1791
  hasMore,
@@ -1448,20 +1793,20 @@ function CursorPagination({
1448
1793
  onFirstPage,
1449
1794
  onNextPage
1450
1795
  }) {
1451
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex justify-between items-center", children: [
1452
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1796
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex justify-between items-center", children: [
1797
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1453
1798
  "button",
1454
1799
  {
1455
1800
  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",
1456
1801
  onClick: onFirstPage,
1457
1802
  disabled: !cursor,
1458
1803
  children: [
1459
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react9.ChevronLeft, { className: "w-4 h-4 mr-1" }),
1804
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.ChevronLeft, { className: "w-4 h-4 mr-1" }),
1460
1805
  "Prima Pagina"
1461
1806
  ]
1462
1807
  }
1463
1808
  ),
1464
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1809
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1465
1810
  "button",
1466
1811
  {
1467
1812
  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",
@@ -1473,7 +1818,7 @@ function CursorPagination({
1473
1818
  disabled: !hasMore,
1474
1819
  children: [
1475
1820
  "Prossima",
1476
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react9.ChevronRight, { className: "w-4 h-4 ml-1" })
1821
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.ChevronRight, { className: "w-4 h-4 ml-1" })
1477
1822
  ]
1478
1823
  }
1479
1824
  )
@@ -1481,7 +1826,7 @@ function CursorPagination({
1481
1826
  }
1482
1827
 
1483
1828
  // src/pages/PaymentsPage.tsx
1484
- var import_jsx_runtime14 = require("react/jsx-runtime");
1829
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1485
1830
  var statusFilterOptions2 = [
1486
1831
  { value: "all", label: "Tutti gli stati" },
1487
1832
  { value: "succeeded", label: "Completati" },
@@ -1490,13 +1835,13 @@ var statusFilterOptions2 = [
1490
1835
  { value: "canceled", label: "Annullati" }
1491
1836
  ];
1492
1837
  function PaymentsPage({ wrapper: Wrapper, header }) {
1493
- const [search, setSearch] = (0, import_react6.useState)("");
1494
- const [statusFilter, setStatusFilter] = (0, import_react6.useState)("all");
1495
- const [cursor, setCursor] = (0, import_react6.useState)();
1496
- const [selectedPayment, setSelectedPayment] = (0, import_react6.useState)(null);
1497
- const [showRefundDialog, setShowRefundDialog] = (0, import_react6.useState)(false);
1498
- const [refundAmount, setRefundAmount] = (0, import_react6.useState)("");
1499
- const [refundReason, setRefundReason] = (0, import_react6.useState)("requested_by_customer");
1838
+ const [search, setSearch] = (0, import_react8.useState)("");
1839
+ const [statusFilter, setStatusFilter] = (0, import_react8.useState)("all");
1840
+ const { cursor, goToNext, goToFirst } = (0, import_growflowbilling_admin_core6.useCursorPagination)();
1841
+ const [selectedPayment, setSelectedPayment] = (0, import_react8.useState)(null);
1842
+ const [showRefundDialog, setShowRefundDialog] = (0, import_react8.useState)(false);
1843
+ const [refundAmount, setRefundAmount] = (0, import_react8.useState)("");
1844
+ const [refundReason, setRefundReason] = (0, import_react8.useState)("requested_by_customer");
1500
1845
  const { data, isLoading, refetch } = (0, import_growflowbilling_admin_core6.useAdminPayments)({
1501
1846
  search: search || void 0,
1502
1847
  status: statusFilter !== "all" ? statusFilter : void 0,
@@ -1524,179 +1869,179 @@ function PaymentsPage({ wrapper: Wrapper, header }) {
1524
1869
  setRefundAmount((payment.amount / 100).toFixed(2));
1525
1870
  setShowRefundDialog(true);
1526
1871
  };
1527
- const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1872
+ const content = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1528
1873
  header,
1529
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "space-y-4", children: [
1530
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1874
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-4", children: [
1875
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1531
1876
  FilterBar,
1532
1877
  {
1533
1878
  searchPlaceholder: "Cerca per email cliente...",
1534
1879
  searchValue: search,
1535
1880
  onSearchChange: (v) => {
1536
1881
  setSearch(v);
1537
- setCursor(void 0);
1882
+ goToFirst();
1538
1883
  },
1539
1884
  statusFilter,
1540
1885
  onStatusFilterChange: (v) => {
1541
1886
  setStatusFilter(v);
1542
- setCursor(void 0);
1887
+ goToFirst();
1543
1888
  },
1544
1889
  statusOptions: statusFilterOptions2,
1545
1890
  onRefresh: refetch
1546
1891
  }
1547
1892
  ),
1548
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1549
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react10.Receipt, { className: "w-4 h-4" }),
1550
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { children: [
1893
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1894
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react11.Receipt, { className: "w-4 h-4" }),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
1551
1896
  payments.length,
1552
1897
  " pagamenti visualizzati"
1553
1898
  ] })
1554
1899
  ] }),
1555
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1556
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1557
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "ID Pagamento" }),
1558
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Importo" }),
1559
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stato" }),
1560
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Cliente" }),
1561
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Descrizione" }),
1562
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Data" }),
1563
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1900
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1901
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1902
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "ID Pagamento" }),
1903
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Importo" }),
1904
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stato" }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Cliente" }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Descrizione" }),
1907
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Data" }),
1908
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1564
1909
  ] }) }),
1565
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SkeletonRows, { rows: 5, columns: 7 }) : payments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { colSpan: 7, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun pagamento trovato" }) }) : payments.map((payment) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1566
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("code", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: (0, import_growflowbilling_admin_core6.truncateId)(payment.id) }) }),
1567
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 font-medium", children: (0, import_growflowbilling_admin_core6.formatCurrencyFromCents)(payment.amount, payment.currency) }),
1568
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(StatusBadge, { label: import_growflowbilling_admin_core6.paymentStatusLabels[payment.status], colorClass: import_growflowbilling_admin_core6.paymentStatusColors[payment.status] }) }),
1569
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4", children: payment.customer_email || /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-muted-foreground", children: "-" }) }),
1570
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 max-w-[200px] truncate", children: payment.description || /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-muted-foreground", children: "-" }) }),
1571
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core6.formatTimestamp)(payment.created, true) }),
1572
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "p-4 text-right", children: payment.status === "succeeded" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 hover:bg-accent", onClick: () => openRefundDialog(payment), children: [
1573
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react10.RotateCcw, { className: "w-4 h-4 mr-1" }),
1910
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SkeletonRows, { rows: 5, columns: 7 }) : payments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { colSpan: 7, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessun pagamento trovato" }) }) : payments.map((payment) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1911
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("code", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: (0, import_growflowbilling_admin_core6.truncateId)(payment.id) }) }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4 font-medium", children: (0, import_growflowbilling_admin_core6.formatCurrencyFromCents)(payment.amount, payment.currency) }),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StatusBadge, { label: import_growflowbilling_admin_core6.paymentStatusLabels[payment.status], colorClass: import_growflowbilling_admin_core6.paymentStatusColors[payment.status] }) }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4", children: payment.customer_email || /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-muted-foreground", children: "-" }) }),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4 max-w-[200px] truncate", children: payment.description || /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-muted-foreground", children: "-" }) }),
1916
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core6.formatTimestamp)(payment.created, true) }),
1917
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { className: "p-4 text-right", children: payment.status === "succeeded" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { className: "inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 hover:bg-accent", onClick: () => openRefundDialog(payment), children: [
1918
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react11.RotateCcw, { className: "w-4 h-4 mr-1" }),
1574
1919
  "Rimborsa"
1575
1920
  ] }) })
1576
1921
  ] }, payment.id)) })
1577
1922
  ] }) }) }),
1578
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CursorPagination, { cursor, hasMore, items: payments, onFirstPage: () => setCursor(void 0), onNextPage: setCursor })
1923
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CursorPagination, { cursor, hasMore, items: payments, onFirstPage: goToFirst, onNextPage: goToNext })
1579
1924
  ] }),
1580
- showRefundDialog && selectedPayment && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1581
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setShowRefundDialog(false) }),
1582
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg", children: [
1583
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h2", { className: "text-lg font-semibold", children: "Rimborso Pagamento" }),
1584
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground mt-1", children: "Effettua un rimborso per il pagamento selezionato" }),
1585
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "space-y-4 py-4", children: [
1586
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "p-3 bg-muted rounded-lg", children: [
1587
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-between items-center", children: [
1588
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-sm text-muted-foreground", children: "Pagamento originale" }),
1589
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-medium", children: (0, import_growflowbilling_admin_core6.formatCurrencyFromCents)(selectedPayment.amount, selectedPayment.currency) })
1925
+ showRefundDialog && selectedPayment && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1926
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setShowRefundDialog(false) }),
1927
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg", children: [
1928
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { className: "text-lg font-semibold", children: "Rimborso Pagamento" }),
1929
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-sm text-muted-foreground mt-1", children: "Effettua un rimborso per il pagamento selezionato" }),
1930
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-4 py-4", children: [
1931
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "p-3 bg-muted rounded-lg", children: [
1932
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex justify-between items-center", children: [
1933
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-sm text-muted-foreground", children: "Pagamento originale" }),
1934
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-medium", children: (0, import_growflowbilling_admin_core6.formatCurrencyFromCents)(selectedPayment.amount, selectedPayment.currency) })
1590
1935
  ] }),
1591
- selectedPayment.customer_email && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { className: "text-sm text-muted-foreground mt-1", children: [
1936
+ selectedPayment.customer_email && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { className: "text-sm text-muted-foreground mt-1", children: [
1592
1937
  "Cliente: ",
1593
1938
  selectedPayment.customer_email
1594
1939
  ] })
1595
1940
  ] }),
1596
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "space-y-2", children: [
1597
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { className: "text-sm font-medium leading-none", children: "Importo Rimborso" }),
1598
- /* @__PURE__ */ (0, import_jsx_runtime14.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: refundAmount, onChange: (e) => setRefundAmount(e.target.value), placeholder: "Lascia vuoto per rimborso totale" })
1941
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-2", children: [
1942
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { className: "text-sm font-medium leading-none", children: "Importo Rimborso" }),
1943
+ /* @__PURE__ */ (0, import_jsx_runtime21.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: refundAmount, onChange: (e) => setRefundAmount(e.target.value), placeholder: "Lascia vuoto per rimborso totale" })
1599
1944
  ] }),
1600
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "space-y-2", children: [
1601
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { className: "text-sm font-medium leading-none", children: "Motivo" }),
1602
- /* @__PURE__ */ (0, import_jsx_runtime14.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: refundReason, onChange: (e) => setRefundReason(e.target.value), children: [
1603
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "requested_by_customer", children: "Richiesto dal cliente" }),
1604
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "duplicate", children: "Pagamento duplicato" }),
1605
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "fraudulent", children: "Fraudolento" })
1945
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-2", children: [
1946
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { className: "text-sm font-medium leading-none", children: "Motivo" }),
1947
+ /* @__PURE__ */ (0, import_jsx_runtime21.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: refundReason, onChange: (e) => setRefundReason(e.target.value), children: [
1948
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "requested_by_customer", children: "Richiesto dal cliente" }),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "duplicate", children: "Pagamento duplicato" }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "fraudulent", children: "Fraudolento" })
1606
1951
  ] })
1607
1952
  ] })
1608
1953
  ] }),
1609
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-end gap-2", children: [
1610
- /* @__PURE__ */ (0, import_jsx_runtime14.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", onClick: () => setShowRefundDialog(false), children: "Annulla" }),
1611
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { 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 disabled:opacity-50", onClick: handleRefund, disabled: refundMutation.isPending, children: refundMutation.isPending ? "Rimborso in corso..." : "Conferma Rimborso" })
1954
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex justify-end gap-2", children: [
1955
+ /* @__PURE__ */ (0, import_jsx_runtime21.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", onClick: () => setShowRefundDialog(false), children: "Annulla" }),
1956
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { 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 disabled:opacity-50", onClick: handleRefund, disabled: refundMutation.isPending, children: refundMutation.isPending ? "Rimborso in corso..." : "Conferma Rimborso" })
1612
1957
  ] })
1613
1958
  ] })
1614
1959
  ] })
1615
1960
  ] });
1616
- return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Wrapper, { children: content }) : content;
1961
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Wrapper, { children: content }) : content;
1617
1962
  }
1618
1963
 
1619
1964
  // src/pages/InvoicesPage.tsx
1620
- var import_react7 = require("react");
1965
+ var import_react9 = require("react");
1621
1966
  var import_sonner5 = require("sonner");
1622
- var import_lucide_react12 = require("lucide-react");
1967
+ var import_lucide_react13 = require("lucide-react");
1623
1968
  var import_growflowbilling_admin_core8 = require("@growflowstudio/growflowbilling-admin-core");
1624
1969
 
1625
1970
  // src/components/invoices/InvoiceDetailsDialog.tsx
1626
- var import_lucide_react11 = require("lucide-react");
1971
+ var import_lucide_react12 = require("lucide-react");
1627
1972
  var import_growflowbilling_admin_core7 = require("@growflowstudio/growflowbilling-admin-core");
1628
- var import_jsx_runtime15 = require("react/jsx-runtime");
1973
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1629
1974
  function InvoiceDetailsDialog({ isOpen, onOpenChange, invoice }) {
1630
1975
  if (!isOpen || !invoice) return null;
1631
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1632
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
1633
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
1634
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
1635
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: "text-lg font-semibold", children: "Dettagli Fattura" }),
1636
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: invoice.number || "Fattura senza numero" })
1976
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1977
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) }),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg", children: [
1979
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col space-y-1.5 pb-4", children: [
1980
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { className: "text-lg font-semibold", children: "Dettagli Fattura" }),
1981
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: invoice.number || "Fattura senza numero" })
1637
1982
  ] }),
1638
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-4", children: [
1639
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1640
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1641
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Stato" }),
1642
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StatusBadge, { label: import_growflowbilling_admin_core7.invoiceStatusLabels[invoice.status], colorClass: import_growflowbilling_admin_core7.invoiceStatusColors[invoice.status], className: "mt-1" })
1983
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-4", children: [
1984
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1985
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
1986
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: "Stato" }),
1987
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StatusBadge, { label: import_growflowbilling_admin_core7.invoiceStatusLabels[invoice.status], colorClass: import_growflowbilling_admin_core7.invoiceStatusColors[invoice.status], className: "mt-1" })
1643
1988
  ] }),
1644
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1645
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Data Creazione" }),
1646
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium mt-1", children: (0, import_growflowbilling_admin_core7.formatTimestamp)(invoice.created) })
1989
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
1990
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: "Data Creazione" }),
1991
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "font-medium mt-1", children: (0, import_growflowbilling_admin_core7.formatTimestamp)(invoice.created) })
1647
1992
  ] })
1648
1993
  ] }),
1649
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1650
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1651
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Importo Dovuto" }),
1652
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium mt-1", children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(invoice.amount_due, invoice.currency) })
1994
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
1995
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
1996
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: "Importo Dovuto" }),
1997
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "font-medium mt-1", children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(invoice.amount_due, invoice.currency) })
1653
1998
  ] }),
1654
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1655
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Importo Pagato" }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium mt-1", children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(invoice.amount_paid, invoice.currency) })
1999
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
2000
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: "Importo Pagato" }),
2001
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "font-medium mt-1", children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(invoice.amount_paid, invoice.currency) })
1657
2002
  ] })
1658
2003
  ] }),
1659
- invoice.amount_remaining > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "p-3 bg-amber-50 dark:bg-amber-900/20 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "text-sm text-amber-700 dark:text-amber-400", children: [
2004
+ invoice.amount_remaining > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "p-3 bg-amber-50 dark:bg-amber-900/20 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { className: "text-sm text-amber-700 dark:text-amber-400", children: [
1660
2005
  "Importo rimanente: ",
1661
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(invoice.amount_remaining, invoice.currency) })
2006
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(invoice.amount_remaining, invoice.currency) })
1662
2007
  ] }) }),
1663
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1664
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Cliente" }),
1665
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium mt-1", children: invoice.customer_name || "Non specificato" }),
1666
- invoice.customer_email && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: invoice.customer_email })
2008
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
2009
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: "Cliente" }),
2010
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "font-medium mt-1", children: invoice.customer_name || "Non specificato" }),
2011
+ invoice.customer_email && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground", children: invoice.customer_email })
1667
2012
  ] }),
1668
- invoice.lines && invoice.lines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1669
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground mb-2", children: "Voci Fattura" }),
1670
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "border rounded-lg divide-y", children: invoice.lines.map((line) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-3 flex justify-between items-center", children: [
1671
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1672
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm font-medium", children: line.description }),
1673
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
2013
+ invoice.lines && invoice.lines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
2014
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm text-muted-foreground mb-2", children: "Voci Fattura" }),
2015
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "border rounded-lg divide-y", children: invoice.lines.map((line) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "p-3 flex justify-between items-center", children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
2017
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm font-medium", children: line.description }),
2018
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
1674
2019
  "Qt\xE0: ",
1675
2020
  line.quantity
1676
2021
  ] })
1677
2022
  ] }),
1678
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium", children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(line.amount, line.currency) })
2023
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "font-medium", children: (0, import_growflowbilling_admin_core7.formatCurrencyFromCents)(line.amount, line.currency) })
1679
2024
  ] }, line.id)) })
1680
2025
  ] }),
1681
- invoice.hosted_invoice_url && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2026
+ invoice.hosted_invoice_url && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1682
2027
  "button",
1683
2028
  {
1684
2029
  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 w-full",
1685
2030
  onClick: () => window.open(invoice.hosted_invoice_url, "_blank"),
1686
2031
  children: [
1687
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react11.ExternalLink, { className: "w-4 h-4 mr-2" }),
2032
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.ExternalLink, { className: "w-4 h-4 mr-2" }),
1688
2033
  "Apri su Stripe"
1689
2034
  ]
1690
2035
  }
1691
2036
  )
1692
2037
  ] }),
1693
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex justify-end pt-4", children: /* @__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", onClick: () => onOpenChange(false), children: "Chiudi" }) })
2038
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex justify-end pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime22.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", onClick: () => onOpenChange(false), children: "Chiudi" }) })
1694
2039
  ] })
1695
2040
  ] });
1696
2041
  }
1697
2042
 
1698
2043
  // src/pages/InvoicesPage.tsx
1699
- var import_jsx_runtime16 = require("react/jsx-runtime");
2044
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1700
2045
  var statusFilterOptions3 = [
1701
2046
  { value: "all", label: "Tutti gli stati" },
1702
2047
  { value: "draft", label: "Bozze" },
@@ -1706,9 +2051,9 @@ var statusFilterOptions3 = [
1706
2051
  { value: "uncollectible", label: "Non Riscuotibili" }
1707
2052
  ];
1708
2053
  function InvoicesPage({ wrapper: Wrapper, header }) {
1709
- const [search, setSearch] = (0, import_react7.useState)("");
1710
- const [statusFilter, setStatusFilter] = (0, import_react7.useState)("all");
1711
- const [cursor, setCursor] = (0, import_react7.useState)();
2054
+ const [search, setSearch] = (0, import_react9.useState)("");
2055
+ const [statusFilter, setStatusFilter] = (0, import_react9.useState)("all");
2056
+ const { cursor, goToNext, goToFirst } = (0, import_growflowbilling_admin_core8.useCursorPagination)();
1712
2057
  const detailsDialog = (0, import_growflowbilling_admin_core8.useDialogState)();
1713
2058
  const voidDialog = (0, import_growflowbilling_admin_core8.useDialogState)();
1714
2059
  const { data, isLoading, refetch } = (0, import_growflowbilling_admin_core8.useAdminInvoices)({
@@ -1736,76 +2081,76 @@ function InvoicesPage({ wrapper: Wrapper, header }) {
1736
2081
  if (invoice.invoice_pdf) window.open(invoice.invoice_pdf, "_blank");
1737
2082
  else if (invoice.hosted_invoice_url) window.open(invoice.hosted_invoice_url, "_blank");
1738
2083
  };
1739
- const content = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2084
+ const content = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1740
2085
  header,
1741
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "space-y-4", children: [
1742
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2086
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-4", children: [
2087
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1743
2088
  FilterBar,
1744
2089
  {
1745
2090
  searchPlaceholder: "Cerca per email o numero fattura...",
1746
2091
  searchValue: search,
1747
2092
  onSearchChange: (v) => {
1748
2093
  setSearch(v);
1749
- setCursor(void 0);
2094
+ goToFirst();
1750
2095
  },
1751
2096
  statusFilter,
1752
2097
  onStatusFilterChange: (v) => {
1753
2098
  setStatusFilter(v);
1754
- setCursor(void 0);
2099
+ goToFirst();
1755
2100
  },
1756
2101
  statusOptions: statusFilterOptions3,
1757
2102
  onRefresh: refetch
1758
2103
  }
1759
2104
  ),
1760
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1761
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react12.FileText, { className: "w-4 h-4" }),
1762
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { children: [
2105
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react13.FileText, { className: "w-4 h-4" }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { children: [
1763
2108
  invoices.length,
1764
2109
  " fatture visualizzate"
1765
2110
  ] })
1766
2111
  ] }),
1767
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
1768
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1769
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Numero" }),
1770
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stato" }),
1771
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Importo Dovuto" }),
1772
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Importo Pagato" }),
1773
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Cliente" }),
1774
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Data" }),
1775
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Scadenza" }),
1776
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
2112
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "rounded-lg border bg-card shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("table", { className: "w-full caption-bottom text-sm", children: [
2113
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("thead", { className: "[&_tr]:border-b", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
2114
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Numero" }),
2115
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Stato" }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Importo Dovuto" }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Importo Pagato" }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Cliente" }),
2119
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Data" }),
2120
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-left font-medium text-muted-foreground", children: "Scadenza" }),
2121
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("th", { className: "h-12 px-4 text-right font-medium text-muted-foreground", children: "Azioni" })
1777
2122
  ] }) }),
1778
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SkeletonRows, { rows: 5, columns: 8 }) : invoices.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { colSpan: 8, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessuna fattura trovata" }) }) : invoices.map((inv) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
1779
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4 font-medium", children: inv.number || /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-muted-foreground", children: "-" }) }),
1780
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatusBadge, { label: import_growflowbilling_admin_core8.invoiceStatusLabels[inv.status], colorClass: import_growflowbilling_admin_core8.invoiceStatusColors[inv.status] }) }),
1781
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4 font-medium", children: (0, import_growflowbilling_admin_core8.formatCurrencyFromCents)(inv.amount_due, inv.currency) }),
1782
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core8.formatCurrencyFromCents)(inv.amount_paid, inv.currency) }),
1783
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col", children: [
1784
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: inv.customer_name || "-" }),
1785
- inv.customer_email && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: inv.customer_email })
2123
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SkeletonRows, { rows: 5, columns: 8 }) : invoices.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { colSpan: 8, className: "p-4 text-center py-8 text-muted-foreground", children: "Nessuna fattura trovata" }) }) : invoices.map((inv) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("tr", { className: "border-b hover:bg-muted/50", children: [
2124
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4 font-medium", children: inv.number || /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-muted-foreground", children: "-" }) }),
2125
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StatusBadge, { label: import_growflowbilling_admin_core8.invoiceStatusLabels[inv.status], colorClass: import_growflowbilling_admin_core8.invoiceStatusColors[inv.status] }) }),
2126
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4 font-medium", children: (0, import_growflowbilling_admin_core8.formatCurrencyFromCents)(inv.amount_due, inv.currency) }),
2127
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core8.formatCurrencyFromCents)(inv.amount_paid, inv.currency) }),
2128
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col", children: [
2129
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: inv.customer_name || "-" }),
2130
+ inv.customer_email && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-xs text-muted-foreground", children: inv.customer_email })
1786
2131
  ] }) }),
1787
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core8.formatTimestamp)(inv.created) }),
1788
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core8.formatTimestamp)(inv.due_date) }),
1789
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-end gap-1", children: [
1790
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => detailsDialog.open(inv), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react12.Eye, { className: "w-4 h-4" }) }),
1791
- (inv.invoice_pdf || inv.hosted_invoice_url) && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => openInvoicePdf(inv), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react12.Download, { className: "w-4 h-4" }) }),
1792
- inv.status === "open" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => sendMutation.mutate(inv.id, { onSuccess: () => import_sonner5.toast.success("Fattura inviata"), onError: (err) => import_sonner5.toast.error(`Errore: ${err.message}`) }), disabled: sendMutation.isPending, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react12.Send, { className: "w-4 h-4" }) }),
1793
- (inv.status === "draft" || inv.status === "open") && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent", onClick: () => voidDialog.open(inv), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react12.XCircle, { className: "w-4 h-4" }) })
2132
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core8.formatTimestamp)(inv.created) }),
2133
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4", children: (0, import_growflowbilling_admin_core8.formatTimestamp)(inv.due_date) }),
2134
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { className: "p-4 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex justify-end gap-1", children: [
2135
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => detailsDialog.open(inv), children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react13.Eye, { className: "w-4 h-4" }) }),
2136
+ (inv.invoice_pdf || inv.hosted_invoice_url) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => openInvoicePdf(inv), children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react13.Download, { className: "w-4 h-4" }) }),
2137
+ inv.status === "open" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent", onClick: () => sendMutation.mutate(inv.id, { onSuccess: () => import_sonner5.toast.success("Fattura inviata"), onError: (err) => import_sonner5.toast.error(`Errore: ${err.message}`) }), disabled: sendMutation.isPending, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react13.Send, { className: "w-4 h-4" }) }),
2138
+ (inv.status === "draft" || inv.status === "open") && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent", onClick: () => voidDialog.open(inv), children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react13.XCircle, { className: "w-4 h-4" }) })
1794
2139
  ] }) })
1795
2140
  ] }, inv.id)) })
1796
2141
  ] }) }) }),
1797
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CursorPagination, { cursor, hasMore, items: invoices, onFirstPage: () => setCursor(void 0), onNextPage: setCursor })
2142
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CursorPagination, { cursor, hasMore, items: invoices, onFirstPage: goToFirst, onNextPage: goToNext })
1798
2143
  ] }),
1799
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(InvoiceDetailsDialog, { isOpen: detailsDialog.isOpen, onOpenChange: (open) => !open && detailsDialog.close(), invoice: detailsDialog.data }),
1800
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2144
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InvoiceDetailsDialog, { isOpen: detailsDialog.isOpen, onOpenChange: (open) => !open && detailsDialog.close(), invoice: detailsDialog.data }),
2145
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1801
2146
  DeleteConfirmDialog,
1802
2147
  {
1803
2148
  isOpen: voidDialog.isOpen,
1804
2149
  onOpenChange: (open) => !open && voidDialog.close(),
1805
2150
  title: "Annullare Fattura?",
1806
- description: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2151
+ description: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1807
2152
  "Stai per annullare la fattura ",
1808
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: voidDialog.data?.number || voidDialog.data?.id }),
2153
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: voidDialog.data?.number || voidDialog.data?.id }),
1809
2154
  ". Una fattura annullata non pu\xF2 essere riattivata."
1810
2155
  ] }),
1811
2156
  onConfirm: handleVoidConfirm,
@@ -1814,279 +2159,363 @@ function InvoicesPage({ wrapper: Wrapper, header }) {
1814
2159
  }
1815
2160
  )
1816
2161
  ] });
1817
- return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Wrapper, { children: content }) : content;
2162
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Wrapper, { children: content }) : content;
1818
2163
  }
1819
2164
 
1820
2165
  // src/pages/FeaturesPage.tsx
1821
- var import_react8 = require("react");
1822
- var import_sonner6 = require("sonner");
1823
- var import_lucide_react13 = require("lucide-react");
2166
+ var import_react10 = require("react");
2167
+ var import_lucide_react15 = require("lucide-react");
2168
+ var import_growflowbilling_admin_core10 = require("@growflowstudio/growflowbilling-admin-core");
2169
+ var import_sonner7 = require("sonner");
2170
+
2171
+ // src/components/features/FeatureFormModal.tsx
1824
2172
  var import_growflowbilling_admin_core9 = require("@growflowstudio/growflowbilling-admin-core");
1825
- var import_jsx_runtime17 = require("react/jsx-runtime");
1826
- function FeaturesPage({ wrapper: Wrapper, header }) {
1827
- const [isCreateDialogOpen, setIsCreateDialogOpen] = (0, import_react8.useState)(false);
1828
- const [editingFeature, setEditingFeature] = (0, import_react8.useState)(null);
1829
- const [deletingFeature, setDeletingFeature] = (0, import_react8.useState)(null);
1830
- const { data, isLoading } = (0, import_growflowbilling_admin_core9.useAdminFeatures)();
2173
+ var import_sonner6 = require("sonner");
2174
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2175
+ function FeatureFormModal({ feature, open, onClose, onSuccess }) {
2176
+ const isEditMode = feature !== null;
1831
2177
  const createMutation = (0, import_growflowbilling_admin_core9.useCreateFeature)();
1832
2178
  const updateMutation = (0, import_growflowbilling_admin_core9.useUpdateFeature)();
1833
- const deleteMutation = (0, import_growflowbilling_admin_core9.useDeleteFeature)();
1834
- const features = data?.features || [];
1835
- const handleCreateFeature = (e) => {
1836
- e.preventDefault();
1837
- const formData = new FormData(e.currentTarget);
1838
- const createData = {
1839
- slug: formData.get("slug"),
1840
- name: formData.get("name"),
1841
- description: formData.get("description") || void 0,
1842
- icon: formData.get("icon") || void 0,
1843
- category: formData.get("category") || void 0,
1844
- is_available: formData.get("is_available") === "on",
1845
- billing_product_id: formData.get("billing_product_id") || void 0
1846
- };
1847
- createMutation.mutate(createData, {
1848
- onSuccess: () => {
1849
- import_sonner6.toast.success("Feature creata con successo");
1850
- setIsCreateDialogOpen(false);
1851
- },
1852
- onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
1853
- });
1854
- };
1855
- const handleUpdateFeature = (e) => {
2179
+ const isPending = createMutation.isPending || updateMutation.isPending;
2180
+ const handleSubmit = (e) => {
1856
2181
  e.preventDefault();
1857
- if (!editingFeature) return;
1858
2182
  const formData = new FormData(e.currentTarget);
1859
- const updateData = {
1860
- name: formData.get("name"),
1861
- description: formData.get("description") || void 0,
1862
- icon: formData.get("icon") || void 0,
1863
- category: formData.get("category") || void 0,
1864
- is_available: formData.get("is_available") === "on",
1865
- billing_product_id: formData.get("billing_product_id") || void 0
1866
- };
1867
- updateMutation.mutate({ id: editingFeature.id, data: updateData }, {
1868
- onSuccess: () => {
1869
- import_sonner6.toast.success("Feature aggiornata con successo");
1870
- setEditingFeature(null);
1871
- },
1872
- onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
1873
- });
2183
+ if (isEditMode) {
2184
+ const updateData = {
2185
+ name: formData.get("name"),
2186
+ description: formData.get("description") || void 0,
2187
+ icon: formData.get("icon") || void 0,
2188
+ category: formData.get("category") || void 0,
2189
+ is_available: formData.get("is_available") === "on",
2190
+ billing_product_id: formData.get("billing_product_id") || void 0
2191
+ };
2192
+ updateMutation.mutate(
2193
+ { id: feature.id, data: updateData },
2194
+ {
2195
+ onSuccess: () => {
2196
+ import_sonner6.toast.success("Feature aggiornata con successo");
2197
+ onSuccess();
2198
+ },
2199
+ onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
2200
+ }
2201
+ );
2202
+ } else {
2203
+ const createData = {
2204
+ slug: formData.get("slug"),
2205
+ name: formData.get("name"),
2206
+ description: formData.get("description") || void 0,
2207
+ icon: formData.get("icon") || void 0,
2208
+ category: formData.get("category") || void 0,
2209
+ is_available: formData.get("is_available") === "on",
2210
+ billing_product_id: formData.get("billing_product_id") || void 0
2211
+ };
2212
+ createMutation.mutate(createData, {
2213
+ onSuccess: () => {
2214
+ import_sonner6.toast.success("Feature creata con successo");
2215
+ onSuccess();
2216
+ },
2217
+ onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
2218
+ });
2219
+ }
1874
2220
  };
2221
+ if (!open) return null;
2222
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2223
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: onClose }),
2224
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("form", { onSubmit: handleSubmit, children: [
2225
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { className: "text-lg font-semibold", children: isEditMode ? "Modifica Feature" : "Crea Nuova Feature" }),
2226
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-sm text-muted-foreground mt-1", children: isEditMode ? `Aggiorna i dettagli della feature "${feature.name}".` : "Configura una nuova feature disponibile." }),
2227
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-4 py-4", children: [
2228
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-2", children: [
2229
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "slug", children: isEditMode ? "Slug (non modificabile)" : "Slug *" }),
2230
+ isEditMode ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2231
+ "input",
2232
+ {
2233
+ value: feature.slug,
2234
+ disabled: true,
2235
+ className: "flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm"
2236
+ }
2237
+ ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
2238
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2239
+ "input",
2240
+ {
2241
+ id: "slug",
2242
+ name: "slug",
2243
+ required: true,
2244
+ placeholder: "ottimizza-dati-prodotti",
2245
+ 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"
2246
+ }
2247
+ ),
2248
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-xs text-muted-foreground", children: "Identificatore univoco (lowercase, trattini)" })
2249
+ ] })
2250
+ ] }),
2251
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-2", children: [
2252
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "name", children: "Nome *" }),
2253
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2254
+ "input",
2255
+ {
2256
+ id: isEditMode ? "edit-name" : "name",
2257
+ name: "name",
2258
+ required: true,
2259
+ defaultValue: feature?.name ?? "",
2260
+ placeholder: "Ottimizza Dati Prodotti",
2261
+ 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"
2262
+ }
2263
+ )
2264
+ ] }),
2265
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-2", children: [
2266
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "description", children: "Descrizione" }),
2267
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2268
+ "textarea",
2269
+ {
2270
+ id: isEditMode ? "edit-description" : "description",
2271
+ name: "description",
2272
+ rows: 3,
2273
+ defaultValue: feature?.description ?? "",
2274
+ placeholder: "Descrizione della feature...",
2275
+ className: "flex min-h-[80px] 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"
2276
+ }
2277
+ )
2278
+ ] }),
2279
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
2280
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-2", children: [
2281
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "icon", children: "Icona Lucide" }),
2282
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2283
+ "input",
2284
+ {
2285
+ id: isEditMode ? "edit-icon" : "icon",
2286
+ name: "icon",
2287
+ defaultValue: feature?.icon ?? "",
2288
+ placeholder: "Package",
2289
+ 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"
2290
+ }
2291
+ )
2292
+ ] }),
2293
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-2", children: [
2294
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "category", children: "Categoria" }),
2295
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2296
+ "input",
2297
+ {
2298
+ id: isEditMode ? "edit-category" : "category",
2299
+ name: "category",
2300
+ defaultValue: feature?.category ?? "",
2301
+ placeholder: "ai, limits, integration...",
2302
+ 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"
2303
+ }
2304
+ )
2305
+ ] })
2306
+ ] }),
2307
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-2", children: [
2308
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "billing_product_id", children: "Billing Product ID (opzionale)" }),
2309
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2310
+ "input",
2311
+ {
2312
+ id: isEditMode ? "edit-billing_product_id" : "billing_product_id",
2313
+ name: "billing_product_id",
2314
+ defaultValue: feature?.billing_product_id ?? "",
2315
+ placeholder: "UUID del prodotto billing",
2316
+ 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"
2317
+ }
2318
+ ),
2319
+ !isEditMode && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-xs text-muted-foreground", children: "Se collegato a un prodotto, la feature viene attivata automaticamente" })
2320
+ ] }),
2321
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-2", children: [
2322
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2323
+ "input",
2324
+ {
2325
+ type: "checkbox",
2326
+ id: isEditMode ? "edit-is_available" : "is_available",
2327
+ name: "is_available",
2328
+ defaultChecked: feature?.is_available ?? true,
2329
+ className: "rounded border-input"
2330
+ }
2331
+ ),
2332
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2333
+ "label",
2334
+ {
2335
+ className: "text-sm font-medium leading-none",
2336
+ htmlFor: isEditMode ? "edit-is_available" : "is_available",
2337
+ children: "Feature disponibile"
2338
+ }
2339
+ )
2340
+ ] })
2341
+ ] }),
2342
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex justify-end gap-2", children: [
2343
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2344
+ "button",
2345
+ {
2346
+ type: "button",
2347
+ 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",
2348
+ onClick: onClose,
2349
+ children: "Annulla"
2350
+ }
2351
+ ),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2353
+ "button",
2354
+ {
2355
+ type: "submit",
2356
+ 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",
2357
+ disabled: isPending,
2358
+ children: isPending ? isEditMode ? "Salvataggio..." : "Creazione..." : isEditMode ? "Salva Modifiche" : "Crea Feature"
2359
+ }
2360
+ )
2361
+ ] })
2362
+ ] }) })
2363
+ ] });
2364
+ }
2365
+
2366
+ // src/components/features/FeatureListItem.tsx
2367
+ var import_lucide_react14 = require("lucide-react");
2368
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2369
+ function FeatureListItem({ feature, onEdit, onDelete }) {
2370
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "border rounded-lg p-4 hover:bg-muted/50 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-start justify-between", children: [
2371
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex-1", children: [
2372
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
2373
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold", children: feature.name }),
2374
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("code", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: feature.slug }),
2375
+ !feature.is_available && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusBadge, { label: "Disattivata", colorClass: "bg-secondary text-secondary-foreground border-transparent" }),
2376
+ feature.billing_product_id && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusBadge, { label: "Con Billing", colorClass: "border" })
2377
+ ] }),
2378
+ feature.description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-sm text-muted-foreground mb-2", children: feature.description }),
2379
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-4 text-xs text-muted-foreground", children: [
2380
+ feature.category && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
2381
+ "Categoria: ",
2382
+ feature.category
2383
+ ] }),
2384
+ feature.icon && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
2385
+ "Icona: ",
2386
+ feature.icon
2387
+ ] })
2388
+ ] })
2389
+ ] }),
2390
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-1", children: [
2391
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2392
+ "button",
2393
+ {
2394
+ className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent",
2395
+ onClick: () => onEdit(feature),
2396
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.Pencil, { className: "w-4 h-4" })
2397
+ }
2398
+ ),
2399
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2400
+ "button",
2401
+ {
2402
+ className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent",
2403
+ onClick: () => onDelete(feature),
2404
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react14.Trash2, { className: "w-4 h-4" })
2405
+ }
2406
+ )
2407
+ ] })
2408
+ ] }) });
2409
+ }
2410
+
2411
+ // src/pages/FeaturesPage.tsx
2412
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2413
+ function FeaturesPage({ wrapper: Wrapper, header }) {
2414
+ const [modalFeature, setModalFeature] = (0, import_react10.useState)(void 0);
2415
+ const [deletingFeature, setDeletingFeature] = (0, import_react10.useState)(null);
2416
+ const isModalOpen = modalFeature !== void 0;
2417
+ const { data, isLoading, refetch } = (0, import_growflowbilling_admin_core10.useAdminFeatures)();
2418
+ const deleteMutation = (0, import_growflowbilling_admin_core10.useDeleteFeature)();
2419
+ const features = data?.features || [];
1875
2420
  const handleDeleteConfirm = () => {
1876
2421
  if (deletingFeature) {
1877
2422
  deleteMutation.mutate(deletingFeature.id, {
1878
2423
  onSuccess: () => {
1879
- import_sonner6.toast.success("Feature eliminata con successo");
2424
+ import_sonner7.toast.success("Feature eliminata con successo");
1880
2425
  setDeletingFeature(null);
1881
2426
  },
1882
- onError: (err) => import_sonner6.toast.error(`Errore: ${err.message}`)
2427
+ onError: (err) => import_sonner7.toast.error(`Errore: ${err.message}`)
1883
2428
  });
1884
2429
  }
1885
2430
  };
1886
- const content = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2431
+ const handleModalSuccess = () => {
2432
+ refetch();
2433
+ setModalFeature(void 0);
2434
+ };
2435
+ const content = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
1887
2436
  header,
1888
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-4", children: [
1889
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between", children: [
1890
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1891
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.Package, { className: "w-4 h-4" }),
1892
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
2437
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "space-y-4", children: [
2438
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between", children: [
2439
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
2440
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react15.Package, { className: "w-4 h-4" }),
2441
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { children: [
1893
2442
  features.length,
1894
2443
  " feature",
1895
2444
  features.length !== 1 ? "s" : "",
1896
2445
  " configurate"
1897
2446
  ] })
1898
2447
  ] }),
1899
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2448
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1900
2449
  "button",
1901
2450
  {
1902
2451
  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",
1903
- onClick: () => setIsCreateDialogOpen(true),
2452
+ onClick: () => setModalFeature(null),
1904
2453
  children: [
1905
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.Plus, { className: "w-4 h-4 mr-2" }),
2454
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react15.Plus, { className: "w-4 h-4 mr-2" }),
1906
2455
  "Nuova Feature"
1907
2456
  ]
1908
2457
  }
1909
2458
  )
1910
2459
  ] }),
1911
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "rounded-lg border bg-card shadow-sm", children: [
1912
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "p-4 border-b", children: [
1913
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("h3", { className: "text-base font-semibold flex items-center gap-2", children: [
1914
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.Package, { className: "w-5 h-5" }),
2460
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "rounded-lg border bg-card shadow-sm", children: [
2461
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "p-4 border-b", children: [
2462
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("h3", { className: "text-base font-semibold flex items-center gap-2", children: [
2463
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react15.Package, { className: "w-5 h-5" }),
1915
2464
  "Features Disponibili"
1916
2465
  ] }),
1917
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm text-muted-foreground mt-1", children: "Le features possono essere collegate a prodotti billing o attivate manualmente." })
2466
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-sm text-muted-foreground mt-1", children: "Le features possono essere collegate a prodotti billing o attivate manualmente." })
1918
2467
  ] }),
1919
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "p-4", children: [
1920
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "h-20 bg-muted animate-pulse rounded-lg" }, i)) }) : features.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "text-center py-12 text-muted-foreground", children: [
1921
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.Package, { className: "mx-auto h-12 w-12 mb-4 opacity-50" }),
1922
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: "Nessuna feature configurata" }),
1923
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2468
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "p-4", children: [
2469
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-20 bg-muted animate-pulse rounded-lg" }, i)) }) : features.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "text-center py-12 text-muted-foreground", children: [
2470
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react15.Package, { className: "mx-auto h-12 w-12 mb-4 opacity-50" }),
2471
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: "Nessuna feature configurata" }),
2472
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1924
2473
  "button",
1925
2474
  {
1926
2475
  className: "text-sm text-primary hover:underline mt-2",
1927
- onClick: () => setIsCreateDialogOpen(true),
2476
+ onClick: () => setModalFeature(null),
1928
2477
  children: "Crea la prima feature"
1929
2478
  }
1930
2479
  )
1931
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "space-y-3", children: features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1932
- "div",
2480
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "space-y-3", children: features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2481
+ FeatureListItem,
1933
2482
  {
1934
- className: "border rounded-lg p-4 hover:bg-muted/50 transition-colors",
1935
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-start justify-between", children: [
1936
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex-1", children: [
1937
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
1938
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-semibold", children: feature.name }),
1939
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: feature.slug }),
1940
- !feature.is_available && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { label: "Disattivata", colorClass: "bg-secondary text-secondary-foreground border-transparent" }),
1941
- feature.billing_product_id && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { label: "Con Billing", colorClass: "border" })
1942
- ] }),
1943
- feature.description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm text-muted-foreground mb-2", children: feature.description }),
1944
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-4 text-xs text-muted-foreground", children: [
1945
- feature.category && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
1946
- "Categoria: ",
1947
- feature.category
1948
- ] }),
1949
- feature.icon && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
1950
- "Icona: ",
1951
- feature.icon
1952
- ] })
1953
- ] })
1954
- ] }),
1955
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1", children: [
1956
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1957
- "button",
1958
- {
1959
- className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent",
1960
- onClick: () => setEditingFeature(feature),
1961
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.Pencil, { className: "w-4 h-4" })
1962
- }
1963
- ),
1964
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1965
- "button",
1966
- {
1967
- className: "inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent",
1968
- onClick: () => setDeletingFeature(feature),
1969
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.Trash2, { className: "w-4 h-4" })
1970
- }
1971
- )
1972
- ] })
1973
- ] })
2483
+ feature,
2484
+ onEdit: (f) => setModalFeature(f),
2485
+ onDelete: (f) => setDeletingFeature(f)
1974
2486
  },
1975
2487
  feature.id
1976
2488
  )) }),
1977
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "mt-6 flex gap-3 items-start rounded-lg border p-3 text-sm", children: [
1978
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react13.AlertCircle, { className: "w-4 h-4 mt-0.5 text-muted-foreground shrink-0" }),
1979
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-muted-foreground text-xs", children: [
1980
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Nota:" }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-6 flex gap-3 items-start rounded-lg border p-3 text-sm", children: [
2490
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react15.AlertCircle, { className: "w-4 h-4 mt-0.5 text-muted-foreground shrink-0" }),
2491
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("p", { className: "text-muted-foreground text-xs", children: [
2492
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("strong", { children: "Nota:" }),
1981
2493
  " Features con un billing_product_id vengono attivate automaticamente quando il cliente sottoscrive il piano corrispondente."
1982
2494
  ] })
1983
2495
  ] })
1984
2496
  ] })
1985
2497
  ] })
1986
2498
  ] }),
1987
- isCreateDialogOpen && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
1988
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setIsCreateDialogOpen(false) }),
1989
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("form", { onSubmit: handleCreateFeature, children: [
1990
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { className: "text-lg font-semibold", children: "Crea Nuova Feature" }),
1991
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm text-muted-foreground mt-1", children: "Configura una nuova feature disponibile." }),
1992
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-4 py-4", children: [
1993
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
1994
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "slug", children: "Slug *" }),
1995
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "slug", name: "slug", required: true, placeholder: "ottimizza-dati-prodotti", 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" }),
1996
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-xs text-muted-foreground", children: "Identificatore univoco (lowercase, trattini)" })
1997
- ] }),
1998
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
1999
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "name", children: "Nome *" }),
2000
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "name", name: "name", required: true, placeholder: "Ottimizza Dati Prodotti", 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" })
2001
- ] }),
2002
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2003
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "description", children: "Descrizione" }),
2004
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("textarea", { id: "description", name: "description", rows: 3, placeholder: "Descrizione della feature...", className: "flex min-h-[80px] 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" })
2005
- ] }),
2006
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
2007
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2008
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "icon", children: "Icona Lucide" }),
2009
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "icon", name: "icon", placeholder: "Package", 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" })
2010
- ] }),
2011
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2012
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "category", children: "Categoria" }),
2013
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "category", name: "category", placeholder: "ai, limits, integration...", 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" })
2014
- ] })
2015
- ] }),
2016
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2017
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "billing_product_id", children: "Billing Product ID (opzionale)" }),
2018
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "billing_product_id", name: "billing_product_id", placeholder: "UUID del prodotto billing", 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" }),
2019
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-xs text-muted-foreground", children: "Se collegato a un prodotto, la feature viene attivata automaticamente" })
2020
- ] }),
2021
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
2022
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { type: "checkbox", id: "is_available", name: "is_available", defaultChecked: true, className: "rounded border-input" }),
2023
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "is_available", children: "Feature disponibile" })
2024
- ] })
2025
- ] }),
2026
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex justify-end gap-2", children: [
2027
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "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", onClick: () => setIsCreateDialogOpen(false), children: "Annulla" }),
2028
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "submit", 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", disabled: createMutation.isPending, children: createMutation.isPending ? "Creazione..." : "Crea Feature" })
2029
- ] })
2030
- ] }) })
2031
- ] }),
2032
- editingFeature && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2033
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "fixed inset-0 bg-black/80", onClick: () => setEditingFeature(null) }),
2034
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("form", { onSubmit: handleUpdateFeature, children: [
2035
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { className: "text-lg font-semibold", children: "Modifica Feature" }),
2036
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-sm text-muted-foreground mt-1", children: [
2037
- 'Aggiorna i dettagli della feature "',
2038
- editingFeature.name,
2039
- '".'
2040
- ] }),
2041
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-4 py-4", children: [
2042
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2043
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", children: "Slug (non modificabile)" }),
2044
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: editingFeature.slug, disabled: true, className: "flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm" })
2045
- ] }),
2046
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2047
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "edit-name", children: "Nome *" }),
2048
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "edit-name", name: "name", required: true, defaultValue: editingFeature.name, 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" })
2049
- ] }),
2050
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2051
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "edit-description", children: "Descrizione" }),
2052
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("textarea", { id: "edit-description", name: "description", rows: 3, defaultValue: editingFeature.description || "", className: "flex min-h-[80px] 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" })
2053
- ] }),
2054
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [
2055
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2056
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "edit-icon", children: "Icona Lucide" }),
2057
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "edit-icon", name: "icon", defaultValue: editingFeature.icon || "", 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" })
2058
- ] }),
2059
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2060
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "edit-category", children: "Categoria" }),
2061
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "edit-category", name: "category", defaultValue: editingFeature.category || "", 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" })
2062
- ] })
2063
- ] }),
2064
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-2", children: [
2065
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "edit-billing_product_id", children: "Billing Product ID" }),
2066
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { id: "edit-billing_product_id", name: "billing_product_id", defaultValue: editingFeature.billing_product_id || "", 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" })
2067
- ] }),
2068
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
2069
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { type: "checkbox", id: "edit-is_available", name: "is_available", defaultChecked: editingFeature.is_available, className: "rounded border-input" }),
2070
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "text-sm font-medium leading-none", htmlFor: "edit-is_available", children: "Feature disponibile" })
2071
- ] })
2072
- ] }),
2073
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex justify-end gap-2", children: [
2074
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "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", onClick: () => setEditingFeature(null), children: "Annulla" }),
2075
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "submit", 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", disabled: updateMutation.isPending, children: updateMutation.isPending ? "Salvataggio..." : "Salva Modifiche" })
2076
- ] })
2077
- ] }) })
2078
- ] }),
2079
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2499
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2500
+ FeatureFormModal,
2501
+ {
2502
+ feature: isModalOpen ? modalFeature ?? null : null,
2503
+ open: isModalOpen,
2504
+ onClose: () => setModalFeature(void 0),
2505
+ onSuccess: handleModalSuccess
2506
+ }
2507
+ ),
2508
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2080
2509
  DeleteConfirmDialog,
2081
2510
  {
2082
2511
  isOpen: !!deletingFeature,
2083
2512
  onOpenChange: (open) => !open && setDeletingFeature(null),
2084
2513
  title: "Eliminare Feature?",
2085
- description: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2514
+ description: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
2086
2515
  "Stai per eliminare la feature ",
2087
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: deletingFeature?.name }),
2516
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("strong", { children: deletingFeature?.name }),
2088
2517
  " (",
2089
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: deletingFeature?.slug }),
2518
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("code", { children: deletingFeature?.slug }),
2090
2519
  "). Questa azione non pu\xF2 essere annullata."
2091
2520
  ] }),
2092
2521
  onConfirm: handleDeleteConfirm,
@@ -2095,7 +2524,7 @@ function FeaturesPage({ wrapper: Wrapper, header }) {
2095
2524
  }
2096
2525
  )
2097
2526
  ] });
2098
- return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Wrapper, { children: content }) : content;
2527
+ return Wrapper ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Wrapper, { children: content }) : content;
2099
2528
  }
2100
2529
 
2101
2530
  // src/nav/billingNavItems.ts
@@ -2127,6 +2556,8 @@ function getBillingNavItems(modules, basePath) {
2127
2556
  BillingAdminProvider,
2128
2557
  CursorPagination,
2129
2558
  DeleteConfirmDialog,
2559
+ FeatureFormModal,
2560
+ FeatureListItem,
2130
2561
  FeaturesPage,
2131
2562
  FilterBar,
2132
2563
  InvoiceDetailsDialog,
@@ -2134,7 +2565,11 @@ function getBillingNavItems(modules, basePath) {
2134
2565
  LimitInput,
2135
2566
  PLAN_COLORS,
2136
2567
  PaymentsPage,
2568
+ PlanDetailsSection,
2569
+ PlanFeaturesSection,
2137
2570
  PlanFormDialog,
2571
+ PlanLimitsSection,
2572
+ PlanPricingSection,
2138
2573
  PlansPage,
2139
2574
  PlansTable,
2140
2575
  ProductFormDialog,
@@ -2142,6 +2577,7 @@ function getBillingNavItems(modules, basePath) {
2142
2577
  SkeletonRows,
2143
2578
  StatusBadge,
2144
2579
  SubscriptionsPage,
2580
+ ToggleSwitch,
2145
2581
  createDefaultPlanFormData,
2146
2582
  defaultProductFormData,
2147
2583
  getBillingNavItems,