@growflowstudio/growflowbilling-admin-ui 2.1.0 → 2.2.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
@@ -73,7 +73,7 @@ function BillingAdminProvider({ config, children }) {
73
73
  }
74
74
 
75
75
  // src/pages/PlansPage.tsx
76
- import { useState as useState2 } from "react";
76
+ import { useEffect, useState as useState2 } from "react";
77
77
  import { toast } from "sonner";
78
78
  import { Plus, RefreshCw, LayoutGrid } from "lucide-react";
79
79
  import {
@@ -159,7 +159,7 @@ function PlansTable({
159
159
  /* @__PURE__ */ jsx5("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Modello" }),
160
160
  /* @__PURE__ */ jsx5("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Prezzo Mensile" }),
161
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" }),
162
+ /* @__PURE__ */ jsx5("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Inizio pagamento" }),
163
163
  /* @__PURE__ */ jsx5("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Attivo" }),
164
164
  /* @__PURE__ */ jsx5("th", { className: "h-12 px-4 text-left align-middle font-medium text-muted-foreground", children: "Stripe" }),
165
165
  /* @__PURE__ */ jsx5("th", { className: "h-12 px-4 text-right align-middle font-medium text-muted-foreground", children: "Azioni" })
@@ -171,10 +171,7 @@ function PlansTable({
171
171
  /* @__PURE__ */ jsx5("td", { className: "p-4 align-middle", children: /* @__PURE__ */ jsx5(StatusBadge, { label: pricingModelLabels[plan.pricing_model], colorClass: "border" }) }),
172
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
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: [
175
- plan.trial_days,
176
- " giorni"
177
- ] }),
174
+ /* @__PURE__ */ jsx5("td", { className: "p-4 align-middle whitespace-nowrap", children: plan.paid_start_date ? new Date(plan.paid_start_date).toLocaleDateString("it-IT") : `giorno ${plan.paid_start_day ?? plan.trial_days + 1}` }),
178
175
  /* @__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
176
  /* @__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(
180
177
  "button",
@@ -371,17 +368,20 @@ function PlanPricingSection({ formData, onFormDataChange }) {
371
368
  )
372
369
  ] }),
373
370
  /* @__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" }),
371
+ /* @__PURE__ */ jsx8("label", { className: "text-sm font-medium leading-none", htmlFor: "paid_start_day", children: "Inizio pagamento (giorno)" }),
375
372
  /* @__PURE__ */ jsx8(
376
373
  "input",
377
374
  {
378
- id: "trial_days",
375
+ id: "paid_start_day",
379
376
  type: "number",
377
+ min: 1,
380
378
  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 })
379
+ value: formData.paid_start_day,
380
+ disabled: !!formData.paid_start_date,
381
+ onChange: (e) => onFormDataChange({ paid_start_day: Math.max(1, parseInt(e.target.value) || 1) })
383
382
  }
384
- )
383
+ ),
384
+ /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: formData.paid_start_day > 1 ? `Trial dal giorno 1 al ${formData.paid_start_day - 1}, prima fattura il giorno ${formData.paid_start_day} dalla registrazione.` : "Fatturato dal primo giorno, nessun trial." })
385
385
  ] }),
386
386
  /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
387
387
  /* @__PURE__ */ jsx8("label", { className: "text-sm font-medium leading-none", htmlFor: "sort_order", children: "Ordine" }),
@@ -396,6 +396,31 @@ function PlanPricingSection({ formData, onFormDataChange }) {
396
396
  }
397
397
  )
398
398
  ] })
399
+ ] }),
400
+ /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
401
+ /* @__PURE__ */ jsx8("label", { className: "text-sm font-medium leading-none", htmlFor: "paid_start_date", children: "Data fissa di inizio pagamento (opzionale)" }),
402
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
403
+ /* @__PURE__ */ jsx8(
404
+ "input",
405
+ {
406
+ id: "paid_start_date",
407
+ type: "date",
408
+ 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 max-w-xs",
409
+ value: formData.paid_start_date,
410
+ onChange: (e) => onFormDataChange({ paid_start_date: e.target.value })
411
+ }
412
+ ),
413
+ formData.paid_start_date && /* @__PURE__ */ jsx8(
414
+ "button",
415
+ {
416
+ type: "button",
417
+ className: "text-sm text-muted-foreground underline-offset-4 hover:underline",
418
+ onClick: () => onFormDataChange({ paid_start_date: "" }),
419
+ children: "Rimuovi"
420
+ }
421
+ )
422
+ ] }),
423
+ /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: "Se compilata, tutti gli store su questo piano vengono fatturati a partire da questa data, ignorando il giorno relativo." })
399
424
  ] })
400
425
  ] });
401
426
  }
@@ -734,6 +759,8 @@ function createDefaultPlanFormData(limitFields = []) {
734
759
  price_yearly: "",
735
760
  currency: "eur",
736
761
  trial_days: 14,
762
+ paid_start_day: 15,
763
+ paid_start_date: "",
737
764
  is_active: true,
738
765
  contact_sales: false,
739
766
  is_public: true,
@@ -922,11 +949,11 @@ function PlansPage({ wrapper: Wrapper, header }) {
922
949
  const deleteMutation = useDeletePlan();
923
950
  const syncMutation = useSyncPlanToStripe();
924
951
  const [publicPlanSlugs, setPublicPlanSlugs] = useState2([]);
925
- useState2(() => {
952
+ useEffect(() => {
926
953
  if (publicPlansConfig?.enabled && publicPlansConfig.fetchFn) {
927
954
  publicPlansConfig.fetchFn().then((r) => setPublicPlanSlugs(r.public_plan_slugs));
928
955
  }
929
- });
956
+ }, [publicPlansConfig]);
930
957
  const plans = data?.items || [];
931
958
  const resetForm = () => {
932
959
  setFormData(createDefaultPlanFormData(limitFields));
@@ -954,6 +981,8 @@ function PlansPage({ wrapper: Wrapper, header }) {
954
981
  price_yearly: plan.price_yearly ? plan.price_yearly.toString() : "",
955
982
  currency: plan.currency,
956
983
  trial_days: plan.trial_days,
984
+ paid_start_day: plan.paid_start_day ?? plan.trial_days + 1,
985
+ paid_start_date: plan.paid_start_date ?? "",
957
986
  is_active: plan.is_active,
958
987
  contact_sales: plan.contact_sales,
959
988
  is_public: publicPlanSlugs.includes(plan.slug),
@@ -989,7 +1018,8 @@ function PlansPage({ wrapper: Wrapper, header }) {
989
1018
  price_monthly: formData.price_monthly ? parseFloat(formData.price_monthly) : void 0,
990
1019
  price_yearly: formData.price_yearly ? parseFloat(formData.price_yearly) : void 0,
991
1020
  currency: formData.currency,
992
- trial_days: formData.trial_days,
1021
+ paid_start_day: formData.paid_start_day,
1022
+ paid_start_date: formData.paid_start_date || null,
993
1023
  is_active: formData.is_active,
994
1024
  contact_sales: formData.contact_sales,
995
1025
  color: formData.color,
@@ -1137,7 +1167,7 @@ import {
1137
1167
  } from "@growflowstudio/growflowbilling-admin-core";
1138
1168
 
1139
1169
  // src/components/products/ProductFormDialog.tsx
1140
- import { useState as useState3, useEffect } from "react";
1170
+ import { useState as useState3, useEffect as useEffect2 } from "react";
1141
1171
  import { Loader2 as Loader23, Link as LinkIcon } from "lucide-react";
1142
1172
  import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1143
1173
  var safeJsonParse = (str, fallback = {}) => {
@@ -1171,7 +1201,7 @@ function ProductFormDialog({
1171
1201
  }) {
1172
1202
  const [formData, setFormData] = useState3(defaultProductFormData);
1173
1203
  const [formErrors, setFormErrors] = useState3({});
1174
- useEffect(() => {
1204
+ useEffect2(() => {
1175
1205
  if (isOpen) {
1176
1206
  if (mode === "edit" && product) {
1177
1207
  const featureSlug = product.extra_data?.feature_slug || "";
@@ -1193,7 +1223,7 @@ function ProductFormDialog({
1193
1223
  setFormErrors({});
1194
1224
  }
1195
1225
  }, [isOpen, mode, product]);
1196
- useEffect(() => {
1226
+ useEffect2(() => {
1197
1227
  if (formData.feature_slug) {
1198
1228
  setFormData((prev) => {
1199
1229
  const parsedData = safeJsonParse(prev.extra_data);