@burdenoff/microfe-billing 2026.528.1 → 2026.530.1

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.
Files changed (26) hide show
  1. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +27 -25
  2. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
  3. package/dist/billing/modules/dashboard/components/BillingAccountCard.js +9 -8
  4. package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
  5. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +7 -6
  6. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
  7. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +9 -7
  8. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
  9. package/dist/billing/modules/dashboard/pages/OverviewPage.js +7 -0
  10. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  11. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +82 -81
  12. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
  13. package/dist/billing/modules/plans/pages/PlanDetailPage.js +105 -104
  14. package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
  15. package/dist/billing/modules/plans/pages/PlanEditPage.js +162 -161
  16. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  17. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +85 -84
  18. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  19. package/dist/billing/modules/plans/pages/PlansListPage.js +115 -114
  20. package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
  21. package/dist/billing/shared/utils/index.js +1 -0
  22. package/dist/billing/shared/utils/planFeatureQuantity.js +11 -0
  23. package/dist/billing/shared/utils/planFeatureQuantity.js.map +1 -0
  24. package/dist/generated/global-operations.js +1 -0
  25. package/dist/generated/global-operations.js.map +1 -1
  26. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PlanDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/plans/pages/PlanDetailPage.tsx"],"sourcesContent":["/**\n * Plans Module - Plan Detail Page\n * Displays detailed information about a single plan\n */\n\nimport { type FC, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { usePlan, usePlanMutations } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n formatCurrency,\n formatPlanDuration,\n formatPlanDurationLabel,\n} from '../../../shared/utils/format';\nimport type { PlanFeature } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n/**\n * Combined quota info for display\n */\ninterface CombinedQuota {\n quotaId: string;\n name: string;\n quotaType: string;\n limitType: string;\n totalValue: number;\n count: number;\n}\n\n/**\n * Combines duplicate quotas by quota ID and aggregates their values\n */\nfunction combineQuotas(features: PlanFeature[]): CombinedQuota[] {\n const quotaMap = new Map<string, CombinedQuota>();\n\n for (const feature of features) {\n if (!feature.quota) continue;\n\n const quotaId = feature.quota.id;\n const limits = feature.quota.limits as { type?: string; value?: number } | null;\n const limitType = limits?.type ?? 'unknown';\n const limitValue = limits?.value ?? 0;\n\n const existing = quotaMap.get(quotaId);\n if (existing) {\n existing.totalValue += limitValue;\n existing.count += 1;\n } else {\n quotaMap.set(quotaId, {\n quotaId,\n name: feature.quota.name ?? 'Unknown Quota',\n quotaType: feature.quota.quotaType ?? '',\n limitType,\n totalValue: limitValue,\n count: 1,\n });\n }\n }\n\n return Array.from(quotaMap.values());\n}\n\nexport const PlanDetailPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const { planId } = useParams<{ planId: string }>();\n const navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n const { plan, isLoading, error, refetch } = usePlan(planId);\n const { togglePlan, isToggling } = usePlanMutations();\n\n // Combine duplicate quotas for cleaner display (must be before any returns)\n const combinedQuotas = useMemo(() => combineQuotas(plan?.features || []), [plan?.features]);\n\n // Permission check\n if (!permissions.canViewPlans) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-muted flex items-center justify-center\">\n <svg\n className=\"size-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground max-w-sm\">\n {tr(\n 'billing.plans.noViewPlanPermission',\n \"You don't have permission to view this plan.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (isLoading) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-10 bg-muted animate-pulse rounded\" />\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <div className=\"border border-border rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-4 w-full bg-muted animate-pulse rounded\" />\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"border border-border rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-muted animate-pulse rounded\" />\n <div className=\"h-10 w-full bg-muted animate-pulse rounded\" />\n </div>\n </div>\n </div>\n );\n }\n\n // Error state\n if (error || !plan) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center\">\n <svg\n className=\"size-6 text-destructive\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.planNotFound', 'Plan not found')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {error?.message ||\n tr(\n 'billing.plans.planNotFoundMessage',\n 'The plan you are looking for does not exist.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => navigateTo('/plans')}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Back to Plans\n </button>\n </div>\n </div>\n );\n }\n\n const handleToggle = async () => {\n if (!permissions.canManagePlans) return;\n try {\n await togglePlan(plan.id, !plan.isActive);\n await refetch();\n } catch (err) {\n console.error('Failed to toggle plan:', err);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex items-start gap-4\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/plans')}\n className=\"p-2 -ml-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-md transition-colors\"\n >\n <svg className=\"size-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold text-foreground\">{plan.name}</h1>\n <span\n className={`px-2 py-1 text-xs font-medium rounded ${\n plan.isActive\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-muted text-muted-foreground'\n }`}\n >\n {plan.isActive ? 'Active' : 'Inactive'}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {formatPlanDurationLabel(plan.duration)} billing plan\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {permissions.canCreateSubscription && plan.isActive && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/checkout/${plan.id}`)}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Subscribe to Plan\n </button>\n )}\n {permissions.canManagePlans && (\n <>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/plans/${plan.id}/edit`)}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Edit Plan\n </button>\n <button\n type=\"button\"\n onClick={handleToggle}\n disabled={isToggling}\n className={`px-4 py-2 text-sm font-medium border border-border rounded-md transition-colors ${\n plan.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {isToggling\n ? tr('billing.plans.processing', 'Processing...')\n : plan.isActive\n ? tr('billing.plans.deactivate', 'Deactivate')\n : tr('billing.plans.activate', 'Activate')}\n </button>\n </>\n )}\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Content */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Pricing Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.pricing', 'Pricing')}\n </h2>\n </div>\n <div className=\"p-6\">\n <div className=\"flex items-baseline gap-1\">\n <span className=\"text-4xl font-bold text-foreground\">\n {formatCurrency(plan.price, plan.currency)}\n </span>\n <span className=\"text-lg text-muted-foreground\">\n / {formatPlanDuration(plan.duration)}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-2\">\n {tr('billing.plans.billed', 'Billed')}{' '}\n {plan.duration === 'monthly'\n ? tr('billing.plans.everyMonth', 'every month')\n : tr('billing.plans.annually', 'annually')}\n </p>\n </div>\n </div>\n\n {/* Features Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.featuresAndQuotas', 'Features & Quotas')} (\n {combinedQuotas.length})\n </h2>\n </div>\n <div className=\"p-6\">\n {combinedQuotas.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.noFeatures', 'No features configured for this plan.')}\n </p>\n ) : (\n <ul className=\"space-y-3\">\n {combinedQuotas.map((quota) => (\n <li\n key={quota.quotaId}\n className=\"flex items-start gap-3 p-3 rounded-lg bg-muted/30\"\n >\n <div className=\"size-8 rounded-full bg-status-success-bg-subtle flex items-center justify-center shrink-0\">\n <svg\n className=\"size-4 text-status-success-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center justify-between\">\n <p className=\"font-medium text-foreground\">{quota.name}</p>\n <span className=\"font-semibold text-foreground\">\n {quota.totalValue.toLocaleString()}\n </span>\n </div>\n <div className=\"flex items-center gap-2 mt-1\">\n <span className=\"text-sm text-muted-foreground capitalize\">\n Type: {quota.limitType}\n </span>\n {quota.quotaType && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-muted text-muted-foreground rounded\">\n {quota.quotaType}\n </span>\n )}\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Plan Details Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.planDetails', 'Plan Details')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.planName', 'Plan Name')}\n </p>\n <p className=\"text-sm font-medium text-foreground mt-0.5\">{plan.name}</p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.status', 'Status')}\n </p>\n <p className=\"text-sm text-foreground mt-0.5\">\n <span\n className={`inline-flex items-center px-2 py-0.5 text-xs font-medium rounded ${\n plan.isActive\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-muted text-muted-foreground'\n }`}\n >\n {plan.isActive ? 'Active' : 'Inactive'}\n </span>\n </p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.price', 'Price')}\n </p>\n <p className=\"text-sm font-medium text-foreground mt-0.5\">\n {formatCurrency(plan.price, plan.currency)} / {formatPlanDuration(plan.duration)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.currency', 'Currency')}\n </p>\n <p className=\"text-sm text-foreground mt-0.5\">{plan.currency}</p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.billingPeriod', 'Billing Period')}\n </p>\n <p className=\"text-sm text-foreground mt-0.5\">\n {formatPlanDurationLabel(plan.duration)}\n </p>\n </div>\n </div>\n </div>\n\n {/* Quick Stats Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.statistics', 'Statistics')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.uniqueQuotas', 'Unique Quotas')}\n </p>\n <p className=\"font-semibold text-foreground\">{combinedQuotas.length}</p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PlanDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/plans/pages/PlanDetailPage.tsx"],"sourcesContent":["/**\n * Plans Module - Plan Detail Page\n * Displays detailed information about a single plan\n */\n\nimport { type FC, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { usePlan, usePlanMutations } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n formatCurrency,\n formatPlanDuration,\n formatPlanDurationLabel,\n} from '../../../shared/utils/format';\nimport { getPlanFeatureQuantity } from '../../../shared/utils/planFeatureQuantity';\nimport type { PlanFeature } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n/**\n * Combined quota info for display\n */\ninterface CombinedQuota {\n quotaId: string;\n name: string;\n quotaType: string;\n limitType: string;\n totalValue: number;\n count: number;\n}\n\n/**\n * Combines duplicate quotas by quota ID and aggregates their values\n */\nfunction combineQuotas(features: PlanFeature[]): CombinedQuota[] {\n const quotaMap = new Map<string, CombinedQuota>();\n\n for (const feature of features) {\n if (!feature.quota) continue;\n\n const quotaId = feature.quota.id;\n const limits = feature.quota.limits as { type?: string; value?: number } | null;\n const limitType = limits?.type ?? 'unknown';\n const limitValue = getPlanFeatureQuantity(feature);\n\n const existing = quotaMap.get(quotaId);\n if (existing) {\n existing.totalValue += limitValue;\n existing.count += 1;\n } else {\n quotaMap.set(quotaId, {\n quotaId,\n name: feature.quota.name ?? 'Unknown Quota',\n quotaType: feature.quota.quotaType ?? '',\n limitType,\n totalValue: limitValue,\n count: 1,\n });\n }\n }\n\n return Array.from(quotaMap.values());\n}\n\nexport const PlanDetailPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const { planId } = useParams<{ planId: string }>();\n const navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n const { plan, isLoading, error, refetch } = usePlan(planId);\n const { togglePlan, isToggling } = usePlanMutations();\n\n // Combine duplicate quotas for cleaner display (must be before any returns)\n const combinedQuotas = useMemo(() => combineQuotas(plan?.features || []), [plan?.features]);\n\n // Permission check\n if (!permissions.canViewPlans) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-muted flex items-center justify-center\">\n <svg\n className=\"size-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground max-w-sm\">\n {tr(\n 'billing.plans.noViewPlanPermission',\n \"You don't have permission to view this plan.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (isLoading) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-10 bg-muted animate-pulse rounded\" />\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <div className=\"border border-border rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-4 w-full bg-muted animate-pulse rounded\" />\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"border border-border rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-muted animate-pulse rounded\" />\n <div className=\"h-10 w-full bg-muted animate-pulse rounded\" />\n </div>\n </div>\n </div>\n );\n }\n\n // Error state\n if (error || !plan) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center\">\n <svg\n className=\"size-6 text-destructive\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.planNotFound', 'Plan not found')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {error?.message ||\n tr(\n 'billing.plans.planNotFoundMessage',\n 'The plan you are looking for does not exist.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => navigateTo('/plans')}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Back to Plans\n </button>\n </div>\n </div>\n );\n }\n\n const handleToggle = async () => {\n if (!permissions.canManagePlans) return;\n try {\n await togglePlan(plan.id, !plan.isActive);\n await refetch();\n } catch (err) {\n console.error('Failed to toggle plan:', err);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex items-start gap-4\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/plans')}\n className=\"p-2 -ml-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-md transition-colors\"\n >\n <svg className=\"size-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold text-foreground\">{plan.name}</h1>\n <span\n className={`px-2 py-1 text-xs font-medium rounded ${\n plan.isActive\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-muted text-muted-foreground'\n }`}\n >\n {plan.isActive ? 'Active' : 'Inactive'}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {formatPlanDurationLabel(plan.duration)} billing plan\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {permissions.canCreateSubscription && plan.isActive && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/checkout/${plan.id}`)}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Subscribe to Plan\n </button>\n )}\n {permissions.canManagePlans && (\n <>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/plans/${plan.id}/edit`)}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Edit Plan\n </button>\n <button\n type=\"button\"\n onClick={handleToggle}\n disabled={isToggling}\n className={`px-4 py-2 text-sm font-medium border border-border rounded-md transition-colors ${\n plan.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {isToggling\n ? tr('billing.plans.processing', 'Processing...')\n : plan.isActive\n ? tr('billing.plans.deactivate', 'Deactivate')\n : tr('billing.plans.activate', 'Activate')}\n </button>\n </>\n )}\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Content */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Pricing Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.pricing', 'Pricing')}\n </h2>\n </div>\n <div className=\"p-6\">\n <div className=\"flex items-baseline gap-1\">\n <span className=\"text-4xl font-bold text-foreground\">\n {formatCurrency(plan.price, plan.currency)}\n </span>\n <span className=\"text-lg text-muted-foreground\">\n / {formatPlanDuration(plan.duration)}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-2\">\n {tr('billing.plans.billed', 'Billed')}{' '}\n {plan.duration === 'monthly'\n ? tr('billing.plans.everyMonth', 'every month')\n : tr('billing.plans.annually', 'annually')}\n </p>\n </div>\n </div>\n\n {/* Features Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.featuresAndQuotas', 'Features & Quotas')} (\n {combinedQuotas.length})\n </h2>\n </div>\n <div className=\"p-6\">\n {combinedQuotas.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.noFeatures', 'No features configured for this plan.')}\n </p>\n ) : (\n <ul className=\"space-y-3\">\n {combinedQuotas.map((quota) => (\n <li\n key={quota.quotaId}\n className=\"flex items-start gap-3 p-3 rounded-lg bg-muted/30\"\n >\n <div className=\"size-8 rounded-full bg-status-success-bg-subtle flex items-center justify-center shrink-0\">\n <svg\n className=\"size-4 text-status-success-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center justify-between\">\n <p className=\"font-medium text-foreground\">{quota.name}</p>\n <span className=\"font-semibold text-foreground\">\n {quota.totalValue.toLocaleString()}\n </span>\n </div>\n <div className=\"flex items-center gap-2 mt-1\">\n <span className=\"text-sm text-muted-foreground capitalize\">\n Type: {quota.limitType}\n </span>\n {quota.quotaType && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-muted text-muted-foreground rounded\">\n {quota.quotaType}\n </span>\n )}\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Plan Details Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.planDetails', 'Plan Details')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.planName', 'Plan Name')}\n </p>\n <p className=\"text-sm font-medium text-foreground mt-0.5\">{plan.name}</p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.status', 'Status')}\n </p>\n <p className=\"text-sm text-foreground mt-0.5\">\n <span\n className={`inline-flex items-center px-2 py-0.5 text-xs font-medium rounded ${\n plan.isActive\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-muted text-muted-foreground'\n }`}\n >\n {plan.isActive ? 'Active' : 'Inactive'}\n </span>\n </p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.price', 'Price')}\n </p>\n <p className=\"text-sm font-medium text-foreground mt-0.5\">\n {formatCurrency(plan.price, plan.currency)} / {formatPlanDuration(plan.duration)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.currency', 'Currency')}\n </p>\n <p className=\"text-sm text-foreground mt-0.5\">{plan.currency}</p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.billingPeriod', 'Billing Period')}\n </p>\n <p className=\"text-sm text-foreground mt-0.5\">\n {formatPlanDurationLabel(plan.duration)}\n </p>\n </div>\n </div>\n </div>\n\n {/* Quick Stats Card */}\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-6 border-b border-border bg-muted/30\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.plans.statistics', 'Statistics')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.plans.uniqueQuotas', 'Unique Quotas')}\n </p>\n <p className=\"font-semibold text-foreground\">{combinedQuotas.length}</p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}