@growflowstudio/billing-admin-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.mts +329 -0
- package/dist/index.d.ts +329 -0
- package/dist/index.js +2152 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2139 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/pages/PlansPage.tsx","../src/components/plans/PlansTable.tsx","../src/components/plans/plan-colors.ts","../src/primitives/utils.ts","../src/components/shared/StatusBadge.tsx","../src/components/shared/SkeletonRows.tsx","../src/components/plans/PlanFormDialog.tsx","../src/components/plans/LimitInput.tsx","../src/components/shared/DeleteConfirmDialog.tsx","../src/pages/ProductsPage.tsx","../src/components/products/ProductFormDialog.tsx","../src/pages/SubscriptionsPage.tsx","../src/components/shared/FilterBar.tsx","../src/pages/PaymentsPage.tsx","../src/components/shared/CursorPagination.tsx","../src/pages/InvoicesPage.tsx","../src/components/invoices/InvoiceDetailsDialog.tsx","../src/pages/FeaturesPage.tsx","../src/nav/billingNavItems.ts"],"sourcesContent":["import React, { useMemo } from 'react';\nimport {\n BillingAdminClientContext,\n createBillingAdminClient,\n type Fetcher,\n} from '@growflowstudio/billing-admin-core';\n\nexport interface LimitFieldConfig {\n key: string;\n label: string;\n defaultValue?: number;\n}\n\nexport interface FeaturesConfig {\n enabled: boolean;\n fetchFn?: () => Promise<{ features: Array<{ slug: string; name: string; description?: string }> }>;\n}\n\nexport interface PublicPlansConfig {\n enabled: boolean;\n fetchFn?: () => Promise<{ public_plan_slugs: string[] }>;\n updateFn?: (slugs: string[]) => Promise<{ public_plan_slugs: string[] }>;\n}\n\n/**\n * Configure which billing modules are enabled for this project.\n * By default, all modules are enabled.\n *\n * Examples:\n * - Booking/WineTracking: { plans: true, subscriptions: true, products: false, features: false }\n * - SweatMate: { plans: true, subscriptions: true, products: true, features: true }\n * - ShopBrain: all enabled (default)\n */\nexport interface BillingModulesConfig {\n plans?: boolean;\n subscriptions?: boolean;\n products?: boolean;\n payments?: boolean;\n invoices?: boolean;\n features?: boolean;\n}\n\nconst DEFAULT_MODULES: Required<BillingModulesConfig> = {\n plans: true,\n subscriptions: true,\n products: true,\n payments: true,\n invoices: true,\n features: true,\n};\n\nexport interface BillingAdminConfig {\n /** Base path for billing admin API (e.g., '/api/v1/billing-admin') */\n basePath: string;\n /** HTTP fetcher function from the host application (handles auth) */\n fetcher: Fetcher;\n /** Locale for number/date formatting (default: 'it-IT') */\n locale?: string;\n /** Default currency (default: 'EUR') */\n currency?: string;\n /**\n * Enable/disable billing modules per project.\n * All modules are enabled by default.\n */\n modules?: BillingModulesConfig;\n /** Plan-specific configurations */\n plans?: {\n /** Configurable limit fields for plan forms */\n limitFields?: LimitFieldConfig[];\n /** Feature selection in plan forms */\n features?: FeaturesConfig;\n /** Public plans toggle (ShopBrain-specific) */\n publicPlans?: PublicPlansConfig;\n };\n /** Product-specific configurations */\n products?: {\n /** Feature linking in product forms */\n features?: FeaturesConfig;\n };\n}\n\nconst BillingAdminConfigContext = React.createContext<BillingAdminConfig | null>(null);\n\nexport function useBillingAdminConfig(): BillingAdminConfig {\n const config = React.useContext(BillingAdminConfigContext);\n if (!config) {\n throw new Error(\n 'useBillingAdminConfig must be used within a BillingAdminProvider.'\n );\n }\n return config;\n}\n\n/** Returns the resolved modules config (with defaults applied) */\nexport function useEnabledModules(): Required<BillingModulesConfig> {\n const config = useBillingAdminConfig();\n return { ...DEFAULT_MODULES, ...config.modules };\n}\n\nexport interface BillingAdminProviderProps {\n config: BillingAdminConfig;\n children: React.ReactNode;\n}\n\nexport function BillingAdminProvider({ config, children }: BillingAdminProviderProps) {\n const client = useMemo(\n () => createBillingAdminClient({\n basePath: config.basePath,\n fetcher: config.fetcher,\n }),\n [config.basePath, config.fetcher]\n );\n\n return (\n <BillingAdminConfigContext.Provider value={config}>\n <BillingAdminClientContext.Provider value={client}>\n {children}\n </BillingAdminClientContext.Provider>\n </BillingAdminConfigContext.Provider>\n );\n}\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { Plus, RefreshCw, LayoutGrid } from 'lucide-react';\nimport {\n useAdminPlans,\n useCreatePlan,\n useUpdatePlan,\n useDeletePlan,\n useSyncPlanToStripe,\n validateSlug,\n validateRequired,\n} from '@growflowstudio/billing-admin-core';\nimport type { AdminPlan, AdminPlanCreate, AdminPlanUpdate } from '@growflowstudio/billing-admin-core';\nimport { useBillingAdminConfig } from '../provider';\nimport { PlansTable } from '../components/plans/PlansTable';\nimport { PlanFormDialog, createDefaultPlanFormData, type PlanFormData } from '../components/plans/PlanFormDialog';\nimport { DeleteConfirmDialog } from '../components/shared/DeleteConfirmDialog';\n\nexport interface PlansPageProps {\n /** Optional wrapper component for the page content */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n /** Optional header component */\n header?: React.ReactNode;\n}\n\nexport function PlansPage({ wrapper: Wrapper, header }: PlansPageProps) {\n const config = useBillingAdminConfig();\n const limitFields = config.plans?.limitFields || [];\n const publicPlansConfig = config.plans?.publicPlans;\n\n const [showForm, setShowForm] = useState(false);\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [selectedPlan, setSelectedPlan] = useState<AdminPlan | null>(null);\n const [formData, setFormData] = useState<PlanFormData>(createDefaultPlanFormData(limitFields));\n const [formErrors, setFormErrors] = useState<Record<string, string>>({});\n\n const { data, isLoading, refetch } = useAdminPlans();\n const createMutation = useCreatePlan();\n const updateMutation = useUpdatePlan();\n const deleteMutation = useDeletePlan();\n const syncMutation = useSyncPlanToStripe();\n\n // Public plans (optional, ShopBrain-specific)\n const [publicPlanSlugs, setPublicPlanSlugs] = useState<string[]>([]);\n useState(() => {\n if (publicPlansConfig?.enabled && publicPlansConfig.fetchFn) {\n publicPlansConfig.fetchFn().then(r => setPublicPlanSlugs(r.public_plan_slugs));\n }\n });\n\n const plans = data?.items || [];\n\n const resetForm = () => {\n setFormData(createDefaultPlanFormData(limitFields));\n setSelectedPlan(null);\n setFormErrors({});\n };\n\n const openCreateForm = () => {\n resetForm();\n setShowForm(true);\n };\n\n const openEditForm = (plan: AdminPlan) => {\n setSelectedPlan(plan);\n const planLimits = plan.limits || {};\n const limits: Record<string, number> = {};\n const limitsUnlimited: Record<string, boolean> = {};\n for (const field of limitFields) {\n const val = planLimits[field.key];\n limits[field.key] = val === -1 ? (field.defaultValue ?? 1) : (val || field.defaultValue || 1);\n limitsUnlimited[field.key] = val === -1;\n }\n setFormData({\n slug: plan.slug,\n name: plan.name,\n description: plan.description || '',\n pricing_model: plan.pricing_model,\n price_monthly: plan.price_monthly ? plan.price_monthly.toString() : '',\n price_yearly: plan.price_yearly ? plan.price_yearly.toString() : '',\n currency: plan.currency,\n trial_days: plan.trial_days,\n is_active: plan.is_active,\n contact_sales: plan.contact_sales,\n is_public: publicPlanSlugs.includes(plan.slug),\n color: plan.color || 'gray',\n limits,\n limits_unlimited: limitsUnlimited,\n features: plan.features?.join('\\n') || '',\n sort_order: plan.sort_order,\n });\n setShowForm(true);\n };\n\n const handleValidate = (): boolean => {\n const errors: Record<string, string> = {};\n const slugErr = validateSlug(formData.slug);\n if (slugErr) errors.slug = slugErr;\n const nameErr = validateRequired(formData.name, 'Il nome');\n if (nameErr) errors.name = nameErr;\n setFormErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async () => {\n if (!handleValidate()) return;\n\n const limits: Record<string, number> = {};\n for (const field of limitFields) {\n limits[field.key] = formData.limits_unlimited[field.key] ? -1 : (formData.limits[field.key] ?? 1);\n }\n\n const planData: AdminPlanCreate | AdminPlanUpdate = {\n slug: formData.slug,\n name: formData.name,\n description: formData.description || undefined,\n pricing_model: formData.pricing_model,\n price_monthly: formData.price_monthly ? parseFloat(formData.price_monthly) : undefined,\n price_yearly: formData.price_yearly ? parseFloat(formData.price_yearly) : undefined,\n currency: formData.currency,\n trial_days: formData.trial_days,\n is_active: formData.is_active,\n contact_sales: formData.contact_sales,\n color: formData.color,\n limits: Object.keys(limits).length > 0 ? limits : undefined,\n features: formData.features.split('\\n').filter((f) => f.trim()),\n sort_order: formData.sort_order,\n };\n\n // Update public plans if configured\n if (publicPlansConfig?.enabled && publicPlansConfig.updateFn) {\n const isCurrentlyPublic = publicPlanSlugs.includes(formData.slug);\n if (formData.is_public !== isCurrentlyPublic) {\n try {\n const newSlugs = formData.is_public\n ? [...publicPlanSlugs, formData.slug]\n : publicPlanSlugs.filter((s) => s !== formData.slug);\n await publicPlansConfig.updateFn(newSlugs);\n setPublicPlanSlugs(newSlugs);\n } catch {\n toast.error(\"Errore nell'aggiornamento della visibilità pubblica\");\n }\n }\n }\n\n if (selectedPlan) {\n updateMutation.mutate({ id: selectedPlan.id, data: planData }, {\n onSuccess: () => { toast.success('Piano aggiornato con successo'); setShowForm(false); resetForm(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n } else {\n createMutation.mutate(planData as AdminPlanCreate, {\n onSuccess: () => { toast.success('Piano creato con successo'); setShowForm(false); resetForm(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const handleDelete = () => {\n if (selectedPlan) {\n deleteMutation.mutate(selectedPlan.id, {\n onSuccess: () => { toast.success('Piano eliminato con successo'); setShowDeleteDialog(false); setSelectedPlan(null); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const content = (\n <>\n {header}\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <LayoutGrid className=\"w-4 h-4\" />\n <span>{plans.length} piani configurati</span>\n </div>\n <div className=\"flex gap-2\">\n <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()}>\n <RefreshCw className=\"w-4 h-4 mr-2\" />Aggiorna\n </button>\n <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}>\n <Plus className=\"w-4 h-4 mr-2\" />Nuovo Piano\n </button>\n </div>\n </div>\n\n <div className=\"rounded-lg border bg-card text-card-foreground shadow-sm\">\n <div className=\"p-0\">\n <PlansTable\n plans={plans}\n isLoading={isLoading}\n onEdit={openEditForm}\n onDelete={(plan) => { setSelectedPlan(plan); setShowDeleteDialog(true); }}\n onSync={(id) => syncMutation.mutate(id, {\n onSuccess: () => toast.success('Piano sincronizzato con Stripe'),\n onError: (err) => toast.error(`Errore sync: ${err.message}`),\n })}\n isSyncing={syncMutation.isPending}\n />\n </div>\n </div>\n </div>\n\n <PlanFormDialog\n open={showForm}\n onOpenChange={setShowForm}\n formData={formData}\n onFormDataChange={(data) => setFormData((prev) => ({ ...prev, ...data }))}\n formErrors={formErrors}\n selectedPlan={selectedPlan}\n onSubmit={handleSubmit}\n isPending={createMutation.isPending || updateMutation.isPending}\n />\n\n <DeleteConfirmDialog\n isOpen={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n title=\"Eliminare Piano?\"\n description={<>Stai per eliminare il piano <strong>{selectedPlan?.name}</strong> (<code>{selectedPlan?.slug}</code>). Questa azione non può essere annullata.</>}\n onConfirm={handleDelete}\n isDeleting={deleteMutation.isPending}\n confirmLabel=\"Elimina Piano\"\n />\n </>\n );\n\n return Wrapper ? <Wrapper>{content}</Wrapper> : content;\n}\n","import { Pencil, Trash2, Upload, Check, X } from 'lucide-react';\nimport type { AdminPlan, AdminPlanPricingModel } from '@growflowstudio/billing-admin-core';\nimport { formatCurrency } from '@growflowstudio/billing-admin-core';\nimport { getPlanColorClass } from './plan-colors';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { SkeletonRows } from '../shared/SkeletonRows';\n\nconst pricingModelLabels: Record<AdminPlanPricingModel, string> = {\n flat: 'Fisso',\n tiered: 'A Scaglioni',\n per_unit: 'Per Unità',\n usage_based: 'A Consumo',\n};\n\ninterface PlansTableProps {\n plans: AdminPlan[];\n isLoading: boolean;\n onEdit: (plan: AdminPlan) => void;\n onDelete: (plan: AdminPlan) => void;\n onSync: (planId: string) => void;\n isSyncing: boolean;\n}\n\nexport function PlansTable({\n plans,\n isLoading,\n onEdit,\n onDelete,\n onSync,\n isSyncing,\n}: PlansTableProps) {\n return (\n <div className=\"relative w-full overflow-auto\">\n <table className=\"w-full caption-bottom text-sm\">\n <thead className=\"[&_tr]:border-b\">\n <tr className=\"border-b transition-colors hover:bg-muted/50\">\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Slug</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Nome</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Colore</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Modello</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Prezzo Mensile</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Prezzo Annuale</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Trial</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Attivo</th>\n <th className=\"h-12 px-4 text-left align-middle font-medium text-muted-foreground\">Stripe</th>\n <th className=\"h-12 px-4 text-right align-middle font-medium text-muted-foreground\">Azioni</th>\n </tr>\n </thead>\n <tbody className=\"[&_tr:last-child]:border-0\">\n {isLoading ? (\n <SkeletonRows rows={3} columns={10} />\n ) : plans.length === 0 ? (\n <tr>\n <td colSpan={10} className=\"p-4 text-center py-8 text-muted-foreground\">\n Nessun piano configurato\n </td>\n </tr>\n ) : (\n plans.map((plan) => (\n <tr key={plan.id} className=\"border-b transition-colors hover:bg-muted/50\">\n <td className=\"p-4 align-middle\">\n <code className=\"text-sm bg-muted px-2 py-0.5 rounded\">{plan.slug}</code>\n </td>\n <td className=\"p-4 align-middle font-medium\">{plan.name}</td>\n <td className=\"p-4 align-middle\">\n <StatusBadge label={plan.color} colorClass={getPlanColorClass(plan.color)} />\n </td>\n <td className=\"p-4 align-middle\">\n <StatusBadge label={pricingModelLabels[plan.pricing_model]} colorClass=\"border\" />\n </td>\n <td className=\"p-4 align-middle\">\n {plan.contact_sales ? (\n <span className=\"text-muted-foreground\">Contattaci</span>\n ) : (\n formatCurrency(plan.price_monthly ?? 0, plan.currency)\n )}\n </td>\n <td className=\"p-4 align-middle\">\n {plan.contact_sales ? (\n <span className=\"text-muted-foreground\">Contattaci</span>\n ) : (\n formatCurrency(plan.price_yearly ?? 0, plan.currency)\n )}\n </td>\n <td className=\"p-4 align-middle\">{plan.trial_days} giorni</td>\n <td className=\"p-4 align-middle\">\n {plan.is_active ? (\n <Check className=\"w-4 h-4 text-green-600\" />\n ) : (\n <X className=\"w-4 h-4 text-muted-foreground\" />\n )}\n </td>\n <td className=\"p-4 align-middle\">\n {plan.stripe_price_id_monthly ? (\n <StatusBadge label=\"Synced\" colorClass=\"bg-green-50 text-green-700 border-green-200\" />\n ) : (\n <button\n className=\"inline-flex items-center justify-center rounded-md text-sm font-medium h-9 w-9 hover:bg-accent hover:text-accent-foreground\"\n onClick={() => onSync(plan.id)}\n disabled={isSyncing}\n >\n <Upload className=\"w-4 h-4\" />\n </button>\n )}\n </td>\n <td className=\"p-4 align-middle text-right\">\n <div className=\"flex justify-end gap-1\">\n <button\n className=\"inline-flex items-center justify-center rounded-md text-sm font-medium h-9 w-9 hover:bg-accent hover:text-accent-foreground\"\n onClick={() => onEdit(plan)}\n >\n <Pencil className=\"w-4 h-4\" />\n </button>\n <button\n 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\"\n onClick={() => onDelete(plan)}\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n","export const PLAN_COLORS = [\n { value: 'gray', label: 'Grigio', className: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400' },\n { value: 'green', label: 'Verde', className: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400' },\n { value: 'blue', label: 'Blu', className: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400' },\n { value: 'purple', label: 'Viola', className: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400' },\n { value: 'amber', label: 'Ambra', className: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400' },\n { value: 'red', label: 'Rosso', className: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400' },\n { value: 'pink', label: 'Rosa', className: 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-400' },\n { value: 'indigo', label: 'Indaco', className: 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400' },\n] as const;\n\nexport type PlanColorValue = typeof PLAN_COLORS[number]['value'];\n\nexport function getPlanColorClass(color: string | undefined): string {\n const found = PLAN_COLORS.find(c => c.value === color);\n return found?.className || PLAN_COLORS[0].className;\n}\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cn } from '../../primitives/utils';\n\ninterface StatusBadgeProps {\n label: string;\n colorClass: string;\n className?: string;\n}\n\nexport function StatusBadge({ label, colorClass, className }: StatusBadgeProps) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors',\n colorClass,\n className,\n )}\n >\n {label}\n </span>\n );\n}\n","interface SkeletonRowsProps {\n rows?: number;\n columns?: number;\n}\n\nexport function SkeletonRows({ rows = 5, columns = 1 }: SkeletonRowsProps) {\n return (\n <>\n {Array.from({ length: rows }).map((_, i) => (\n <tr key={i}>\n <td colSpan={columns} className=\"p-4\">\n <div className=\"h-10 w-full animate-pulse rounded-md bg-muted\" />\n </td>\n </tr>\n ))}\n </>\n );\n}\n","import { useState, useEffect } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Loader2, X as XIcon } from 'lucide-react';\nimport type { AdminPlan, AdminPlanPricingModel } from '@growflowstudio/billing-admin-core';\nimport { useBillingAdminConfig, type LimitFieldConfig } from '../../provider';\nimport { PLAN_COLORS, getPlanColorClass } from './plan-colors';\nimport { LimitInput } from './LimitInput';\n\nexport interface PlanFormData {\n slug: string;\n name: string;\n description: string;\n pricing_model: AdminPlanPricingModel;\n price_monthly: string;\n price_yearly: string;\n currency: string;\n trial_days: number;\n is_active: boolean;\n contact_sales: boolean;\n is_public: boolean;\n color: string;\n limits: Record<string, number>;\n limits_unlimited: Record<string, boolean>;\n features: string;\n sort_order: number;\n}\n\nexport function createDefaultPlanFormData(limitFields: LimitFieldConfig[] = []): PlanFormData {\n const limits: Record<string, number> = {};\n const limitsUnlimited: Record<string, boolean> = {};\n for (const field of limitFields) {\n limits[field.key] = field.defaultValue ?? 1;\n limitsUnlimited[field.key] = false;\n }\n return {\n slug: '',\n name: '',\n description: '',\n pricing_model: 'flat',\n price_monthly: '',\n price_yearly: '',\n currency: 'eur',\n trial_days: 14,\n is_active: true,\n contact_sales: false,\n is_public: true,\n color: 'gray',\n limits,\n limits_unlimited: limitsUnlimited,\n features: '',\n sort_order: 0,\n };\n}\n\ninterface PlanFormDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n formData: PlanFormData;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n formErrors: Record<string, string>;\n selectedPlan: AdminPlan | null;\n onSubmit: () => void;\n isPending: boolean;\n}\n\nexport function PlanFormDialog({\n open,\n onOpenChange,\n formData,\n onFormDataChange,\n formErrors,\n selectedPlan,\n onSubmit,\n isPending,\n}: PlanFormDialogProps) {\n const config = useBillingAdminConfig();\n const limitFields = config.plans?.limitFields || [];\n const featuresConfig = config.plans?.features;\n\n const { data: featuresData } = useQuery({\n queryKey: ['billing-admin-available-features'],\n queryFn: () => featuresConfig?.fetchFn?.() ?? Promise.resolve({ features: [] }),\n enabled: !!featuresConfig?.enabled && !!featuresConfig?.fetchFn,\n });\n\n const availableFeatures = featuresData?.features || [];\n const [selectedFeatureSlugs, setSelectedFeatureSlugs] = useState<string[]>([]);\n\n useEffect(() => {\n if (formData.features) {\n const slugs = formData.features.split('\\n').map(line => line.trim()).filter(Boolean);\n setSelectedFeatureSlugs(slugs);\n }\n }, [formData.features]);\n\n const handleFeatureToggle = (slug: string, checked: boolean) => {\n const updated = checked\n ? [...selectedFeatureSlugs, slug]\n : selectedFeatureSlugs.filter(s => s !== slug);\n setSelectedFeatureSlugs(updated);\n onFormDataChange({ features: updated.join('\\n') });\n };\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => onOpenChange(false)} />\n <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\">\n <div className=\"flex flex-col space-y-1.5 pb-4\">\n <h2 className=\"text-lg font-semibold leading-none tracking-tight\">\n {selectedPlan ? 'Modifica Piano' : 'Nuovo Piano'}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {selectedPlan ? 'Modifica le impostazioni del piano selezionato' : 'Crea un nuovo piano di abbonamento'}\n </p>\n </div>\n\n <div className=\"grid gap-4 py-4\">\n {/* Slug + Name */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"slug\">Slug *</label>\n <input\n id=\"slug\"\n 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\"\n value={formData.slug}\n onChange={(e) => onFormDataChange({ slug: e.target.value })}\n placeholder=\"es. pro, enterprise\"\n disabled={!!selectedPlan}\n />\n {formErrors.slug && <p className=\"text-xs text-destructive\">{formErrors.slug}</p>}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"name\">Nome *</label>\n <input\n id=\"name\"\n 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\"\n value={formData.name}\n onChange={(e) => onFormDataChange({ name: e.target.value })}\n placeholder=\"es. Piano Pro\"\n />\n {formErrors.name && <p className=\"text-xs text-destructive\">{formErrors.name}</p>}\n </div>\n </div>\n\n {/* Description */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"description\">Descrizione</label>\n <textarea\n id=\"description\"\n 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\"\n value={formData.description}\n onChange={(e) => onFormDataChange({ description: e.target.value })}\n placeholder=\"Descrizione del piano...\"\n rows={2}\n />\n </div>\n\n {/* Pricing */}\n <div className=\"grid grid-cols-3 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Modello Pricing</label>\n <select\n 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\"\n value={formData.pricing_model}\n onChange={(e) => onFormDataChange({ pricing_model: e.target.value as AdminPlanPricingModel })}\n >\n <option value=\"flat\">Fisso</option>\n <option value=\"tiered\">A Scaglioni</option>\n <option value=\"per_unit\">Per Unità</option>\n <option value=\"usage_based\">A Consumo</option>\n </select>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"price_monthly\">Prezzo Mensile</label>\n <input\n id=\"price_monthly\"\n type=\"number\"\n step=\"0.01\"\n 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\"\n value={formData.price_monthly}\n onChange={(e) => onFormDataChange({ price_monthly: e.target.value })}\n placeholder=\"0.00\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"price_yearly\">Prezzo Annuale</label>\n <input\n id=\"price_yearly\"\n type=\"number\"\n step=\"0.01\"\n 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\"\n value={formData.price_yearly}\n onChange={(e) => onFormDataChange({ price_yearly: e.target.value })}\n placeholder=\"0.00\"\n />\n </div>\n </div>\n\n {/* Currency, Trial, Sort */}\n <div className=\"grid grid-cols-3 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Valuta</label>\n <select\n 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\"\n value={formData.currency}\n onChange={(e) => onFormDataChange({ currency: e.target.value })}\n >\n <option value=\"eur\">EUR</option>\n <option value=\"usd\">USD</option>\n <option value=\"gbp\">GBP</option>\n </select>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"trial_days\">Giorni Trial</label>\n <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 })} />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"sort_order\">Ordine</label>\n <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 })} />\n </div>\n </div>\n\n {/* Color + Switches */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Colore Badge</label>\n <select\n 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\"\n value={formData.color}\n onChange={(e) => onFormDataChange({ color: e.target.value })}\n >\n {PLAN_COLORS.map((color) => (\n <option key={color.value} value={color.value}>{color.label}</option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground\">\n Anteprima: <span className={`inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${getPlanColorClass(formData.color)}`}>{formData.name || 'Piano'}</span>\n </p>\n </div>\n <div className=\"space-y-4 pt-6\">\n <ToggleSwitch label=\"Piano Attivo\" checked={formData.is_active} onChange={(v) => onFormDataChange({ is_active: v })} />\n <ToggleSwitch label=\"Contattaci per Prezzi\" checked={formData.contact_sales} onChange={(v) => onFormDataChange({ contact_sales: v })} />\n <ToggleSwitch label=\"Visibile in Homepage\" checked={formData.is_public} onChange={(v) => onFormDataChange({ is_public: v })} />\n </div>\n </div>\n\n {/* Limits (configurable per project) */}\n {limitFields.length > 0 && (\n <div className=\"space-y-3\">\n <label className=\"text-sm font-medium leading-none\">Limiti Piano</label>\n <div className=\"grid grid-cols-2 gap-3\">\n {limitFields.map((field) => (\n <LimitInput\n key={field.key}\n id={`limit_${field.key}`}\n label={field.label}\n value={formData.limits[field.key] ?? field.defaultValue ?? 1}\n isUnlimited={formData.limits_unlimited[field.key] ?? false}\n onValueChange={(v) => onFormDataChange({ limits: { ...formData.limits, [field.key]: v } })}\n onUnlimitedChange={(v) => onFormDataChange({ limits_unlimited: { ...formData.limits_unlimited, [field.key]: v } })}\n />\n ))}\n </div>\n </div>\n )}\n\n {/* Features (optional, configured per project) */}\n {featuresConfig?.enabled && availableFeatures.length > 0 && (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Features Incluse nel Piano</label>\n <div className=\"border rounded-lg p-3 space-y-2 max-h-64 overflow-y-auto\">\n {availableFeatures.map((feature) => (\n <div key={feature.slug} className=\"flex items-center gap-3 p-2 hover:bg-muted/50 rounded\">\n <input\n type=\"checkbox\"\n id={`feature-${feature.slug}`}\n checked={selectedFeatureSlugs.includes(feature.slug)}\n onChange={(e) => handleFeatureToggle(feature.slug, e.target.checked)}\n className=\"h-4 w-4 rounded border-input\"\n />\n <div className=\"flex-1\">\n <label htmlFor={`feature-${feature.slug}`} className=\"text-sm font-medium cursor-pointer\">\n {feature.name}\n </label>\n {feature.description && <p className=\"text-xs text-muted-foreground\">{feature.description}</p>}\n </div>\n <code className=\"text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded\">{feature.slug}</code>\n </div>\n ))}\n </div>\n {selectedFeatureSlugs.length > 0 && (\n <div className=\"flex flex-wrap gap-2 pt-2\">\n {selectedFeatureSlugs.map((slug) => {\n const feature = availableFeatures.find(f => f.slug === slug);\n return (\n <span key={slug} 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\">\n {feature?.name || slug}\n <button type=\"button\" onClick={() => handleFeatureToggle(slug, false)} className=\"ml-1 hover:bg-destructive/20 rounded-full\">\n <XIcon className=\"h-3 w-3\" />\n </button>\n </span>\n );\n })}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4\">\n <button\n 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\"\n onClick={() => onOpenChange(false)}\n >\n Annulla\n </button>\n <button\n 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\"\n onClick={onSubmit}\n disabled={isPending}\n >\n {isPending && <Loader2 className=\"w-4 h-4 animate-spin mr-2\" />}\n {selectedPlan ? 'Salva Modifiche' : 'Crea Piano'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction ToggleSwitch({ label, checked, onChange }: { label: string; checked: boolean; onChange: (v: boolean) => void }) {\n return (\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n onClick={() => onChange(!checked)}\n className={`peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${\n checked ? 'bg-primary' : 'bg-input'\n }`}\n >\n <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'}`} />\n </button>\n <span className=\"text-sm font-medium leading-none\">{label}</span>\n </div>\n );\n}\n","interface LimitInputProps {\n id: string;\n label: string;\n value: number;\n isUnlimited: boolean;\n onValueChange: (value: number) => void;\n onUnlimitedChange: (unlimited: boolean) => void;\n min?: number;\n}\n\nexport function LimitInput({\n id,\n label,\n value,\n isUnlimited,\n onValueChange,\n onUnlimitedChange,\n min = 1,\n}: LimitInputProps) {\n return (\n <div className=\"space-y-2 p-3 border rounded-lg\">\n <div className=\"flex items-center justify-between\">\n <label htmlFor={id} className=\"text-sm font-medium leading-none\">\n {label}\n </label>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isUnlimited}\n onClick={() => onUnlimitedChange(!isUnlimited)}\n className={`peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors ${\n isUnlimited ? 'bg-primary' : 'bg-input'\n }`}\n >\n <span\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n isUnlimited ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n <span className=\"text-xs text-muted-foreground\">Illimitati</span>\n </div>\n </div>\n <input\n id={id}\n type=\"number\"\n min={min}\n value={value}\n onChange={(e) => onValueChange(parseInt(e.target.value) || min)}\n disabled={isUnlimited}\n 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 disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n","import React from 'react';\nimport { Loader2 } from 'lucide-react';\n\ninterface DeleteConfirmDialogProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n title?: string;\n description: React.ReactNode;\n onConfirm: () => void;\n isDeleting: boolean;\n confirmLabel?: string;\n cancelLabel?: string;\n}\n\n/**\n * Reusable confirmation dialog for destructive actions.\n * Uses native HTML dialog to avoid requiring shadcn AlertDialog as peer dependency.\n * Consumer projects can override this component via the provider if needed.\n */\nexport function DeleteConfirmDialog({\n isOpen,\n onOpenChange,\n title = 'Sei sicuro?',\n description,\n onConfirm,\n isDeleting,\n confirmLabel = 'Elimina',\n cancelLabel = 'Annulla',\n}: DeleteConfirmDialogProps) {\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div\n className=\"fixed inset-0 bg-black/80\"\n onClick={() => onOpenChange(false)}\n />\n <div className=\"relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg\">\n <div className=\"flex flex-col space-y-2 text-center sm:text-left\">\n <h2 className=\"text-lg font-semibold\">{title}</h2>\n <div className=\"text-sm text-muted-foreground\">{description}</div>\n </div>\n <div className=\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 mt-4\">\n <button\n 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\"\n onClick={() => onOpenChange(false)}\n >\n {cancelLabel}\n </button>\n <button\n 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\"\n onClick={onConfirm}\n disabled={isDeleting}\n >\n {isDeleting && <Loader2 className=\"w-4 h-4 animate-spin mr-2\" />}\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { toast } from 'sonner';\nimport { Plus, RefreshCw, Pencil, Trash2, Upload, Package, Check, X, Link as LinkIcon } from 'lucide-react';\nimport { useQuery } from '@tanstack/react-query';\nimport {\n useAdminProducts,\n useCreateProduct,\n useUpdateProduct,\n useDeleteProduct,\n useSyncProductToStripe,\n useDialogState,\n formatCurrencyFromCents,\n} from '@growflowstudio/billing-admin-core';\nimport type { AdminProduct, AdminProductCreate, AdminProductUpdate } from '@growflowstudio/billing-admin-core';\nimport { useBillingAdminConfig } from '../provider';\nimport { ProductFormDialog, type ProductFormData } from '../components/products/ProductFormDialog';\nimport { DeleteConfirmDialog } from '../components/shared/DeleteConfirmDialog';\nimport { StatusBadge } from '../components/shared/StatusBadge';\nimport { SkeletonRows } from '../components/shared/SkeletonRows';\n\nexport interface ProductsPageProps {\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n header?: React.ReactNode;\n}\n\nexport function ProductsPage({ wrapper: Wrapper, header }: ProductsPageProps) {\n const config = useBillingAdminConfig();\n const featuresConfig = config.products?.features;\n\n const createDialog = useDialogState();\n const editDialog = useDialogState<AdminProduct>();\n const deleteDialog = useDialogState<AdminProduct>();\n\n const { data, isLoading, refetch } = useAdminProducts({ is_active: true });\n const createMutation = useCreateProduct();\n const updateMutation = useUpdateProduct();\n const deleteMutation = useDeleteProduct();\n const syncMutation = useSyncProductToStripe();\n\n const { data: featuresData } = useQuery({\n queryKey: ['billing-admin-product-features'],\n queryFn: () => featuresConfig?.fetchFn?.() ?? Promise.resolve({ features: [] }),\n enabled: !!featuresConfig?.enabled && !!featuresConfig?.fetchFn,\n });\n\n const products = data?.items || [];\n const features = featuresData?.features || [];\n\n const handleCreateSubmit = (formData: ProductFormData) => {\n const priceCents = Math.round(parseFloat(formData.price_cents) * 100);\n const createData: AdminProductCreate = {\n name: formData.name,\n description: formData.description || undefined,\n price_cents: priceCents,\n currency: formData.currency,\n recurring_interval: formData.recurring_interval || undefined,\n category: formData.category || undefined,\n is_active: formData.is_active,\n sync_stripe: formData.sync_stripe,\n extra_data: JSON.parse(formData.extra_data),\n };\n createMutation.mutate(createData, {\n onSuccess: () => { toast.success('Prodotto creato'); createDialog.close(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n };\n\n const handleEditSubmit = (formData: ProductFormData) => {\n if (!editDialog.data) return;\n const priceCents = Math.round(parseFloat(formData.price_cents) * 100);\n const updateData: AdminProductUpdate = {\n name: formData.name,\n description: formData.description || undefined,\n price_cents: priceCents,\n currency: formData.currency,\n recurring_interval: formData.recurring_interval || undefined,\n category: formData.category || undefined,\n is_active: formData.is_active,\n extra_data: JSON.parse(formData.extra_data),\n };\n updateMutation.mutate({ id: editDialog.data.id, data: updateData }, {\n onSuccess: () => { toast.success('Prodotto aggiornato'); editDialog.close(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n };\n\n const handleDeleteConfirm = () => {\n if (deleteDialog.data) {\n deleteMutation.mutate(deleteDialog.data.id, {\n onSuccess: () => { toast.success('Prodotto disattivato'); deleteDialog.close(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const content = (\n <>\n {header}\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Package className=\"w-4 h-4\" /><span>{products.length} prodotti configurati</span>\n </div>\n <div className=\"flex gap-2\">\n <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()}>\n <RefreshCw className=\"w-4 h-4 mr-2\" />Aggiorna\n </button>\n <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()}>\n <Plus className=\"w-4 h-4 mr-2\" />Nuovo Prodotto\n </button>\n </div>\n </div>\n\n <div className=\"rounded-lg border bg-card shadow-sm\">\n <div className=\"relative w-full overflow-auto\">\n <table className=\"w-full caption-bottom text-sm\">\n <thead className=\"[&_tr]:border-b\">\n <tr className=\"border-b hover:bg-muted/50\">\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Nome</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Categoria</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Prezzo</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Ricorrenza</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Attivo</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Stripe</th>\n <th className=\"h-12 px-4 text-right font-medium text-muted-foreground\">Azioni</th>\n </tr>\n </thead>\n <tbody>\n {isLoading ? (\n <SkeletonRows rows={3} columns={7} />\n ) : products.length === 0 ? (\n <tr><td colSpan={7} className=\"p-4 text-center py-8 text-muted-foreground\">Nessun prodotto configurato</td></tr>\n ) : (\n products.map((product) => {\n const hasFeature = !!product.extra_data?.feature_slug;\n return (\n <tr key={product.id} className=\"border-b hover:bg-muted/50\">\n <td className=\"p-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{product.name}</span>\n {hasFeature && <StatusBadge label=\"Feature\" colorClass=\"bg-blue-50 text-blue-700 border-blue-200\" />}\n </div>\n {product.description && <div className=\"text-sm text-muted-foreground truncate max-w-xs\">{product.description}</div>}\n </div>\n </td>\n <td className=\"p-4\"><StatusBadge label={product.category || 'feature'} colorClass=\"border\" /></td>\n <td className=\"p-4\">{formatCurrencyFromCents(product.price_cents, product.currency)}</td>\n <td className=\"p-4\">\n {product.recurring_interval ? (\n <StatusBadge label={product.recurring_interval === 'month' ? 'Mensile' : product.recurring_interval === 'year' ? 'Annuale' : product.recurring_interval} colorClass=\"bg-secondary text-secondary-foreground border-transparent\" />\n ) : (\n <span className=\"text-muted-foreground\">Una tantum</span>\n )}\n </td>\n <td className=\"p-4\">\n {product.is_active ? <Check className=\"w-4 h-4 text-green-600\" /> : <X className=\"w-4 h-4 text-muted-foreground\" />}\n </td>\n <td className=\"p-4\">\n {product.stripe_product_id ? (\n <StatusBadge label=\"Synced\" colorClass=\"bg-green-50 text-green-700 border-green-200\" />\n ) : (\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\" onClick={() => syncMutation.mutate(product.id, { onSuccess: () => toast.success('Sincronizzato'), onError: (err) => toast.error(`Errore: ${err.message}`) })} disabled={syncMutation.isPending}>\n <Upload className=\"w-4 h-4\" />\n </button>\n )}\n </td>\n <td className=\"p-4 text-right\">\n <div className=\"flex justify-end gap-1\">\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\" onClick={() => editDialog.open(product)}><Pencil className=\"w-4 h-4\" /></button>\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent\" onClick={() => deleteDialog.open(product)}><Trash2 className=\"w-4 h-4\" /></button>\n </div>\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <ProductFormDialog isOpen={createDialog.isOpen} onOpenChange={(open) => open ? createDialog.open() : createDialog.close()} mode=\"create\" features={features} onSubmit={handleCreateSubmit} isSubmitting={createMutation.isPending} />\n <ProductFormDialog isOpen={editDialog.isOpen} onOpenChange={(open) => open ? editDialog.open(editDialog.data) : editDialog.close()} mode=\"edit\" product={editDialog.data} features={features} onSubmit={handleEditSubmit} isSubmitting={updateMutation.isPending} />\n <DeleteConfirmDialog isOpen={deleteDialog.isOpen} onOpenChange={(open) => !open && deleteDialog.close()} title=\"Disattivare Prodotto?\" description={<>Stai per disattivare il prodotto <strong>{deleteDialog.data?.name}</strong>. Il prodotto non sarà più acquistabile.</>} onConfirm={handleDeleteConfirm} isDeleting={deleteMutation.isPending} confirmLabel=\"Disattiva Prodotto\" />\n </>\n );\n\n return Wrapper ? <Wrapper>{content}</Wrapper> : content;\n}\n","import { useState, useEffect } from 'react';\nimport { Loader2, Link as LinkIcon } from 'lucide-react';\nimport type { AdminProduct, RecurringInterval } from '@growflowstudio/billing-admin-core';\n\nexport interface ProductFormData {\n name: string;\n description: string;\n price_cents: string;\n currency: string;\n recurring_interval: RecurringInterval | '';\n category: string;\n is_active: boolean;\n sync_stripe: boolean;\n feature_slug: string;\n extra_data: string;\n}\n\nexport const defaultProductFormData: ProductFormData = {\n name: '',\n description: '',\n price_cents: '',\n currency: 'eur',\n recurring_interval: '',\n category: 'feature',\n is_active: true,\n sync_stripe: true,\n feature_slug: '',\n extra_data: '{}',\n};\n\ninterface AvailableFeature {\n slug: string;\n name: string;\n}\n\ninterface ProductFormDialogProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n mode: 'create' | 'edit';\n product?: AdminProduct | null;\n features?: AvailableFeature[];\n onSubmit: (data: ProductFormData) => void;\n isSubmitting: boolean;\n}\n\nexport function ProductFormDialog({\n isOpen,\n onOpenChange,\n mode,\n product,\n features = [],\n onSubmit,\n isSubmitting,\n}: ProductFormDialogProps) {\n const [formData, setFormData] = useState<ProductFormData>(defaultProductFormData);\n const [formErrors, setFormErrors] = useState<Record<string, string>>({});\n\n useEffect(() => {\n if (isOpen) {\n if (mode === 'edit' && product) {\n const featureSlug = product.extra_data?.feature_slug as string || '';\n setFormData({\n name: product.name,\n description: product.description || '',\n price_cents: (product.price_cents / 100).toString(),\n currency: product.currency,\n recurring_interval: product.recurring_interval || '',\n category: product.category || 'feature',\n is_active: product.is_active,\n sync_stripe: false,\n feature_slug: featureSlug,\n extra_data: product.extra_data ? JSON.stringify(product.extra_data, null, 2) : '{}',\n });\n } else {\n setFormData(defaultProductFormData);\n }\n setFormErrors({});\n }\n }, [isOpen, mode, product]);\n\n useEffect(() => {\n if (formData.feature_slug) {\n setFormData(prev => {\n try {\n const parsedData = JSON.parse(prev.extra_data);\n const updated = { ...parsedData, feature_slug: formData.feature_slug };\n return { ...prev, extra_data: JSON.stringify(updated, null, 2) };\n } catch {\n return { ...prev, extra_data: JSON.stringify({ feature_slug: formData.feature_slug }, null, 2) };\n }\n });\n }\n }, [formData.feature_slug]);\n\n const validateForm = (): boolean => {\n const errors: Record<string, string> = {};\n if (!formData.name.trim()) errors.name = 'Il nome è obbligatorio';\n if (!formData.price_cents || parseFloat(formData.price_cents) < 0) errors.price_cents = 'Il prezzo deve essere un numero positivo';\n try { JSON.parse(formData.extra_data); } catch { errors.extra_data = 'JSON non valido per extra_data'; }\n setFormErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = () => {\n if (validateForm()) onSubmit(formData);\n };\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => onOpenChange(false)} />\n <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\">\n <div className=\"flex flex-col space-y-1.5 pb-4\">\n <h2 className=\"text-lg font-semibold\">{mode === 'create' ? 'Nuovo Prodotto' : 'Modifica Prodotto'}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {mode === 'create' ? 'Crea un nuovo prodotto / feature acquistabile' : 'Modifica le impostazioni del prodotto selezionato'}\n </p>\n </div>\n\n <div className=\"grid gap-4 py-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Nome *</label>\n <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\" />\n {formErrors.name && <p className=\"text-xs text-destructive\">{formErrors.name}</p>}\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Descrizione</label>\n <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} />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Prezzo</label>\n <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\" />\n {formErrors.price_cents && <p className=\"text-xs text-destructive\">{formErrors.price_cents}</p>}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Valuta</label>\n <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 })}>\n <option value=\"eur\">EUR</option>\n <option value=\"usd\">USD</option>\n <option value=\"gbp\">GBP</option>\n </select>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Ricorrenza</label>\n <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 as RecurringInterval) })}>\n <option value=\"one_time\">Una tantum</option>\n <option value=\"month\">Mensile</option>\n <option value=\"year\">Annuale</option>\n </select>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Categoria</label>\n <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 })}>\n <option value=\"feature\">Feature</option>\n <option value=\"addon\">Add-on</option>\n <option value=\"service\">Servizio</option>\n <option value=\"credits\">Crediti</option>\n </select>\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <ToggleRow label=\"Prodotto Attivo\" checked={formData.is_active} onChange={(v) => setFormData({ ...formData, is_active: v })} />\n {mode === 'create' && (\n <ToggleRow label=\"Sincronizza su Stripe\" checked={formData.sync_stripe} onChange={(v) => setFormData({ ...formData, sync_stripe: v })} />\n )}\n </div>\n\n {features.length > 0 && (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Collega a Feature</label>\n <select\n 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\"\n value={formData.feature_slug || 'none'}\n onChange={(e) => setFormData({ ...formData, feature_slug: e.target.value === 'none' ? '' : e.target.value })}\n >\n <option value=\"none\">Nessuna feature</option>\n {features.map((f) => (\n <option key={f.slug} value={f.slug}>{f.name} ({f.slug})</option>\n ))}\n </select>\n {formData.feature_slug && (\n <div className=\"flex items-center gap-2 p-2 bg-blue-50 border border-blue-200 rounded text-sm\">\n <LinkIcon className=\"w-4 h-4 text-blue-600\" />\n <span className=\"text-blue-900\">Collegato a: <strong>{formData.feature_slug}</strong></span>\n </div>\n )}\n </div>\n )}\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Extra Data (JSON)</label>\n <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} />\n {formErrors.extra_data && <p className=\"text-xs text-destructive\">{formErrors.extra_data}</p>}\n </div>\n </div>\n\n <div className=\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4\">\n <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)}>Annulla</button>\n <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}>\n {isSubmitting && <Loader2 className=\"w-4 h-4 animate-spin mr-2\" />}\n {mode === 'create' ? 'Crea Prodotto' : 'Salva Modifiche'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction ToggleRow({ label, checked, onChange }: { label: string; checked: boolean; onChange: (v: boolean) => void }) {\n return (\n <div className=\"flex items-center gap-2\">\n <button type=\"button\" role=\"switch\" aria-checked={checked} onClick={() => onChange(!checked)}\n 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'}`}>\n <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'}`} />\n </button>\n <span className=\"text-sm font-medium leading-none\">{label}</span>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { Search, RefreshCw, Eye, XCircle, CreditCard, Calendar, User } from 'lucide-react';\nimport {\n useAdminSubscriptions,\n useCancelSubscription,\n formatDate,\n subscriptionStatusColors,\n subscriptionStatusLabels,\n} from '@growflowstudio/billing-admin-core';\nimport type { AdminSubscription, AdminSubscriptionStatus } from '@growflowstudio/billing-admin-core';\nimport { StatusBadge } from '../components/shared/StatusBadge';\nimport { SkeletonRows } from '../components/shared/SkeletonRows';\nimport { FilterBar } from '../components/shared/FilterBar';\n\nexport interface SubscriptionsPageProps {\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n header?: React.ReactNode;\n}\n\nconst statusFilterOptions = [\n { value: 'all', label: 'Tutti gli stati' },\n { value: 'active', label: 'Attivi' },\n { value: 'trialing', label: 'In Prova' },\n { value: 'past_due', label: 'Scaduti' },\n { value: 'canceled', label: 'Cancellati' },\n { value: 'unpaid', label: 'Non Pagati' },\n];\n\nexport function SubscriptionsPage({ wrapper: Wrapper, header }: SubscriptionsPageProps) {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('all');\n const [selectedSub, setSelectedSub] = useState<AdminSubscription | null>(null);\n const [showDetails, setShowDetails] = useState(false);\n const [showCancelDialog, setShowCancelDialog] = useState(false);\n const [cancelAtPeriodEnd, setCancelAtPeriodEnd] = useState(true);\n\n const { data, isLoading, refetch } = useAdminSubscriptions({\n search: search || undefined,\n status: statusFilter !== 'all' ? (statusFilter as AdminSubscriptionStatus) : undefined,\n limit: 100,\n });\n const cancelMutation = useCancelSubscription();\n\n const subscriptions = data?.items || [];\n const total = data?.total || 0;\n\n const handleCancel = () => {\n if (selectedSub) {\n cancelMutation.mutate({ id: selectedSub.id, atPeriodEnd: cancelAtPeriodEnd }, {\n onSuccess: () => { toast.success('Abbonamento cancellato'); setShowCancelDialog(false); setSelectedSub(null); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const content = (\n <>\n {header}\n <div className=\"space-y-4\">\n <FilterBar\n searchPlaceholder=\"Cerca per email o ID esterno...\"\n searchValue={search}\n onSearchChange={setSearch}\n statusFilter={statusFilter}\n onStatusFilterChange={setStatusFilter}\n statusOptions={statusFilterOptions}\n onRefresh={refetch}\n />\n\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <CreditCard className=\"w-4 h-4\" />\n <span>{total} abbonament{total === 1 ? 'o' : 'i'} trovati</span>\n </div>\n\n <div className=\"rounded-lg border bg-card shadow-sm\">\n <div className=\"relative w-full overflow-auto\">\n <table className=\"w-full caption-bottom text-sm\">\n <thead className=\"[&_tr]:border-b\">\n <tr className=\"border-b hover:bg-muted/50\">\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Subscriber</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Piano</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Stato</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Ciclo</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Periodo</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Trial End</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Creato</th>\n <th className=\"h-12 px-4 text-right font-medium text-muted-foreground\">Azioni</th>\n </tr>\n </thead>\n <tbody>\n {isLoading ? (\n <SkeletonRows rows={5} columns={8} />\n ) : subscriptions.length === 0 ? (\n <tr><td colSpan={8} className=\"p-4 text-center py-8 text-muted-foreground\">Nessun abbonamento trovato</td></tr>\n ) : (\n subscriptions.map((sub) => (\n <tr key={sub.id} className=\"border-b hover:bg-muted/50\">\n <td className=\"p-4\">\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{sub.subscriber_email}</span>\n <span className=\"text-xs text-muted-foreground\">{sub.subscriber_external_id}</span>\n </div>\n </td>\n <td className=\"p-4\">\n <span className=\"font-medium\">{sub.plan_name}</span>\n <span className=\"text-xs text-muted-foreground ml-1\">({sub.plan_slug})</span>\n </td>\n <td className=\"p-4\"><StatusBadge label={subscriptionStatusLabels[sub.status]} colorClass={subscriptionStatusColors[sub.status]} /></td>\n <td className=\"p-4 capitalize\">{sub.billing_cycle}</td>\n <td className=\"p-4 text-sm\">{formatDate(sub.current_period_start)} - {formatDate(sub.current_period_end)}</td>\n <td className=\"p-4\">{formatDate(sub.trial_end)}</td>\n <td className=\"p-4\">{formatDate(sub.created_at)}</td>\n <td className=\"p-4 text-right\">\n <div className=\"flex justify-end gap-1\">\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\" onClick={() => { setSelectedSub(sub); setShowDetails(true); }}>\n <Eye className=\"w-4 h-4\" />\n </button>\n {sub.status !== 'canceled' && (\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent\" onClick={() => { setSelectedSub(sub); setShowCancelDialog(true); }}>\n <XCircle className=\"w-4 h-4\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n {/* Details Dialog */}\n {showDetails && selectedSub && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => setShowDetails(false)} />\n <div className=\"relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg\">\n <h2 className=\"text-lg font-semibold mb-1\">Dettagli Abbonamento</h2>\n <p className=\"text-sm text-muted-foreground mb-4\">Informazioni complete</p>\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">Subscriber</p>\n <div className=\"flex items-center gap-2 mt-1\"><User className=\"w-4 h-4 text-muted-foreground\" /><span className=\"font-medium\">{selectedSub.subscriber_email}</span></div>\n <p className=\"text-xs text-muted-foreground mt-1\">ID: {selectedSub.subscriber_external_id}</p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">Piano</p>\n <div className=\"flex items-center gap-2 mt-1\"><CreditCard className=\"w-4 h-4 text-muted-foreground\" /><span className=\"font-medium\">{selectedSub.plan_name}</span></div>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">Stato</p>\n <StatusBadge label={subscriptionStatusLabels[selectedSub.status]} colorClass={subscriptionStatusColors[selectedSub.status]} className=\"mt-1\" />\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">Ciclo</p>\n <p className=\"font-medium capitalize mt-1\">{selectedSub.billing_cycle}</p>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">Periodo</p>\n <div className=\"flex items-center gap-2 mt-1\"><Calendar className=\"w-4 h-4 text-muted-foreground\" /><span>{formatDate(selectedSub.current_period_start)} - {formatDate(selectedSub.current_period_end)}</span></div>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">Fine Trial</p>\n <p className=\"mt-1\">{formatDate(selectedSub.trial_end)}</p>\n </div>\n </div>\n {selectedSub.canceled_at && (\n <div className=\"p-3 bg-destructive/10 rounded-lg\">\n <p className=\"text-sm text-destructive font-medium\">Cancellato il {formatDate(selectedSub.canceled_at)}</p>\n {selectedSub.cancel_at && <p className=\"text-xs text-destructive/80 mt-1\">Termina il {formatDate(selectedSub.cancel_at)}</p>}\n </div>\n )}\n {selectedSub.stripe_subscription_id && (\n <div>\n <p className=\"text-sm text-muted-foreground\">Stripe ID</p>\n <code className=\"text-xs bg-muted px-2 py-1 rounded mt-1 inline-block\">{selectedSub.stripe_subscription_id}</code>\n </div>\n )}\n </div>\n <div className=\"flex justify-end pt-4\">\n <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)}>Chiudi</button>\n </div>\n </div>\n </div>\n )}\n\n {/* Cancel Dialog */}\n {showCancelDialog && selectedSub && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => setShowCancelDialog(false)} />\n <div className=\"relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg\">\n <h2 className=\"text-lg font-semibold\">Cancellare Abbonamento?</h2>\n <p className=\"text-sm text-muted-foreground mt-1\">Stai per cancellare l'abbonamento di <strong>{selectedSub.subscriber_email}</strong>.</p>\n <div className=\"py-4\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input type=\"checkbox\" checked={cancelAtPeriodEnd} onChange={(e) => setCancelAtPeriodEnd(e.target.checked)} className=\"rounded border-input\" />\n <span className=\"text-sm\">Cancella alla fine del periodo corrente (consigliato)</span>\n </label>\n <p className=\"text-xs text-muted-foreground mt-2\">\n {cancelAtPeriodEnd ? \"L'abbonamento rimarrà attivo fino alla fine del periodo.\" : \"L'abbonamento verrà cancellato immediatamente.\"}\n </p>\n </div>\n <div className=\"flex justify-end gap-2\">\n <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)}>Annulla</button>\n <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}>\n {cancelMutation.isPending ? 'Cancellazione...' : 'Conferma Cancellazione'}\n </button>\n </div>\n </div>\n </div>\n )}\n </>\n );\n\n return Wrapper ? <Wrapper>{content}</Wrapper> : content;\n}\n","import { Search, RefreshCw } from 'lucide-react';\n\ninterface FilterOption {\n value: string;\n label: string;\n}\n\ninterface FilterBarProps {\n searchPlaceholder?: string;\n searchValue: string;\n onSearchChange: (value: string) => void;\n statusFilter?: string;\n onStatusFilterChange?: (value: string) => void;\n statusOptions?: FilterOption[];\n onRefresh: () => void;\n}\n\nexport function FilterBar({\n searchPlaceholder = 'Cerca...',\n searchValue,\n onSearchChange,\n statusFilter,\n onStatusFilterChange,\n statusOptions,\n onRefresh,\n}: FilterBarProps) {\n return (\n <div className=\"rounded-lg border bg-card text-card-foreground shadow-sm\">\n <div className=\"p-6 pt-6\">\n <div className=\"flex flex-col sm:flex-row gap-4\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground\" />\n <input\n 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\"\n placeholder={searchPlaceholder}\n value={searchValue}\n onChange={(e) => onSearchChange(e.target.value)}\n />\n </div>\n {statusOptions && onStatusFilterChange && (\n <select\n 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\"\n value={statusFilter || 'all'}\n onChange={(e) => onStatusFilterChange(e.target.value)}\n >\n {statusOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )}\n <button\n 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\"\n onClick={onRefresh}\n >\n <RefreshCw className=\"w-4 h-4 mr-2\" />\n Aggiorna\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { RotateCcw, Receipt, ChevronLeft, ChevronRight } from 'lucide-react';\nimport {\n useAdminPayments,\n useRefundPayment,\n formatCurrencyFromCents,\n formatTimestamp,\n truncateId,\n paymentStatusColors,\n paymentStatusLabels,\n} from '@growflowstudio/billing-admin-core';\nimport type { AdminPayment } from '@growflowstudio/billing-admin-core';\nimport { StatusBadge } from '../components/shared/StatusBadge';\nimport { SkeletonRows } from '../components/shared/SkeletonRows';\nimport { FilterBar } from '../components/shared/FilterBar';\nimport { CursorPagination } from '../components/shared/CursorPagination';\n\nexport interface PaymentsPageProps {\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n header?: React.ReactNode;\n}\n\nconst statusFilterOptions = [\n { value: 'all', label: 'Tutti gli stati' },\n { value: 'succeeded', label: 'Completati' },\n { value: 'pending', label: 'In Attesa' },\n { value: 'failed', label: 'Falliti' },\n { value: 'canceled', label: 'Annullati' },\n];\n\nexport function PaymentsPage({ wrapper: Wrapper, header }: PaymentsPageProps) {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('all');\n const [cursor, setCursor] = useState<string | undefined>();\n const [selectedPayment, setSelectedPayment] = useState<AdminPayment | null>(null);\n const [showRefundDialog, setShowRefundDialog] = useState(false);\n const [refundAmount, setRefundAmount] = useState('');\n const [refundReason, setRefundReason] = useState<'duplicate' | 'fraudulent' | 'requested_by_customer'>('requested_by_customer');\n\n const { data, isLoading, refetch } = useAdminPayments({\n search: search || undefined,\n status: statusFilter !== 'all' ? statusFilter : undefined,\n limit: 25,\n starting_after: cursor,\n });\n const refundMutation = useRefundPayment();\n\n const payments = data?.data || [];\n const hasMore = data?.has_more || false;\n\n const handleRefund = () => {\n if (!selectedPayment) return;\n const amountCents = refundAmount ? Math.round(parseFloat(refundAmount) * 100) : undefined;\n refundMutation.mutate({ id: selectedPayment.id, amount: amountCents, reason: refundReason }, {\n onSuccess: () => { toast.success('Rimborso effettuato'); setShowRefundDialog(false); setSelectedPayment(null); setRefundAmount(''); },\n onError: (err) => toast.error(`Errore rimborso: ${err.message}`),\n });\n };\n\n const openRefundDialog = (payment: AdminPayment) => {\n setSelectedPayment(payment);\n setRefundAmount((payment.amount / 100).toFixed(2));\n setShowRefundDialog(true);\n };\n\n const content = (\n <>\n {header}\n <div className=\"space-y-4\">\n <FilterBar\n searchPlaceholder=\"Cerca per email cliente...\"\n searchValue={search}\n onSearchChange={(v) => { setSearch(v); setCursor(undefined); }}\n statusFilter={statusFilter}\n onStatusFilterChange={(v) => { setStatusFilter(v); setCursor(undefined); }}\n statusOptions={statusFilterOptions}\n onRefresh={refetch}\n />\n\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Receipt className=\"w-4 h-4\" /><span>{payments.length} pagamenti visualizzati</span>\n </div>\n\n <div className=\"rounded-lg border bg-card shadow-sm\">\n <div className=\"relative w-full overflow-auto\">\n <table className=\"w-full caption-bottom text-sm\">\n <thead className=\"[&_tr]:border-b\">\n <tr className=\"border-b hover:bg-muted/50\">\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">ID Pagamento</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Importo</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Stato</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Cliente</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Descrizione</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Data</th>\n <th className=\"h-12 px-4 text-right font-medium text-muted-foreground\">Azioni</th>\n </tr>\n </thead>\n <tbody>\n {isLoading ? (\n <SkeletonRows rows={5} columns={7} />\n ) : payments.length === 0 ? (\n <tr><td colSpan={7} className=\"p-4 text-center py-8 text-muted-foreground\">Nessun pagamento trovato</td></tr>\n ) : (\n payments.map((payment) => (\n <tr key={payment.id} className=\"border-b hover:bg-muted/50\">\n <td className=\"p-4\"><code className=\"text-xs bg-muted px-2 py-0.5 rounded\">{truncateId(payment.id)}</code></td>\n <td className=\"p-4 font-medium\">{formatCurrencyFromCents(payment.amount, payment.currency)}</td>\n <td className=\"p-4\"><StatusBadge label={paymentStatusLabels[payment.status]} colorClass={paymentStatusColors[payment.status]} /></td>\n <td className=\"p-4\">{payment.customer_email || <span className=\"text-muted-foreground\">-</span>}</td>\n <td className=\"p-4 max-w-[200px] truncate\">{payment.description || <span className=\"text-muted-foreground\">-</span>}</td>\n <td className=\"p-4\">{formatTimestamp(payment.created, true)}</td>\n <td className=\"p-4 text-right\">\n {payment.status === 'succeeded' && (\n <button className=\"inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 hover:bg-accent\" onClick={() => openRefundDialog(payment)}>\n <RotateCcw className=\"w-4 h-4 mr-1\" />Rimborsa\n </button>\n )}\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </div>\n\n <CursorPagination cursor={cursor} hasMore={hasMore} items={payments} onFirstPage={() => setCursor(undefined)} onNextPage={setCursor} />\n </div>\n\n {/* Refund Dialog */}\n {showRefundDialog && selectedPayment && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => setShowRefundDialog(false)} />\n <div className=\"relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg\">\n <h2 className=\"text-lg font-semibold\">Rimborso Pagamento</h2>\n <p className=\"text-sm text-muted-foreground mt-1\">Effettua un rimborso per il pagamento selezionato</p>\n <div className=\"space-y-4 py-4\">\n <div className=\"p-3 bg-muted rounded-lg\">\n <div className=\"flex justify-between items-center\">\n <span className=\"text-sm text-muted-foreground\">Pagamento originale</span>\n <span className=\"font-medium\">{formatCurrencyFromCents(selectedPayment.amount, selectedPayment.currency)}</span>\n </div>\n {selectedPayment.customer_email && <p className=\"text-sm text-muted-foreground mt-1\">Cliente: {selectedPayment.customer_email}</p>}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Importo Rimborso</label>\n <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\" />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Motivo</label>\n <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 as typeof refundReason)}>\n <option value=\"requested_by_customer\">Richiesto dal cliente</option>\n <option value=\"duplicate\">Pagamento duplicato</option>\n <option value=\"fraudulent\">Fraudolento</option>\n </select>\n </div>\n </div>\n <div className=\"flex justify-end gap-2\">\n <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)}>Annulla</button>\n <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}>\n {refundMutation.isPending ? 'Rimborso in corso...' : 'Conferma Rimborso'}\n </button>\n </div>\n </div>\n </div>\n )}\n </>\n );\n\n return Wrapper ? <Wrapper>{content}</Wrapper> : content;\n}\n","import { ChevronLeft, ChevronRight } from 'lucide-react';\n\ninterface CursorPaginationProps {\n cursor: string | undefined;\n hasMore: boolean;\n items: Array<{ id: string }>;\n onFirstPage: () => void;\n onNextPage: (lastItemId: string) => void;\n}\n\nexport function CursorPagination({\n cursor,\n hasMore,\n items,\n onFirstPage,\n onNextPage,\n}: CursorPaginationProps) {\n return (\n <div className=\"flex justify-between items-center\">\n <button\n 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\"\n onClick={onFirstPage}\n disabled={!cursor}\n >\n <ChevronLeft className=\"w-4 h-4 mr-1\" />\n Prima Pagina\n </button>\n <button\n 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\"\n onClick={() => {\n if (items.length > 0) {\n onNextPage(items[items.length - 1].id);\n }\n }}\n disabled={!hasMore}\n >\n Prossima\n <ChevronRight className=\"w-4 h-4 ml-1\" />\n </button>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { Eye, Send, XCircle, Download, FileText } from 'lucide-react';\nimport {\n useAdminInvoices,\n useSendInvoice,\n useVoidInvoice,\n useDialogState,\n formatCurrencyFromCents,\n formatTimestamp,\n invoiceStatusColors,\n invoiceStatusLabels,\n} from '@growflowstudio/billing-admin-core';\nimport type { AdminInvoice } from '@growflowstudio/billing-admin-core';\nimport { StatusBadge } from '../components/shared/StatusBadge';\nimport { SkeletonRows } from '../components/shared/SkeletonRows';\nimport { FilterBar } from '../components/shared/FilterBar';\nimport { CursorPagination } from '../components/shared/CursorPagination';\nimport { InvoiceDetailsDialog } from '../components/invoices/InvoiceDetailsDialog';\nimport { DeleteConfirmDialog } from '../components/shared/DeleteConfirmDialog';\n\nexport interface InvoicesPageProps {\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n header?: React.ReactNode;\n}\n\nconst statusFilterOptions = [\n { value: 'all', label: 'Tutti gli stati' },\n { value: 'draft', label: 'Bozze' },\n { value: 'open', label: 'Aperte' },\n { value: 'paid', label: 'Pagate' },\n { value: 'void', label: 'Annullate' },\n { value: 'uncollectible', label: 'Non Riscuotibili' },\n];\n\nexport function InvoicesPage({ wrapper: Wrapper, header }: InvoicesPageProps) {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('all');\n const [cursor, setCursor] = useState<string | undefined>();\n\n const detailsDialog = useDialogState<AdminInvoice>();\n const voidDialog = useDialogState<AdminInvoice>();\n\n const { data, isLoading, refetch } = useAdminInvoices({\n search: search || undefined,\n status: statusFilter !== 'all' ? statusFilter : undefined,\n limit: 25,\n starting_after: cursor,\n });\n const sendMutation = useSendInvoice();\n const voidMutation = useVoidInvoice();\n\n const invoices = data?.data || [];\n const hasMore = data?.has_more || false;\n\n const handleVoidConfirm = () => {\n if (voidDialog.data) {\n voidMutation.mutate(voidDialog.data.id, {\n onSuccess: () => { toast.success('Fattura annullata'); voidDialog.close(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const openInvoicePdf = (invoice: AdminInvoice) => {\n if (invoice.invoice_pdf) window.open(invoice.invoice_pdf, '_blank');\n else if (invoice.hosted_invoice_url) window.open(invoice.hosted_invoice_url, '_blank');\n };\n\n const content = (\n <>\n {header}\n <div className=\"space-y-4\">\n <FilterBar\n searchPlaceholder=\"Cerca per email o numero fattura...\"\n searchValue={search}\n onSearchChange={(v) => { setSearch(v); setCursor(undefined); }}\n statusFilter={statusFilter}\n onStatusFilterChange={(v) => { setStatusFilter(v); setCursor(undefined); }}\n statusOptions={statusFilterOptions}\n onRefresh={refetch}\n />\n\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <FileText className=\"w-4 h-4\" /><span>{invoices.length} fatture visualizzate</span>\n </div>\n\n <div className=\"rounded-lg border bg-card shadow-sm\">\n <div className=\"relative w-full overflow-auto\">\n <table className=\"w-full caption-bottom text-sm\">\n <thead className=\"[&_tr]:border-b\">\n <tr className=\"border-b hover:bg-muted/50\">\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Numero</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Stato</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Importo Dovuto</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Importo Pagato</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Cliente</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Data</th>\n <th className=\"h-12 px-4 text-left font-medium text-muted-foreground\">Scadenza</th>\n <th className=\"h-12 px-4 text-right font-medium text-muted-foreground\">Azioni</th>\n </tr>\n </thead>\n <tbody>\n {isLoading ? (\n <SkeletonRows rows={5} columns={8} />\n ) : invoices.length === 0 ? (\n <tr><td colSpan={8} className=\"p-4 text-center py-8 text-muted-foreground\">Nessuna fattura trovata</td></tr>\n ) : (\n invoices.map((inv) => (\n <tr key={inv.id} className=\"border-b hover:bg-muted/50\">\n <td className=\"p-4 font-medium\">{inv.number || <span className=\"text-muted-foreground\">-</span>}</td>\n <td className=\"p-4\"><StatusBadge label={invoiceStatusLabels[inv.status]} colorClass={invoiceStatusColors[inv.status]} /></td>\n <td className=\"p-4 font-medium\">{formatCurrencyFromCents(inv.amount_due, inv.currency)}</td>\n <td className=\"p-4\">{formatCurrencyFromCents(inv.amount_paid, inv.currency)}</td>\n <td className=\"p-4\">\n <div className=\"flex flex-col\">\n <span>{inv.customer_name || '-'}</span>\n {inv.customer_email && <span className=\"text-xs text-muted-foreground\">{inv.customer_email}</span>}\n </div>\n </td>\n <td className=\"p-4\">{formatTimestamp(inv.created)}</td>\n <td className=\"p-4\">{formatTimestamp(inv.due_date)}</td>\n <td className=\"p-4 text-right\">\n <div className=\"flex justify-end gap-1\">\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\" onClick={() => detailsDialog.open(inv)}><Eye className=\"w-4 h-4\" /></button>\n {(inv.invoice_pdf || inv.hosted_invoice_url) && (\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\" onClick={() => openInvoicePdf(inv)}><Download className=\"w-4 h-4\" /></button>\n )}\n {inv.status === 'open' && (\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\" onClick={() => sendMutation.mutate(inv.id, { onSuccess: () => toast.success('Fattura inviata'), onError: (err) => toast.error(`Errore: ${err.message}`) })} disabled={sendMutation.isPending}><Send className=\"w-4 h-4\" /></button>\n )}\n {(inv.status === 'draft' || inv.status === 'open') && (\n <button className=\"inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent\" onClick={() => voidDialog.open(inv)}><XCircle className=\"w-4 h-4\" /></button>\n )}\n </div>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </div>\n\n <CursorPagination cursor={cursor} hasMore={hasMore} items={invoices} onFirstPage={() => setCursor(undefined)} onNextPage={setCursor} />\n </div>\n\n <InvoiceDetailsDialog isOpen={detailsDialog.isOpen} onOpenChange={(open) => !open && detailsDialog.close()} invoice={detailsDialog.data} />\n\n <DeleteConfirmDialog\n isOpen={voidDialog.isOpen}\n onOpenChange={(open) => !open && voidDialog.close()}\n title=\"Annullare Fattura?\"\n description={<>Stai per annullare la fattura <strong>{voidDialog.data?.number || voidDialog.data?.id}</strong>. Una fattura annullata non può essere riattivata.</>}\n onConfirm={handleVoidConfirm}\n isDeleting={voidMutation.isPending}\n confirmLabel=\"Conferma Annullamento\"\n />\n </>\n );\n\n return Wrapper ? <Wrapper>{content}</Wrapper> : content;\n}\n","import { ExternalLink } from 'lucide-react';\nimport type { AdminInvoice } from '@growflowstudio/billing-admin-core';\nimport { formatCurrencyFromCents, formatTimestamp, invoiceStatusColors, invoiceStatusLabels } from '@growflowstudio/billing-admin-core';\nimport { StatusBadge } from '../shared/StatusBadge';\n\ninterface InvoiceDetailsDialogProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n invoice: AdminInvoice | null | undefined;\n}\n\nexport function InvoiceDetailsDialog({ isOpen, onOpenChange, invoice }: InvoiceDetailsDialogProps) {\n if (!isOpen || !invoice) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => onOpenChange(false)} />\n <div className=\"relative z-50 w-full max-w-lg rounded-lg border bg-background p-6 shadow-lg\">\n <div className=\"flex flex-col space-y-1.5 pb-4\">\n <h2 className=\"text-lg font-semibold\">Dettagli Fattura</h2>\n <p className=\"text-sm text-muted-foreground\">{invoice.number || 'Fattura senza numero'}</p>\n </div>\n\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">Stato</p>\n <StatusBadge label={invoiceStatusLabels[invoice.status]} colorClass={invoiceStatusColors[invoice.status]} className=\"mt-1\" />\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">Data Creazione</p>\n <p className=\"font-medium mt-1\">{formatTimestamp(invoice.created)}</p>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">Importo Dovuto</p>\n <p className=\"font-medium mt-1\">{formatCurrencyFromCents(invoice.amount_due, invoice.currency)}</p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">Importo Pagato</p>\n <p className=\"font-medium mt-1\">{formatCurrencyFromCents(invoice.amount_paid, invoice.currency)}</p>\n </div>\n </div>\n\n {invoice.amount_remaining > 0 && (\n <div className=\"p-3 bg-amber-50 dark:bg-amber-900/20 rounded-lg\">\n <p className=\"text-sm text-amber-700 dark:text-amber-400\">\n Importo rimanente: <strong>{formatCurrencyFromCents(invoice.amount_remaining, invoice.currency)}</strong>\n </p>\n </div>\n )}\n\n <div>\n <p className=\"text-sm text-muted-foreground\">Cliente</p>\n <p className=\"font-medium mt-1\">{invoice.customer_name || 'Non specificato'}</p>\n {invoice.customer_email && <p className=\"text-sm text-muted-foreground\">{invoice.customer_email}</p>}\n </div>\n\n {invoice.lines && invoice.lines.length > 0 && (\n <div>\n <p className=\"text-sm text-muted-foreground mb-2\">Voci Fattura</p>\n <div className=\"border rounded-lg divide-y\">\n {invoice.lines.map((line) => (\n <div key={line.id} className=\"p-3 flex justify-between items-center\">\n <div>\n <p className=\"text-sm font-medium\">{line.description}</p>\n <p className=\"text-xs text-muted-foreground\">Qtà: {line.quantity}</p>\n </div>\n <p className=\"font-medium\">{formatCurrencyFromCents(line.amount, line.currency)}</p>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {invoice.hosted_invoice_url && (\n <button\n 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\"\n onClick={() => window.open(invoice.hosted_invoice_url!, '_blank')}\n >\n <ExternalLink className=\"w-4 h-4 mr-2\" />\n Apri su Stripe\n </button>\n )}\n </div>\n\n <div className=\"flex justify-end pt-4\">\n <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)}>Chiudi</button>\n </div>\n </div>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { Plus, Pencil, Trash2, Package, AlertCircle } from 'lucide-react';\nimport {\n useAdminFeatures,\n useCreateFeature,\n useUpdateFeature,\n useDeleteFeature,\n} from '@growflowstudio/billing-admin-core';\nimport type { AdminFeature, AdminFeatureCreate, AdminFeatureUpdate } from '@growflowstudio/billing-admin-core';\nimport { StatusBadge } from '../components/shared/StatusBadge';\nimport { DeleteConfirmDialog } from '../components/shared/DeleteConfirmDialog';\n\nexport interface FeaturesPageProps {\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n header?: React.ReactNode;\n}\n\nexport function FeaturesPage({ wrapper: Wrapper, header }: FeaturesPageProps) {\n const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);\n const [editingFeature, setEditingFeature] = useState<AdminFeature | null>(null);\n const [deletingFeature, setDeletingFeature] = useState<AdminFeature | null>(null);\n\n const { data, isLoading } = useAdminFeatures();\n const createMutation = useCreateFeature();\n const updateMutation = useUpdateFeature();\n const deleteMutation = useDeleteFeature();\n\n const features = data?.features || [];\n\n const handleCreateFeature = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n\n const createData: AdminFeatureCreate = {\n slug: formData.get('slug') as string,\n name: formData.get('name') as string,\n description: (formData.get('description') as string) || undefined,\n icon: (formData.get('icon') as string) || undefined,\n category: (formData.get('category') as string) || undefined,\n is_available: formData.get('is_available') === 'on',\n billing_product_id: (formData.get('billing_product_id') as string) || undefined,\n };\n\n createMutation.mutate(createData, {\n onSuccess: () => { toast.success('Feature creata con successo'); setIsCreateDialogOpen(false); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n };\n\n const handleUpdateFeature = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n if (!editingFeature) return;\n\n const formData = new FormData(e.currentTarget);\n\n const updateData: AdminFeatureUpdate = {\n name: formData.get('name') as string,\n description: (formData.get('description') as string) || undefined,\n icon: (formData.get('icon') as string) || undefined,\n category: (formData.get('category') as string) || undefined,\n is_available: formData.get('is_available') === 'on',\n billing_product_id: (formData.get('billing_product_id') as string) || undefined,\n };\n\n updateMutation.mutate({ id: editingFeature.id, data: updateData }, {\n onSuccess: () => { toast.success('Feature aggiornata con successo'); setEditingFeature(null); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n };\n\n const handleDeleteConfirm = () => {\n if (deletingFeature) {\n deleteMutation.mutate(deletingFeature.id, {\n onSuccess: () => { toast.success('Feature eliminata con successo'); setDeletingFeature(null); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const content = (\n <>\n {header}\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Package className=\"w-4 h-4\" />\n <span>{features.length} feature{features.length !== 1 ? 's' : ''} configurate</span>\n </div>\n <button\n 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\"\n onClick={() => setIsCreateDialogOpen(true)}\n >\n <Plus className=\"w-4 h-4 mr-2\" />Nuova Feature\n </button>\n </div>\n\n <div className=\"rounded-lg border bg-card shadow-sm\">\n <div className=\"p-4 border-b\">\n <h3 className=\"text-base font-semibold flex items-center gap-2\">\n <Package className=\"w-5 h-5\" />\n Features Disponibili\n </h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Le features possono essere collegate a prodotti billing o attivate manualmente.\n </p>\n </div>\n <div className=\"p-4\">\n {isLoading ? (\n <div className=\"space-y-3\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-20 bg-muted animate-pulse rounded-lg\" />\n ))}\n </div>\n ) : features.length === 0 ? (\n <div className=\"text-center py-12 text-muted-foreground\">\n <Package className=\"mx-auto h-12 w-12 mb-4 opacity-50\" />\n <p>Nessuna feature configurata</p>\n <button\n className=\"text-sm text-primary hover:underline mt-2\"\n onClick={() => setIsCreateDialogOpen(true)}\n >\n Crea la prima feature\n </button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {features.map((feature) => (\n <div\n key={feature.id}\n className=\"border rounded-lg p-4 hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2 mb-2\">\n <span className=\"font-semibold\">{feature.name}</span>\n <code className=\"text-xs bg-muted px-2 py-0.5 rounded\">{feature.slug}</code>\n {!feature.is_available && (\n <StatusBadge label=\"Disattivata\" colorClass=\"bg-secondary text-secondary-foreground border-transparent\" />\n )}\n {feature.billing_product_id && (\n <StatusBadge label=\"Con Billing\" colorClass=\"border\" />\n )}\n </div>\n {feature.description && (\n <p className=\"text-sm text-muted-foreground mb-2\">{feature.description}</p>\n )}\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n {feature.category && <span>Categoria: {feature.category}</span>}\n {feature.icon && <span>Icona: {feature.icon}</span>}\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n className=\"inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent\"\n onClick={() => setEditingFeature(feature)}\n >\n <Pencil className=\"w-4 h-4\" />\n </button>\n <button\n className=\"inline-flex items-center justify-center rounded-md h-9 w-9 text-destructive hover:bg-accent\"\n onClick={() => setDeletingFeature(feature)}\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"mt-6 flex gap-3 items-start rounded-lg border p-3 text-sm\">\n <AlertCircle className=\"w-4 h-4 mt-0.5 text-muted-foreground shrink-0\" />\n <p className=\"text-muted-foreground text-xs\">\n <strong>Nota:</strong> Features con un billing_product_id vengono attivate automaticamente\n quando il cliente sottoscrive il piano corrispondente.\n </p>\n </div>\n </div>\n </div>\n </div>\n\n {/* Create Feature Dialog */}\n {isCreateDialogOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => setIsCreateDialogOpen(false)} />\n <div className=\"relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg\">\n <form onSubmit={handleCreateFeature}>\n <h2 className=\"text-lg font-semibold\">Crea Nuova Feature</h2>\n <p className=\"text-sm text-muted-foreground mt-1\">Configura una nuova feature disponibile.</p>\n <div className=\"space-y-4 py-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"slug\">Slug *</label>\n <input id=\"slug\" name=\"slug\" required 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\" />\n <p className=\"text-xs text-muted-foreground\">Identificatore univoco (lowercase, trattini)</p>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"name\">Nome *</label>\n <input id=\"name\" name=\"name\" required 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\" />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"description\">Descrizione</label>\n <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\" />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"icon\">Icona Lucide</label>\n <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\" />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"category\">Categoria</label>\n <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\" />\n </div>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"billing_product_id\">Billing Product ID (opzionale)</label>\n <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\" />\n <p className=\"text-xs text-muted-foreground\">Se collegato a un prodotto, la feature viene attivata automaticamente</p>\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"checkbox\" id=\"is_available\" name=\"is_available\" defaultChecked className=\"rounded border-input\" />\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"is_available\">Feature disponibile</label>\n </div>\n </div>\n <div className=\"flex justify-end gap-2\">\n <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)}>Annulla</button>\n <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}>\n {createMutation.isPending ? 'Creazione...' : 'Crea Feature'}\n </button>\n </div>\n </form>\n </div>\n </div>\n )}\n\n {/* Edit Feature Dialog */}\n {editingFeature && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"fixed inset-0 bg-black/80\" onClick={() => setEditingFeature(null)} />\n <div className=\"relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg\">\n <form onSubmit={handleUpdateFeature}>\n <h2 className=\"text-lg font-semibold\">Modifica Feature</h2>\n <p className=\"text-sm text-muted-foreground mt-1\">Aggiorna i dettagli della feature "{editingFeature.name}".</p>\n <div className=\"space-y-4 py-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\">Slug (non modificabile)</label>\n <input value={editingFeature.slug} disabled className=\"flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm\" />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"edit-name\">Nome *</label>\n <input id=\"edit-name\" name=\"name\" required 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\" />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"edit-description\">Descrizione</label>\n <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\" />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"edit-icon\">Icona Lucide</label>\n <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\" />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"edit-category\">Categoria</label>\n <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\" />\n </div>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"edit-billing_product_id\">Billing Product ID</label>\n <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\" />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"checkbox\" id=\"edit-is_available\" name=\"is_available\" defaultChecked={editingFeature.is_available} className=\"rounded border-input\" />\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"edit-is_available\">Feature disponibile</label>\n </div>\n </div>\n <div className=\"flex justify-end gap-2\">\n <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)}>Annulla</button>\n <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}>\n {updateMutation.isPending ? 'Salvataggio...' : 'Salva Modifiche'}\n </button>\n </div>\n </form>\n </div>\n </div>\n )}\n\n <DeleteConfirmDialog\n isOpen={!!deletingFeature}\n onOpenChange={(open) => !open && setDeletingFeature(null)}\n title=\"Eliminare Feature?\"\n description={<>Stai per eliminare la feature <strong>{deletingFeature?.name}</strong> (<code>{deletingFeature?.slug}</code>). Questa azione non può essere annullata.</>}\n onConfirm={handleDeleteConfirm}\n isDeleting={deleteMutation.isPending}\n confirmLabel=\"Elimina Feature\"\n />\n </>\n );\n\n return Wrapper ? <Wrapper>{content}</Wrapper> : content;\n}\n","import type { BillingModulesConfig } from '../provider';\n\nexport interface BillingNavItem {\n key: string;\n label: string;\n /** Lucide icon name (consumer maps to actual icon component) */\n icon: string;\n /** Suggested href path (consumer can override) */\n href: string;\n}\n\nconst ALL_NAV_ITEMS: BillingNavItem[] = [\n { key: 'plans', label: 'Piani', icon: 'LayoutGrid', href: '/admin/plans' },\n { key: 'subscriptions', label: 'Abbonamenti', icon: 'CreditCard', href: '/admin/subscriptions' },\n { key: 'products', label: 'Prodotti', icon: 'Package', href: '/admin/products' },\n { key: 'features', label: 'Features', icon: 'Puzzle', href: '/admin/features' },\n { key: 'payments', label: 'Pagamenti', icon: 'Receipt', href: '/admin/payments' },\n { key: 'invoices', label: 'Fatture', icon: 'FileText', href: '/admin/invoices' },\n];\n\n/**\n * Returns navigation items filtered by enabled modules.\n *\n * @param modules - The modules config from BillingAdminProvider\n * @param basePath - Optional base path prefix (e.g., '/dashboard')\n */\nexport function getBillingNavItems(\n modules?: BillingModulesConfig,\n basePath?: string,\n): BillingNavItem[] {\n const enabled = {\n plans: true,\n subscriptions: true,\n products: true,\n payments: true,\n invoices: true,\n features: true,\n ...modules,\n };\n\n return ALL_NAV_ITEMS\n .filter((item) => enabled[item.key as keyof typeof enabled] !== false)\n .map((item) => ({\n ...item,\n href: basePath ? `${basePath}${item.href}` : item.href,\n }));\n}\n"],"mappings":"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","names":["useState","jsx","jsx","jsx","jsx","jsxs","jsx","jsxs","Loader2","jsx","jsxs","Fragment","jsx","jsxs","useState","data","toast","Plus","RefreshCw","Pencil","Trash2","Upload","Check","X","useQuery","useState","useEffect","Loader2","jsx","jsxs","Fragment","jsx","jsxs","useQuery","toast","RefreshCw","Plus","Check","X","Upload","Pencil","Trash2","useState","toast","RefreshCw","jsx","jsxs","Fragment","jsx","jsxs","useState","toast","useState","toast","formatCurrencyFromCents","jsx","jsxs","Fragment","jsx","jsxs","statusFilterOptions","useState","toast","formatCurrencyFromCents","useState","toast","Eye","XCircle","useDialogState","formatCurrencyFromCents","formatTimestamp","invoiceStatusColors","invoiceStatusLabels","formatCurrencyFromCents","formatTimestamp","jsx","jsxs","formatTimestamp","formatCurrencyFromCents","Fragment","jsx","jsxs","statusFilterOptions","useState","useDialogState","toast","invoiceStatusLabels","invoiceStatusColors","formatCurrencyFromCents","formatTimestamp","Eye","XCircle","useState","toast","Plus","Pencil","Trash2","Package","Fragment","jsx","jsxs","useState","toast","Package","Plus","Pencil","Trash2"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@growflowstudio/billing-admin-ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "shadcn/ui billing admin components - pages, forms, tables, and dialogs for GrowFlow Billing",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
21
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
26
|
+
"prepublishOnly": "pnpm run build"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@growflowstudio/billing-admin-core": "workspace:^",
|
|
30
|
+
"@radix-ui/react-alert-dialog": "^1.1.0",
|
|
31
|
+
"@radix-ui/react-checkbox": "^1.1.0",
|
|
32
|
+
"@radix-ui/react-dialog": "^1.1.0",
|
|
33
|
+
"@radix-ui/react-label": "^2.1.0",
|
|
34
|
+
"@radix-ui/react-select": "^2.1.0",
|
|
35
|
+
"@radix-ui/react-switch": "^1.1.0",
|
|
36
|
+
"class-variance-authority": "^0.7.0",
|
|
37
|
+
"clsx": "^2.1.0",
|
|
38
|
+
"tailwind-merge": "^2.2.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@tanstack/react-query": "^5.0.0",
|
|
42
|
+
"lucide-react": ">=0.300.0",
|
|
43
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
44
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
45
|
+
"sonner": "^1.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@tanstack/react-query": "^5.90.0",
|
|
49
|
+
"@types/react": "^18.2.0",
|
|
50
|
+
"@types/react-dom": "^18.2.0",
|
|
51
|
+
"autoprefixer": "^10.4.0",
|
|
52
|
+
"lucide-react": "^0.460.0",
|
|
53
|
+
"postcss": "^8.4.0",
|
|
54
|
+
"react": "^18.2.0",
|
|
55
|
+
"react-dom": "^18.2.0",
|
|
56
|
+
"sonner": "^1.7.0",
|
|
57
|
+
"tailwindcss": "^3.4.0",
|
|
58
|
+
"tsup": "^8.0.1",
|
|
59
|
+
"typescript": "^5.3.2",
|
|
60
|
+
"vitest": "^2.1.0"
|
|
61
|
+
},
|
|
62
|
+
"keywords": [
|
|
63
|
+
"billing",
|
|
64
|
+
"admin",
|
|
65
|
+
"shadcn",
|
|
66
|
+
"ui",
|
|
67
|
+
"growflow",
|
|
68
|
+
"react"
|
|
69
|
+
],
|
|
70
|
+
"author": {
|
|
71
|
+
"name": "GrowFlow Studio",
|
|
72
|
+
"email": "dev@growflow.studio",
|
|
73
|
+
"url": "https://growflow.studio"
|
|
74
|
+
},
|
|
75
|
+
"license": "MIT",
|
|
76
|
+
"repository": {
|
|
77
|
+
"type": "git",
|
|
78
|
+
"url": "https://github.com/giuliogarofalo/billingflow",
|
|
79
|
+
"directory": "sdk/frontend/ui"
|
|
80
|
+
},
|
|
81
|
+
"homepage": "https://github.com/giuliogarofalo/billingflow/tree/main/sdk/frontend/ui",
|
|
82
|
+
"bugs": "https://github.com/giuliogarofalo/billingflow/issues",
|
|
83
|
+
"publishConfig": {
|
|
84
|
+
"access": "public"
|
|
85
|
+
}
|
|
86
|
+
}
|