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