@growflowstudio/growflowbilling-admin-ui 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/components/shared/ErrorBoundary.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/shared/ToggleSwitch.tsx","../src/components/plans/PlanDetailsSection.tsx","../src/components/plans/PlanPricingSection.tsx","../src/components/plans/LimitInput.tsx","../src/components/plans/PlanLimitsSection.tsx","../src/components/plans/PlanFeaturesSection.tsx","../src/lib/plan-feature-state.ts","../src/components/plans/PlanFeatureRow.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/components/features/FeatureFormModal.tsx","../src/components/features/FeatureListItem.tsx","../src/nav/billingNavItems.ts"],"sourcesContent":["import React, { useMemo } from 'react';\nimport {\n BillingAdminClientContext,\n createBillingAdminClient,\n type Fetcher,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport { ErrorBoundary } from './components/shared/ErrorBoundary';\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 <ErrorBoundary>\n {children}\n </ErrorBoundary>\n </BillingAdminClientContext.Provider>\n </BillingAdminConfigContext.Provider>\n );\n}\n","import React, { Component } from 'react';\n\ninterface Props {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n console.error('[BillingSDK] Error caught by boundary:', error, errorInfo);\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div style={{ padding: '1rem', textAlign: 'center', color: '#666' }}>\n <p>Something went wrong in the billing module.</p>\n <button\n onClick={() => this.setState({ hasError: false, error: null })}\n style={{ marginTop: '0.5rem', cursor: 'pointer' }}\n >\n Try again\n </button>\n </div>\n );\n }\n return this.props.children;\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 useDialogState,\n validateRequired,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminPlan, AdminPlanCreate, AdminPlanUpdate } from '@growflowstudio/growflowbilling-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 formDialog = useDialogState<AdminPlan>();\n const deleteDialog = useDialogState<AdminPlan>();\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 setFormErrors({});\n };\n\n const openCreateForm = () => {\n resetForm();\n formDialog.open(undefined);\n };\n\n const openEditForm = (plan: AdminPlan) => {\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 ui_visibility: plan.ui_visibility ?? {},\n sort_order: plan.sort_order,\n });\n formDialog.open(plan);\n };\n\n const handleValidate = (): boolean => {\n const errors: Record<string, string> = {};\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 // Compute slug inline at submit time to avoid React state race conditions.\n // The onChange handler sets slug as a UX preview, but we always recompute\n // here as a fallback so a fast submit never sends an empty slug.\n const resolvedSlug =\n formData.slug.trim() ||\n formData.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');\n\n // Sync the resolved slug back so validation and downstream usage see it.\n const finalFormData = { ...formData, slug: resolvedSlug };\n\n if (!handleValidate()) return;\n\n const limits: Record<string, number> = {};\n for (const field of limitFields) {\n limits[field.key] = finalFormData.limits_unlimited[field.key] ? -1 : (finalFormData.limits[field.key] ?? 1);\n }\n\n const planData: AdminPlanCreate | AdminPlanUpdate = {\n slug: finalFormData.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 // Send the full map — empty ``{}`` is meaningful (clears any\n // lingering overrides) so we never fall back to ``undefined``.\n ui_visibility: formData.ui_visibility ?? {},\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(finalFormData.slug);\n if (finalFormData.is_public !== isCurrentlyPublic) {\n try {\n const newSlugs = finalFormData.is_public\n ? [...publicPlanSlugs, finalFormData.slug]\n : publicPlanSlugs.filter((s) => s !== finalFormData.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 (formDialog.data) {\n updateMutation.mutate({ id: formDialog.data.id, data: planData }, {\n onSuccess: () => { toast.success('Piano aggiornato con successo'); formDialog.close(); 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'); formDialog.close(); resetForm(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const handleDelete = () => {\n if (deleteDialog.data) {\n deleteMutation.mutate(deleteDialog.data.id, {\n onSuccess: () => { toast.success('Piano eliminato con successo'); 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 <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) => deleteDialog.open(plan)}\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={formDialog.isOpen}\n onOpenChange={(open) => { if (!open) { formDialog.close(); resetForm(); } }}\n formData={formData}\n onFormDataChange={(data) => setFormData((prev) => ({ ...prev, ...data }))}\n formErrors={formErrors}\n selectedPlan={formDialog.data ?? null}\n onSubmit={handleSubmit}\n isPending={createMutation.isPending || updateMutation.isPending}\n />\n\n <DeleteConfirmDialog\n isOpen={deleteDialog.isOpen}\n onOpenChange={(open) => { if (!open) deleteDialog.close(); }}\n title=\"Eliminare Piano?\"\n description={<>Stai per eliminare il piano <strong>{deleteDialog.data?.name}</strong> (<code>{deleteDialog.data?.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/growflowbilling-admin-core';\nimport { formatCurrency } from '@growflowstudio/growflowbilling-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 { useMemo } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Loader2 } from 'lucide-react';\nimport type {\n AdminPlan,\n AdminPlanPricingModel,\n Visibility,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport { useBillingAdminConfig, type LimitFieldConfig } from '../../provider';\nimport { PlanDetailsSection } from './PlanDetailsSection';\nimport { PlanPricingSection } from './PlanPricingSection';\nimport { PlanLimitsSection } from './PlanLimitsSection';\nimport { PlanFeaturesSection } from './PlanFeaturesSection';\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 /**\n * Newline-separated feature slugs — legacy shape kept for compatibility\n * with existing submit logic in ``PlansPage``. The unified feature\n * editor writes to this field via ``applyFeatureState``.\n */\n features: string;\n /**\n * Per-feature UI visibility overrides (tri-state). Managed atomically\n * with ``features`` by ``PlanFeaturesSection``.\n */\n ui_visibility: Record<string, Visibility>;\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 ui_visibility: {},\n sort_order: 0,\n };\n}\n\nfunction generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport interface 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 const isCreating = !selectedPlan;\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\n // Derive the current feature slug list from the newline-separated form\n // field. No useState mirror — the form state is the single source of\n // truth and derivations stay in sync automatically on every edit.\n const selectedFeatureSlugs = useMemo<string[]>(\n () =>\n formData.features\n ? formData.features\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n : [],\n [formData.features],\n );\n\n const uiVisibility = useMemo<Record<string, Visibility>>(\n () => formData.ui_visibility ?? {},\n [formData.ui_visibility],\n );\n\n const handleNameChange = (name: string) => {\n if (isCreating) {\n onFormDataChange({ name, slug: generateSlug(name) });\n } else {\n onFormDataChange({ name });\n }\n };\n\n // Every feature-state toggle rewrites both ``features`` and\n // ``ui_visibility`` in one atomic update so the two fields cannot drift.\n const handleFeatureStateChange = (next: {\n features: string[];\n uiVisibility: Record<string, Visibility>;\n }) => {\n onFormDataChange({\n features: next.features.join('\\n'),\n ui_visibility: next.uiVisibility,\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 {/* Header */}\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\n ? 'Modifica le impostazioni del piano selezionato'\n : 'Crea un nuovo piano di abbonamento'}\n </p>\n </div>\n\n {/* Form sections */}\n <div className=\"grid gap-4 py-4\">\n <PlanDetailsSection\n formData={formData}\n formErrors={formErrors}\n isCreating={isCreating}\n onFormDataChange={onFormDataChange}\n onNameChange={handleNameChange}\n />\n <PlanPricingSection formData={formData} onFormDataChange={onFormDataChange} />\n <PlanLimitsSection\n limitFields={limitFields}\n formData={formData}\n onFormDataChange={onFormDataChange}\n />\n {featuresConfig?.enabled && (\n <PlanFeaturesSection\n availableFeatures={availableFeatures}\n selectedFeatureSlugs={selectedFeatureSlugs}\n uiVisibility={uiVisibility}\n onFeatureStateChange={handleFeatureStateChange}\n />\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","interface ToggleSwitchProps {\n label: string;\n checked: boolean;\n onChange: (value: boolean) => void;\n}\n\nexport function ToggleSwitch({ label, checked, onChange }: ToggleSwitchProps) {\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\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n checked ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n <span className=\"text-sm font-medium leading-none\">{label}</span>\n </div>\n );\n}\n","import type { PlanFormData } from './PlanFormDialog';\nimport { PLAN_COLORS, getPlanColorClass } from './plan-colors';\nimport { ToggleSwitch } from '../shared/ToggleSwitch';\n\ninterface PlanDetailsSectionProps {\n formData: PlanFormData;\n formErrors: Record<string, string>;\n isCreating: boolean;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n onNameChange: (name: string) => void;\n}\n\nexport function PlanDetailsSection({\n formData,\n formErrors,\n onFormDataChange,\n onNameChange,\n}: PlanDetailsSectionProps) {\n return (\n <>\n {/* Name */}\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) => onNameChange(e.target.value)}\n placeholder=\"es. Piano Pro\"\n />\n {formErrors.name && <p className=\"text-xs text-destructive\">{formErrors.name}</p>}\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 {/* 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:{' '}\n <span className={`inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${getPlanColorClass(formData.color)}`}>\n {formData.name || 'Piano'}\n </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 );\n}\n","import type { AdminPlanPricingModel } from '@growflowstudio/growflowbilling-admin-core';\nimport type { PlanFormData } from './PlanFormDialog';\n\ninterface PlanPricingSectionProps {\n formData: PlanFormData;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n}\n\nexport function PlanPricingSection({ formData, onFormDataChange }: PlanPricingSectionProps) {\n return (\n <>\n {/* Pricing model + prices */}\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 days, sort order */}\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\n id=\"trial_days\"\n type=\"number\"\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.trial_days}\n onChange={(e) => onFormDataChange({ trial_days: parseInt(e.target.value) || 0 })}\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"sort_order\">Ordine</label>\n <input\n id=\"sort_order\"\n type=\"number\"\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.sort_order}\n onChange={(e) => onFormDataChange({ sort_order: parseInt(e.target.value) || 0 })}\n />\n </div>\n </div>\n </>\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 type { LimitFieldConfig } from '../../provider';\nimport type { PlanFormData } from './PlanFormDialog';\nimport { LimitInput } from './LimitInput';\n\ninterface PlanLimitsSectionProps {\n limitFields: LimitFieldConfig[];\n formData: PlanFormData;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n}\n\nexport function PlanLimitsSection({ limitFields, formData, onFormDataChange }: PlanLimitsSectionProps) {\n if (limitFields.length === 0) return null;\n\n return (\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","import { useMemo, useState } from 'react';\nimport type { Visibility } from '@growflowstudio/growflowbilling-admin-core';\nimport type { PlanFormData } from './PlanFormDialog';\nimport {\n applyFeatureState,\n featureStateFromPlan,\n summarizeFeatureStates,\n type FeatureState,\n} from '../../lib/plan-feature-state';\nimport { PlanFeatureRow } from './PlanFeatureRow';\n\ninterface AvailableFeature {\n slug: string;\n name: string;\n description?: string;\n}\n\nexport interface PlanFeaturesSectionProps {\n availableFeatures: AvailableFeature[];\n /** Current included feature slugs (mirror of ``plan.features``). */\n selectedFeatureSlugs: string[];\n /** Current UI visibility overrides (mirror of ``plan.ui_visibility``). */\n uiVisibility: Record<string, Visibility>;\n /**\n * Called when the admin picks a new state for a slug. Receives the\n * atomically-updated ``features`` array and ``uiVisibility`` map;\n * callers MUST write both back to the parent form state.\n */\n onFeatureStateChange: (next: {\n features: string[];\n uiVisibility: Record<string, Visibility>;\n }) => void;\n}\n\n/**\n * Unified feature-state editor for the plan form.\n *\n * Replaces the old split between \"Features Incluse nel Piano\" checkboxes\n * and a separate visibility dropdown. One row per feature, one dropdown\n * per row with 3 user-facing states (``Non inclusa``, ``Teaser``,\n * ``Inclusa``) plus an advanced ``Sunset`` option behind a toggle. Every\n * state change writes ``plan.features`` and ``plan.ui_visibility``\n * atomically via ``applyFeatureState`` so the two fields can never drift.\n */\nexport function PlanFeaturesSection({\n availableFeatures,\n selectedFeatureSlugs,\n uiVisibility,\n onFeatureStateChange,\n}: PlanFeaturesSectionProps) {\n const [showSunset, setShowSunset] = useState(false);\n\n // Walk the union of catalog slugs + slugs already referenced by the plan\n // (covers custom overrides that don't exist in the current feature\n // catalog) so nothing the admin touched disappears silently.\n const rowSlugs = useMemo(() => {\n const out = new Set<string>(availableFeatures.map((f) => f.slug));\n for (const slug of selectedFeatureSlugs) out.add(slug);\n for (const slug of Object.keys(uiVisibility)) out.add(slug);\n return Array.from(out).sort();\n }, [availableFeatures, selectedFeatureSlugs, uiVisibility]);\n\n const stateCounts = useMemo(\n () => summarizeFeatureStates(selectedFeatureSlugs, uiVisibility),\n [selectedFeatureSlugs, uiVisibility],\n );\n\n const handleChange = (slug: string, next: FeatureState) => {\n const result = applyFeatureState(\n slug,\n next,\n selectedFeatureSlugs,\n uiVisibility,\n );\n onFeatureStateChange(result);\n };\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <label className=\"text-sm font-medium leading-none\">\n Funzionalità del piano\n </label>\n <div className=\"flex items-center gap-1 text-xs\">\n {stateCounts.on > 0 && (\n <span className=\"inline-flex items-center rounded-md border px-1.5 py-0.5 bg-green-100 text-green-800 border-green-300 dark:bg-green-900/30 dark:text-green-400 dark:border-green-700\">\n {stateCounts.on} inclusa{stateCounts.on !== 1 ? 'e' : ''}\n </span>\n )}\n {stateCounts.teaser > 0 && (\n <span className=\"inline-flex items-center rounded-md border px-1.5 py-0.5 bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-700\">\n {stateCounts.teaser} teaser\n </span>\n )}\n {stateCounts.sunset > 0 && (\n <span className=\"inline-flex items-center rounded-md border px-1.5 py-0.5 bg-rose-100 text-rose-800 border-rose-300 dark:bg-rose-900/30 dark:text-rose-400 dark:border-rose-700\">\n {stateCounts.sunset} sunset\n </span>\n )}\n </div>\n </div>\n\n <p className=\"text-xs text-muted-foreground\">\n Per ogni funzionalità scegli lo stato: <strong>Non inclusa</strong>{' '}\n (default), <strong>Teaser</strong> (mostrata come locked con CTA\n upgrade), o <strong>Inclusa</strong> (attiva). Lo stato scrive\n automaticamente le feature del piano e la visibility UI.\n </p>\n\n <div className=\"border rounded-lg p-2 space-y-1 max-h-[320px] overflow-y-auto\">\n {rowSlugs.length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n Nessuna funzionalità disponibile nel catalogo.\n </p>\n ) : (\n rowSlugs.map((slug) => {\n const feature = availableFeatures.find((f) => f.slug === slug);\n const state = featureStateFromPlan(\n slug,\n selectedFeatureSlugs,\n uiVisibility,\n );\n return (\n <PlanFeatureRow\n key={slug}\n slug={slug}\n name={feature?.name}\n description={feature?.description}\n state={state}\n showSunset={showSunset}\n onChange={handleChange}\n />\n );\n })\n )}\n </div>\n\n <div className=\"flex items-center gap-2 pt-1\">\n <input\n id=\"show-advanced-state\"\n type=\"checkbox\"\n checked={showSunset}\n onChange={(e) => setShowSunset(e.target.checked)}\n className=\"h-4 w-4 rounded border-input cursor-pointer\"\n />\n <label\n htmlFor=\"show-advanced-state\"\n className=\"text-xs text-muted-foreground cursor-pointer\"\n >\n Mostra stato avanzato &quot;Sunset&quot; (feature deprecate)\n </label>\n </div>\n </div>\n );\n}\n\n// Re-export type so callers can type feature data without coupling to internal shape\nexport type { PlanFormData };\n","/**\n * Plan × Feature state — canonical helpers.\n *\n * The backend stores per-plan feature configuration in two fields:\n *\n * - ``plan.features: string[]`` — slugs included in the plan.\n * - ``plan.ui_visibility: Record<slug, Visibility>`` — tri-state UI\n * override map.\n *\n * The admin UX exposes 3 user-facing states (``off | teaser | on``) plus\n * an advanced ``sunset`` state. This module is the ONLY place in the\n * billing admin UI that translates between the two raw backend fields\n * and the user-facing state. Every component that displays or writes\n * feature state must import from here — no inline logic.\n */\n\nimport type { Visibility } from '@growflowstudio/growflowbilling-admin-core';\n\nexport type FeatureState = 'off' | 'teaser' | 'on' | 'sunset';\n\nexport const FEATURE_STATE_LABELS: Record<FeatureState, string> = {\n off: 'Non inclusa',\n teaser: 'Teaser',\n on: 'Inclusa',\n sunset: 'Sunset (admin)',\n};\n\nexport const FEATURE_STATE_DESCRIPTIONS: Record<FeatureState, string> = {\n off: 'Non disponibile per gli utenti di questo piano (default).',\n teaser:\n 'Mostrata in sidebar come locked con CTA upgrade. Non attivata funzionalmente.',\n on: 'Inclusa nel piano e pienamente accessibile.',\n sunset:\n 'Tecnicamente nel piano ma nascosta. Uso raro (deprecazioni / incidenti).',\n};\n\n/**\n * Derive the user-facing state for a feature slug from the two raw backend\n * fields. Inverse of ``applyFeatureState``.\n *\n * Resolution table:\n *\n * | in ``features`` | ``ui_visibility[slug]`` | → state |\n * |-----------------|-------------------------|-------------|\n * | no | absent / 'hidden' | 'off' |\n * | no | 'teaser' | 'teaser' |\n * | no | 'visible' | 'off' (*) |\n * | yes | absent / 'visible' | 'on' |\n * | yes | 'teaser' | 'on' (*) |\n * | yes | 'hidden' | 'sunset' |\n *\n * (*) semantically invalid combinations normalised to the closest valid\n * state rather than surfacing a \"bug\" state to the admin.\n */\nexport function featureStateFromPlan(\n slug: string,\n features: string[] | null | undefined,\n uiVisibility: Record<string, Visibility> | null | undefined,\n): FeatureState {\n const inPlan = (features ?? []).includes(slug);\n const ui = (uiVisibility ?? {})[slug];\n\n if (inPlan) {\n if (ui === 'hidden') return 'sunset';\n return 'on';\n }\n\n if (ui === 'teaser') return 'teaser';\n return 'off';\n}\n\n/**\n * Apply a user-facing state transition to the raw backend fields.\n *\n * Immutable — returns new arrays/objects so React re-renders correctly.\n * This is the ONLY function that writes ``features`` + ``ui_visibility``\n * together. Callers must not edit the two fields independently.\n */\nexport function applyFeatureState(\n slug: string,\n state: FeatureState,\n features: string[] | null | undefined,\n uiVisibility: Record<string, Visibility> | null | undefined,\n): {\n features: string[];\n uiVisibility: Record<string, Visibility>;\n} {\n const nextFeaturesSet = new Set(features ?? []);\n const nextUi: Record<string, Visibility> = { ...(uiVisibility ?? {}) };\n\n switch (state) {\n case 'off':\n nextFeaturesSet.delete(slug);\n delete nextUi[slug];\n break;\n case 'teaser':\n nextFeaturesSet.delete(slug);\n nextUi[slug] = 'teaser';\n break;\n case 'on':\n nextFeaturesSet.add(slug);\n // Implicit 'visible' — don't write it to keep the map small.\n delete nextUi[slug];\n break;\n case 'sunset':\n nextFeaturesSet.add(slug);\n nextUi[slug] = 'hidden';\n break;\n }\n\n return {\n features: Array.from(nextFeaturesSet),\n uiVisibility: nextUi,\n };\n}\n\n/**\n * Count features by state for summary displays.\n *\n * Walks the union of ``features`` and ``uiVisibility`` keys so every\n * slug that has ANY configuration is counted. Slugs absent from both\n * are considered ``off`` and not counted (they're the invisible default).\n */\nexport function summarizeFeatureStates(\n features: string[] | null | undefined,\n uiVisibility: Record<string, Visibility> | null | undefined,\n): Record<FeatureState, number> {\n const counts: Record<FeatureState, number> = {\n off: 0,\n teaser: 0,\n on: 0,\n sunset: 0,\n };\n\n const slugs = new Set<string>([\n ...(features ?? []),\n ...Object.keys(uiVisibility ?? {}),\n ]);\n\n for (const slug of slugs) {\n const state = featureStateFromPlan(slug, features, uiVisibility);\n counts[state] += 1;\n }\n\n return counts;\n}\n","import { Check, CircleSlash, Lock, Archive } from 'lucide-react';\nimport {\n FEATURE_STATE_DESCRIPTIONS,\n type FeatureState,\n} from '../../lib/plan-feature-state';\n\n// Visual config for each state. Colocated with the row because this\n// component is the only place the tag is rendered at full size in the\n// plan editor; the plans table uses its own compact variant.\nconst STATE_VISUAL: Record<\n FeatureState,\n {\n label: string;\n Icon: typeof Check;\n classes: string;\n }\n> = {\n off: {\n label: 'Non inclusa',\n Icon: CircleSlash,\n classes: 'bg-muted text-muted-foreground border-muted-foreground/20',\n },\n teaser: {\n label: 'Teaser',\n Icon: Lock,\n classes:\n 'bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-700',\n },\n on: {\n label: 'Inclusa',\n Icon: Check,\n classes:\n 'bg-green-100 text-green-800 border-green-300 dark:bg-green-900/30 dark:text-green-400 dark:border-green-700',\n },\n sunset: {\n label: 'Sunset',\n Icon: Archive,\n classes:\n 'bg-rose-100 text-rose-800 border-rose-300 dark:bg-rose-900/30 dark:text-rose-400 dark:border-rose-700',\n },\n};\n\nexport interface PlanFeatureRowProps {\n /** Feature slug (stable identifier) */\n slug: string;\n /** Display name; falls back to slug when undefined */\n name?: string;\n /** Optional description shown under the name */\n description?: string | null;\n /** Current resolved state for this slug in this plan */\n state: FeatureState;\n /** Whether the advanced \"sunset\" option is visible in the dropdown */\n showSunset?: boolean;\n /** Called when the admin picks a new state from the dropdown */\n onChange: (slug: string, next: FeatureState) => void;\n /** Optional secondary action (e.g. remove a custom teaser-only slug) */\n onRemove?: () => void;\n}\n\nexport function PlanFeatureRow({\n slug,\n name,\n description,\n state,\n showSunset = false,\n onChange,\n onRemove,\n}: PlanFeatureRowProps) {\n const visual = STATE_VISUAL[state];\n const Icon = visual.Icon;\n\n return (\n <div className=\"flex items-start gap-3 p-2 rounded-md hover:bg-muted/50 transition-colors\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-sm font-medium truncate\">{name || slug}</span>\n <span\n className={`inline-flex items-center h-5 text-[10px] px-1.5 gap-1 rounded-md border ${visual.classes}`}\n >\n <Icon className=\"h-3 w-3 mr-1\" />\n {visual.label}\n </span>\n </div>\n {description && (\n <p className=\"text-xs text-muted-foreground mt-0.5 line-clamp-1\">\n {description}\n </p>\n )}\n <code className=\"text-[10px] text-muted-foreground bg-muted px-1.5 py-0.5 rounded mt-1 inline-block\">\n {slug}\n </code>\n </div>\n\n <select\n value={state}\n onChange={(e) => onChange(slug, e.target.value as FeatureState)}\n aria-label={`Stato per ${slug}`}\n className=\"h-8 w-[140px] text-xs flex-shrink-0 rounded-md border border-input bg-background px-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <option value=\"off\" title={FEATURE_STATE_DESCRIPTIONS.off}>\n Non inclusa\n </option>\n <option value=\"teaser\" title={FEATURE_STATE_DESCRIPTIONS.teaser}>\n Teaser\n </option>\n <option value=\"on\" title={FEATURE_STATE_DESCRIPTIONS.on}>\n Inclusa\n </option>\n {showSunset && (\n <option value=\"sunset\" title={FEATURE_STATE_DESCRIPTIONS.sunset}>\n Sunset (admin)\n </option>\n )}\n </select>\n\n {onRemove && (\n <button\n type=\"button\"\n onClick={onRemove}\n className=\"text-muted-foreground hover:text-destructive text-xs mt-1\"\n aria-label={`Rimuovi override ${slug}`}\n >\n ✕\n </button>\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/growflowbilling-admin-core';\nimport type { AdminProduct, AdminProductCreate, AdminProductUpdate } from '@growflowstudio/growflowbilling-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/growflowbilling-admin-core';\n\n// Safe JSON parse helper — never throws; returns fallback on malformed input.\nconst safeJsonParse = (str: string, fallback: Record<string, unknown> = {}): Record<string, unknown> => {\n try {\n const parsed: unknown = JSON.parse(str);\n return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : fallback;\n } catch {\n return fallback;\n }\n};\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 const parsedData = safeJsonParse(prev.extra_data);\n const updated = { ...parsedData, feature_slug: formData.feature_slug };\n return { ...prev, extra_data: JSON.stringify(updated, null, 2) };\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 // Validate that extra_data is valid JSON — safeJsonParse used in submit paths,\n // here we only need to surface a user-facing error message on invalid input.\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/growflowbilling-admin-core';\nimport type { AdminSubscription, AdminSubscriptionStatus } from '@growflowstudio/growflowbilling-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 useCursorPagination,\n formatCurrencyFromCents,\n formatTimestamp,\n truncateId,\n paymentStatusColors,\n paymentStatusLabels,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminPayment } from '@growflowstudio/growflowbilling-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, goToNext, goToFirst } = useCursorPagination();\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); goToFirst(); }}\n statusFilter={statusFilter}\n onStatusFilterChange={(v) => { setStatusFilter(v); goToFirst(); }}\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={goToFirst} onNextPage={goToNext} />\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 useCursorPagination,\n formatCurrencyFromCents,\n formatTimestamp,\n invoiceStatusColors,\n invoiceStatusLabels,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminInvoice } from '@growflowstudio/growflowbilling-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, goToNext, goToFirst } = useCursorPagination();\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); goToFirst(); }}\n statusFilter={statusFilter}\n onStatusFilterChange={(v) => { setStatusFilter(v); goToFirst(); }}\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={goToFirst} onNextPage={goToNext} />\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/growflowbilling-admin-core';\nimport { formatCurrencyFromCents, formatTimestamp, invoiceStatusColors, invoiceStatusLabels } from '@growflowstudio/growflowbilling-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 { Plus, Package, AlertCircle } from 'lucide-react';\nimport { useAdminFeatures, useDeleteFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport { toast } from 'sonner';\nimport { DeleteConfirmDialog } from '../components/shared/DeleteConfirmDialog';\nimport { FeatureFormModal } from '../components/features/FeatureFormModal';\nimport { FeatureListItem } from '../components/features/FeatureListItem';\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 [modalFeature, setModalFeature] = useState<AdminFeature | null | undefined>(undefined);\n const [deletingFeature, setDeletingFeature] = useState<AdminFeature | null>(null);\n\n // undefined = modal closed, null = create mode, AdminFeature = edit mode\n const isModalOpen = modalFeature !== undefined;\n\n const { data, isLoading, refetch } = useAdminFeatures();\n const deleteMutation = useDeleteFeature();\n\n const features = data?.features || [];\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 handleModalSuccess = () => {\n refetch();\n setModalFeature(undefined);\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={() => setModalFeature(null)}\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={() => setModalFeature(null)}\n >\n Crea la prima feature\n </button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {features.map((feature) => (\n <FeatureListItem\n key={feature.id}\n feature={feature}\n onEdit={(f) => setModalFeature(f)}\n onDelete={(f) => setDeletingFeature(f)}\n />\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 <FeatureFormModal\n feature={isModalOpen ? (modalFeature ?? null) : null}\n open={isModalOpen}\n onClose={() => setModalFeature(undefined)}\n onSuccess={handleModalSuccess}\n />\n\n <DeleteConfirmDialog\n isOpen={!!deletingFeature}\n onOpenChange={(open) => !open && setDeletingFeature(null)}\n title=\"Eliminare Feature?\"\n description={\n <>\n Stai per eliminare la feature <strong>{deletingFeature?.name}</strong> (\n <code>{deletingFeature?.slug}</code>). Questa azione non può essere annullata.\n </>\n }\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 { useCreateFeature, useUpdateFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminFeature, AdminFeatureCreate, AdminFeatureUpdate } from '@growflowstudio/growflowbilling-admin-core';\nimport { toast } from 'sonner';\n\nexport interface FeatureFormModalProps {\n /** null = create mode, defined = edit mode */\n feature: AdminFeature | null;\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\nexport function FeatureFormModal({ feature, open, onClose, onSuccess }: FeatureFormModalProps) {\n const isEditMode = feature !== null;\n const createMutation = useCreateFeature();\n const updateMutation = useUpdateFeature();\n const isPending = createMutation.isPending || updateMutation.isPending;\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n\n if (isEditMode) {\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 updateMutation.mutate(\n { id: feature.id, data: updateData },\n {\n onSuccess: () => { toast.success('Feature aggiornata con successo'); onSuccess(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n },\n );\n } else {\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 createMutation.mutate(createData, {\n onSuccess: () => { toast.success('Feature creata con successo'); onSuccess(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\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={onClose} />\n <div className=\"relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-lg font-semibold\">\n {isEditMode ? 'Modifica Feature' : 'Crea Nuova Feature'}\n </h2>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {isEditMode\n ? `Aggiorna i dettagli della feature \"${feature.name}\".`\n : 'Configura una nuova feature disponibile.'}\n </p>\n\n <div className=\"space-y-4 py-4\">\n {/* Slug: editable on create, read-only on edit */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"slug\">\n {isEditMode ? 'Slug (non modificabile)' : 'Slug *'}\n </label>\n {isEditMode ? (\n <input\n value={feature.slug}\n disabled\n className=\"flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm\"\n />\n ) : (\n <>\n <input\n id=\"slug\"\n name=\"slug\"\n required\n placeholder=\"ottimizza-dati-prodotti\"\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 />\n <p className=\"text-xs text-muted-foreground\">Identificatore univoco (lowercase, trattini)</p>\n </>\n )}\n </div>\n\n {/* Name */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"name\">Nome *</label>\n <input\n id={isEditMode ? 'edit-name' : 'name'}\n name=\"name\"\n required\n defaultValue={feature?.name ?? ''}\n placeholder=\"Ottimizza Dati Prodotti\"\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 />\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={isEditMode ? 'edit-description' : 'description'}\n name=\"description\"\n rows={3}\n defaultValue={feature?.description ?? ''}\n placeholder=\"Descrizione della feature...\"\n 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 />\n </div>\n\n {/* Icon + Category */}\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\n id={isEditMode ? 'edit-icon' : 'icon'}\n name=\"icon\"\n defaultValue={feature?.icon ?? ''}\n placeholder=\"Package\"\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 />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"category\">Categoria</label>\n <input\n id={isEditMode ? 'edit-category' : 'category'}\n name=\"category\"\n defaultValue={feature?.category ?? ''}\n placeholder=\"ai, limits, integration...\"\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 />\n </div>\n </div>\n\n {/* Billing product ID */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"billing_product_id\">\n Billing Product ID (opzionale)\n </label>\n <input\n id={isEditMode ? 'edit-billing_product_id' : 'billing_product_id'}\n name=\"billing_product_id\"\n defaultValue={feature?.billing_product_id ?? ''}\n placeholder=\"UUID del prodotto billing\"\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 />\n {!isEditMode && (\n <p className=\"text-xs text-muted-foreground\">\n Se collegato a un prodotto, la feature viene attivata automaticamente\n </p>\n )}\n </div>\n\n {/* Availability checkbox */}\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n id={isEditMode ? 'edit-is_available' : 'is_available'}\n name=\"is_available\"\n defaultChecked={feature?.is_available ?? true}\n className=\"rounded border-input\"\n />\n <label\n className=\"text-sm font-medium leading-none\"\n htmlFor={isEditMode ? 'edit-is_available' : 'is_available'}\n >\n Feature disponibile\n </label>\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"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\"\n onClick={onClose}\n >\n Annulla\n </button>\n <button\n type=\"submit\"\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 disabled={isPending}\n >\n {isPending\n ? isEditMode ? 'Salvataggio...' : 'Creazione...'\n : isEditMode ? 'Salva Modifiche' : 'Crea Feature'}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n","import { Pencil, Trash2 } from 'lucide-react';\nimport type { AdminFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport { StatusBadge } from '../shared/StatusBadge';\n\ninterface FeatureListItemProps {\n feature: AdminFeature;\n onEdit: (feature: AdminFeature) => void;\n onDelete: (feature: AdminFeature) => void;\n}\n\nexport function FeatureListItem({ feature, onEdit, onDelete }: FeatureListItemProps) {\n return (\n <div className=\"border rounded-lg p-4 hover:bg-muted/50 transition-colors\">\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={() => onEdit(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={() => onDelete(feature)}\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n );\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":";AAAA,OAAOA,UAAS,eAAe;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OAEK;;;ACLP,SAAgB,iBAAiB;AA6BzB,SACE,KADF;AAjBD,IAAM,gBAAN,cAA4B,UAAwB;AAAA,EACzD,YAAY,OAAc;AACxB,UAAM,KAAK;AACX,SAAK,QAAQ,EAAE,UAAU,OAAO,OAAO,KAAK;AAAA,EAC9C;AAAA,EAEA,OAAO,yBAAyB,OAAqB;AACnD,WAAO,EAAE,UAAU,MAAM,MAAM;AAAA,EACjC;AAAA,EAEA,kBAAkB,OAAc,WAAkC;AAChE,YAAQ,MAAM,0CAA0C,OAAO,SAAS;AAAA,EAC1E;AAAA,EAEA,SAA0B;AACxB,QAAI,KAAK,MAAM,UAAU;AACvB,aAAO,KAAK,MAAM,YAChB,qBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,OAAO,GAChE;AAAA,4BAAC,OAAE,yDAA2C;AAAA,QAC9C;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,KAAK,SAAS,EAAE,UAAU,OAAO,OAAO,KAAK,CAAC;AAAA,YAC7D,OAAO,EAAE,WAAW,UAAU,QAAQ,UAAU;AAAA,YACjD;AAAA;AAAA,QAED;AAAA,SACF;AAAA,IAEJ;AACA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;;;AD2EQ,gBAAAC,YAAA;AA1ER,IAAM,kBAAkD;AAAA,EACtD,OAAO;AAAA,EACP,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AACZ;AAgCA,IAAM,4BAA4BC,OAAM,cAAyC,IAAI;AAE9E,SAAS,wBAA4C;AAC1D,QAAM,SAASA,OAAM,WAAW,yBAAyB;AACzD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,oBAAoD;AAClE,QAAM,SAAS,sBAAsB;AACrC,SAAO,EAAE,GAAG,iBAAiB,GAAG,OAAO,QAAQ;AACjD;AAOO,SAAS,qBAAqB,EAAE,QAAQ,SAAS,GAA8B;AACpF,QAAM,SAAS;AAAA,IACb,MAAM,yBAAyB;AAAA,MAC7B,UAAU,OAAO;AAAA,MACjB,SAAS,OAAO;AAAA,IAClB,CAAC;AAAA,IACD,CAAC,OAAO,UAAU,OAAO,OAAO;AAAA,EAClC;AAEA,SACE,gBAAAD,KAAC,0BAA0B,UAA1B,EAAmC,OAAO,QACzC,0BAAAA,KAAC,0BAA0B,UAA1B,EAAmC,OAAO,QACzC,0BAAAA,KAAC,iBACE,UACH,GACF,GACF;AAEJ;;;AE3HA,SAAS,YAAAE,iBAAgB;AACzB,SAAS,aAAa;AACtB,SAAS,MAAM,WAAW,kBAAkB;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACXP,SAAS,QAAQ,QAAQ,QAAQ,OAAO,SAAS;AAEjD,SAAS,sBAAsB;;;ACFxB,IAAM,cAAc;AAAA,EACzB,EAAE,OAAO,QAAQ,OAAO,UAAU,WAAW,gEAAgE;AAAA,EAC7G,EAAE,OAAO,SAAS,OAAO,SAAS,WAAW,uEAAuE;AAAA,EACpH,EAAE,OAAO,QAAQ,OAAO,OAAO,WAAW,mEAAmE;AAAA,EAC7G,EAAE,OAAO,UAAU,OAAO,SAAS,WAAW,2EAA2E;AAAA,EACzH,EAAE,OAAO,SAAS,OAAO,SAAS,WAAW,uEAAuE;AAAA,EACpH,EAAE,OAAO,OAAO,OAAO,SAAS,WAAW,+DAA+D;AAAA,EAC1G,EAAE,OAAO,QAAQ,OAAO,QAAQ,WAAW,mEAAmE;AAAA,EAC9G,EAAE,OAAO,UAAU,OAAO,UAAU,WAAW,2EAA2E;AAC5H;AAIO,SAAS,kBAAkB,OAAmC;AACnE,QAAM,QAAQ,YAAY,KAAK,OAAK,EAAE,UAAU,KAAK;AACrD,SAAO,OAAO,aAAa,YAAY,CAAC,EAAE;AAC5C;;;AChBA,SAA0B,YAAY;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ACKI,gBAAAC,YAAA;AAFG,SAAS,YAAY,EAAE,OAAO,YAAY,UAAU,GAAqB;AAC9E,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;ACbI,mBAIQ,OAAAC,YAJR;AAFG,SAAS,aAAa,EAAE,OAAO,GAAG,UAAU,EAAE,GAAsB;AACzE,SACE,gBAAAA,KAAA,YACG,gBAAM,KAAK,EAAE,QAAQ,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,MACpC,gBAAAA,KAAC,QACC,0BAAAA,KAAC,QAAG,SAAS,SAAS,WAAU,OAC9B,0BAAAA,KAAC,SAAI,WAAU,iDAAgD,GACjE,KAHO,CAIT,CACD,GACH;AAEJ;;;AJkBU,SACE,OAAAC,MADF,QAAAC,aAAA;AA5BV,IAAM,qBAA4D;AAAA,EAChE,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,aAAa;AACf;AAWO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,SACE,gBAAAD,KAAC,SAAI,WAAU,iCACb,0BAAAC,MAAC,WAAM,WAAU,iCACf;AAAA,oBAAAD,KAAC,WAAM,WAAU,mBACf,0BAAAC,MAAC,QAAG,WAAU,gDACZ;AAAA,sBAAAD,KAAC,QAAG,WAAU,sEAAqE,kBAAI;AAAA,MACvF,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,kBAAI;AAAA,MACvF,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,oBAAM;AAAA,MACzF,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,qBAAO;AAAA,MAC1F,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,4BAAc;AAAA,MACjG,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,4BAAc;AAAA,MACjG,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,mBAAK;AAAA,MACxF,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,oBAAM;AAAA,MACzF,gBAAAA,KAAC,QAAG,WAAU,sEAAqE,oBAAM;AAAA,MACzF,gBAAAA,KAAC,QAAG,WAAU,uEAAsE,oBAAM;AAAA,OAC5F,GACF;AAAA,IACA,gBAAAA,KAAC,WAAM,WAAU,8BACd,sBACC,gBAAAA,KAAC,gBAAa,MAAM,GAAG,SAAS,IAAI,IAClC,MAAM,WAAW,IACnB,gBAAAA,KAAC,QACC,0BAAAA,KAAC,QAAG,SAAS,IAAI,WAAU,8CAA6C,sCAExE,GACF,IAEA,MAAM,IAAI,CAAC,SACT,gBAAAC,MAAC,QAAiB,WAAU,gDAC1B;AAAA,sBAAAD,KAAC,QAAG,WAAU,oBACZ,0BAAAA,KAAC,UAAK,WAAU,wCAAwC,eAAK,MAAK,GACpE;AAAA,MACA,gBAAAA,KAAC,QAAG,WAAU,gCAAgC,eAAK,MAAK;AAAA,MACxD,gBAAAA,KAAC,QAAG,WAAU,oBACZ,0BAAAA,KAAC,eAAY,OAAO,KAAK,OAAO,YAAY,kBAAkB,KAAK,KAAK,GAAG,GAC7E;AAAA,MACA,gBAAAA,KAAC,QAAG,WAAU,oBACZ,0BAAAA,KAAC,eAAY,OAAO,mBAAmB,KAAK,aAAa,GAAG,YAAW,UAAS,GAClF;AAAA,MACA,gBAAAA,KAAC,QAAG,WAAU,oBACX,eAAK,gBACJ,gBAAAA,KAAC,UAAK,WAAU,yBAAwB,wBAAU,IAElD,eAAe,KAAK,iBAAiB,GAAG,KAAK,QAAQ,GAEzD;AAAA,MACA,gBAAAA,KAAC,QAAG,WAAU,oBACX,eAAK,gBACJ,gBAAAA,KAAC,UAAK,WAAU,yBAAwB,wBAAU,IAElD,eAAe,KAAK,gBAAgB,GAAG,KAAK,QAAQ,GAExD;AAAA,MACA,gBAAAC,MAAC,QAAG,WAAU,oBAAoB;AAAA,aAAK;AAAA,QAAW;AAAA,SAAO;AAAA,MACzD,gBAAAD,KAAC,QAAG,WAAU,oBACX,eAAK,YACJ,gBAAAA,KAAC,SAAM,WAAU,0BAAyB,IAE1C,gBAAAA,KAAC,KAAE,WAAU,iCAAgC,GAEjD;AAAA,MACA,gBAAAA,KAAC,QAAG,WAAU,oBACX,eAAK,0BACJ,gBAAAA,KAAC,eAAY,OAAM,UAAS,YAAW,+CAA8C,IAErF,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,OAAO,KAAK,EAAE;AAAA,UAC7B,UAAU;AAAA,UAEV,0BAAAA,KAAC,UAAO,WAAU,WAAU;AAAA;AAAA,MAC9B,GAEJ;AAAA,MACA,gBAAAA,KAAC,QAAG,WAAU,+BACZ,0BAAAC,MAAC,SAAI,WAAU,0BACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM,OAAO,IAAI;AAAA,YAE1B,0BAAAA,KAAC,UAAO,WAAU,WAAU;AAAA;AAAA,QAC9B;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM,SAAS,IAAI;AAAA,YAE5B,0BAAAA,KAAC,UAAO,WAAU,WAAU;AAAA;AAAA,QAC9B;AAAA,SACF,GACF;AAAA,SA7DO,KAAK,EA8Dd,CACD,GAEL;AAAA,KACF,GACF;AAEJ;;;AKhIA,SAAS,WAAAE,gBAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,eAAe;;;ACMpB,SAUI,OAAAC,MAVJ,QAAAC,aAAA;AAFG,SAAS,aAAa,EAAE,OAAO,SAAS,SAAS,GAAsB;AAC5E,SACE,gBAAAA,MAAC,SAAI,WAAU,2BACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,gBAAc;AAAA,QACd,SAAS,MAAM,SAAS,CAAC,OAAO;AAAA,QAChC,WAAW,4HACT,UAAU,eAAe,UAC3B;AAAA,QAEA,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,sGACT,UAAU,kBAAkB,eAC9B;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,IACA,gBAAAA,KAAC,UAAK,WAAU,oCAAoC,iBAAM;AAAA,KAC5D;AAEJ;;;ACRI,qBAAAE,WAGI,OAAAC,MADF,QAAAC,aAFF;AAPG,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE,gBAAAA,MAAAF,WAAA,EAEE;AAAA,oBAAAE,MAAC,SAAI,WAAU,aACb;AAAA,sBAAAD,KAAC,WAAM,WAAU,oCAAmC,SAAQ,QAAO,oBAAM;AAAA,MACzE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,WAAU;AAAA,UACV,OAAO,SAAS;AAAA,UAChB,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,UAC5C,aAAY;AAAA;AAAA,MACd;AAAA,MACC,WAAW,QAAQ,gBAAAA,KAAC,OAAE,WAAU,4BAA4B,qBAAW,MAAK;AAAA,OAC/E;AAAA,IAGA,gBAAAC,MAAC,SAAI,WAAU,aACb;AAAA,sBAAAD,KAAC,WAAM,WAAU,oCAAmC,SAAQ,eAAc,yBAAW;AAAA,MACrF,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,WAAU;AAAA,UACV,OAAO,SAAS;AAAA,UAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,aAAa,EAAE,OAAO,MAAM,CAAC;AAAA,UACjE,aAAY;AAAA,UACZ,MAAM;AAAA;AAAA,MACR;AAAA,OACF;AAAA,IAGA,gBAAAC,MAAC,SAAI,WAAU,0BACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,0BAAY;AAAA,QAChE,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,OAAO,EAAE,OAAO,MAAM,CAAC;AAAA,YAE1D,sBAAY,IAAI,CAAC,UAChB,gBAAAA,KAAC,YAAyB,OAAO,MAAM,OAAQ,gBAAM,SAAxC,MAAM,KAAwC,CAC5D;AAAA;AAAA,QACH;AAAA,QACA,gBAAAC,MAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,UAChC;AAAA,UACX,gBAAAD,KAAC,UAAK,WAAW,oFAAoF,kBAAkB,SAAS,KAAK,CAAC,IACnI,mBAAS,QAAQ,SACpB;AAAA,WACF;AAAA,SACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,kBACb;AAAA,wBAAAD,KAAC,gBAAa,OAAM,gBAAe,SAAS,SAAS,WAAW,UAAU,CAAC,MAAM,iBAAiB,EAAE,WAAW,EAAE,CAAC,GAAG;AAAA,QACrH,gBAAAA,KAAC,gBAAa,OAAM,yBAAwB,SAAS,SAAS,eAAe,UAAU,CAAC,MAAM,iBAAiB,EAAE,eAAe,EAAE,CAAC,GAAG;AAAA,QACtI,gBAAAA,KAAC,gBAAa,OAAM,wBAAuB,SAAS,SAAS,WAAW,UAAU,CAAC,MAAM,iBAAiB,EAAE,WAAW,EAAE,CAAC,GAAG;AAAA,SAC/H;AAAA,OACF;AAAA,KACF;AAEJ;;;AChEI,qBAAAE,WAIM,OAAAC,MACA,QAAAC,aALN;AAFG,SAAS,mBAAmB,EAAE,UAAU,iBAAiB,GAA4B;AAC1F,SACE,gBAAAA,MAAAF,WAAA,EAEE;AAAA,oBAAAE,MAAC,SAAI,WAAU,0BACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,6BAAe;AAAA,QACnE,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,eAAe,EAAE,OAAO,MAA+B,CAAC;AAAA,YAE5F;AAAA,8BAAAD,KAAC,YAAO,OAAM,QAAO,mBAAK;AAAA,cAC1B,gBAAAA,KAAC,YAAO,OAAM,UAAS,yBAAW;AAAA,cAClC,gBAAAA,KAAC,YAAO,OAAM,YAAW,0BAAS;AAAA,cAClC,gBAAAA,KAAC,YAAO,OAAM,eAAc,uBAAS;AAAA;AAAA;AAAA,QACvC;AAAA,SACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,SAAQ,iBAAgB,4BAAc;AAAA,QAC1F,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,MAAK;AAAA,YACL,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,eAAe,EAAE,OAAO,MAAM,CAAC;AAAA,YACnE,aAAY;AAAA;AAAA,QACd;AAAA,SACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,SAAQ,gBAAe,4BAAc;AAAA,QACzF,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,MAAK;AAAA,YACL,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,cAAc,EAAE,OAAO,MAAM,CAAC;AAAA,YAClE,aAAY;AAAA;AAAA,QACd;AAAA,SACF;AAAA,OACF;AAAA,IAGA,gBAAAC,MAAC,SAAI,WAAU,0BACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,oBAAM;AAAA,QAC1D,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,UAAU,EAAE,OAAO,MAAM,CAAC;AAAA,YAE9D;AAAA,8BAAAD,KAAC,YAAO,OAAM,OAAM,iBAAG;AAAA,cACvB,gBAAAA,KAAC,YAAO,OAAM,OAAM,iBAAG;AAAA,cACvB,gBAAAA,KAAC,YAAO,OAAM,OAAM,iBAAG;AAAA;AAAA;AAAA,QACzB;AAAA,SACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,SAAQ,cAAa,0BAAY;AAAA,QACrF,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,YAAY,SAAS,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;AAAA;AAAA,QACjF;AAAA,SACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,aACb;AAAA,wBAAAD,KAAC,WAAM,WAAU,oCAAmC,SAAQ,cAAa,oBAAM;AAAA,QAC/E,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,MAAM,iBAAiB,EAAE,YAAY,SAAS,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;AAAA;AAAA,QACjF;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;;;ACnEQ,gBAAAE,MAGA,QAAAC,aAHA;AAZD,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AACR,GAAoB;AAClB,SACE,gBAAAA,MAAC,SAAI,WAAU,mCACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,sBAAAD,KAAC,WAAM,SAAS,IAAI,WAAU,oCAC3B,iBACH;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,2BACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAc;AAAA,YACd,SAAS,MAAM,kBAAkB,CAAC,WAAW;AAAA,YAC7C,WAAW,4HACT,cAAc,eAAe,UAC/B;AAAA,YAEA,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,sGACT,cAAc,kBAAkB,eAClC;AAAA;AAAA,YACF;AAAA;AAAA,QACF;AAAA,QACA,gBAAAA,KAAC,UAAK,WAAU,iCAAgC,wBAAU;AAAA,SAC5D;AAAA,OACF;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,UAAU,CAAC,MAAM,cAAc,SAAS,EAAE,OAAO,KAAK,KAAK,GAAG;AAAA,QAC9D,UAAU;AAAA,QACV,WAAU;AAAA;AAAA,IACZ;AAAA,KACF;AAEJ;;;ACzCI,SACE,OAAAE,OADF,QAAAC,aAAA;AAJG,SAAS,kBAAkB,EAAE,aAAa,UAAU,iBAAiB,GAA2B;AACrG,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,SACE,gBAAAA,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD,MAAC,WAAM,WAAU,oCAAmC,0BAAY;AAAA,IAChE,gBAAAA,MAAC,SAAI,WAAU,0BACZ,sBAAY,IAAI,CAAC,UAChB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,IAAI,SAAS,MAAM,GAAG;AAAA,QACtB,OAAO,MAAM;AAAA,QACb,OAAO,SAAS,OAAO,MAAM,GAAG,KAAK,MAAM,gBAAgB;AAAA,QAC3D,aAAa,SAAS,iBAAiB,MAAM,GAAG,KAAK;AAAA,QACrD,eAAe,CAAC,MAAM,iBAAiB,EAAE,QAAQ,EAAE,GAAG,SAAS,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,EAAE,CAAC;AAAA,QACzF,mBAAmB,CAAC,MAAM,iBAAiB,EAAE,kBAAkB,EAAE,GAAG,SAAS,kBAAkB,CAAC,MAAM,GAAG,GAAG,EAAE,EAAE,CAAC;AAAA;AAAA,MAN5G,MAAM;AAAA,IAOb,CACD,GACH;AAAA,KACF;AAEJ;;;AC/BA,SAAS,WAAAE,UAAS,gBAAgB;;;AC2B3B,IAAM,6BAA2D;AAAA,EACtE,KAAK;AAAA,EACL,QACE;AAAA,EACF,IAAI;AAAA,EACJ,QACE;AACJ;AAoBO,SAAS,qBACd,MACA,UACA,cACc;AACd,QAAM,UAAU,YAAY,CAAC,GAAG,SAAS,IAAI;AAC7C,QAAM,MAAM,gBAAgB,CAAC,GAAG,IAAI;AAEpC,MAAI,QAAQ;AACV,QAAI,OAAO,SAAU,QAAO;AAC5B,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAU,QAAO;AAC5B,SAAO;AACT;AASO,SAAS,kBACd,MACA,OACA,UACA,cAIA;AACA,QAAM,kBAAkB,IAAI,IAAI,YAAY,CAAC,CAAC;AAC9C,QAAM,SAAqC,EAAE,GAAI,gBAAgB,CAAC,EAAG;AAErE,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,sBAAgB,OAAO,IAAI;AAC3B,aAAO,OAAO,IAAI;AAClB;AAAA,IACF,KAAK;AACH,sBAAgB,OAAO,IAAI;AAC3B,aAAO,IAAI,IAAI;AACf;AAAA,IACF,KAAK;AACH,sBAAgB,IAAI,IAAI;AAExB,aAAO,OAAO,IAAI;AAClB;AAAA,IACF,KAAK;AACH,sBAAgB,IAAI,IAAI;AACxB,aAAO,IAAI,IAAI;AACf;AAAA,EACJ;AAEA,SAAO;AAAA,IACL,UAAU,MAAM,KAAK,eAAe;AAAA,IACpC,cAAc;AAAA,EAChB;AACF;AASO,SAAS,uBACd,UACA,cAC8B;AAC9B,QAAM,SAAuC;AAAA,IAC3C,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,IAAI;AAAA,IACJ,QAAQ;AAAA,EACV;AAEA,QAAM,QAAQ,oBAAI,IAAY;AAAA,IAC5B,GAAI,YAAY,CAAC;AAAA,IACjB,GAAG,OAAO,KAAK,gBAAgB,CAAC,CAAC;AAAA,EACnC,CAAC;AAED,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,qBAAqB,MAAM,UAAU,YAAY;AAC/D,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO;AACT;;;ACjJA,SAAS,SAAAC,QAAO,aAAa,MAAM,eAAe;AA2ExC,gBAAAC,OACA,QAAAC,aADA;AAlEV,IAAM,eAOF;AAAA,EACF,KAAK;AAAA,IACH,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SACE;AAAA,EACJ;AAAA,EACA,IAAI;AAAA,IACF,OAAO;AAAA,IACP,MAAMC;AAAA,IACN,SACE;AAAA,EACJ;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SACE;AAAA,EACJ;AACF;AAmBO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,SAAS,aAAa,KAAK;AACjC,QAAM,OAAO,OAAO;AAEpB,SACE,gBAAAD,MAAC,SAAI,WAAU,6EACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,kBACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,wBAAAD,MAAC,UAAK,WAAU,gCAAgC,kBAAQ,MAAK;AAAA,QAC7D,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,2EAA2E,OAAO,OAAO;AAAA,YAEpG;AAAA,8BAAAD,MAAC,QAAK,WAAU,gBAAe;AAAA,cAC9B,OAAO;AAAA;AAAA;AAAA,QACV;AAAA,SACF;AAAA,MACC,eACC,gBAAAA,MAAC,OAAE,WAAU,qDACV,uBACH;AAAA,MAEF,gBAAAA,MAAC,UAAK,WAAU,sFACb,gBACH;AAAA,OACF;AAAA,IAEA,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,UAAU,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,KAAqB;AAAA,QAC9D,cAAY,aAAa,IAAI;AAAA,QAC7B,WAAU;AAAA,QAEV;AAAA,0BAAAD,MAAC,YAAO,OAAM,OAAM,OAAO,2BAA2B,KAAK,yBAE3D;AAAA,UACA,gBAAAA,MAAC,YAAO,OAAM,UAAS,OAAO,2BAA2B,QAAQ,oBAEjE;AAAA,UACA,gBAAAA,MAAC,YAAO,OAAM,MAAK,OAAO,2BAA2B,IAAI,qBAEzD;AAAA,UACC,cACC,gBAAAA,MAAC,YAAO,OAAM,UAAS,OAAO,2BAA2B,QAAQ,4BAEjE;AAAA;AAAA;AAAA,IAEJ;AAAA,IAEC,YACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QACV,cAAY,oBAAoB,IAAI;AAAA,QACrC;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;;;AF/CQ,gBAAAG,OAKI,QAAAC,aALJ;AApCD,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6B;AAC3B,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAKlD,QAAM,WAAWC,SAAQ,MAAM;AAC7B,UAAM,MAAM,IAAI,IAAY,kBAAkB,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAChE,eAAW,QAAQ,qBAAsB,KAAI,IAAI,IAAI;AACrD,eAAW,QAAQ,OAAO,KAAK,YAAY,EAAG,KAAI,IAAI,IAAI;AAC1D,WAAO,MAAM,KAAK,GAAG,EAAE,KAAK;AAAA,EAC9B,GAAG,CAAC,mBAAmB,sBAAsB,YAAY,CAAC;AAE1D,QAAM,cAAcA;AAAA,IAClB,MAAM,uBAAuB,sBAAsB,YAAY;AAAA,IAC/D,CAAC,sBAAsB,YAAY;AAAA,EACrC;AAEA,QAAM,eAAe,CAAC,MAAc,SAAuB;AACzD,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,yBAAqB,MAAM;AAAA,EAC7B;AAEA,SACE,gBAAAD,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,qDACb;AAAA,sBAAAD,MAAC,WAAM,WAAU,oCAAmC,uCAEpD;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,mCACZ;AAAA,oBAAY,KAAK,KAChB,gBAAAA,MAAC,UAAK,WAAU,wKACb;AAAA,sBAAY;AAAA,UAAG;AAAA,UAAS,YAAY,OAAO,IAAI,MAAM;AAAA,WACxD;AAAA,QAED,YAAY,SAAS,KACpB,gBAAAA,MAAC,UAAK,WAAU,wKACb;AAAA,sBAAY;AAAA,UAAO;AAAA,WACtB;AAAA,QAED,YAAY,SAAS,KACpB,gBAAAA,MAAC,UAAK,WAAU,kKACb;AAAA,sBAAY;AAAA,UAAO;AAAA,WACtB;AAAA,SAEJ;AAAA,OACF;AAAA,IAEA,gBAAAA,MAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,MACJ,gBAAAD,MAAC,YAAO,yBAAW;AAAA,MAAU;AAAA,MAAI;AAAA,MAC7D,gBAAAA,MAAC,YAAO,oBAAM;AAAA,MAAS;AAAA,MACtB,gBAAAA,MAAC,YAAO,qBAAO;AAAA,MAAS;AAAA,OAEtC;AAAA,IAEA,gBAAAA,MAAC,SAAI,WAAU,iEACZ,mBAAS,WAAW,IACnB,gBAAAA,MAAC,OAAE,WAAU,kDAAiD,+DAE9D,IAEA,SAAS,IAAI,CAAC,SAAS;AACrB,YAAM,UAAU,kBAAkB,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC7D,YAAM,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,MAAM,SAAS;AAAA,UACf,aAAa,SAAS;AAAA,UACtB;AAAA,UACA;AAAA,UACA,UAAU;AAAA;AAAA,QANL;AAAA,MAOP;AAAA,IAEJ,CAAC,GAEL;AAAA,IAEA,gBAAAC,MAAC,SAAI,WAAU,gCACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,OAAO;AAAA,UAC/C,WAAU;AAAA;AAAA,MACZ;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;;;ANCM,gBAAAG,OAGE,QAAAC,cAHF;AAhHC,SAAS,0BAA0B,cAAkC,CAAC,GAAiB;AAC5F,QAAM,SAAiC,CAAC;AACxC,QAAM,kBAA2C,CAAC;AAClD,aAAW,SAAS,aAAa;AAC/B,WAAO,MAAM,GAAG,IAAI,MAAM,gBAAgB;AAC1C,oBAAgB,MAAM,GAAG,IAAI;AAAA,EAC/B;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,eAAe;AAAA,IACf,eAAe;AAAA,IACf,cAAc;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,eAAe;AAAA,IACf,WAAW;AAAA,IACX,OAAO;AAAA,IACP;AAAA,IACA,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,eAAe,CAAC;AAAA,IAChB,YAAY;AAAA,EACd;AACF;AAEA,SAAS,aAAa,MAAsB;AAC1C,SAAO,KACJ,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,UAAU,EAAE;AACzB;AAaO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,SAAS,sBAAsB;AACrC,QAAM,cAAc,OAAO,OAAO,eAAe,CAAC;AAClD,QAAM,iBAAiB,OAAO,OAAO;AACrC,QAAM,aAAa,CAAC;AAEpB,QAAM,EAAE,MAAM,aAAa,IAAI,SAAS;AAAA,IACtC,UAAU,CAAC,kCAAkC;AAAA,IAC7C,SAAS,MAAM,gBAAgB,UAAU,KAAK,QAAQ,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;AAAA,IAC9E,SAAS,CAAC,CAAC,gBAAgB,WAAW,CAAC,CAAC,gBAAgB;AAAA,EAC1D,CAAC;AAED,QAAM,oBAAoB,cAAc,YAAY,CAAC;AAKrD,QAAM,uBAAuBC;AAAA,IAC3B,MACE,SAAS,WACL,SAAS,SACN,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO,IACjB,CAAC;AAAA,IACP,CAAC,SAAS,QAAQ;AAAA,EACpB;AAEA,QAAM,eAAeA;AAAA,IACnB,MAAM,SAAS,iBAAiB,CAAC;AAAA,IACjC,CAAC,SAAS,aAAa;AAAA,EACzB;AAEA,QAAM,mBAAmB,CAAC,SAAiB;AACzC,QAAI,YAAY;AACd,uBAAiB,EAAE,MAAM,MAAM,aAAa,IAAI,EAAE,CAAC;AAAA,IACrD,OAAO;AACL,uBAAiB,EAAE,KAAK,CAAC;AAAA,IAC3B;AAAA,EACF;AAIA,QAAM,2BAA2B,CAAC,SAG5B;AACJ,qBAAiB;AAAA,MACf,UAAU,KAAK,SAAS,KAAK,IAAI;AAAA,MACjC,eAAe,KAAK;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,KAAM,QAAO;AAElB,SACE,gBAAAD,OAAC,SAAI,WAAU,uDACb;AAAA,oBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,MAAM,aAAa,KAAK,GAAG;AAAA,IAC/E,gBAAAC,OAAC,SAAI,WAAU,6GAEb;AAAA,sBAAAA,OAAC,SAAI,WAAU,kCACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,qDACX,yBAAe,mBAAmB,eACrC;AAAA,QACA,gBAAAA,MAAC,OAAE,WAAU,iCACV,yBACG,mDACA,sCACN;AAAA,SACF;AAAA,MAGA,gBAAAC,OAAC,SAAI,WAAU,mBACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc;AAAA;AAAA,QAChB;AAAA,QACA,gBAAAA,MAAC,sBAAmB,UAAoB,kBAAoC;AAAA,QAC5E,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QACC,gBAAgB,WACf,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,sBAAsB;AAAA;AAAA,QACxB;AAAA,SAEJ;AAAA,MAGA,gBAAAC,OAAC,SAAI,WAAU,sEACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM,aAAa,KAAK;AAAA,YAClC;AAAA;AAAA,QAED;AAAA,QACA,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS;AAAA,YACT,UAAU;AAAA,YAET;AAAA,2BAAa,gBAAAD,MAAC,WAAQ,WAAU,6BAA4B;AAAA,cAC5D,eAAe,oBAAoB;AAAA;AAAA;AAAA,QACtC;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;;;ASrNA,SAAS,WAAAG,gBAAe;AAgClB,gBAAAC,OAKE,QAAAC,cALF;AAdC,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAChB,GAA6B;AAC3B,MAAI,CAAC,OAAQ,QAAO;AAEpB,SACE,gBAAAA,OAAC,SAAI,WAAU,uDACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM,aAAa,KAAK;AAAA;AAAA,IACnC;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,+EACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,oDACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,yBAAyB,iBAAM;AAAA,QAC7C,gBAAAA,MAAC,SAAI,WAAU,iCAAiC,uBAAY;AAAA,SAC9D;AAAA,MACA,gBAAAC,OAAC,SAAI,WAAU,sEACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM,aAAa,KAAK;AAAA,YAEhC;AAAA;AAAA,QACH;AAAA,QACA,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS;AAAA,YACT,UAAU;AAAA,YAET;AAAA,4BAAc,gBAAAD,MAACD,UAAA,EAAQ,WAAU,6BAA4B;AAAA,cAC7D;AAAA;AAAA;AAAA,QACH;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;;;AfyHY,SA6CS,YAAAG,WA7CT,OAAAC,OACA,QAAAC,cADA;AA7JL,SAAS,UAAU,EAAE,SAAS,SAAS,OAAO,GAAmB;AACtE,QAAM,SAAS,sBAAsB;AACrC,QAAM,cAAc,OAAO,OAAO,eAAe,CAAC;AAClD,QAAM,oBAAoB,OAAO,OAAO;AAExC,QAAM,aAAa,eAA0B;AAC7C,QAAM,eAAe,eAA0B;AAC/C,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAuB,0BAA0B,WAAW,CAAC;AAC7F,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAiC,CAAC,CAAC;AAEvE,QAAM,EAAE,MAAM,WAAW,QAAQ,IAAI,cAAc;AACnD,QAAM,iBAAiB,cAAc;AACrC,QAAM,iBAAiB,cAAc;AACrC,QAAM,iBAAiB,cAAc;AACrC,QAAM,eAAe,oBAAoB;AAGzC,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAmB,CAAC,CAAC;AACnE,EAAAA,UAAS,MAAM;AACb,QAAI,mBAAmB,WAAW,kBAAkB,SAAS;AAC3D,wBAAkB,QAAQ,EAAE,KAAK,OAAK,mBAAmB,EAAE,iBAAiB,CAAC;AAAA,IAC/E;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,MAAM,SAAS,CAAC;AAE9B,QAAM,YAAY,MAAM;AACtB,gBAAY,0BAA0B,WAAW,CAAC;AAClD,kBAAc,CAAC,CAAC;AAAA,EAClB;AAEA,QAAM,iBAAiB,MAAM;AAC3B,cAAU;AACV,eAAW,KAAK,MAAS;AAAA,EAC3B;AAEA,QAAM,eAAe,CAAC,SAAoB;AACxC,UAAM,aAAa,KAAK,UAAU,CAAC;AACnC,UAAM,SAAiC,CAAC;AACxC,UAAM,kBAA2C,CAAC;AAClD,eAAW,SAAS,aAAa;AAC/B,YAAM,MAAM,WAAW,MAAM,GAAG;AAChC,aAAO,MAAM,GAAG,IAAI,QAAQ,KAAM,MAAM,gBAAgB,IAAM,OAAO,MAAM,gBAAgB;AAC3F,sBAAgB,MAAM,GAAG,IAAI,QAAQ;AAAA,IACvC;AACA,gBAAY;AAAA,MACV,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe,KAAK;AAAA,MACpB,eAAe,KAAK,gBAAgB,KAAK,cAAc,SAAS,IAAI;AAAA,MACpE,cAAc,KAAK,eAAe,KAAK,aAAa,SAAS,IAAI;AAAA,MACjE,UAAU,KAAK;AAAA,MACf,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,eAAe,KAAK;AAAA,MACpB,WAAW,gBAAgB,SAAS,KAAK,IAAI;AAAA,MAC7C,OAAO,KAAK,SAAS;AAAA,MACrB;AAAA,MACA,kBAAkB;AAAA,MAClB,UAAU,KAAK,UAAU,KAAK,IAAI,KAAK;AAAA,MACvC,eAAe,KAAK,iBAAiB,CAAC;AAAA,MACtC,YAAY,KAAK;AAAA,IACnB,CAAC;AACD,eAAW,KAAK,IAAI;AAAA,EACtB;AAEA,QAAM,iBAAiB,MAAe;AACpC,UAAM,SAAiC,CAAC;AACxC,UAAM,UAAU,iBAAiB,SAAS,MAAM,SAAS;AACzD,QAAI,QAAS,QAAO,OAAO;AAC3B,kBAAc,MAAM;AACpB,WAAO,OAAO,KAAK,MAAM,EAAE,WAAW;AAAA,EACxC;AAEA,QAAM,eAAe,YAAY;AAI/B,UAAM,eACJ,SAAS,KAAK,KAAK,KACnB,SAAS,KAAK,YAAY,EAAE,QAAQ,eAAe,GAAG,EAAE,QAAQ,UAAU,EAAE;AAG9E,UAAM,gBAAgB,EAAE,GAAG,UAAU,MAAM,aAAa;AAExD,QAAI,CAAC,eAAe,EAAG;AAEvB,UAAM,SAAiC,CAAC;AACxC,eAAW,SAAS,aAAa;AAC/B,aAAO,MAAM,GAAG,IAAI,cAAc,iBAAiB,MAAM,GAAG,IAAI,KAAM,cAAc,OAAO,MAAM,GAAG,KAAK;AAAA,IAC3G;AAEA,UAAM,WAA8C;AAAA,MAClD,MAAM,cAAc;AAAA,MACpB,MAAM,SAAS;AAAA,MACf,aAAa,SAAS,eAAe;AAAA,MACrC,eAAe,SAAS;AAAA,MACxB,eAAe,SAAS,gBAAgB,WAAW,SAAS,aAAa,IAAI;AAAA,MAC7E,cAAc,SAAS,eAAe,WAAW,SAAS,YAAY,IAAI;AAAA,MAC1E,UAAU,SAAS;AAAA,MACnB,YAAY,SAAS;AAAA,MACrB,WAAW,SAAS;AAAA,MACpB,eAAe,SAAS;AAAA,MACxB,OAAO,SAAS;AAAA,MAChB,QAAQ,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,SAAS;AAAA,MAClD,UAAU,SAAS,SAAS,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA;AAAA;AAAA,MAG9D,eAAe,SAAS,iBAAiB,CAAC;AAAA,MAC1C,YAAY,SAAS;AAAA,IACvB;AAGA,QAAI,mBAAmB,WAAW,kBAAkB,UAAU;AAC5D,YAAM,oBAAoB,gBAAgB,SAAS,cAAc,IAAI;AACrE,UAAI,cAAc,cAAc,mBAAmB;AACjD,YAAI;AACF,gBAAM,WAAW,cAAc,YAC3B,CAAC,GAAG,iBAAiB,cAAc,IAAI,IACvC,gBAAgB,OAAO,CAAC,MAAM,MAAM,cAAc,IAAI;AAC1D,gBAAM,kBAAkB,SAAS,QAAQ;AACzC,6BAAmB,QAAQ;AAAA,QAC7B,QAAQ;AACN,gBAAM,MAAM,wDAAqD;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW,MAAM;AACnB,qBAAe,OAAO,EAAE,IAAI,WAAW,KAAK,IAAI,MAAM,SAAS,GAAG;AAAA,QAChE,WAAW,MAAM;AAAE,gBAAM,QAAQ,+BAA+B;AAAG,qBAAW,MAAM;AAAG,oBAAU;AAAA,QAAG;AAAA,QACpG,SAAS,CAAC,QAAQ,MAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH,OAAO;AACL,qBAAe,OAAO,UAA6B;AAAA,QACjD,WAAW,MAAM;AAAE,gBAAM,QAAQ,2BAA2B;AAAG,qBAAW,MAAM;AAAG,oBAAU;AAAA,QAAG;AAAA,QAChG,SAAS,CAAC,QAAQ,MAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,eAAe,MAAM;AACzB,QAAI,aAAa,MAAM;AACrB,qBAAe,OAAO,aAAa,KAAK,IAAI;AAAA,QAC1C,WAAW,MAAM;AAAE,gBAAM,QAAQ,8BAA8B;AAAG,uBAAa,MAAM;AAAA,QAAG;AAAA,QACxF,SAAS,CAAC,QAAQ,MAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UACJ,gBAAAD,OAAAF,WAAA,EACG;AAAA;AAAA,IACD,gBAAAE,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,qCACb;AAAA,wBAAAA,OAAC,SAAI,WAAU,yDACb;AAAA,0BAAAD,MAAC,cAAW,WAAU,WAAU;AAAA,UAChC,gBAAAC,OAAC,UAAM;AAAA,kBAAM;AAAA,YAAO;AAAA,aAAkB;AAAA,WACxC;AAAA,QACA,gBAAAA,OAAC,SAAI,WAAU,cACb;AAAA,0BAAAA,OAAC,YAAO,WAAU,qIAAoI,SAAS,MAAM,QAAQ,GAC3K;AAAA,4BAAAD,MAAC,aAAU,WAAU,gBAAe;AAAA,YAAE;AAAA,aACxC;AAAA,UACA,gBAAAC,OAAC,YAAO,WAAU,gJAA+I,SAAS,gBACxK;AAAA,4BAAAD,MAAC,QAAK,WAAU,gBAAe;AAAA,YAAE;AAAA,aACnC;AAAA,WACF;AAAA,SACF;AAAA,MAEA,gBAAAA,MAAC,SAAI,WAAU,4DACb,0BAAAA,MAAC,SAAI,WAAU,OACb,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,UAAU,CAAC,SAAS,aAAa,KAAK,IAAI;AAAA,UAC1C,QAAQ,CAAC,OAAO,aAAa,OAAO,IAAI;AAAA,YACtC,WAAW,MAAM,MAAM,QAAQ,gCAAgC;AAAA,YAC/D,SAAS,CAAC,QAAQ,MAAM,MAAM,gBAAgB,IAAI,OAAO,EAAE;AAAA,UAC7D,CAAC;AAAA,UACD,WAAW,aAAa;AAAA;AAAA,MAC1B,GACF,GACF;AAAA,OACF;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,WAAW;AAAA,QACjB,cAAc,CAAC,SAAS;AAAE,cAAI,CAAC,MAAM;AAAE,uBAAW,MAAM;AAAG,sBAAU;AAAA,UAAG;AAAA,QAAE;AAAA,QAC1E;AAAA,QACA,kBAAkB,CAACG,UAAS,YAAY,CAAC,UAAU,EAAE,GAAG,MAAM,GAAGA,MAAK,EAAE;AAAA,QACxE;AAAA,QACA,cAAc,WAAW,QAAQ;AAAA,QACjC,UAAU;AAAA,QACV,WAAW,eAAe,aAAa,eAAe;AAAA;AAAA,IACxD;AAAA,IAEA,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,aAAa;AAAA,QACrB,cAAc,CAAC,SAAS;AAAE,cAAI,CAAC,KAAM,cAAa,MAAM;AAAA,QAAG;AAAA,QAC3D,OAAM;AAAA,QACN,aAAa,gBAAAC,OAAAF,WAAA,EAAE;AAAA;AAAA,UAA4B,gBAAAC,MAAC,YAAQ,uBAAa,MAAM,MAAK;AAAA,UAAS;AAAA,UAAE,gBAAAA,MAAC,UAAM,uBAAa,MAAM,MAAK;AAAA,UAAO;AAAA,WAA0C;AAAA,QACvK,WAAW;AAAA,QACX,YAAY,eAAe;AAAA,QAC3B,cAAa;AAAA;AAAA,IACf;AAAA,KACF;AAGF,SAAO,UAAU,gBAAAA,MAAC,WAAS,mBAAQ,IAAa;AAClD;;;AgB5OA,SAAS,SAAAI,cAAa;AACtB,SAAS,QAAAC,OAAM,aAAAC,YAAW,UAAAC,SAAQ,UAAAC,SAAQ,UAAAC,SAAQ,SAAS,SAAAC,QAAO,KAAAC,UAA2B;AAC7F,SAAS,YAAAC,iBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,OACK;;;ACXP,SAAS,YAAAC,WAAU,iBAAiB;AACpC,SAAS,WAAAC,UAAS,QAAQ,gBAAgB;AAwHpC,gBAAAC,OAEE,QAAAC,cAFF;AApHN,IAAM,gBAAgB,CAAC,KAAa,WAAoC,CAAC,MAA+B;AACtG,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,WAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,CAAC,MAAM,QAAQ,MAAM,IACxE,SACD;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAeO,IAAM,yBAA0C;AAAA,EACrD,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,EACb,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AACd;AAiBO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW,CAAC;AAAA,EACZ;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,CAAC,UAAU,WAAW,IAAIH,UAA0B,sBAAsB;AAChF,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAiC,CAAC,CAAC;AAEvE,YAAU,MAAM;AACd,QAAI,QAAQ;AACV,UAAI,SAAS,UAAU,SAAS;AAC9B,cAAM,cAAc,QAAQ,YAAY,gBAA0B;AAClE,oBAAY;AAAA,UACV,MAAM,QAAQ;AAAA,UACd,aAAa,QAAQ,eAAe;AAAA,UACpC,cAAc,QAAQ,cAAc,KAAK,SAAS;AAAA,UAClD,UAAU,QAAQ;AAAA,UAClB,oBAAoB,QAAQ,sBAAsB;AAAA,UAClD,UAAU,QAAQ,YAAY;AAAA,UAC9B,WAAW,QAAQ;AAAA,UACnB,aAAa;AAAA,UACb,cAAc;AAAA,UACd,YAAY,QAAQ,aAAa,KAAK,UAAU,QAAQ,YAAY,MAAM,CAAC,IAAI;AAAA,QACjF,CAAC;AAAA,MACH,OAAO;AACL,oBAAY,sBAAsB;AAAA,MACpC;AACA,oBAAc,CAAC,CAAC;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,OAAO,CAAC;AAE1B,YAAU,MAAM;AACd,QAAI,SAAS,cAAc;AACzB,kBAAY,UAAQ;AAClB,cAAM,aAAa,cAAc,KAAK,UAAU;AAChD,cAAM,UAAU,EAAE,GAAG,YAAY,cAAc,SAAS,aAAa;AACrE,eAAO,EAAE,GAAG,MAAM,YAAY,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;AAAA,MACjE,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,SAAS,YAAY,CAAC;AAE1B,QAAM,eAAe,MAAe;AAClC,UAAM,SAAiC,CAAC;AACxC,QAAI,CAAC,SAAS,KAAK,KAAK,EAAG,QAAO,OAAO;AACzC,QAAI,CAAC,SAAS,eAAe,WAAW,SAAS,WAAW,IAAI,EAAG,QAAO,cAAc;AAGxF,QAAI;AAAE,WAAK,MAAM,SAAS,UAAU;AAAA,IAAG,QAAQ;AAAE,aAAO,aAAa;AAAA,IAAkC;AACvG,kBAAc,MAAM;AACpB,WAAO,OAAO,KAAK,MAAM,EAAE,WAAW;AAAA,EACxC;AAEA,QAAM,eAAe,MAAM;AACzB,QAAI,aAAa,EAAG,UAAS,QAAQ;AAAA,EACvC;AAEA,MAAI,CAAC,OAAQ,QAAO;AAEpB,SACE,gBAAAG,OAAC,SAAI,WAAU,uDACb;AAAA,oBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,MAAM,aAAa,KAAK,GAAG;AAAA,IAC/E,gBAAAC,OAAC,SAAI,WAAU,4GACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,kCACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,yBAAyB,mBAAS,WAAW,mBAAmB,qBAAoB;AAAA,QAClG,gBAAAA,MAAC,OAAE,WAAU,iCACV,mBAAS,WAAW,kDAAkD,qDACzE;AAAA,SACF;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,mBACb;AAAA,wBAAAA,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,oBAAM;AAAA,UAC1D,gBAAAA,MAAC,WAAM,WAAU,6LAA4L,OAAO,SAAS,MAAM,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,MAAM,EAAE,OAAO,MAAM,CAAC,GAAG,aAAY,+BAA8B;AAAA,UACjV,WAAW,QAAQ,gBAAAA,MAAC,OAAE,WAAU,4BAA4B,qBAAW,MAAK;AAAA,WAC/E;AAAA,QAEA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,yBAAW;AAAA,UAC/D,gBAAAA,MAAC,cAAS,WAAU,qMAAoM,OAAO,SAAS,aAAa,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,aAAa,EAAE,OAAO,MAAM,CAAC,GAAG,MAAM,GAAG;AAAA,WAC5U;AAAA,QAEA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAA,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,oBAAM;AAAA,YAC1D,gBAAAA,MAAC,WAAM,MAAK,UAAS,MAAK,QAAO,WAAU,2JAA0J,OAAO,SAAS,aAAa,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,aAAa,EAAE,OAAO,MAAM,CAAC,GAAG,aAAY,SAAQ;AAAA,YACjU,WAAW,eAAe,gBAAAA,MAAC,OAAE,WAAU,4BAA4B,qBAAW,aAAY;AAAA,aAC7F;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,oBAAM;AAAA,YAC1D,gBAAAC,OAAC,YAAO,WAAU,2JAA0J,OAAO,SAAS,UAAU,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,UAAU,EAAE,OAAO,MAAM,CAAC,GAC1Q;AAAA,8BAAAD,MAAC,YAAO,OAAM,OAAM,iBAAG;AAAA,cACvB,gBAAAA,MAAC,YAAO,OAAM,OAAM,iBAAG;AAAA,cACvB,gBAAAA,MAAC,YAAO,OAAM,OAAM,iBAAG;AAAA,eACzB;AAAA,aACF;AAAA,WACF;AAAA,QAEA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAA,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,wBAAU;AAAA,YAC9D,gBAAAC,OAAC,YAAO,WAAU,2JAA0J,OAAO,SAAS,sBAAsB,YAAY,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,oBAAoB,EAAE,OAAO,UAAU,aAAa,KAAM,EAAE,OAAO,MAA4B,CAAC,GACxW;AAAA,8BAAAD,MAAC,YAAO,OAAM,YAAW,wBAAU;AAAA,cACnC,gBAAAA,MAAC,YAAO,OAAM,SAAQ,qBAAO;AAAA,cAC7B,gBAAAA,MAAC,YAAO,OAAM,QAAO,qBAAO;AAAA,eAC9B;AAAA,aACF;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,uBAAS;AAAA,YAC7D,gBAAAC,OAAC,YAAO,WAAU,2JAA0J,OAAO,SAAS,UAAU,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,UAAU,EAAE,OAAO,MAAM,CAAC,GAC1Q;AAAA,8BAAAD,MAAC,YAAO,OAAM,WAAU,qBAAO;AAAA,cAC/B,gBAAAA,MAAC,YAAO,OAAM,SAAQ,oBAAM;AAAA,cAC5B,gBAAAA,MAAC,YAAO,OAAM,WAAU,sBAAQ;AAAA,cAChC,gBAAAA,MAAC,YAAO,OAAM,WAAU,qBAAO;AAAA,eACjC;AAAA,aACF;AAAA,WACF;AAAA,QAEA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,aAAU,OAAM,mBAAkB,SAAS,SAAS,WAAW,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,WAAW,EAAE,CAAC,GAAG;AAAA,UAC5H,SAAS,YACR,gBAAAA,MAAC,aAAU,OAAM,yBAAwB,SAAS,SAAS,aAAa,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,aAAa,EAAE,CAAC,GAAG;AAAA,WAE3I;AAAA,QAEC,SAAS,SAAS,KACjB,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,+BAAiB;AAAA,UACrE,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,SAAS,gBAAgB;AAAA,cAChC,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,cAAc,EAAE,OAAO,UAAU,SAAS,KAAK,EAAE,OAAO,MAAM,CAAC;AAAA,cAE3G;AAAA,gCAAAD,MAAC,YAAO,OAAM,QAAO,6BAAe;AAAA,gBACnC,SAAS,IAAI,CAAC,MACb,gBAAAC,OAAC,YAAoB,OAAO,EAAE,MAAO;AAAA,oBAAE;AAAA,kBAAK;AAAA,kBAAG,EAAE;AAAA,kBAAK;AAAA,qBAAzC,EAAE,IAAwC,CACxD;AAAA;AAAA;AAAA,UACH;AAAA,UACC,SAAS,gBACR,gBAAAA,OAAC,SAAI,WAAU,iFACb;AAAA,4BAAAD,MAAC,YAAS,WAAU,yBAAwB;AAAA,YAC5C,gBAAAC,OAAC,UAAK,WAAU,iBAAgB;AAAA;AAAA,cAAa,gBAAAD,MAAC,YAAQ,mBAAS,cAAa;AAAA,eAAS;AAAA,aACvF;AAAA,WAEJ;AAAA,QAGF,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,+BAAiB;AAAA,UACrE,gBAAAA,MAAC,cAAS,WAAU,6KAA4K,OAAO,SAAS,YAAY,UAAU,CAAC,MAAM,YAAY,EAAE,GAAG,UAAU,YAAY,EAAE,OAAO,MAAM,CAAC,GAAG,MAAM,GAAG;AAAA,UAC/S,WAAW,cAAc,gBAAAA,MAAC,OAAE,WAAU,4BAA4B,qBAAW,YAAW;AAAA,WAC3F;AAAA,SACF;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,sEACb;AAAA,wBAAAD,MAAC,YAAO,WAAU,wJAAuJ,SAAS,MAAM,aAAa,KAAK,GAAG,qBAAO;AAAA,QACpN,gBAAAC,OAAC,YAAO,WAAU,oKAAmK,SAAS,cAAc,UAAU,cACnN;AAAA,0BAAgB,gBAAAD,MAACD,UAAA,EAAQ,WAAU,6BAA4B;AAAA,UAC/D,SAAS,WAAW,kBAAkB;AAAA,WACzC;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,UAAU,EAAE,OAAO,SAAS,SAAS,GAAwE;AACpH,SACE,gBAAAE,OAAC,SAAI,WAAU,2BACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QAAO,MAAK;AAAA,QAAS,MAAK;AAAA,QAAS,gBAAc;AAAA,QAAS,SAAS,MAAM,SAAS,CAAC,OAAO;AAAA,QACzF,WAAW,uHAAuH,UAAU,eAAe,UAAU;AAAA,QACrK,0BAAAA,MAAC,UAAK,WAAW,+FAA+F,UAAU,kBAAkB,eAAe,IAAI;AAAA;AAAA,IACjK;AAAA,IACA,gBAAAA,MAAC,UAAK,WAAU,oCAAoC,iBAAM;AAAA,KAC5D;AAEJ;;;ADxIY,SAoF8I,YAAAE,WApF9I,OAAAC,OAA+B,QAAAC,cAA/B;AA5EL,SAAS,aAAa,EAAE,SAAS,SAAS,OAAO,GAAsB;AAC5E,QAAM,SAAS,sBAAsB;AACrC,QAAM,iBAAiB,OAAO,UAAU;AAExC,QAAM,eAAeC,gBAAe;AACpC,QAAM,aAAaA,gBAA6B;AAChD,QAAM,eAAeA,gBAA6B;AAElD,QAAM,EAAE,MAAM,WAAW,QAAQ,IAAI,iBAAiB,EAAE,WAAW,KAAK,CAAC;AACzE,QAAM,iBAAiB,iBAAiB;AACxC,QAAM,iBAAiB,iBAAiB;AACxC,QAAM,iBAAiB,iBAAiB;AACxC,QAAM,eAAe,uBAAuB;AAE5C,QAAM,EAAE,MAAM,aAAa,IAAIC,UAAS;AAAA,IACtC,UAAU,CAAC,gCAAgC;AAAA,IAC3C,SAAS,MAAM,gBAAgB,UAAU,KAAK,QAAQ,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;AAAA,IAC9E,SAAS,CAAC,CAAC,gBAAgB,WAAW,CAAC,CAAC,gBAAgB;AAAA,EAC1D,CAAC;AAED,QAAM,WAAW,MAAM,SAAS,CAAC;AACjC,QAAM,WAAW,cAAc,YAAY,CAAC;AAE5C,QAAM,qBAAqB,CAAC,aAA8B;AACxD,UAAM,aAAa,KAAK,MAAM,WAAW,SAAS,WAAW,IAAI,GAAG;AACpE,UAAM,aAAiC;AAAA,MACrC,MAAM,SAAS;AAAA,MACf,aAAa,SAAS,eAAe;AAAA,MACrC,aAAa;AAAA,MACb,UAAU,SAAS;AAAA,MACnB,oBAAoB,SAAS,sBAAsB;AAAA,MACnD,UAAU,SAAS,YAAY;AAAA,MAC/B,WAAW,SAAS;AAAA,MACpB,aAAa,SAAS;AAAA,MACtB,YAAY,KAAK,MAAM,SAAS,UAAU;AAAA,IAC5C;AACA,mBAAe,OAAO,YAAY;AAAA,MAChC,WAAW,MAAM;AAAE,QAAAC,OAAM,QAAQ,iBAAiB;AAAG,qBAAa,MAAM;AAAA,MAAG;AAAA,MAC3E,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,IACxD,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,CAAC,aAA8B;AACtD,QAAI,CAAC,WAAW,KAAM;AACtB,UAAM,aAAa,KAAK,MAAM,WAAW,SAAS,WAAW,IAAI,GAAG;AACpE,UAAM,aAAiC;AAAA,MACrC,MAAM,SAAS;AAAA,MACf,aAAa,SAAS,eAAe;AAAA,MACrC,aAAa;AAAA,MACb,UAAU,SAAS;AAAA,MACnB,oBAAoB,SAAS,sBAAsB;AAAA,MACnD,UAAU,SAAS,YAAY;AAAA,MAC/B,WAAW,SAAS;AAAA,MACpB,YAAY,KAAK,MAAM,SAAS,UAAU;AAAA,IAC5C;AACA,mBAAe,OAAO,EAAE,IAAI,WAAW,KAAK,IAAI,MAAM,WAAW,GAAG;AAAA,MAClE,WAAW,MAAM;AAAE,QAAAA,OAAM,QAAQ,qBAAqB;AAAG,mBAAW,MAAM;AAAA,MAAG;AAAA,MAC7E,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,IACxD,CAAC;AAAA,EACH;AAEA,QAAM,sBAAsB,MAAM;AAChC,QAAI,aAAa,MAAM;AACrB,qBAAe,OAAO,aAAa,KAAK,IAAI;AAAA,QAC1C,WAAW,MAAM;AAAE,UAAAA,OAAM,QAAQ,sBAAsB;AAAG,uBAAa,MAAM;AAAA,QAAG;AAAA,QAChF,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UACJ,gBAAAH,OAAAF,WAAA,EACG;AAAA;AAAA,IACD,gBAAAE,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,qCACb;AAAA,wBAAAA,OAAC,SAAI,WAAU,yDACb;AAAA,0BAAAD,MAAC,WAAQ,WAAU,WAAU;AAAA,UAAE,gBAAAC,OAAC,UAAM;AAAA,qBAAS;AAAA,YAAO;AAAA,aAAqB;AAAA,WAC7E;AAAA,QACA,gBAAAA,OAAC,SAAI,WAAU,cACb;AAAA,0BAAAA,OAAC,YAAO,WAAU,qIAAoI,SAAS,MAAM,QAAQ,GAC3K;AAAA,4BAAAD,MAACK,YAAA,EAAU,WAAU,gBAAe;AAAA,YAAE;AAAA,aACxC;AAAA,UACA,gBAAAJ,OAAC,YAAO,WAAU,gJAA+I,SAAS,MAAM,aAAa,KAAK,GAChM;AAAA,4BAAAD,MAACM,OAAA,EAAK,WAAU,gBAAe;AAAA,YAAE;AAAA,aACnC;AAAA,WACF;AAAA,SACF;AAAA,MAEA,gBAAAN,MAAC,SAAI,WAAU,uCACb,0BAAAA,MAAC,SAAI,WAAU,iCACb,0BAAAC,OAAC,WAAM,WAAU,iCACf;AAAA,wBAAAD,MAAC,WAAM,WAAU,mBACf,0BAAAC,OAAC,QAAG,WAAU,8BACZ;AAAA,0BAAAD,MAAC,QAAG,WAAU,yDAAwD,kBAAI;AAAA,UAC1E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,uBAAS;AAAA,UAC/E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,oBAAM;AAAA,UAC5E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,wBAAU;AAAA,UAChF,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,oBAAM;AAAA,UAC5E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,oBAAM;AAAA,UAC5E,gBAAAA,MAAC,QAAG,WAAU,0DAAyD,oBAAM;AAAA,WAC/E,GACF;AAAA,QACA,gBAAAA,MAAC,WACE,sBACC,gBAAAA,MAAC,gBAAa,MAAM,GAAG,SAAS,GAAG,IACjC,SAAS,WAAW,IACtB,gBAAAA,MAAC,QAAG,0BAAAA,MAAC,QAAG,SAAS,GAAG,WAAU,8CAA6C,yCAA2B,GAAK,IAE3G,SAAS,IAAI,CAAC,YAAY;AACxB,gBAAM,aAAa,CAAC,CAAC,QAAQ,YAAY;AACzC,iBACE,gBAAAC,OAAC,QAAoB,WAAU,8BAC7B;AAAA,4BAAAD,MAAC,QAAG,WAAU,OACZ,0BAAAC,OAAC,SACC;AAAA,8BAAAA,OAAC,SAAI,WAAU,2BACb;AAAA,gCAAAD,MAAC,UAAK,WAAU,eAAe,kBAAQ,MAAK;AAAA,gBAC3C,cAAc,gBAAAA,MAAC,eAAY,OAAM,WAAU,YAAW,4CAA2C;AAAA,iBACpG;AAAA,cACC,QAAQ,eAAe,gBAAAA,MAAC,SAAI,WAAU,mDAAmD,kBAAQ,aAAY;AAAA,eAChH,GACF;AAAA,YACA,gBAAAA,MAAC,QAAG,WAAU,OAAM,0BAAAA,MAAC,eAAY,OAAO,QAAQ,YAAY,WAAW,YAAW,UAAS,GAAE;AAAA,YAC7F,gBAAAA,MAAC,QAAG,WAAU,OAAO,kCAAwB,QAAQ,aAAa,QAAQ,QAAQ,GAAE;AAAA,YACpF,gBAAAA,MAAC,QAAG,WAAU,OACX,kBAAQ,qBACP,gBAAAA,MAAC,eAAY,OAAO,QAAQ,uBAAuB,UAAU,YAAY,QAAQ,uBAAuB,SAAS,YAAY,QAAQ,oBAAoB,YAAW,6DAA4D,IAEhO,gBAAAA,MAAC,UAAK,WAAU,yBAAwB,wBAAU,GAEtD;AAAA,YACA,gBAAAA,MAAC,QAAG,WAAU,OACX,kBAAQ,YAAY,gBAAAA,MAACO,QAAA,EAAM,WAAU,0BAAyB,IAAK,gBAAAP,MAACQ,IAAA,EAAE,WAAU,iCAAgC,GACnH;AAAA,YACA,gBAAAR,MAAC,QAAG,WAAU,OACX,kBAAQ,oBACP,gBAAAA,MAAC,eAAY,OAAM,UAAS,YAAW,+CAA8C,IAErF,gBAAAA,MAAC,YAAO,WAAU,8EAA6E,SAAS,MAAM,aAAa,OAAO,QAAQ,IAAI,EAAE,WAAW,MAAMI,OAAM,QAAQ,eAAe,GAAG,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE,EAAE,CAAC,GAAG,UAAU,aAAa,WAClR,0BAAAJ,MAACS,SAAA,EAAO,WAAU,WAAU,GAC9B,GAEJ;AAAA,YACA,gBAAAT,MAAC,QAAG,WAAU,kBACZ,0BAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,8BAAAD,MAAC,YAAO,WAAU,8EAA6E,SAAS,MAAM,WAAW,KAAK,OAAO,GAAG,0BAAAA,MAACU,SAAA,EAAO,WAAU,WAAU,GAAE;AAAA,cACtK,gBAAAV,MAAC,YAAO,WAAU,+FAA8F,SAAS,MAAM,aAAa,KAAK,OAAO,GAAG,0BAAAA,MAACW,SAAA,EAAO,WAAU,WAAU,GAAE;AAAA,eAC3L,GACF;AAAA,eApCO,QAAQ,EAqCjB;AAAA,QAEJ,CAAC,GAEL;AAAA,SACF,GACF,GACF;AAAA,OACF;AAAA,IAEA,gBAAAX,MAAC,qBAAkB,QAAQ,aAAa,QAAQ,cAAc,CAAC,SAAS,OAAO,aAAa,KAAK,IAAI,aAAa,MAAM,GAAG,MAAK,UAAS,UAAoB,UAAU,oBAAoB,cAAc,eAAe,WAAW;AAAA,IACnO,gBAAAA,MAAC,qBAAkB,QAAQ,WAAW,QAAQ,cAAc,CAAC,SAAS,OAAO,WAAW,KAAK,WAAW,IAAI,IAAI,WAAW,MAAM,GAAG,MAAK,QAAO,SAAS,WAAW,MAAM,UAAoB,UAAU,kBAAkB,cAAc,eAAe,WAAW;AAAA,IAClQ,gBAAAA,MAAC,uBAAoB,QAAQ,aAAa,QAAQ,cAAc,CAAC,SAAS,CAAC,QAAQ,aAAa,MAAM,GAAG,OAAM,yBAAwB,aAAa,gBAAAC,OAAAF,WAAA,EAAE;AAAA;AAAA,MAAiC,gBAAAC,MAAC,YAAQ,uBAAa,MAAM,MAAK;AAAA,MAAS;AAAA,OAAwC,GAAK,WAAW,qBAAqB,YAAY,eAAe,WAAW,cAAa,sBAAqB;AAAA,KACxX;AAGF,SAAO,UAAU,gBAAAA,MAAC,WAAS,mBAAQ,IAAa;AAClD;;;AE7LA,SAAS,YAAAY,iBAAgB;AACzB,SAAS,SAAAC,cAAa;AACtB,SAA4B,KAAK,SAAS,YAAY,UAAU,YAAY;AAC5E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACTP,SAAS,QAAQ,aAAAC,kBAAiB;AA8BxB,SACE,OAAAC,OADF,QAAAC,cAAA;AAbH,SAAS,UAAU;AAAA,EACxB,oBAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,SACE,gBAAAD,MAAC,SAAI,WAAU,4DACb,0BAAAA,MAAC,SAAI,WAAU,YACb,0BAAAC,OAAC,SAAI,WAAU,mCACb;AAAA,oBAAAA,OAAC,SAAI,WAAU,mBACb;AAAA,sBAAAD,MAAC,UAAO,WAAU,0EAAyE;AAAA,MAC3F,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,aAAa;AAAA,UACb,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA;AAAA,MAChD;AAAA,OACF;AAAA,IACC,iBAAiB,wBAChB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,gBAAgB;AAAA,QACvB,UAAU,CAAC,MAAM,qBAAqB,EAAE,OAAO,KAAK;AAAA,QAEnD,wBAAc,IAAI,CAAC,QAClB,gBAAAA,MAAC,YAAuB,OAAO,IAAI,OAChC,cAAI,SADM,IAAI,KAEjB,CACD;AAAA;AAAA,IACH;AAAA,IAEF,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QAET;AAAA,0BAAAD,MAACD,YAAA,EAAU,WAAU,gBAAe;AAAA,UAAE;AAAA;AAAA;AAAA,IAExC;AAAA,KACF,GACF,GACF;AAEJ;;;ADNI,qBAAAG,WAGI,OAAAC,OAYE,QAAAC,cAfN;AArCJ,IAAM,sBAAsB;AAAA,EAC1B,EAAE,OAAO,OAAO,OAAO,kBAAkB;AAAA,EACzC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,EACnC,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,EACvC,EAAE,OAAO,YAAY,OAAO,UAAU;AAAA,EACtC,EAAE,OAAO,YAAY,OAAO,aAAa;AAAA,EACzC,EAAE,OAAO,UAAU,OAAO,aAAa;AACzC;AAEO,SAAS,kBAAkB,EAAE,SAAS,SAAS,OAAO,GAA2B;AACtF,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,EAAE;AACvC,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AACtD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAmC,IAAI;AAC7E,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAS,KAAK;AAC9D,QAAM,CAAC,mBAAmB,oBAAoB,IAAIA,UAAS,IAAI;AAE/D,QAAM,EAAE,MAAM,WAAW,QAAQ,IAAI,sBAAsB;AAAA,IACzD,QAAQ,UAAU;AAAA,IAClB,QAAQ,iBAAiB,QAAS,eAA2C;AAAA,IAC7E,OAAO;AAAA,EACT,CAAC;AACD,QAAM,iBAAiB,sBAAsB;AAE7C,QAAM,gBAAgB,MAAM,SAAS,CAAC;AACtC,QAAM,QAAQ,MAAM,SAAS;AAE7B,QAAM,eAAe,MAAM;AACzB,QAAI,aAAa;AACf,qBAAe,OAAO,EAAE,IAAI,YAAY,IAAI,aAAa,kBAAkB,GAAG;AAAA,QAC5E,WAAW,MAAM;AAAE,UAAAC,OAAM,QAAQ,wBAAwB;AAAG,8BAAoB,KAAK;AAAG,yBAAe,IAAI;AAAA,QAAG;AAAA,QAC9G,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UACJ,gBAAAF,OAAAF,WAAA,EACG;AAAA;AAAA,IACD,gBAAAE,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,mBAAkB;AAAA,UAClB,aAAa;AAAA,UACb,gBAAgB;AAAA,UAChB;AAAA,UACA,sBAAsB;AAAA,UACtB,eAAe;AAAA,UACf,WAAW;AAAA;AAAA,MACb;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,yDACb;AAAA,wBAAAD,MAAC,cAAW,WAAU,WAAU;AAAA,QAChC,gBAAAC,OAAC,UAAM;AAAA;AAAA,UAAM;AAAA,UAAY,UAAU,IAAI,MAAM;AAAA,UAAI;AAAA,WAAQ;AAAA,SAC3D;AAAA,MAEA,gBAAAD,MAAC,SAAI,WAAU,uCACb,0BAAAA,MAAC,SAAI,WAAU,iCACb,0BAAAC,OAAC,WAAM,WAAU,iCACf;AAAA,wBAAAD,MAAC,WAAM,WAAU,mBACf,0BAAAC,OAAC,QAAG,WAAU,8BACZ;AAAA,0BAAAD,MAAC,QAAG,WAAU,yDAAwD,wBAAU;AAAA,UAChF,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,mBAAK;AAAA,UAC3E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,mBAAK;AAAA,UAC3E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,mBAAK;AAAA,UAC3E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,qBAAO;AAAA,UAC7E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,uBAAS;AAAA,UAC/E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,oBAAM;AAAA,UAC5E,gBAAAA,MAAC,QAAG,WAAU,0DAAyD,oBAAM;AAAA,WAC/E,GACF;AAAA,QACA,gBAAAA,MAAC,WACE,sBACC,gBAAAA,MAAC,gBAAa,MAAM,GAAG,SAAS,GAAG,IACjC,cAAc,WAAW,IAC3B,gBAAAA,MAAC,QAAG,0BAAAA,MAAC,QAAG,SAAS,GAAG,WAAU,8CAA6C,wCAA0B,GAAK,IAE1G,cAAc,IAAI,CAAC,QACjB,gBAAAC,OAAC,QAAgB,WAAU,8BACzB;AAAA,0BAAAD,MAAC,QAAG,WAAU,OACZ,0BAAAC,OAAC,SAAI,WAAU,iBACb;AAAA,4BAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,kBAAiB;AAAA,YACpD,gBAAAA,MAAC,UAAK,WAAU,iCAAiC,cAAI,wBAAuB;AAAA,aAC9E,GACF;AAAA,UACA,gBAAAC,OAAC,QAAG,WAAU,OACZ;AAAA,4BAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,WAAU;AAAA,YAC7C,gBAAAC,OAAC,UAAK,WAAU,sCAAqC;AAAA;AAAA,cAAE,IAAI;AAAA,cAAU;AAAA,eAAC;AAAA,aACxE;AAAA,UACA,gBAAAD,MAAC,QAAG,WAAU,OAAM,0BAAAA,MAAC,eAAY,OAAO,yBAAyB,IAAI,MAAM,GAAG,YAAY,yBAAyB,IAAI,MAAM,GAAG,GAAE;AAAA,UAClI,gBAAAA,MAAC,QAAG,WAAU,kBAAkB,cAAI,eAAc;AAAA,UAClD,gBAAAC,OAAC,QAAG,WAAU,eAAe;AAAA,uBAAW,IAAI,oBAAoB;AAAA,YAAE;AAAA,YAAI,WAAW,IAAI,kBAAkB;AAAA,aAAE;AAAA,UACzG,gBAAAD,MAAC,QAAG,WAAU,OAAO,qBAAW,IAAI,SAAS,GAAE;AAAA,UAC/C,gBAAAA,MAAC,QAAG,WAAU,OAAO,qBAAW,IAAI,UAAU,GAAE;AAAA,UAChD,gBAAAA,MAAC,QAAG,WAAU,kBACZ,0BAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,4BAAAD,MAAC,YAAO,WAAU,8EAA6E,SAAS,MAAM;AAAE,6BAAe,GAAG;AAAG,6BAAe,IAAI;AAAA,YAAG,GACzJ,0BAAAA,MAAC,OAAI,WAAU,WAAU,GAC3B;AAAA,YACC,IAAI,WAAW,cACd,gBAAAA,MAAC,YAAO,WAAU,+FAA8F,SAAS,MAAM;AAAE,6BAAe,GAAG;AAAG,kCAAoB,IAAI;AAAA,YAAG,GAC/K,0BAAAA,MAAC,WAAQ,WAAU,WAAU,GAC/B;AAAA,aAEJ,GACF;AAAA,aA3BO,IAAI,EA4Bb,CACD,GAEL;AAAA,SACF,GACF,GACF;AAAA,OACF;AAAA,IAGC,eAAe,eACd,gBAAAC,OAAC,SAAI,WAAU,uDACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,MAAM,eAAe,KAAK,GAAG;AAAA,MACjF,gBAAAC,OAAC,SAAI,WAAU,+EACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,8BAA6B,kCAAoB;AAAA,QAC/D,gBAAAA,MAAC,OAAE,WAAU,sCAAqC,mCAAqB;AAAA,QACvE,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAA,OAAC,SAAI,WAAU,0BACb;AAAA,4BAAAA,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,iCAAgC,wBAAU;AAAA,cACvD,gBAAAC,OAAC,SAAI,WAAU,gCAA+B;AAAA,gCAAAD,MAAC,QAAK,WAAU,iCAAgC;AAAA,gBAAE,gBAAAA,MAAC,UAAK,WAAU,eAAe,sBAAY,kBAAiB;AAAA,iBAAO;AAAA,cACnK,gBAAAC,OAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,gBAAK,YAAY;AAAA,iBAAuB;AAAA,eAC5F;AAAA,YACA,gBAAAA,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,iCAAgC,mBAAK;AAAA,cAClD,gBAAAC,OAAC,SAAI,WAAU,gCAA+B;AAAA,gCAAAD,MAAC,cAAW,WAAU,iCAAgC;AAAA,gBAAE,gBAAAA,MAAC,UAAK,WAAU,eAAe,sBAAY,WAAU;AAAA,iBAAO;AAAA,eACpK;AAAA,aACF;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,4BAAAA,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,iCAAgC,mBAAK;AAAA,cAClD,gBAAAA,MAAC,eAAY,OAAO,yBAAyB,YAAY,MAAM,GAAG,YAAY,yBAAyB,YAAY,MAAM,GAAG,WAAU,QAAO;AAAA,eAC/I;AAAA,YACA,gBAAAC,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,iCAAgC,mBAAK;AAAA,cAClD,gBAAAA,MAAC,OAAE,WAAU,+BAA+B,sBAAY,eAAc;AAAA,eACxE;AAAA,aACF;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,4BAAAA,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,iCAAgC,qBAAO;AAAA,cACpD,gBAAAC,OAAC,SAAI,WAAU,gCAA+B;AAAA,gCAAAD,MAAC,YAAS,WAAU,iCAAgC;AAAA,gBAAE,gBAAAC,OAAC,UAAM;AAAA,6BAAW,YAAY,oBAAoB;AAAA,kBAAE;AAAA,kBAAI,WAAW,YAAY,kBAAkB;AAAA,mBAAE;AAAA,iBAAO;AAAA,eAChN;AAAA,YACA,gBAAAA,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,iCAAgC,wBAAU;AAAA,cACvD,gBAAAA,MAAC,OAAE,WAAU,QAAQ,qBAAW,YAAY,SAAS,GAAE;AAAA,eACzD;AAAA,aACF;AAAA,UACC,YAAY,eACX,gBAAAC,OAAC,SAAI,WAAU,oCACb;AAAA,4BAAAA,OAAC,OAAE,WAAU,wCAAuC;AAAA;AAAA,cAAe,WAAW,YAAY,WAAW;AAAA,eAAE;AAAA,YACtG,YAAY,aAAa,gBAAAA,OAAC,OAAE,WAAU,oCAAmC;AAAA;AAAA,cAAY,WAAW,YAAY,SAAS;AAAA,eAAE;AAAA,aAC1H;AAAA,UAED,YAAY,0BACX,gBAAAA,OAAC,SACC;AAAA,4BAAAD,MAAC,OAAE,WAAU,iCAAgC,uBAAS;AAAA,YACtD,gBAAAA,MAAC,UAAK,WAAU,wDAAwD,sBAAY,wBAAuB;AAAA,aAC7G;AAAA,WAEJ;AAAA,QACA,gBAAAA,MAAC,SAAI,WAAU,yBACb,0BAAAA,MAAC,YAAO,WAAU,2IAA0I,SAAS,MAAM,eAAe,KAAK,GAAG,oBAAM,GAC1M;AAAA,SACF;AAAA,OACF;AAAA,IAID,oBAAoB,eACnB,gBAAAC,OAAC,SAAI,WAAU,uDACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,MAAM,oBAAoB,KAAK,GAAG;AAAA,MACtF,gBAAAC,OAAC,SAAI,WAAU,+EACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,yBAAwB,qCAAuB;AAAA,QAC7D,gBAAAC,OAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,UAAqC,gBAAAD,MAAC,YAAQ,sBAAY,kBAAiB;AAAA,UAAS;AAAA,WAAC;AAAA,QACvI,gBAAAC,OAAC,SAAI,WAAU,QACb;AAAA,0BAAAA,OAAC,WAAM,WAAU,0CACf;AAAA,4BAAAD,MAAC,WAAM,MAAK,YAAW,SAAS,mBAAmB,UAAU,CAAC,MAAM,qBAAqB,EAAE,OAAO,OAAO,GAAG,WAAU,wBAAuB;AAAA,YAC7I,gBAAAA,MAAC,UAAK,WAAU,WAAU,mEAAqD;AAAA,aACjF;AAAA,UACA,gBAAAA,MAAC,OAAE,WAAU,sCACV,8BAAoB,gEAA6D,qDACpF;AAAA,WACF;AAAA,QACA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAD,MAAC,YAAO,WAAU,2IAA0I,SAAS,MAAM,oBAAoB,KAAK,GAAG,qBAAO;AAAA,UAC9M,gBAAAA,MAAC,YAAO,WAAU,gLAA+K,SAAS,cAAc,UAAU,eAAe,WAC9O,yBAAe,YAAY,qBAAqB,0BACnD;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KAEJ;AAGF,SAAO,UAAU,gBAAAA,MAAC,WAAS,mBAAQ,IAAa;AAClD;;;AE9NA,SAAS,YAAAI,iBAAgB;AACzB,SAAS,SAAAC,cAAa;AACtB,SAAS,WAAW,eAA0C;AAC9D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,2BAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACZP,SAAS,aAAa,oBAAoB;AAmBpC,SAKE,OAAAC,OALF,QAAAC,cAAA;AATC,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,SACE,gBAAAA,OAAC,SAAI,WAAU,qCACb;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU,CAAC;AAAA,QAEX;AAAA,0BAAAD,MAAC,eAAY,WAAU,gBAAe;AAAA,UAAE;AAAA;AAAA;AAAA,IAE1C;AAAA,IACA,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM;AACb,cAAI,MAAM,SAAS,GAAG;AACpB,uBAAW,MAAM,MAAM,SAAS,CAAC,EAAE,EAAE;AAAA,UACvC;AAAA,QACF;AAAA,QACA,UAAU,CAAC;AAAA,QACZ;AAAA;AAAA,UAEC,gBAAAD,MAAC,gBAAa,WAAU,gBAAe;AAAA;AAAA;AAAA,IACzC;AAAA,KACF;AAEJ;;;AD2BI,qBAAAE,WAGI,OAAAC,OAWiC,QAAAC,cAdrC;AA5CJ,IAAMC,uBAAsB;AAAA,EAC1B,EAAE,OAAO,OAAO,OAAO,kBAAkB;AAAA,EACzC,EAAE,OAAO,aAAa,OAAO,aAAa;AAAA,EAC1C,EAAE,OAAO,WAAW,OAAO,YAAY;AAAA,EACvC,EAAE,OAAO,UAAU,OAAO,UAAU;AAAA,EACpC,EAAE,OAAO,YAAY,OAAO,YAAY;AAC1C;AAEO,SAAS,aAAa,EAAE,SAAS,SAAS,OAAO,GAAsB;AAC5E,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,EAAE;AACvC,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AACtD,QAAM,EAAE,QAAQ,UAAU,UAAU,IAAI,oBAAoB;AAC5D,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAA8B,IAAI;AAChF,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAS,KAAK;AAC9D,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,EAAE;AACnD,QAAM,CAAC,cAAc,eAAe,IAAIA,UAA+D,uBAAuB;AAE9H,QAAM,EAAE,MAAM,WAAW,QAAQ,IAAI,iBAAiB;AAAA,IACpD,QAAQ,UAAU;AAAA,IAClB,QAAQ,iBAAiB,QAAQ,eAAe;AAAA,IAChD,OAAO;AAAA,IACP,gBAAgB;AAAA,EAClB,CAAC;AACD,QAAM,iBAAiB,iBAAiB;AAExC,QAAM,WAAW,MAAM,QAAQ,CAAC;AAChC,QAAM,UAAU,MAAM,YAAY;AAElC,QAAM,eAAe,MAAM;AACzB,QAAI,CAAC,gBAAiB;AACtB,UAAM,cAAc,eAAe,KAAK,MAAM,WAAW,YAAY,IAAI,GAAG,IAAI;AAChF,mBAAe,OAAO,EAAE,IAAI,gBAAgB,IAAI,QAAQ,aAAa,QAAQ,aAAa,GAAG;AAAA,MAC3F,WAAW,MAAM;AAAE,QAAAC,OAAM,QAAQ,qBAAqB;AAAG,4BAAoB,KAAK;AAAG,2BAAmB,IAAI;AAAG,wBAAgB,EAAE;AAAA,MAAG;AAAA,MACpI,SAAS,CAAC,QAAQA,OAAM,MAAM,oBAAoB,IAAI,OAAO,EAAE;AAAA,IACjE,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,CAAC,YAA0B;AAClD,uBAAmB,OAAO;AAC1B,qBAAiB,QAAQ,SAAS,KAAK,QAAQ,CAAC,CAAC;AACjD,wBAAoB,IAAI;AAAA,EAC1B;AAEA,QAAM,UACJ,gBAAAH,OAAAF,WAAA,EACG;AAAA;AAAA,IACD,gBAAAE,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,mBAAkB;AAAA,UAClB,aAAa;AAAA,UACb,gBAAgB,CAAC,MAAM;AAAE,sBAAU,CAAC;AAAG,sBAAU;AAAA,UAAG;AAAA,UACpD;AAAA,UACA,sBAAsB,CAAC,MAAM;AAAE,4BAAgB,CAAC;AAAG,sBAAU;AAAA,UAAG;AAAA,UAChE,eAAeE;AAAA,UACf,WAAW;AAAA;AAAA,MACb;AAAA,MAEA,gBAAAD,OAAC,SAAI,WAAU,yDACb;AAAA,wBAAAD,MAAC,WAAQ,WAAU,WAAU;AAAA,QAAE,gBAAAC,OAAC,UAAM;AAAA,mBAAS;AAAA,UAAO;AAAA,WAAuB;AAAA,SAC/E;AAAA,MAEA,gBAAAD,MAAC,SAAI,WAAU,uCACb,0BAAAA,MAAC,SAAI,WAAU,iCACb,0BAAAC,OAAC,WAAM,WAAU,iCACf;AAAA,wBAAAD,MAAC,WAAM,WAAU,mBACf,0BAAAC,OAAC,QAAG,WAAU,8BACZ;AAAA,0BAAAD,MAAC,QAAG,WAAU,yDAAwD,0BAAY;AAAA,UAClF,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,qBAAO;AAAA,UAC7E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,mBAAK;AAAA,UAC3E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,qBAAO;AAAA,UAC7E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,yBAAW;AAAA,UACjF,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,kBAAI;AAAA,UAC1E,gBAAAA,MAAC,QAAG,WAAU,0DAAyD,oBAAM;AAAA,WAC/E,GACF;AAAA,QACA,gBAAAA,MAAC,WACE,sBACC,gBAAAA,MAAC,gBAAa,MAAM,GAAG,SAAS,GAAG,IACjC,SAAS,WAAW,IACtB,gBAAAA,MAAC,QAAG,0BAAAA,MAAC,QAAG,SAAS,GAAG,WAAU,8CAA6C,sCAAwB,GAAK,IAExG,SAAS,IAAI,CAAC,YACZ,gBAAAC,OAAC,QAAoB,WAAU,8BAC7B;AAAA,0BAAAD,MAAC,QAAG,WAAU,OAAM,0BAAAA,MAAC,UAAK,WAAU,wCAAwC,qBAAW,QAAQ,EAAE,GAAE,GAAO;AAAA,UAC1G,gBAAAA,MAAC,QAAG,WAAU,mBAAmB,UAAAK,yBAAwB,QAAQ,QAAQ,QAAQ,QAAQ,GAAE;AAAA,UAC3F,gBAAAL,MAAC,QAAG,WAAU,OAAM,0BAAAA,MAAC,eAAY,OAAO,oBAAoB,QAAQ,MAAM,GAAG,YAAY,oBAAoB,QAAQ,MAAM,GAAG,GAAE;AAAA,UAChI,gBAAAA,MAAC,QAAG,WAAU,OAAO,kBAAQ,kBAAkB,gBAAAA,MAAC,UAAK,WAAU,yBAAwB,eAAC,GAAQ;AAAA,UAChG,gBAAAA,MAAC,QAAG,WAAU,8BAA8B,kBAAQ,eAAe,gBAAAA,MAAC,UAAK,WAAU,yBAAwB,eAAC,GAAQ;AAAA,UACpH,gBAAAA,MAAC,QAAG,WAAU,OAAO,0BAAgB,QAAQ,SAAS,IAAI,GAAE;AAAA,UAC5D,gBAAAA,MAAC,QAAG,WAAU,kBACX,kBAAQ,WAAW,eAClB,gBAAAC,OAAC,YAAO,WAAU,mGAAkG,SAAS,MAAM,iBAAiB,OAAO,GACzJ;AAAA,4BAAAD,MAAC,aAAU,WAAU,gBAAe;AAAA,YAAE;AAAA,aACxC,GAEJ;AAAA,aAbO,QAAQ,EAcjB,CACD,GAEL;AAAA,SACF,GACF,GACF;AAAA,MAEA,gBAAAA,MAAC,oBAAiB,QAAgB,SAAkB,OAAO,UAAU,aAAa,WAAW,YAAY,UAAU;AAAA,OACrH;AAAA,IAGC,oBAAoB,mBACnB,gBAAAC,OAAC,SAAI,WAAU,uDACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,MAAM,oBAAoB,KAAK,GAAG;AAAA,MACtF,gBAAAC,OAAC,SAAI,WAAU,+EACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,yBAAwB,gCAAkB;AAAA,QACxD,gBAAAA,MAAC,OAAE,WAAU,sCAAqC,+DAAiD;AAAA,QACnG,gBAAAC,OAAC,SAAI,WAAU,kBACb;AAAA,0BAAAA,OAAC,SAAI,WAAU,2BACb;AAAA,4BAAAA,OAAC,SAAI,WAAU,qCACb;AAAA,8BAAAD,MAAC,UAAK,WAAU,iCAAgC,iCAAmB;AAAA,cACnE,gBAAAA,MAAC,UAAK,WAAU,eAAe,UAAAK,yBAAwB,gBAAgB,QAAQ,gBAAgB,QAAQ,GAAE;AAAA,eAC3G;AAAA,YACC,gBAAgB,kBAAkB,gBAAAJ,OAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,cAAU,gBAAgB;AAAA,eAAe;AAAA,aAChI;AAAA,UACA,gBAAAA,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,8BAAgB;AAAA,YACpE,gBAAAA,MAAC,WAAM,MAAK,UAAS,MAAK,QAAO,WAAU,2JAA0J,OAAO,cAAc,UAAU,CAAC,MAAM,gBAAgB,EAAE,OAAO,KAAK,GAAG,aAAY,oCAAmC;AAAA,aAC7T;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,oBAAM;AAAA,YAC1D,gBAAAC,OAAC,YAAO,WAAU,2JAA0J,OAAO,cAAc,UAAU,CAAC,MAAM,gBAAgB,EAAE,OAAO,KAA4B,GACrQ;AAAA,8BAAAD,MAAC,YAAO,OAAM,yBAAwB,mCAAqB;AAAA,cAC3D,gBAAAA,MAAC,YAAO,OAAM,aAAY,iCAAmB;AAAA,cAC7C,gBAAAA,MAAC,YAAO,OAAM,cAAa,yBAAW;AAAA,eACxC;AAAA,aACF;AAAA,WACF;AAAA,QACA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAD,MAAC,YAAO,WAAU,2IAA0I,SAAS,MAAM,oBAAoB,KAAK,GAAG,qBAAO;AAAA,UAC9M,gBAAAA,MAAC,YAAO,WAAU,gLAA+K,SAAS,cAAc,UAAU,eAAe,WAC9O,yBAAe,YAAY,yBAAyB,qBACvD;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KAEJ;AAGF,SAAO,UAAU,gBAAAA,MAAC,WAAS,mBAAQ,IAAa;AAClD;;;AE5KA,SAAS,YAAAM,iBAAgB;AACzB,SAAS,SAAAC,cAAa;AACtB,SAAS,OAAAC,MAAK,MAAM,WAAAC,UAAS,UAAU,gBAAgB;AACvD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,2BAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,uBAAAC;AAAA,OACK;;;ACbP,SAAS,oBAAoB;AAE7B,SAAS,2BAAAC,0BAAyB,mBAAAC,kBAAiB,qBAAqB,2BAA2B;AAc7F,gBAAAC,OAEE,QAAAC,cAFF;AALC,SAAS,qBAAqB,EAAE,QAAQ,cAAc,QAAQ,GAA8B;AACjG,MAAI,CAAC,UAAU,CAAC,QAAS,QAAO;AAEhC,SACE,gBAAAA,OAAC,SAAI,WAAU,uDACb;AAAA,oBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,MAAM,aAAa,KAAK,GAAG;AAAA,IAC/E,gBAAAC,OAAC,SAAI,WAAU,+EACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,kCACb;AAAA,wBAAAD,MAAC,QAAG,WAAU,yBAAwB,8BAAgB;AAAA,QACtD,gBAAAA,MAAC,OAAE,WAAU,iCAAiC,kBAAQ,UAAU,wBAAuB;AAAA,SACzF;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,wBAAAA,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAA,OAAC,SACC;AAAA,4BAAAD,MAAC,OAAE,WAAU,iCAAgC,mBAAK;AAAA,YAClD,gBAAAA,MAAC,eAAY,OAAO,oBAAoB,QAAQ,MAAM,GAAG,YAAY,oBAAoB,QAAQ,MAAM,GAAG,WAAU,QAAO;AAAA,aAC7H;AAAA,UACA,gBAAAC,OAAC,SACC;AAAA,4BAAAD,MAAC,OAAE,WAAU,iCAAgC,4BAAc;AAAA,YAC3D,gBAAAA,MAAC,OAAE,WAAU,oBAAoB,UAAAE,iBAAgB,QAAQ,OAAO,GAAE;AAAA,aACpE;AAAA,WACF;AAAA,QAEA,gBAAAD,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAA,OAAC,SACC;AAAA,4BAAAD,MAAC,OAAE,WAAU,iCAAgC,4BAAc;AAAA,YAC3D,gBAAAA,MAAC,OAAE,WAAU,oBAAoB,UAAAG,yBAAwB,QAAQ,YAAY,QAAQ,QAAQ,GAAE;AAAA,aACjG;AAAA,UACA,gBAAAF,OAAC,SACC;AAAA,4BAAAD,MAAC,OAAE,WAAU,iCAAgC,4BAAc;AAAA,YAC3D,gBAAAA,MAAC,OAAE,WAAU,oBAAoB,UAAAG,yBAAwB,QAAQ,aAAa,QAAQ,QAAQ,GAAE;AAAA,aAClG;AAAA,WACF;AAAA,QAEC,QAAQ,mBAAmB,KAC1B,gBAAAH,MAAC,SAAI,WAAU,mDACb,0BAAAC,OAAC,OAAE,WAAU,8CAA6C;AAAA;AAAA,UACrC,gBAAAD,MAAC,YAAQ,UAAAG,yBAAwB,QAAQ,kBAAkB,QAAQ,QAAQ,GAAE;AAAA,WAClG,GACF;AAAA,QAGF,gBAAAF,OAAC,SACC;AAAA,0BAAAD,MAAC,OAAE,WAAU,iCAAgC,qBAAO;AAAA,UACpD,gBAAAA,MAAC,OAAE,WAAU,oBAAoB,kBAAQ,iBAAiB,mBAAkB;AAAA,UAC3E,QAAQ,kBAAkB,gBAAAA,MAAC,OAAE,WAAU,iCAAiC,kBAAQ,gBAAe;AAAA,WAClG;AAAA,QAEC,QAAQ,SAAS,QAAQ,MAAM,SAAS,KACvC,gBAAAC,OAAC,SACC;AAAA,0BAAAD,MAAC,OAAE,WAAU,sCAAqC,0BAAY;AAAA,UAC9D,gBAAAA,MAAC,SAAI,WAAU,8BACZ,kBAAQ,MAAM,IAAI,CAAC,SAClB,gBAAAC,OAAC,SAAkB,WAAU,yCAC3B;AAAA,4BAAAA,OAAC,SACC;AAAA,8BAAAD,MAAC,OAAE,WAAU,uBAAuB,eAAK,aAAY;AAAA,cACrD,gBAAAC,OAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,gBAAM,KAAK;AAAA,iBAAS;AAAA,eACnE;AAAA,YACA,gBAAAD,MAAC,OAAE,WAAU,eAAe,UAAAG,yBAAwB,KAAK,QAAQ,KAAK,QAAQ,GAAE;AAAA,eALxE,KAAK,EAMf,CACD,GACH;AAAA,WACF;AAAA,QAGD,QAAQ,sBACP,gBAAAF;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM,OAAO,KAAK,QAAQ,oBAAqB,QAAQ;AAAA,YAEhE;AAAA,8BAAAD,MAAC,gBAAa,WAAU,gBAAe;AAAA,cAAE;AAAA;AAAA;AAAA,QAE3C;AAAA,SAEJ;AAAA,MAEA,gBAAAA,MAAC,SAAI,WAAU,yBACb,0BAAAA,MAAC,YAAO,WAAU,2IAA0I,SAAS,MAAM,aAAa,KAAK,GAAG,oBAAM,GACxM;AAAA,OACF;AAAA,KACF;AAEJ;;;ADpBQ,SAgFa,YAAAI,WAhFb,OAAAC,OAWkC,QAAAC,cAXlC;AA/CR,IAAMC,uBAAsB;AAAA,EAC1B,EAAE,OAAO,OAAO,OAAO,kBAAkB;AAAA,EACzC,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,EACjC,EAAE,OAAO,QAAQ,OAAO,SAAS;AAAA,EACjC,EAAE,OAAO,QAAQ,OAAO,SAAS;AAAA,EACjC,EAAE,OAAO,QAAQ,OAAO,YAAY;AAAA,EACpC,EAAE,OAAO,iBAAiB,OAAO,mBAAmB;AACtD;AAEO,SAAS,aAAa,EAAE,SAAS,SAAS,OAAO,GAAsB;AAC5E,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,EAAE;AACvC,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AACtD,QAAM,EAAE,QAAQ,UAAU,UAAU,IAAIC,qBAAoB;AAE5D,QAAM,gBAAgBC,gBAA6B;AACnD,QAAM,aAAaA,gBAA6B;AAEhD,QAAM,EAAE,MAAM,WAAW,QAAQ,IAAI,iBAAiB;AAAA,IACpD,QAAQ,UAAU;AAAA,IAClB,QAAQ,iBAAiB,QAAQ,eAAe;AAAA,IAChD,OAAO;AAAA,IACP,gBAAgB;AAAA,EAClB,CAAC;AACD,QAAM,eAAe,eAAe;AACpC,QAAM,eAAe,eAAe;AAEpC,QAAM,WAAW,MAAM,QAAQ,CAAC;AAChC,QAAM,UAAU,MAAM,YAAY;AAElC,QAAM,oBAAoB,MAAM;AAC9B,QAAI,WAAW,MAAM;AACnB,mBAAa,OAAO,WAAW,KAAK,IAAI;AAAA,QACtC,WAAW,MAAM;AAAE,UAAAC,OAAM,QAAQ,mBAAmB;AAAG,qBAAW,MAAM;AAAA,QAAG;AAAA,QAC3E,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,iBAAiB,CAAC,YAA0B;AAChD,QAAI,QAAQ,YAAa,QAAO,KAAK,QAAQ,aAAa,QAAQ;AAAA,aACzD,QAAQ,mBAAoB,QAAO,KAAK,QAAQ,oBAAoB,QAAQ;AAAA,EACvF;AAEA,QAAM,UACJ,gBAAAL,OAAAF,WAAA,EACG;AAAA;AAAA,IACD,gBAAAE,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,mBAAkB;AAAA,UAClB,aAAa;AAAA,UACb,gBAAgB,CAAC,MAAM;AAAE,sBAAU,CAAC;AAAG,sBAAU;AAAA,UAAG;AAAA,UACpD;AAAA,UACA,sBAAsB,CAAC,MAAM;AAAE,4BAAgB,CAAC;AAAG,sBAAU;AAAA,UAAG;AAAA,UAChE,eAAeE;AAAA,UACf,WAAW;AAAA;AAAA,MACb;AAAA,MAEA,gBAAAD,OAAC,SAAI,WAAU,yDACb;AAAA,wBAAAD,MAAC,YAAS,WAAU,WAAU;AAAA,QAAE,gBAAAC,OAAC,UAAM;AAAA,mBAAS;AAAA,UAAO;AAAA,WAAqB;AAAA,SAC9E;AAAA,MAEA,gBAAAD,MAAC,SAAI,WAAU,uCACb,0BAAAA,MAAC,SAAI,WAAU,iCACb,0BAAAC,OAAC,WAAM,WAAU,iCACf;AAAA,wBAAAD,MAAC,WAAM,WAAU,mBACf,0BAAAC,OAAC,QAAG,WAAU,8BACZ;AAAA,0BAAAD,MAAC,QAAG,WAAU,yDAAwD,oBAAM;AAAA,UAC5E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,mBAAK;AAAA,UAC3E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,4BAAc;AAAA,UACpF,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,4BAAc;AAAA,UACpF,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,qBAAO;AAAA,UAC7E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,kBAAI;AAAA,UAC1E,gBAAAA,MAAC,QAAG,WAAU,yDAAwD,sBAAQ;AAAA,UAC9E,gBAAAA,MAAC,QAAG,WAAU,0DAAyD,oBAAM;AAAA,WAC/E,GACF;AAAA,QACA,gBAAAA,MAAC,WACE,sBACC,gBAAAA,MAAC,gBAAa,MAAM,GAAG,SAAS,GAAG,IACjC,SAAS,WAAW,IACtB,gBAAAA,MAAC,QAAG,0BAAAA,MAAC,QAAG,SAAS,GAAG,WAAU,8CAA6C,qCAAuB,GAAK,IAEvG,SAAS,IAAI,CAAC,QACZ,gBAAAC,OAAC,QAAgB,WAAU,8BACzB;AAAA,0BAAAD,MAAC,QAAG,WAAU,mBAAmB,cAAI,UAAU,gBAAAA,MAAC,UAAK,WAAU,yBAAwB,eAAC,GAAQ;AAAA,UAChG,gBAAAA,MAAC,QAAG,WAAU,OAAM,0BAAAA,MAAC,eAAY,OAAOO,qBAAoB,IAAI,MAAM,GAAG,YAAYC,qBAAoB,IAAI,MAAM,GAAG,GAAE;AAAA,UACxH,gBAAAR,MAAC,QAAG,WAAU,mBAAmB,UAAAS,yBAAwB,IAAI,YAAY,IAAI,QAAQ,GAAE;AAAA,UACvF,gBAAAT,MAAC,QAAG,WAAU,OAAO,UAAAS,yBAAwB,IAAI,aAAa,IAAI,QAAQ,GAAE;AAAA,UAC5E,gBAAAT,MAAC,QAAG,WAAU,OACZ,0BAAAC,OAAC,SAAI,WAAU,iBACb;AAAA,4BAAAD,MAAC,UAAM,cAAI,iBAAiB,KAAI;AAAA,YAC/B,IAAI,kBAAkB,gBAAAA,MAAC,UAAK,WAAU,iCAAiC,cAAI,gBAAe;AAAA,aAC7F,GACF;AAAA,UACA,gBAAAA,MAAC,QAAG,WAAU,OAAO,UAAAU,iBAAgB,IAAI,OAAO,GAAE;AAAA,UAClD,gBAAAV,MAAC,QAAG,WAAU,OAAO,UAAAU,iBAAgB,IAAI,QAAQ,GAAE;AAAA,UACnD,gBAAAV,MAAC,QAAG,WAAU,kBACZ,0BAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,4BAAAD,MAAC,YAAO,WAAU,8EAA6E,SAAS,MAAM,cAAc,KAAK,GAAG,GAAG,0BAAAA,MAACW,MAAA,EAAI,WAAU,WAAU,GAAE;AAAA,aAChK,IAAI,eAAe,IAAI,uBACvB,gBAAAX,MAAC,YAAO,WAAU,8EAA6E,SAAS,MAAM,eAAe,GAAG,GAAG,0BAAAA,MAAC,YAAS,WAAU,WAAU,GAAE;AAAA,YAEpK,IAAI,WAAW,UACd,gBAAAA,MAAC,YAAO,WAAU,8EAA6E,SAAS,MAAM,aAAa,OAAO,IAAI,IAAI,EAAE,WAAW,MAAMM,OAAM,QAAQ,iBAAiB,GAAG,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE,EAAE,CAAC,GAAG,UAAU,aAAa,WAAW,0BAAAN,MAAC,QAAK,WAAU,WAAU,GAAE;AAAA,aAEzT,IAAI,WAAW,WAAW,IAAI,WAAW,WACzC,gBAAAA,MAAC,YAAO,WAAU,+FAA8F,SAAS,MAAM,WAAW,KAAK,GAAG,GAAG,0BAAAA,MAACY,UAAA,EAAQ,WAAU,WAAU,GAAE;AAAA,aAExL,GACF;AAAA,aA1BO,IAAI,EA2Bb,CACD,GAEL;AAAA,SACF,GACF,GACF;AAAA,MAEA,gBAAAZ,MAAC,oBAAiB,QAAgB,SAAkB,OAAO,UAAU,aAAa,WAAW,YAAY,UAAU;AAAA,OACrH;AAAA,IAEA,gBAAAA,MAAC,wBAAqB,QAAQ,cAAc,QAAQ,cAAc,CAAC,SAAS,CAAC,QAAQ,cAAc,MAAM,GAAG,SAAS,cAAc,MAAM;AAAA,IAEzI,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,WAAW;AAAA,QACnB,cAAc,CAAC,SAAS,CAAC,QAAQ,WAAW,MAAM;AAAA,QAClD,OAAM;AAAA,QACN,aAAa,gBAAAC,OAAAF,WAAA,EAAE;AAAA;AAAA,UAA8B,gBAAAC,MAAC,YAAQ,qBAAW,MAAM,UAAU,WAAW,MAAM,IAAG;AAAA,UAAS;AAAA,WAAkD;AAAA,QAChK,WAAW;AAAA,QACX,YAAY,aAAa;AAAA,QACzB,cAAa;AAAA;AAAA,IACf;AAAA,KACF;AAGF,SAAO,UAAU,gBAAAA,MAAC,WAAS,mBAAQ,IAAa;AAClD;;;AEnKA,SAAS,YAAAa,iBAAgB;AACzB,SAAS,QAAAC,OAAM,WAAAC,UAAS,mBAAmB;AAC3C,SAAS,kBAAkB,wBAAwB;AAEnD,SAAS,SAAAC,cAAa;;;ACJtB,SAAS,kBAAkB,wBAAwB;AAEnD,SAAS,SAAAC,cAAa;AAyDhB,SAyBU,YAAAC,WAzBV,OAAAC,OAyBU,QAAAC,cAzBV;AA/CC,SAAS,iBAAiB,EAAE,SAAS,MAAM,SAAS,UAAU,GAA0B;AAC7F,QAAM,aAAa,YAAY;AAC/B,QAAM,iBAAiB,iBAAiB;AACxC,QAAM,iBAAiB,iBAAiB;AACxC,QAAM,YAAY,eAAe,aAAa,eAAe;AAE7D,QAAM,eAAe,CAAC,MAAwC;AAC5D,MAAE,eAAe;AACjB,UAAM,WAAW,IAAI,SAAS,EAAE,aAAa;AAE7C,QAAI,YAAY;AACd,YAAM,aAAiC;AAAA,QACrC,MAAM,SAAS,IAAI,MAAM;AAAA,QACzB,aAAc,SAAS,IAAI,aAAa,KAAgB;AAAA,QACxD,MAAO,SAAS,IAAI,MAAM,KAAgB;AAAA,QAC1C,UAAW,SAAS,IAAI,UAAU,KAAgB;AAAA,QAClD,cAAc,SAAS,IAAI,cAAc,MAAM;AAAA,QAC/C,oBAAqB,SAAS,IAAI,oBAAoB,KAAgB;AAAA,MACxE;AACA,qBAAe;AAAA,QACb,EAAE,IAAI,QAAQ,IAAI,MAAM,WAAW;AAAA,QACnC;AAAA,UACE,WAAW,MAAM;AAAE,YAAAH,OAAM,QAAQ,iCAAiC;AAAG,sBAAU;AAAA,UAAG;AAAA,UAClF,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,QACxD;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,aAAiC;AAAA,QACrC,MAAM,SAAS,IAAI,MAAM;AAAA,QACzB,MAAM,SAAS,IAAI,MAAM;AAAA,QACzB,aAAc,SAAS,IAAI,aAAa,KAAgB;AAAA,QACxD,MAAO,SAAS,IAAI,MAAM,KAAgB;AAAA,QAC1C,UAAW,SAAS,IAAI,UAAU,KAAgB;AAAA,QAClD,cAAc,SAAS,IAAI,cAAc,MAAM;AAAA,QAC/C,oBAAqB,SAAS,IAAI,oBAAoB,KAAgB;AAAA,MACxE;AACA,qBAAe,OAAO,YAAY;AAAA,QAChC,WAAW,MAAM;AAAE,UAAAA,OAAM,QAAQ,6BAA6B;AAAG,oBAAU;AAAA,QAAG;AAAA,QAC9E,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,CAAC,KAAM,QAAO;AAElB,SACE,gBAAAG,OAAC,SAAI,WAAU,uDACb;AAAA,oBAAAD,MAAC,SAAI,WAAU,6BAA4B,SAAS,SAAS;AAAA,IAC7D,gBAAAA,MAAC,SAAI,WAAU,+EACb,0BAAAC,OAAC,UAAK,UAAU,cACd;AAAA,sBAAAD,MAAC,QAAG,WAAU,yBACX,uBAAa,qBAAqB,sBACrC;AAAA,MACA,gBAAAA,MAAC,OAAE,WAAU,sCACV,uBACG,sCAAsC,QAAQ,IAAI,OAClD,4CACN;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,kBAEb;AAAA,wBAAAA,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,SAAQ,QACzD,uBAAa,4BAA4B,UAC5C;AAAA,UACC,aACC,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,QAAQ;AAAA,cACf,UAAQ;AAAA,cACR,WAAU;AAAA;AAAA,UACZ,IAEA,gBAAAC,OAAAF,WAAA,EACE;AAAA,4BAAAC;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,UAAQ;AAAA,gBACR,aAAY;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,YACA,gBAAAA,MAAC,OAAE,WAAU,iCAAgC,0DAA4C;AAAA,aAC3F;AAAA,WAEJ;AAAA,QAGA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,SAAQ,QAAO,oBAAM;AAAA,UACzE,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,aAAa,cAAc;AAAA,cAC/B,MAAK;AAAA,cACL,UAAQ;AAAA,cACR,cAAc,SAAS,QAAQ;AAAA,cAC/B,aAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ;AAAA,WACF;AAAA,QAGA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,SAAQ,eAAc,yBAAW;AAAA,UACrF,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,aAAa,qBAAqB;AAAA,cACtC,MAAK;AAAA,cACL,MAAM;AAAA,cACN,cAAc,SAAS,eAAe;AAAA,cACtC,aAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ;AAAA,WACF;AAAA,QAGA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,0BAAAA,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,SAAQ,QAAO,0BAAY;AAAA,YAC/E,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI,aAAa,cAAc;AAAA,gBAC/B,MAAK;AAAA,gBACL,cAAc,SAAS,QAAQ;AAAA,gBAC/B,aAAY;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,oCAAmC,SAAQ,YAAW,uBAAS;AAAA,YAChF,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI,aAAa,kBAAkB;AAAA,gBACnC,MAAK;AAAA,gBACL,cAAc,SAAS,YAAY;AAAA,gBACnC,aAAY;AAAA,gBACZ,WAAU;AAAA;AAAA,YACZ;AAAA,aACF;AAAA,WACF;AAAA,QAGA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,0BAAAD,MAAC,WAAM,WAAU,oCAAmC,SAAQ,sBAAqB,4CAEjF;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,aAAa,4BAA4B;AAAA,cAC7C,MAAK;AAAA,cACL,cAAc,SAAS,sBAAsB;AAAA,cAC7C,aAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ;AAAA,UACC,CAAC,cACA,gBAAAA,MAAC,OAAE,WAAU,iCAAgC,mFAE7C;AAAA,WAEJ;AAAA,QAGA,gBAAAC,OAAC,SAAI,WAAU,2BACb;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,IAAI,aAAa,sBAAsB;AAAA,cACvC,MAAK;AAAA,cACL,gBAAgB,SAAS,gBAAgB;AAAA,cACzC,WAAU;AAAA;AAAA,UACZ;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,aAAa,sBAAsB;AAAA,cAC7C;AAAA;AAAA,UAED;AAAA,WACF;AAAA,SACF;AAAA,MAEA,gBAAAC,OAAC,SAAI,WAAU,0BACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS;AAAA,YACV;AAAA;AAAA,QAED;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,UAAU;AAAA,YAET,sBACG,aAAa,mBAAmB,iBAChC,aAAa,oBAAoB;AAAA;AAAA,QACvC;AAAA,SACF;AAAA,OACF,GACF;AAAA,KACF;AAEJ;;;AC9MA,SAAS,UAAAE,SAAQ,UAAAC,eAAc;AAerB,SACE,OAAAC,OADF,QAAAC,cAAA;AALH,SAAS,gBAAgB,EAAE,SAAS,QAAQ,SAAS,GAAyB;AACnF,SACE,gBAAAD,MAAC,SAAI,WAAU,6DACb,0BAAAC,OAAC,SAAI,WAAU,oCACb;AAAA,oBAAAA,OAAC,SAAI,WAAU,UACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,gCACb;AAAA,wBAAAD,MAAC,UAAK,WAAU,iBAAiB,kBAAQ,MAAK;AAAA,QAC9C,gBAAAA,MAAC,UAAK,WAAU,wCAAwC,kBAAQ,MAAK;AAAA,QACpE,CAAC,QAAQ,gBACR,gBAAAA,MAAC,eAAY,OAAM,eAAc,YAAW,6DAA4D;AAAA,QAEzG,QAAQ,sBACP,gBAAAA,MAAC,eAAY,OAAM,eAAc,YAAW,UAAS;AAAA,SAEzD;AAAA,MACC,QAAQ,eACP,gBAAAA,MAAC,OAAE,WAAU,sCAAsC,kBAAQ,aAAY;AAAA,MAEzE,gBAAAC,OAAC,SAAI,WAAU,yDACZ;AAAA,gBAAQ,YAAY,gBAAAA,OAAC,UAAK;AAAA;AAAA,UAAY,QAAQ;AAAA,WAAS;AAAA,QACvD,QAAQ,QAAQ,gBAAAA,OAAC,UAAK;AAAA;AAAA,UAAQ,QAAQ;AAAA,WAAK;AAAA,SAC9C;AAAA,OACF;AAAA,IACA,gBAAAA,OAAC,SAAI,WAAU,2BACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,OAAO,OAAO;AAAA,UAE7B,0BAAAA,MAACE,SAAA,EAAO,WAAU,WAAU;AAAA;AAAA,MAC9B;AAAA,MACA,gBAAAF;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,SAAS,OAAO;AAAA,UAE/B,0BAAAA,MAACG,SAAA,EAAO,WAAU,WAAU;AAAA;AAAA,MAC9B;AAAA,OACF;AAAA,KACF,GACF;AAEJ;;;AFJY,SA2EF,YAAAC,YA3EE,OAAAC,OACA,QAAAC,cADA;AAhCL,SAAS,aAAa,EAAE,SAAS,SAAS,OAAO,GAAsB;AAC5E,QAAM,CAAC,cAAc,eAAe,IAAIC,UAA0C,MAAS;AAC3F,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAA8B,IAAI;AAGhF,QAAM,cAAc,iBAAiB;AAErC,QAAM,EAAE,MAAM,WAAW,QAAQ,IAAI,iBAAiB;AACtD,QAAM,iBAAiB,iBAAiB;AAExC,QAAM,WAAW,MAAM,YAAY,CAAC;AAEpC,QAAM,sBAAsB,MAAM;AAChC,QAAI,iBAAiB;AACnB,qBAAe,OAAO,gBAAgB,IAAI;AAAA,QACxC,WAAW,MAAM;AAAE,UAAAC,OAAM,QAAQ,gCAAgC;AAAG,6BAAmB,IAAI;AAAA,QAAG;AAAA,QAC9F,SAAS,CAAC,QAAQA,OAAM,MAAM,WAAW,IAAI,OAAO,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,qBAAqB,MAAM;AAC/B,YAAQ;AACR,oBAAgB,MAAS;AAAA,EAC3B;AAEA,QAAM,UACJ,gBAAAF,OAAAF,YAAA,EACG;AAAA;AAAA,IACD,gBAAAE,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,qCACb;AAAA,wBAAAA,OAAC,SAAI,WAAU,yDACb;AAAA,0BAAAD,MAACI,UAAA,EAAQ,WAAU,WAAU;AAAA,UAC7B,gBAAAH,OAAC,UAAM;AAAA,qBAAS;AAAA,YAAO;AAAA,YAAS,SAAS,WAAW,IAAI,MAAM;AAAA,YAAG;AAAA,aAAY;AAAA,WAC/E;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM,gBAAgB,IAAI;AAAA,YAEnC;AAAA,8BAAAD,MAACK,OAAA,EAAK,WAAU,gBAAe;AAAA,cAAE;AAAA;AAAA;AAAA,QACnC;AAAA,SACF;AAAA,MAEA,gBAAAJ,OAAC,SAAI,WAAU,uCACb;AAAA,wBAAAA,OAAC,SAAI,WAAU,gBACb;AAAA,0BAAAA,OAAC,QAAG,WAAU,mDACZ;AAAA,4BAAAD,MAACI,UAAA,EAAQ,WAAU,WAAU;AAAA,YAAE;AAAA,aAEjC;AAAA,UACA,gBAAAJ,MAAC,OAAE,WAAU,sCAAqC,6FAElD;AAAA,WACF;AAAA,QACA,gBAAAC,OAAC,SAAI,WAAU,OACZ;AAAA,sBACC,gBAAAD,MAAC,SAAI,WAAU,aACZ,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,gBAAAA,MAAC,SAAY,WAAU,4CAAb,CAAsD,CACjE,GACH,IACE,SAAS,WAAW,IACtB,gBAAAC,OAAC,SAAI,WAAU,2CACb;AAAA,4BAAAD,MAACI,UAAA,EAAQ,WAAU,qCAAoC;AAAA,YACvD,gBAAAJ,MAAC,OAAE,yCAA2B;AAAA,YAC9B,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,SAAS,MAAM,gBAAgB,IAAI;AAAA,gBACpC;AAAA;AAAA,YAED;AAAA,aACF,IAEA,gBAAAA,MAAC,SAAI,WAAU,aACZ,mBAAS,IAAI,CAAC,YACb,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA,QAAQ,CAAC,MAAM,gBAAgB,CAAC;AAAA,cAChC,UAAU,CAAC,MAAM,mBAAmB,CAAC;AAAA;AAAA,YAHhC,QAAQ;AAAA,UAIf,CACD,GACH;AAAA,UAGF,gBAAAC,OAAC,SAAI,WAAU,6DACb;AAAA,4BAAAD,MAAC,eAAY,WAAU,iDAAgD;AAAA,YACvE,gBAAAC,OAAC,OAAE,WAAU,iCACX;AAAA,8BAAAD,MAAC,YAAO,mBAAK;AAAA,cAAS;AAAA,eAExB;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,cAAe,gBAAgB,OAAQ;AAAA,QAChD,MAAM;AAAA,QACN,SAAS,MAAM,gBAAgB,MAAS;AAAA,QACxC,WAAW;AAAA;AAAA,IACb;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,CAAC,CAAC;AAAA,QACV,cAAc,CAAC,SAAS,CAAC,QAAQ,mBAAmB,IAAI;AAAA,QACxD,OAAM;AAAA,QACN,aACE,gBAAAC,OAAAF,YAAA,EAAE;AAAA;AAAA,UAC8B,gBAAAC,MAAC,YAAQ,2BAAiB,MAAK;AAAA,UAAS;AAAA,UACtE,gBAAAA,MAAC,UAAM,2BAAiB,MAAK;AAAA,UAAO;AAAA,WACtC;AAAA,QAEF,WAAW;AAAA,QACX,YAAY,eAAe;AAAA,QAC3B,cAAa;AAAA;AAAA,IACf;AAAA,KACF;AAGF,SAAO,UAAU,gBAAAA,MAAC,WAAS,mBAAQ,IAAa;AAClD;;;AG3HA,IAAM,gBAAkC;AAAA,EACtC,EAAE,KAAK,SAAS,OAAO,SAAS,MAAM,cAAc,MAAM,eAAe;AAAA,EACzE,EAAE,KAAK,iBAAiB,OAAO,eAAe,MAAM,cAAc,MAAM,uBAAuB;AAAA,EAC/F,EAAE,KAAK,YAAY,OAAO,YAAY,MAAM,WAAW,MAAM,kBAAkB;AAAA,EAC/E,EAAE,KAAK,YAAY,OAAO,YAAY,MAAM,UAAU,MAAM,kBAAkB;AAAA,EAC9E,EAAE,KAAK,YAAY,OAAO,aAAa,MAAM,WAAW,MAAM,kBAAkB;AAAA,EAChF,EAAE,KAAK,YAAY,OAAO,WAAW,MAAM,YAAY,MAAM,kBAAkB;AACjF;AAQO,SAAS,mBACd,SACA,UACkB;AAClB,QAAM,UAAU;AAAA,IACd,OAAO;AAAA,IACP,eAAe;AAAA,IACf,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,GAAG;AAAA,EACL;AAEA,SAAO,cACJ,OAAO,CAAC,SAAS,QAAQ,KAAK,GAA2B,MAAM,KAAK,EACpE,IAAI,CAAC,UAAU;AAAA,IACd,GAAG;AAAA,IACH,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,IAAI,KAAK,KAAK;AAAA,EACpD,EAAE;AACN;","names":["React","jsx","React","useState","jsx","jsx","jsx","jsxs","useMemo","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","useMemo","Check","jsx","jsxs","Check","jsx","jsxs","useMemo","jsx","jsxs","useMemo","Loader2","jsx","jsxs","Fragment","jsx","jsxs","useState","data","toast","Plus","RefreshCw","Pencil","Trash2","Upload","Check","X","useQuery","useDialogState","useState","Loader2","jsx","jsxs","Fragment","jsx","jsxs","useDialogState","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","useCursorPagination","formatCurrencyFromCents","formatTimestamp","invoiceStatusColors","invoiceStatusLabels","formatCurrencyFromCents","formatTimestamp","jsx","jsxs","formatTimestamp","formatCurrencyFromCents","Fragment","jsx","jsxs","statusFilterOptions","useState","useCursorPagination","useDialogState","toast","invoiceStatusLabels","invoiceStatusColors","formatCurrencyFromCents","formatTimestamp","Eye","XCircle","useState","Plus","Package","toast","toast","Fragment","jsx","jsxs","Pencil","Trash2","jsx","jsxs","Pencil","Trash2","Fragment","jsx","jsxs","useState","toast","Package","Plus"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/components/shared/ErrorBoundary.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/shared/ToggleSwitch.tsx","../src/components/plans/PlanDetailsSection.tsx","../src/components/plans/PlanPricingSection.tsx","../src/components/plans/LimitInput.tsx","../src/components/plans/PlanLimitsSection.tsx","../src/components/plans/PlanFeaturesSection.tsx","../src/lib/plan-feature-state.ts","../src/components/plans/PlanFeatureRow.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/components/features/FeatureFormModal.tsx","../src/components/features/FeatureListItem.tsx","../src/nav/billingNavItems.ts"],"sourcesContent":["import React, { useMemo } from 'react';\nimport {\n BillingAdminClientContext,\n createBillingAdminClient,\n type Fetcher,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport { ErrorBoundary } from './components/shared/ErrorBoundary';\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 <ErrorBoundary>\n {children}\n </ErrorBoundary>\n </BillingAdminClientContext.Provider>\n </BillingAdminConfigContext.Provider>\n );\n}\n","import React, { Component } from 'react';\n\ninterface Props {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n console.error('[BillingSDK] Error caught by boundary:', error, errorInfo);\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div style={{ padding: '1rem', textAlign: 'center', color: '#666' }}>\n <p>Something went wrong in the billing module.</p>\n <button\n onClick={() => this.setState({ hasError: false, error: null })}\n style={{ marginTop: '0.5rem', cursor: 'pointer' }}\n >\n Try again\n </button>\n </div>\n );\n }\n return this.props.children;\n }\n}\n","import { useEffect, 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 useDialogState,\n validateRequired,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminPlan, AdminPlanCreate, AdminPlanUpdate } from '@growflowstudio/growflowbilling-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 formDialog = useDialogState<AdminPlan>();\n const deleteDialog = useDialogState<AdminPlan>();\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 useEffect(() => {\n if (publicPlansConfig?.enabled && publicPlansConfig.fetchFn) {\n publicPlansConfig.fetchFn().then(r => setPublicPlanSlugs(r.public_plan_slugs));\n }\n }, [publicPlansConfig]);\n\n const plans = data?.items || [];\n\n const resetForm = () => {\n setFormData(createDefaultPlanFormData(limitFields));\n setFormErrors({});\n };\n\n const openCreateForm = () => {\n resetForm();\n formDialog.open(undefined);\n };\n\n const openEditForm = (plan: AdminPlan) => {\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 paid_start_day: plan.paid_start_day ?? plan.trial_days + 1,\n paid_start_date: plan.paid_start_date ?? '',\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 ui_visibility: plan.ui_visibility ?? {},\n sort_order: plan.sort_order,\n });\n formDialog.open(plan);\n };\n\n const handleValidate = (): boolean => {\n const errors: Record<string, string> = {};\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 // Compute slug inline at submit time to avoid React state race conditions.\n // The onChange handler sets slug as a UX preview, but we always recompute\n // here as a fallback so a fast submit never sends an empty slug.\n const resolvedSlug =\n formData.slug.trim() ||\n formData.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');\n\n // Sync the resolved slug back so validation and downstream usage see it.\n const finalFormData = { ...formData, slug: resolvedSlug };\n\n if (!handleValidate()) return;\n\n const limits: Record<string, number> = {};\n for (const field of limitFields) {\n limits[field.key] = finalFormData.limits_unlimited[field.key] ? -1 : (finalFormData.limits[field.key] ?? 1);\n }\n\n const planData: AdminPlanCreate | AdminPlanUpdate = {\n slug: finalFormData.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 paid_start_day: formData.paid_start_day,\n paid_start_date: formData.paid_start_date || null,\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 // Send the full map — empty ``{}`` is meaningful (clears any\n // lingering overrides) so we never fall back to ``undefined``.\n ui_visibility: formData.ui_visibility ?? {},\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(finalFormData.slug);\n if (finalFormData.is_public !== isCurrentlyPublic) {\n try {\n const newSlugs = finalFormData.is_public\n ? [...publicPlanSlugs, finalFormData.slug]\n : publicPlanSlugs.filter((s) => s !== finalFormData.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 (formDialog.data) {\n updateMutation.mutate({ id: formDialog.data.id, data: planData }, {\n onSuccess: () => { toast.success('Piano aggiornato con successo'); formDialog.close(); 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'); formDialog.close(); resetForm(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\n }\n };\n\n const handleDelete = () => {\n if (deleteDialog.data) {\n deleteMutation.mutate(deleteDialog.data.id, {\n onSuccess: () => { toast.success('Piano eliminato con successo'); 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 <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) => deleteDialog.open(plan)}\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={formDialog.isOpen}\n onOpenChange={(open) => { if (!open) { formDialog.close(); resetForm(); } }}\n formData={formData}\n onFormDataChange={(data) => setFormData((prev) => ({ ...prev, ...data }))}\n formErrors={formErrors}\n selectedPlan={formDialog.data ?? null}\n onSubmit={handleSubmit}\n isPending={createMutation.isPending || updateMutation.isPending}\n />\n\n <DeleteConfirmDialog\n isOpen={deleteDialog.isOpen}\n onOpenChange={(open) => { if (!open) deleteDialog.close(); }}\n title=\"Eliminare Piano?\"\n description={<>Stai per eliminare il piano <strong>{deleteDialog.data?.name}</strong> (<code>{deleteDialog.data?.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/growflowbilling-admin-core';\nimport { formatCurrency } from '@growflowstudio/growflowbilling-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\">Inizio pagamento</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 whitespace-nowrap\">\n {plan.paid_start_date\n ? new Date(plan.paid_start_date).toLocaleDateString('it-IT')\n : `giorno ${plan.paid_start_day ?? plan.trial_days + 1}`}\n </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 { useMemo } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Loader2 } from 'lucide-react';\nimport type {\n AdminPlan,\n AdminPlanPricingModel,\n Visibility,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport { useBillingAdminConfig, type LimitFieldConfig } from '../../provider';\nimport { PlanDetailsSection } from './PlanDetailsSection';\nimport { PlanPricingSection } from './PlanPricingSection';\nimport { PlanLimitsSection } from './PlanLimitsSection';\nimport { PlanFeaturesSection } from './PlanFeaturesSection';\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 /** Day from signup (day 1 = signup day) on which billing starts. */\n paid_start_day: number;\n /** Absolute start date (YYYY-MM-DD); overrides `paid_start_day` when set. */\n paid_start_date: string;\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 /**\n * Newline-separated feature slugs — legacy shape kept for compatibility\n * with existing submit logic in ``PlansPage``. The unified feature\n * editor writes to this field via ``applyFeatureState``.\n */\n features: string;\n /**\n * Per-feature UI visibility overrides (tri-state). Managed atomically\n * with ``features`` by ``PlanFeaturesSection``.\n */\n ui_visibility: Record<string, Visibility>;\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 paid_start_day: 15,\n paid_start_date: '',\n is_active: true,\n contact_sales: false,\n is_public: true,\n color: 'gray',\n limits,\n limits_unlimited: limitsUnlimited,\n features: '',\n ui_visibility: {},\n sort_order: 0,\n };\n}\n\nfunction generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport interface 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 const isCreating = !selectedPlan;\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\n // Derive the current feature slug list from the newline-separated form\n // field. No useState mirror — the form state is the single source of\n // truth and derivations stay in sync automatically on every edit.\n const selectedFeatureSlugs = useMemo<string[]>(\n () =>\n formData.features\n ? formData.features\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n : [],\n [formData.features],\n );\n\n const uiVisibility = useMemo<Record<string, Visibility>>(\n () => formData.ui_visibility ?? {},\n [formData.ui_visibility],\n );\n\n const handleNameChange = (name: string) => {\n if (isCreating) {\n onFormDataChange({ name, slug: generateSlug(name) });\n } else {\n onFormDataChange({ name });\n }\n };\n\n // Every feature-state toggle rewrites both ``features`` and\n // ``ui_visibility`` in one atomic update so the two fields cannot drift.\n const handleFeatureStateChange = (next: {\n features: string[];\n uiVisibility: Record<string, Visibility>;\n }) => {\n onFormDataChange({\n features: next.features.join('\\n'),\n ui_visibility: next.uiVisibility,\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 {/* Header */}\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\n ? 'Modifica le impostazioni del piano selezionato'\n : 'Crea un nuovo piano di abbonamento'}\n </p>\n </div>\n\n {/* Form sections */}\n <div className=\"grid gap-4 py-4\">\n <PlanDetailsSection\n formData={formData}\n formErrors={formErrors}\n isCreating={isCreating}\n onFormDataChange={onFormDataChange}\n onNameChange={handleNameChange}\n />\n <PlanPricingSection formData={formData} onFormDataChange={onFormDataChange} />\n <PlanLimitsSection\n limitFields={limitFields}\n formData={formData}\n onFormDataChange={onFormDataChange}\n />\n {featuresConfig?.enabled && (\n <PlanFeaturesSection\n availableFeatures={availableFeatures}\n selectedFeatureSlugs={selectedFeatureSlugs}\n uiVisibility={uiVisibility}\n onFeatureStateChange={handleFeatureStateChange}\n />\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","interface ToggleSwitchProps {\n label: string;\n checked: boolean;\n onChange: (value: boolean) => void;\n}\n\nexport function ToggleSwitch({ label, checked, onChange }: ToggleSwitchProps) {\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\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n checked ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n <span className=\"text-sm font-medium leading-none\">{label}</span>\n </div>\n );\n}\n","import type { PlanFormData } from './PlanFormDialog';\nimport { PLAN_COLORS, getPlanColorClass } from './plan-colors';\nimport { ToggleSwitch } from '../shared/ToggleSwitch';\n\ninterface PlanDetailsSectionProps {\n formData: PlanFormData;\n formErrors: Record<string, string>;\n isCreating: boolean;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n onNameChange: (name: string) => void;\n}\n\nexport function PlanDetailsSection({\n formData,\n formErrors,\n onFormDataChange,\n onNameChange,\n}: PlanDetailsSectionProps) {\n return (\n <>\n {/* Name */}\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) => onNameChange(e.target.value)}\n placeholder=\"es. Piano Pro\"\n />\n {formErrors.name && <p className=\"text-xs text-destructive\">{formErrors.name}</p>}\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 {/* 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:{' '}\n <span className={`inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${getPlanColorClass(formData.color)}`}>\n {formData.name || 'Piano'}\n </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 );\n}\n","import type { AdminPlanPricingModel } from '@growflowstudio/growflowbilling-admin-core';\nimport type { PlanFormData } from './PlanFormDialog';\n\ninterface PlanPricingSectionProps {\n formData: PlanFormData;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n}\n\nexport function PlanPricingSection({ formData, onFormDataChange }: PlanPricingSectionProps) {\n return (\n <>\n {/* Pricing model + prices */}\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 days, sort order */}\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=\"paid_start_day\">\n Inizio pagamento (giorno)\n </label>\n <input\n id=\"paid_start_day\"\n type=\"number\"\n min={1}\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.paid_start_day}\n disabled={!!formData.paid_start_date}\n onChange={(e) =>\n onFormDataChange({ paid_start_day: Math.max(1, parseInt(e.target.value) || 1) })\n }\n />\n <p className=\"text-xs text-muted-foreground\">\n {formData.paid_start_day > 1\n ? `Trial dal giorno 1 al ${formData.paid_start_day - 1}, prima fattura il giorno ${formData.paid_start_day} dalla registrazione.`\n : 'Fatturato dal primo giorno, nessun trial.'}\n </p>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"sort_order\">Ordine</label>\n <input\n id=\"sort_order\"\n type=\"number\"\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.sort_order}\n onChange={(e) => onFormDataChange({ sort_order: parseInt(e.target.value) || 0 })}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"paid_start_date\">\n Data fissa di inizio pagamento (opzionale)\n </label>\n <div className=\"flex items-center gap-2\">\n <input\n id=\"paid_start_date\"\n type=\"date\"\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 max-w-xs\"\n value={formData.paid_start_date}\n onChange={(e) => onFormDataChange({ paid_start_date: e.target.value })}\n />\n {formData.paid_start_date && (\n <button\n type=\"button\"\n className=\"text-sm text-muted-foreground underline-offset-4 hover:underline\"\n onClick={() => onFormDataChange({ paid_start_date: '' })}\n >\n Rimuovi\n </button>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n Se compilata, tutti gli store su questo piano vengono fatturati a partire da questa\n data, ignorando il giorno relativo.\n </p>\n </div>\n </>\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 type { LimitFieldConfig } from '../../provider';\nimport type { PlanFormData } from './PlanFormDialog';\nimport { LimitInput } from './LimitInput';\n\ninterface PlanLimitsSectionProps {\n limitFields: LimitFieldConfig[];\n formData: PlanFormData;\n onFormDataChange: (data: Partial<PlanFormData>) => void;\n}\n\nexport function PlanLimitsSection({ limitFields, formData, onFormDataChange }: PlanLimitsSectionProps) {\n if (limitFields.length === 0) return null;\n\n return (\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","import { useMemo, useState } from 'react';\nimport type { Visibility } from '@growflowstudio/growflowbilling-admin-core';\nimport type { PlanFormData } from './PlanFormDialog';\nimport {\n applyFeatureState,\n featureStateFromPlan,\n summarizeFeatureStates,\n type FeatureState,\n} from '../../lib/plan-feature-state';\nimport { PlanFeatureRow } from './PlanFeatureRow';\n\ninterface AvailableFeature {\n slug: string;\n name: string;\n description?: string;\n}\n\nexport interface PlanFeaturesSectionProps {\n availableFeatures: AvailableFeature[];\n /** Current included feature slugs (mirror of ``plan.features``). */\n selectedFeatureSlugs: string[];\n /** Current UI visibility overrides (mirror of ``plan.ui_visibility``). */\n uiVisibility: Record<string, Visibility>;\n /**\n * Called when the admin picks a new state for a slug. Receives the\n * atomically-updated ``features`` array and ``uiVisibility`` map;\n * callers MUST write both back to the parent form state.\n */\n onFeatureStateChange: (next: {\n features: string[];\n uiVisibility: Record<string, Visibility>;\n }) => void;\n}\n\n/**\n * Unified feature-state editor for the plan form.\n *\n * Replaces the old split between \"Features Incluse nel Piano\" checkboxes\n * and a separate visibility dropdown. One row per feature, one dropdown\n * per row with 3 user-facing states (``Non inclusa``, ``Teaser``,\n * ``Inclusa``) plus an advanced ``Sunset`` option behind a toggle. Every\n * state change writes ``plan.features`` and ``plan.ui_visibility``\n * atomically via ``applyFeatureState`` so the two fields can never drift.\n */\nexport function PlanFeaturesSection({\n availableFeatures,\n selectedFeatureSlugs,\n uiVisibility,\n onFeatureStateChange,\n}: PlanFeaturesSectionProps) {\n const [showSunset, setShowSunset] = useState(false);\n\n // Walk the union of catalog slugs + slugs already referenced by the plan\n // (covers custom overrides that don't exist in the current feature\n // catalog) so nothing the admin touched disappears silently.\n const rowSlugs = useMemo(() => {\n const out = new Set<string>(availableFeatures.map((f) => f.slug));\n for (const slug of selectedFeatureSlugs) out.add(slug);\n for (const slug of Object.keys(uiVisibility)) out.add(slug);\n return Array.from(out).sort();\n }, [availableFeatures, selectedFeatureSlugs, uiVisibility]);\n\n const stateCounts = useMemo(\n () => summarizeFeatureStates(selectedFeatureSlugs, uiVisibility),\n [selectedFeatureSlugs, uiVisibility],\n );\n\n const handleChange = (slug: string, next: FeatureState) => {\n const result = applyFeatureState(\n slug,\n next,\n selectedFeatureSlugs,\n uiVisibility,\n );\n onFeatureStateChange(result);\n };\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <label className=\"text-sm font-medium leading-none\">\n Funzionalità del piano\n </label>\n <div className=\"flex items-center gap-1 text-xs\">\n {stateCounts.on > 0 && (\n <span className=\"inline-flex items-center rounded-md border px-1.5 py-0.5 bg-green-100 text-green-800 border-green-300 dark:bg-green-900/30 dark:text-green-400 dark:border-green-700\">\n {stateCounts.on} inclusa{stateCounts.on !== 1 ? 'e' : ''}\n </span>\n )}\n {stateCounts.teaser > 0 && (\n <span className=\"inline-flex items-center rounded-md border px-1.5 py-0.5 bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-700\">\n {stateCounts.teaser} teaser\n </span>\n )}\n {stateCounts.sunset > 0 && (\n <span className=\"inline-flex items-center rounded-md border px-1.5 py-0.5 bg-rose-100 text-rose-800 border-rose-300 dark:bg-rose-900/30 dark:text-rose-400 dark:border-rose-700\">\n {stateCounts.sunset} sunset\n </span>\n )}\n </div>\n </div>\n\n <p className=\"text-xs text-muted-foreground\">\n Per ogni funzionalità scegli lo stato: <strong>Non inclusa</strong>{' '}\n (default), <strong>Teaser</strong> (mostrata come locked con CTA\n upgrade), o <strong>Inclusa</strong> (attiva). Lo stato scrive\n automaticamente le feature del piano e la visibility UI.\n </p>\n\n <div className=\"border rounded-lg p-2 space-y-1 max-h-[320px] overflow-y-auto\">\n {rowSlugs.length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n Nessuna funzionalità disponibile nel catalogo.\n </p>\n ) : (\n rowSlugs.map((slug) => {\n const feature = availableFeatures.find((f) => f.slug === slug);\n const state = featureStateFromPlan(\n slug,\n selectedFeatureSlugs,\n uiVisibility,\n );\n return (\n <PlanFeatureRow\n key={slug}\n slug={slug}\n name={feature?.name}\n description={feature?.description}\n state={state}\n showSunset={showSunset}\n onChange={handleChange}\n />\n );\n })\n )}\n </div>\n\n <div className=\"flex items-center gap-2 pt-1\">\n <input\n id=\"show-advanced-state\"\n type=\"checkbox\"\n checked={showSunset}\n onChange={(e) => setShowSunset(e.target.checked)}\n className=\"h-4 w-4 rounded border-input cursor-pointer\"\n />\n <label\n htmlFor=\"show-advanced-state\"\n className=\"text-xs text-muted-foreground cursor-pointer\"\n >\n Mostra stato avanzato &quot;Sunset&quot; (feature deprecate)\n </label>\n </div>\n </div>\n );\n}\n\n// Re-export type so callers can type feature data without coupling to internal shape\nexport type { PlanFormData };\n","/**\n * Plan × Feature state — canonical helpers.\n *\n * The backend stores per-plan feature configuration in two fields:\n *\n * - ``plan.features: string[]`` — slugs included in the plan.\n * - ``plan.ui_visibility: Record<slug, Visibility>`` — tri-state UI\n * override map.\n *\n * The admin UX exposes 3 user-facing states (``off | teaser | on``) plus\n * an advanced ``sunset`` state. This module is the ONLY place in the\n * billing admin UI that translates between the two raw backend fields\n * and the user-facing state. Every component that displays or writes\n * feature state must import from here — no inline logic.\n */\n\nimport type { Visibility } from '@growflowstudio/growflowbilling-admin-core';\n\nexport type FeatureState = 'off' | 'teaser' | 'on' | 'sunset';\n\nexport const FEATURE_STATE_LABELS: Record<FeatureState, string> = {\n off: 'Non inclusa',\n teaser: 'Teaser',\n on: 'Inclusa',\n sunset: 'Sunset (admin)',\n};\n\nexport const FEATURE_STATE_DESCRIPTIONS: Record<FeatureState, string> = {\n off: 'Non disponibile per gli utenti di questo piano (default).',\n teaser:\n 'Mostrata in sidebar come locked con CTA upgrade. Non attivata funzionalmente.',\n on: 'Inclusa nel piano e pienamente accessibile.',\n sunset:\n 'Tecnicamente nel piano ma nascosta. Uso raro (deprecazioni / incidenti).',\n};\n\n/**\n * Derive the user-facing state for a feature slug from the two raw backend\n * fields. Inverse of ``applyFeatureState``.\n *\n * Resolution table:\n *\n * | in ``features`` | ``ui_visibility[slug]`` | → state |\n * |-----------------|-------------------------|-------------|\n * | no | absent / 'hidden' | 'off' |\n * | no | 'teaser' | 'teaser' |\n * | no | 'visible' | 'off' (*) |\n * | yes | absent / 'visible' | 'on' |\n * | yes | 'teaser' | 'on' (*) |\n * | yes | 'hidden' | 'sunset' |\n *\n * (*) semantically invalid combinations normalised to the closest valid\n * state rather than surfacing a \"bug\" state to the admin.\n */\nexport function featureStateFromPlan(\n slug: string,\n features: string[] | null | undefined,\n uiVisibility: Record<string, Visibility> | null | undefined,\n): FeatureState {\n const inPlan = (features ?? []).includes(slug);\n const ui = (uiVisibility ?? {})[slug];\n\n if (inPlan) {\n if (ui === 'hidden') return 'sunset';\n return 'on';\n }\n\n if (ui === 'teaser') return 'teaser';\n return 'off';\n}\n\n/**\n * Apply a user-facing state transition to the raw backend fields.\n *\n * Immutable — returns new arrays/objects so React re-renders correctly.\n * This is the ONLY function that writes ``features`` + ``ui_visibility``\n * together. Callers must not edit the two fields independently.\n */\nexport function applyFeatureState(\n slug: string,\n state: FeatureState,\n features: string[] | null | undefined,\n uiVisibility: Record<string, Visibility> | null | undefined,\n): {\n features: string[];\n uiVisibility: Record<string, Visibility>;\n} {\n const nextFeaturesSet = new Set(features ?? []);\n const nextUi: Record<string, Visibility> = { ...(uiVisibility ?? {}) };\n\n switch (state) {\n case 'off':\n nextFeaturesSet.delete(slug);\n delete nextUi[slug];\n break;\n case 'teaser':\n nextFeaturesSet.delete(slug);\n nextUi[slug] = 'teaser';\n break;\n case 'on':\n nextFeaturesSet.add(slug);\n // Implicit 'visible' — don't write it to keep the map small.\n delete nextUi[slug];\n break;\n case 'sunset':\n nextFeaturesSet.add(slug);\n nextUi[slug] = 'hidden';\n break;\n }\n\n return {\n features: Array.from(nextFeaturesSet),\n uiVisibility: nextUi,\n };\n}\n\n/**\n * Count features by state for summary displays.\n *\n * Walks the union of ``features`` and ``uiVisibility`` keys so every\n * slug that has ANY configuration is counted. Slugs absent from both\n * are considered ``off`` and not counted (they're the invisible default).\n */\nexport function summarizeFeatureStates(\n features: string[] | null | undefined,\n uiVisibility: Record<string, Visibility> | null | undefined,\n): Record<FeatureState, number> {\n const counts: Record<FeatureState, number> = {\n off: 0,\n teaser: 0,\n on: 0,\n sunset: 0,\n };\n\n const slugs = new Set<string>([\n ...(features ?? []),\n ...Object.keys(uiVisibility ?? {}),\n ]);\n\n for (const slug of slugs) {\n const state = featureStateFromPlan(slug, features, uiVisibility);\n counts[state] += 1;\n }\n\n return counts;\n}\n","import { Check, CircleSlash, Lock, Archive } from 'lucide-react';\nimport {\n FEATURE_STATE_DESCRIPTIONS,\n type FeatureState,\n} from '../../lib/plan-feature-state';\n\n// Visual config for each state. Colocated with the row because this\n// component is the only place the tag is rendered at full size in the\n// plan editor; the plans table uses its own compact variant.\nconst STATE_VISUAL: Record<\n FeatureState,\n {\n label: string;\n Icon: typeof Check;\n classes: string;\n }\n> = {\n off: {\n label: 'Non inclusa',\n Icon: CircleSlash,\n classes: 'bg-muted text-muted-foreground border-muted-foreground/20',\n },\n teaser: {\n label: 'Teaser',\n Icon: Lock,\n classes:\n 'bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-700',\n },\n on: {\n label: 'Inclusa',\n Icon: Check,\n classes:\n 'bg-green-100 text-green-800 border-green-300 dark:bg-green-900/30 dark:text-green-400 dark:border-green-700',\n },\n sunset: {\n label: 'Sunset',\n Icon: Archive,\n classes:\n 'bg-rose-100 text-rose-800 border-rose-300 dark:bg-rose-900/30 dark:text-rose-400 dark:border-rose-700',\n },\n};\n\nexport interface PlanFeatureRowProps {\n /** Feature slug (stable identifier) */\n slug: string;\n /** Display name; falls back to slug when undefined */\n name?: string;\n /** Optional description shown under the name */\n description?: string | null;\n /** Current resolved state for this slug in this plan */\n state: FeatureState;\n /** Whether the advanced \"sunset\" option is visible in the dropdown */\n showSunset?: boolean;\n /** Called when the admin picks a new state from the dropdown */\n onChange: (slug: string, next: FeatureState) => void;\n /** Optional secondary action (e.g. remove a custom teaser-only slug) */\n onRemove?: () => void;\n}\n\nexport function PlanFeatureRow({\n slug,\n name,\n description,\n state,\n showSunset = false,\n onChange,\n onRemove,\n}: PlanFeatureRowProps) {\n const visual = STATE_VISUAL[state];\n const Icon = visual.Icon;\n\n return (\n <div className=\"flex items-start gap-3 p-2 rounded-md hover:bg-muted/50 transition-colors\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-sm font-medium truncate\">{name || slug}</span>\n <span\n className={`inline-flex items-center h-5 text-[10px] px-1.5 gap-1 rounded-md border ${visual.classes}`}\n >\n <Icon className=\"h-3 w-3 mr-1\" />\n {visual.label}\n </span>\n </div>\n {description && (\n <p className=\"text-xs text-muted-foreground mt-0.5 line-clamp-1\">\n {description}\n </p>\n )}\n <code className=\"text-[10px] text-muted-foreground bg-muted px-1.5 py-0.5 rounded mt-1 inline-block\">\n {slug}\n </code>\n </div>\n\n <select\n value={state}\n onChange={(e) => onChange(slug, e.target.value as FeatureState)}\n aria-label={`Stato per ${slug}`}\n className=\"h-8 w-[140px] text-xs flex-shrink-0 rounded-md border border-input bg-background px-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <option value=\"off\" title={FEATURE_STATE_DESCRIPTIONS.off}>\n Non inclusa\n </option>\n <option value=\"teaser\" title={FEATURE_STATE_DESCRIPTIONS.teaser}>\n Teaser\n </option>\n <option value=\"on\" title={FEATURE_STATE_DESCRIPTIONS.on}>\n Inclusa\n </option>\n {showSunset && (\n <option value=\"sunset\" title={FEATURE_STATE_DESCRIPTIONS.sunset}>\n Sunset (admin)\n </option>\n )}\n </select>\n\n {onRemove && (\n <button\n type=\"button\"\n onClick={onRemove}\n className=\"text-muted-foreground hover:text-destructive text-xs mt-1\"\n aria-label={`Rimuovi override ${slug}`}\n >\n ✕\n </button>\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/growflowbilling-admin-core';\nimport type { AdminProduct, AdminProductCreate, AdminProductUpdate } from '@growflowstudio/growflowbilling-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/growflowbilling-admin-core';\n\n// Safe JSON parse helper — never throws; returns fallback on malformed input.\nconst safeJsonParse = (str: string, fallback: Record<string, unknown> = {}): Record<string, unknown> => {\n try {\n const parsed: unknown = JSON.parse(str);\n return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : fallback;\n } catch {\n return fallback;\n }\n};\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 const parsedData = safeJsonParse(prev.extra_data);\n const updated = { ...parsedData, feature_slug: formData.feature_slug };\n return { ...prev, extra_data: JSON.stringify(updated, null, 2) };\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 // Validate that extra_data is valid JSON — safeJsonParse used in submit paths,\n // here we only need to surface a user-facing error message on invalid input.\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/growflowbilling-admin-core';\nimport type { AdminSubscription, AdminSubscriptionStatus } from '@growflowstudio/growflowbilling-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 useCursorPagination,\n formatCurrencyFromCents,\n formatTimestamp,\n truncateId,\n paymentStatusColors,\n paymentStatusLabels,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminPayment } from '@growflowstudio/growflowbilling-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, goToNext, goToFirst } = useCursorPagination();\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); goToFirst(); }}\n statusFilter={statusFilter}\n onStatusFilterChange={(v) => { setStatusFilter(v); goToFirst(); }}\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={goToFirst} onNextPage={goToNext} />\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 useCursorPagination,\n formatCurrencyFromCents,\n formatTimestamp,\n invoiceStatusColors,\n invoiceStatusLabels,\n} from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminInvoice } from '@growflowstudio/growflowbilling-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, goToNext, goToFirst } = useCursorPagination();\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); goToFirst(); }}\n statusFilter={statusFilter}\n onStatusFilterChange={(v) => { setStatusFilter(v); goToFirst(); }}\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={goToFirst} onNextPage={goToNext} />\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/growflowbilling-admin-core';\nimport { formatCurrencyFromCents, formatTimestamp, invoiceStatusColors, invoiceStatusLabels } from '@growflowstudio/growflowbilling-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 { Plus, Package, AlertCircle } from 'lucide-react';\nimport { useAdminFeatures, useDeleteFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport { toast } from 'sonner';\nimport { DeleteConfirmDialog } from '../components/shared/DeleteConfirmDialog';\nimport { FeatureFormModal } from '../components/features/FeatureFormModal';\nimport { FeatureListItem } from '../components/features/FeatureListItem';\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 [modalFeature, setModalFeature] = useState<AdminFeature | null | undefined>(undefined);\n const [deletingFeature, setDeletingFeature] = useState<AdminFeature | null>(null);\n\n // undefined = modal closed, null = create mode, AdminFeature = edit mode\n const isModalOpen = modalFeature !== undefined;\n\n const { data, isLoading, refetch } = useAdminFeatures();\n const deleteMutation = useDeleteFeature();\n\n const features = data?.features || [];\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 handleModalSuccess = () => {\n refetch();\n setModalFeature(undefined);\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={() => setModalFeature(null)}\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={() => setModalFeature(null)}\n >\n Crea la prima feature\n </button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {features.map((feature) => (\n <FeatureListItem\n key={feature.id}\n feature={feature}\n onEdit={(f) => setModalFeature(f)}\n onDelete={(f) => setDeletingFeature(f)}\n />\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 <FeatureFormModal\n feature={isModalOpen ? (modalFeature ?? null) : null}\n open={isModalOpen}\n onClose={() => setModalFeature(undefined)}\n onSuccess={handleModalSuccess}\n />\n\n <DeleteConfirmDialog\n isOpen={!!deletingFeature}\n onOpenChange={(open) => !open && setDeletingFeature(null)}\n title=\"Eliminare Feature?\"\n description={\n <>\n Stai per eliminare la feature <strong>{deletingFeature?.name}</strong> (\n <code>{deletingFeature?.slug}</code>). Questa azione non può essere annullata.\n </>\n }\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 { useCreateFeature, useUpdateFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport type { AdminFeature, AdminFeatureCreate, AdminFeatureUpdate } from '@growflowstudio/growflowbilling-admin-core';\nimport { toast } from 'sonner';\n\nexport interface FeatureFormModalProps {\n /** null = create mode, defined = edit mode */\n feature: AdminFeature | null;\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\nexport function FeatureFormModal({ feature, open, onClose, onSuccess }: FeatureFormModalProps) {\n const isEditMode = feature !== null;\n const createMutation = useCreateFeature();\n const updateMutation = useUpdateFeature();\n const isPending = createMutation.isPending || updateMutation.isPending;\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n\n if (isEditMode) {\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 updateMutation.mutate(\n { id: feature.id, data: updateData },\n {\n onSuccess: () => { toast.success('Feature aggiornata con successo'); onSuccess(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n },\n );\n } else {\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 createMutation.mutate(createData, {\n onSuccess: () => { toast.success('Feature creata con successo'); onSuccess(); },\n onError: (err) => toast.error(`Errore: ${err.message}`),\n });\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={onClose} />\n <div className=\"relative z-50 w-full max-w-md rounded-lg border bg-background p-6 shadow-lg\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-lg font-semibold\">\n {isEditMode ? 'Modifica Feature' : 'Crea Nuova Feature'}\n </h2>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {isEditMode\n ? `Aggiorna i dettagli della feature \"${feature.name}\".`\n : 'Configura una nuova feature disponibile.'}\n </p>\n\n <div className=\"space-y-4 py-4\">\n {/* Slug: editable on create, read-only on edit */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"slug\">\n {isEditMode ? 'Slug (non modificabile)' : 'Slug *'}\n </label>\n {isEditMode ? (\n <input\n value={feature.slug}\n disabled\n className=\"flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm\"\n />\n ) : (\n <>\n <input\n id=\"slug\"\n name=\"slug\"\n required\n placeholder=\"ottimizza-dati-prodotti\"\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 />\n <p className=\"text-xs text-muted-foreground\">Identificatore univoco (lowercase, trattini)</p>\n </>\n )}\n </div>\n\n {/* Name */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"name\">Nome *</label>\n <input\n id={isEditMode ? 'edit-name' : 'name'}\n name=\"name\"\n required\n defaultValue={feature?.name ?? ''}\n placeholder=\"Ottimizza Dati Prodotti\"\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 />\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={isEditMode ? 'edit-description' : 'description'}\n name=\"description\"\n rows={3}\n defaultValue={feature?.description ?? ''}\n placeholder=\"Descrizione della feature...\"\n 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 />\n </div>\n\n {/* Icon + Category */}\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\n id={isEditMode ? 'edit-icon' : 'icon'}\n name=\"icon\"\n defaultValue={feature?.icon ?? ''}\n placeholder=\"Package\"\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 />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"category\">Categoria</label>\n <input\n id={isEditMode ? 'edit-category' : 'category'}\n name=\"category\"\n defaultValue={feature?.category ?? ''}\n placeholder=\"ai, limits, integration...\"\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 />\n </div>\n </div>\n\n {/* Billing product ID */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium leading-none\" htmlFor=\"billing_product_id\">\n Billing Product ID (opzionale)\n </label>\n <input\n id={isEditMode ? 'edit-billing_product_id' : 'billing_product_id'}\n name=\"billing_product_id\"\n defaultValue={feature?.billing_product_id ?? ''}\n placeholder=\"UUID del prodotto billing\"\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 />\n {!isEditMode && (\n <p className=\"text-xs text-muted-foreground\">\n Se collegato a un prodotto, la feature viene attivata automaticamente\n </p>\n )}\n </div>\n\n {/* Availability checkbox */}\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n id={isEditMode ? 'edit-is_available' : 'is_available'}\n name=\"is_available\"\n defaultChecked={feature?.is_available ?? true}\n className=\"rounded border-input\"\n />\n <label\n className=\"text-sm font-medium leading-none\"\n htmlFor={isEditMode ? 'edit-is_available' : 'is_available'}\n >\n Feature disponibile\n </label>\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"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\"\n onClick={onClose}\n >\n Annulla\n </button>\n <button\n type=\"submit\"\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 disabled={isPending}\n >\n {isPending\n ? isEditMode ? 'Salvataggio...' : 'Creazione...'\n : isEditMode ? 'Salva Modifiche' : 'Crea Feature'}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n","import { Pencil, Trash2 } from 'lucide-react';\nimport type { AdminFeature } from '@growflowstudio/growflowbilling-admin-core';\nimport { StatusBadge } from '../shared/StatusBadge';\n\ninterface FeatureListItemProps {\n feature: AdminFeature;\n onEdit: (feature: AdminFeature) => void;\n onDelete: (feature: AdminFeature) => void;\n}\n\nexport function FeatureListItem({ feature, onEdit, onDelete }: FeatureListItemProps) {\n return (\n <div className=\"border rounded-lg p-4 hover:bg-muted/50 transition-colors\">\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={() => onEdit(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={() => onDelete(feature)}\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n );\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":["React","jsx","React","useState","jsx","jsx","jsx","jsxs","useMemo","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","useMemo","Check","jsx","jsxs","Check","jsx","jsxs","useMemo","jsx","jsxs","useMemo","Loader2","jsx","jsxs","Fragment","jsx","jsxs","useState","data","toast","Plus","RefreshCw","Pencil","Trash2","Upload","Check","X","useQuery","useDialogState","useState","useEffect","Loader2","jsx","jsxs","Fragment","jsx","jsxs","useDialogState","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","useCursorPagination","formatCurrencyFromCents","formatTimestamp","invoiceStatusColors","invoiceStatusLabels","formatCurrencyFromCents","formatTimestamp","jsx","jsxs","formatTimestamp","formatCurrencyFromCents","Fragment","jsx","jsxs","statusFilterOptions","useState","useCursorPagination","useDialogState","toast","invoiceStatusLabels","invoiceStatusColors","formatCurrencyFromCents","formatTimestamp","Eye","XCircle","useState","Plus","Package","toast","toast","Fragment","jsx","jsxs","Pencil","Trash2","jsx","jsxs","Pencil","Trash2","Fragment","jsx","jsxs","useState","toast","Package","Plus"]}