@burdenoff/microfe-billing 2026.515.6 → 2026.516.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 (29) hide show
  1. package/dist/billing/modules/billing/pages/InvoicesListPage.js +1 -1
  2. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  3. package/dist/billing/modules/billing/pages/RefundsPage.js +1 -1
  4. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  5. package/dist/billing/modules/checkout/components/OrderSummary.js +4 -4
  6. package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
  7. package/dist/billing/modules/checkout/pages/CheckoutPage.d.ts.map +1 -1
  8. package/dist/billing/modules/checkout/pages/CheckoutPage.js +2 -2
  9. package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
  10. package/dist/billing/modules/dashboard/pages/OverviewPage.js +2 -2
  11. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  12. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +2 -2
  13. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  14. package/dist/billing/modules/quota/pages/QuotaPage.js +1 -1
  15. package/dist/billing/modules/quota/pages/QuotaPage.js.map +1 -1
  16. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.d.ts.map +1 -1
  17. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +101 -44
  18. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  19. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.d.ts.map +1 -1
  20. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +105 -46
  21. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  22. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +3 -3
  23. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  24. package/dist/billing/modules/usage/pages/UsagePage.js +3 -3
  25. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  26. package/dist/billing/shared/types/graphql.d.ts +2 -0
  27. package/dist/billing/shared/types/graphql.d.ts.map +1 -1
  28. package/dist/billing/shared/types/graphql.js.map +1 -1
  29. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../../../../src/billing/modules/dashboard/pages/OverviewPage.tsx"],"sourcesContent":["/**\n * Billing Overview Page\n * Main dashboard for billing showing accounts, subscriptions, payment methods, and addons\n */\n\nimport { type FC, useState, useCallback, useEffect } from 'react';\nimport {\n Plus,\n Building2,\n RefreshCw,\n Loader2,\n Wallet,\n ChevronDown,\n Check,\n Activity,\n Receipt,\n ArrowRight,\n Sparkles,\n Crown,\n Coins,\n} from 'lucide-react';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { StatCard } from '../../../shared/components/StatCard';\nimport { EmptyState } from '../../../shared/components/EmptyState';\nimport { ServerError } from '../../../shared/components/ServerError';\nimport { AccessDenied } from '../../../shared/components/AccessDenied';\nimport { isServerError } from '../../../shared/utils';\nimport { useBillingOverviewData, useDashboardMutations } from '../hooks';\nimport {\n BillingAccountCard,\n PaymentMethodsSection,\n ActiveSubscriptionCard,\n RecommendedAddonsSection,\n CreateBillingAccountModal,\n AddPaymentMethodModal,\n} from '../components';\nimport { useAddonCartStore } from '../../addons/store/addonCartStore';\nimport { FloatingCartDrawer } from '../../addons/components/FloatingCartDrawer';\nimport {\n getStoredBillingAccountId,\n setStoredBillingAccountId,\n} from '../../../hooks/useBillingAccountSelection';\nimport { withBillingAccountId } from '../../../shared/utils/navigation';\nimport type {\n BillingAccount,\n CreateBillingAccountInput,\n SetBillingAddressInput,\n Addon,\n} from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nexport const OverviewPage: 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 { navigate, basePath, orgId, productId } = useBilling();\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n\n const [selectedAccountId, setSelectedAccountIdState] = useState<string | null>(() =>\n getStoredBillingAccountId(orgId)\n );\n\n const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const [isAccountSelectorOpen, setIsAccountSelectorOpen] = useState(false);\n const [isAddPaymentModalOpen, setIsAddPaymentModalOpen] = useState(false);\n const [selectedSubscriptionIndex, setSelectedSubscriptionIndex] = useState(0);\n const [isSubscriptionSelectorOpen, setIsSubscriptionSelectorOpen] = useState(false);\n\n const {\n billingAccounts,\n currentAccount,\n paymentMethods,\n activeSubscriptions,\n hasActiveSubscription,\n recommendedAddons,\n isLoading,\n error,\n refetchAll,\n } = useBillingOverviewData(selectedAccountId, productId);\n\n const currentAccountId = currentAccount?.id;\n const isLoadingAddons = isLoading;\n\n const setSelectedAccountId = useCallback(\n (accountId: string | null) => {\n setSelectedAccountIdState(accountId);\n setStoredBillingAccountId(orgId, accountId);\n },\n [orgId]\n );\n\n // Addon cart store for add to cart functionality\n const { addToCart, isInCart, getCartItem, updateQuantity, removeFromCart } = useAddonCartStore();\n\n const {\n createBillingAccount,\n setBillingAddress,\n setDefaultPaymentMethod,\n deletePaymentMethod,\n isCreatingAccount,\n } = useDashboardMutations();\n\n // Reset subscription selector when account changes or subscriptions change\n useEffect(() => {\n setSelectedSubscriptionIndex(0);\n setIsSubscriptionSelectorOpen(false);\n }, [currentAccountId, activeSubscriptions.length]);\n\n useEffect(() => {\n if (selectedAccountId && billingAccounts.length > 0) {\n const accountExists = billingAccounts.some((account) => account.id === selectedAccountId);\n if (!accountExists) {\n setSelectedAccountId(null);\n }\n }\n }, [billingAccounts, selectedAccountId, setSelectedAccountId]);\n\n useEffect(() => {\n if (!selectedAccountId && billingAccounts.length > 0) {\n const defaultAccount =\n billingAccounts.find((account) => account.isDefault) ?? billingAccounts[0];\n setSelectedAccountId(defaultAccount.id);\n }\n }, [billingAccounts, selectedAccountId, setSelectedAccountId]);\n\n // Derive selected subscription from active subscriptions\n const selectedSubscription =\n activeSubscriptions[selectedSubscriptionIndex] || activeSubscriptions[0] || null;\n\n // Helper for navigation - properly joins basePath and path\n const navigateTo = useCallback(\n (path: string) => {\n // Handle path joining to avoid double slashes (e.g., / + /plans = //plans)\n let fullPath = path;\n if (basePath && basePath !== '/') {\n // Remove trailing slash from basePath and leading slash from path if needed\n const base = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;\n const suffix = path.startsWith('/') ? path : `/${path}`;\n fullPath = `${base}${suffix}`;\n }\n navigate(fullPath);\n },\n [navigate, basePath]\n );\n\n // Handlers\n const handleCreateAccount = useCallback(\n async (\n input: CreateBillingAccountInput,\n address?: Omit<SetBillingAddressInput, 'billingAccountId'>\n ) => {\n setCreateError(null);\n try {\n const newAccount = await createBillingAccount(input);\n\n // If address data provided, set the billing address\n if (address && newAccount.id) {\n await setBillingAddress({\n billingAccountId: newAccount.id,\n ...address,\n });\n }\n\n setIsCreateModalOpen(false);\n setSelectedAccountId(newAccount.id);\n emit('billing.billing_account.created', {\n route: '/billing/overview',\n entityId: newAccount.id,\n source: 'overview',\n });\n await refetchAll();\n } catch (err) {\n setCreateError(err instanceof Error ? err.message : 'Failed to create billing account');\n }\n },\n [createBillingAccount, emit, refetchAll, setBillingAddress, setSelectedAccountId]\n );\n\n const handleAddPaymentMethod = useCallback(() => {\n setIsAddPaymentModalOpen(true);\n }, []);\n\n // Helper to refetch the current account data\n const refetchCurrentAccount = useCallback(async () => {\n await refetchAll();\n }, [refetchAll]);\n\n const handlePaymentMethodAdded = useCallback(async () => {\n emit('billing.payment_method.added', {\n route: '/billing/overview',\n entityId: currentAccountId,\n source: 'overview',\n });\n await refetchCurrentAccount();\n }, [currentAccountId, emit, refetchCurrentAccount]);\n\n const handleSetDefaultPaymentMethod = useCallback(\n async (id: string) => {\n if (!currentAccountId) return;\n await setDefaultPaymentMethod(id, currentAccountId);\n emit('billing.payment_method.default_set', {\n route: '/billing/overview',\n entityId: id,\n source: 'overview',\n });\n await refetchCurrentAccount();\n },\n [currentAccountId, emit, setDefaultPaymentMethod, refetchCurrentAccount]\n );\n\n const handleDeletePaymentMethod = useCallback(\n async (id: string) => {\n if (!currentAccountId) return;\n await deletePaymentMethod(id, currentAccountId);\n emit('billing.payment_method.deleted', {\n route: '/billing/overview',\n entityId: id,\n source: 'overview',\n });\n await refetchCurrentAccount();\n },\n [currentAccountId, deletePaymentMethod, emit, refetchCurrentAccount]\n );\n\n const handleSelectAccount = useCallback(\n (account: BillingAccount) => {\n setSelectedAccountId(account.id);\n setIsAccountSelectorOpen(false);\n },\n [setSelectedAccountId]\n );\n\n const handleRefresh = useCallback(async () => {\n await refetchAll();\n }, [refetchAll]);\n\n // Handler for adding addon to cart\n const handleAddToCart = useCallback(\n (addon: Addon) => {\n addToCart(addon);\n },\n [addToCart]\n );\n\n // Handler to check if addon is in cart\n const handleIsInCart = useCallback(\n (addonId: string) => {\n return isInCart(addonId);\n },\n [isInCart]\n );\n\n // Handler to get cart quantity for addon\n const handleGetCartQuantity = useCallback(\n (addonId: string) => {\n const item = getCartItem(addonId);\n return item?.quantity || 0;\n },\n [getCartItem]\n );\n\n // Handler to update quantity in cart\n const handleUpdateQuantity = useCallback(\n (addonId: string, quantity: number) => {\n if (quantity <= 0) {\n removeFromCart(addonId);\n } else {\n updateQuantity(addonId, quantity);\n }\n },\n [updateQuantity, removeFromCart]\n );\n\n // Handler to remove from cart\n const handleRemoveFromCart = useCallback(\n (addonId: string) => {\n removeFromCart(addonId);\n },\n [removeFromCart]\n );\n\n // Permission check - must be after all hooks are defined\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view billing information.\" />;\n }\n\n // Error state\n if (error && isServerError(error) && !isLoading) {\n return (\n <div className=\"p-6\">\n <ServerError\n title=\"Server Unavailable\"\n message=\"Unable to load billing overview. The server might be down or experiencing issues.\"\n onRetry={handleRefresh}\n showRetry\n />\n </div>\n );\n }\n\n // Loading state\n if (isLoading && !currentAccount) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"flex flex-col items-center gap-3\">\n <Loader2 className=\"w-8 h-8 animate-spin text-primary\" />\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.overview.loadingInfo', 'Loading billing information...')}\n </p>\n </div>\n </div>\n );\n }\n\n // No billing accounts state\n if (!isLoading && billingAccounts.length === 0) {\n return (\n <div className=\"p-6\">\n <header className=\"mb-8\">\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.overview.title', 'Billing Overview')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\n 'billing.overview.emptySetupDescription',\n 'Set up billing to manage subscriptions, payments, and invoices'\n )}\n </p>\n </header>\n <EmptyState\n icon={<Building2 className=\"w-6 h-6 text-muted-foreground\" />}\n title={tr('billing.overview.emptyTitle', 'No billing account')}\n description={tr(\n 'billing.overview.emptyDescription',\n 'Create a billing account to start managing your subscriptions and payments'\n )}\n action={\n permissions.canManageBillingAccount ? (\n <button\n onClick={() => setIsCreateModalOpen(true)}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('billing.overview.createBillingAccount', 'Create Billing Account')}\n </button>\n ) : undefined\n }\n />\n\n <CreateBillingAccountModal\n isOpen={isCreateModalOpen}\n onClose={() => {\n setIsCreateModalOpen(false);\n setCreateError(null);\n }}\n onSubmit={handleCreateAccount}\n isSubmitting={isCreatingAccount}\n error={createError}\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-6 space-y-8\">\n {/* Header */}\n <header className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.overview.title', 'Billing Overview')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\n 'billing.overview.description',\n 'Manage your billing accounts, subscriptions, and payment methods'\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleRefresh}\n className=\"p-2 rounded-lg border border-border hover:bg-muted text-muted-foreground hover:text-foreground transition-colors\"\n aria-label={tr('billing.overview.refresh', 'Refresh')}\n >\n <RefreshCw className={`w-4 h-4 ${isLoading ? 'animate-spin' : ''}`} />\n </button>\n {permissions.canManageBillingAccount && billingAccounts.length > 0 && (\n <button\n onClick={() => setIsCreateModalOpen(true)}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n <span className=\"hidden sm:inline\">\n {tr('billing.overview.newAccount', 'New Account')}\n </span>\n </button>\n )}\n </div>\n </header>\n\n {/* Account Selector (if multiple accounts) */}\n {billingAccounts.length > 1 && (\n <div className=\"relative\">\n <button\n onClick={() => setIsAccountSelectorOpen(!isAccountSelectorOpen)}\n className=\"w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center\">\n <Building2 className=\"w-4 h-4 text-primary\" />\n </div>\n <div className=\"text-left\">\n <p className=\"text-sm font-medium text-foreground\">\n {currentAccount?.name || tr('billing.overview.selectAccount', 'Select Account')}\n </p>\n <p className=\"text-xs text-muted-foreground\">{currentAccount?.email}</p>\n </div>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-muted-foreground transition-transform ${isAccountSelectorOpen ? 'rotate-180' : ''}`}\n />\n </button>\n\n {isAccountSelectorOpen && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setIsAccountSelectorOpen(false)} />\n <div className=\"absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto\">\n {billingAccounts.map((account) => (\n <button\n key={account.id}\n onClick={() => handleSelectAccount(account)}\n className=\"w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"w-8 h-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0\">\n <Building2 className=\"w-4 h-4 text-muted-foreground\" />\n </div>\n <div className=\"text-left min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {account.name}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">{account.email}</p>\n </div>\n </div>\n {currentAccount?.id === account.id && (\n <Check className=\"w-4 h-4 text-primary flex-shrink-0\" />\n )}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Stats Row */}\n {currentAccount && (\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <StatCard\n label={tr('billing.overview.stats.creditBalance', 'Credit Balance')}\n value={`${(currentAccount.creditAmount || 0).toLocaleString()} Credits`}\n icon={<Wallet className=\"w-5 h-5\" />}\n />\n <StatCard\n label={tr('billing.overview.stats.activePlans', 'Active Plans')}\n value={\n activeSubscriptions.length > 0\n ? activeSubscriptions.length === 1\n ? activeSubscriptions[0]?.plan?.name || '1 Plan'\n : `${activeSubscriptions.length} ${tr('billing.overview.stats.plansSuffix', 'Plans')}`\n : tr('billing.overview.stats.none', 'None')\n }\n icon={<RefreshCw className=\"w-5 h-5\" />}\n />\n <StatCard\n label={tr('billing.overview.stats.paymentMethods', 'Payment Methods')}\n value={paymentMethods.length}\n icon={<Building2 className=\"w-5 h-5\" />}\n />\n <StatCard\n label={tr('billing.overview.stats.paymentCurrency', 'Payment Currency')}\n value={currentAccount.currency || 'USD'}\n icon={<Building2 className=\"w-5 h-5\" />}\n />\n </div>\n )}\n\n {/* Main Content Grid */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Left Column - Billing Account & Subscription */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Billing Account Card */}\n {currentAccount && (\n <BillingAccountCard\n account={currentAccount}\n isDefault={currentAccount.isDefault ?? false}\n onEdit={() =>\n currentAccount && navigateTo(`/settings?billingAccountId=${currentAccount.id}`)\n }\n onViewTransactions={() => navigateTo(`/transactions/${currentAccount.id}`)}\n onViewCreditTransactions={() =>\n navigateTo(`/creditTransactions/${currentAccount.id}`)\n }\n />\n )}\n\n {/* Active Subscriptions */}\n <div className=\"space-y-3\">\n {/* Subscription Selector (if multiple subscriptions) */}\n {activeSubscriptions.length > 1 && (\n <div className=\"relative\">\n <button\n onClick={() => setIsSubscriptionSelectorOpen(!isSubscriptionSelectorOpen)}\n className=\"w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center\">\n <Crown className=\"w-4 h-4 text-primary\" />\n </div>\n <div className=\"text-left\">\n <p className=\"text-sm font-medium text-foreground\">\n {selectedSubscription?.plan?.name ||\n tr('billing.overview.selectSubscription', 'Select Subscription')}\n {selectedSubscription?.plan?.product?.name && (\n <span className=\"text-muted-foreground font-normal\">\n {' '}\n · {selectedSubscription.plan.product.name}\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {activeSubscriptions.length}{' '}\n {tr('billing.overview.activeSubscriptions', 'active subscriptions')}\n </p>\n </div>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-muted-foreground transition-transform ${isSubscriptionSelectorOpen ? 'rotate-180' : ''}`}\n />\n </button>\n\n {isSubscriptionSelectorOpen && (\n <>\n <div\n className=\"fixed inset-0 z-10\"\n onClick={() => setIsSubscriptionSelectorOpen(false)}\n />\n <div className=\"absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto\">\n {activeSubscriptions.map((subscription, index) => (\n <button\n key={subscription.id}\n onClick={() => {\n setSelectedSubscriptionIndex(index);\n setIsSubscriptionSelectorOpen(false);\n }}\n className=\"w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"w-8 h-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0\">\n <Crown className=\"w-4 h-4 text-muted-foreground\" />\n </div>\n <div className=\"text-left min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {subscription.plan?.name ||\n tr('billing.overview.subscription', 'Subscription')}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">\n {subscription.plan?.product?.name ||\n tr('billing.overview.unknownProduct', 'Unknown Product')}{' '}\n · {tr('billing.overview.ends', 'Ends')}{' '}\n {new Date(subscription.endDate).toLocaleDateString()}\n </p>\n </div>\n </div>\n {selectedSubscriptionIndex === index && (\n <Check className=\"w-4 h-4 text-primary flex-shrink-0\" />\n )}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Single Subscription Card */}\n <ActiveSubscriptionCard\n subscription={selectedSubscription}\n onViewDetails={() =>\n selectedSubscription &&\n navigateTo(\n withBillingAccountId(\n `/subscriptions/${selectedSubscription.id}`,\n selectedSubscription.billingAccountId ?? currentAccount?.id\n )\n )\n }\n onUpgrade={() =>\n selectedSubscription &&\n navigateTo(\n withBillingAccountId(\n `/subscriptions/${selectedSubscription.id}/upgrade`,\n selectedSubscription.billingAccountId ?? currentAccount?.id\n )\n )\n }\n onManage={() =>\n currentAccount && navigateTo(`/subscriptions?billingAccountId=${currentAccount.id}`)\n }\n onPurchasePlan={() => navigateTo('/plans')}\n />\n </div>\n\n {/* Payment Methods */}\n {currentAccount && (\n <PaymentMethodsSection\n paymentMethods={paymentMethods}\n billingAccountId={currentAccount.id}\n onAddPaymentMethod={handleAddPaymentMethod}\n onSetDefault={handleSetDefaultPaymentMethod}\n onDelete={handleDeletePaymentMethod}\n isLoading={isLoading}\n />\n )}\n </div>\n\n {/* Right Column - Quick Actions & Info */}\n <div className=\"space-y-6\">\n {/* Quick Actions */}\n <section className=\"border border-border rounded-lg bg-card p-4\">\n <h3 className=\"font-semibold text-foreground mb-4\">Quick Actions</h3>\n <div className=\"space-y-2\">\n <button\n onClick={() => currentAccount && navigateTo(`/transactions/${currentAccount.id}`)}\n disabled={!currentAccount}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <div className=\"w-8 h-8 rounded bg-status-info-bg-subtle flex items-center justify-center\">\n <Receipt className=\"w-4 h-4 text-accent-blue\" />\n </div>\n View Transactions\n </button>\n <button\n onClick={() =>\n currentAccount && navigateTo(`/creditTransactions/${currentAccount.id}`)\n }\n disabled={!currentAccount}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <div className=\"w-8 h-8 rounded bg-status-warning-bg-subtle flex items-center justify-center\">\n <Wallet className=\"w-4 h-4 text-status-warning-text\" />\n </div>\n Credit History\n </button>\n <button\n onClick={() => navigateTo('/checkout/credits')}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <div className=\"w-8 h-8 rounded bg-status-success-bg-subtle flex items-center justify-center\">\n <Coins className=\"w-4 h-4 text-status-success-text\" />\n </div>\n Purchase Credits\n </button>\n <button\n onClick={() =>\n currentAccount && navigateTo(`/usage?billingAccountId=${currentAccount.id}`)\n }\n disabled={!currentAccount}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <div className=\"w-8 h-8 rounded bg-accent-violet-subtle flex items-center justify-center\">\n <Activity className=\"w-4 h-4 text-accent-violet\" />\n </div>\n Usage Analytics\n </button>\n </div>\n </section>\n\n {/* Get Started (if no subscription) */}\n {!hasActiveSubscription && (\n <section className=\"border border-border rounded-lg bg-gradient-to-br from-primary/5 to-primary/10 p-4\">\n <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0\">\n <Sparkles className=\"w-5 h-5 text-primary\" />\n </div>\n <div>\n <h3 className=\"font-semibold text-foreground\">Get Started</h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Choose a plan that fits your needs to unlock all features\n </p>\n </div>\n </div>\n <button\n onClick={() => navigateTo('/plans')}\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n Browse Plans\n <ArrowRight className=\"w-4 h-4\" />\n </button>\n </section>\n )}\n </div>\n </div>\n\n {/* Recommended Addons (only if has subscription) - Limited to 3 with cart support */}\n <RecommendedAddonsSection\n addons={recommendedAddons}\n hasSubscription={hasActiveSubscription}\n onViewAddon={(addonId) => navigateTo(`/addons/${addonId}`)}\n onPurchaseAddon={(addonId) => navigateTo(`/addons/${addonId}?action=purchase`)}\n onViewAllAddons={() => navigateTo('/addons')}\n onAddToCart={handleAddToCart}\n isInCart={handleIsInCart}\n getCartQuantity={handleGetCartQuantity}\n onUpdateQuantity={handleUpdateQuantity}\n onRemoveFromCart={handleRemoveFromCart}\n maxAddons={3}\n isLoading={isLoadingAddons}\n />\n\n {/* Floating Cart Drawer - shows when items are in cart */}\n <FloatingCartDrawer />\n\n {/* Create Billing Account Modal */}\n <CreateBillingAccountModal\n isOpen={isCreateModalOpen}\n onClose={() => {\n setIsCreateModalOpen(false);\n setCreateError(null);\n }}\n onSubmit={handleCreateAccount}\n isSubmitting={isCreatingAccount}\n error={createError}\n />\n\n {/* Add Payment Method Modal */}\n {currentAccount && (\n <AddPaymentMethodModal\n isOpen={isAddPaymentModalOpen}\n onClose={() => setIsAddPaymentModalOpen(false)}\n billingAccountId={currentAccount.id}\n currency={currentAccount.currency}\n country={currentAccount.billingAddresses?.[0]?.country}\n onSuccess={handlePaymentMethodAdded}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../../../../src/billing/modules/dashboard/pages/OverviewPage.tsx"],"sourcesContent":["/**\n * Billing Overview Page\n * Main dashboard for billing showing accounts, subscriptions, payment methods, and addons\n */\n\nimport { type FC, useState, useCallback, useEffect } from 'react';\nimport {\n Plus,\n Building2,\n RefreshCw,\n Loader2,\n Wallet,\n ChevronDown,\n Check,\n Activity,\n Receipt,\n ArrowRight,\n Sparkles,\n Crown,\n Coins,\n} from 'lucide-react';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { StatCard } from '../../../shared/components/StatCard';\nimport { EmptyState } from '../../../shared/components/EmptyState';\nimport { ServerError } from '../../../shared/components/ServerError';\nimport { AccessDenied } from '../../../shared/components/AccessDenied';\nimport { isServerError } from '../../../shared/utils';\nimport { useBillingOverviewData, useDashboardMutations } from '../hooks';\nimport {\n BillingAccountCard,\n PaymentMethodsSection,\n ActiveSubscriptionCard,\n RecommendedAddonsSection,\n CreateBillingAccountModal,\n AddPaymentMethodModal,\n} from '../components';\nimport { useAddonCartStore } from '../../addons/store/addonCartStore';\nimport { FloatingCartDrawer } from '../../addons/components/FloatingCartDrawer';\nimport {\n getStoredBillingAccountId,\n setStoredBillingAccountId,\n} from '../../../hooks/useBillingAccountSelection';\nimport { withBillingAccountId } from '../../../shared/utils/navigation';\nimport type {\n BillingAccount,\n CreateBillingAccountInput,\n SetBillingAddressInput,\n Addon,\n} from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nexport const OverviewPage: 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 { navigate, basePath, orgId, productId } = useBilling();\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n\n const [selectedAccountId, setSelectedAccountIdState] = useState<string | null>(() =>\n getStoredBillingAccountId(orgId)\n );\n\n const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const [isAccountSelectorOpen, setIsAccountSelectorOpen] = useState(false);\n const [isAddPaymentModalOpen, setIsAddPaymentModalOpen] = useState(false);\n const [selectedSubscriptionIndex, setSelectedSubscriptionIndex] = useState(0);\n const [isSubscriptionSelectorOpen, setIsSubscriptionSelectorOpen] = useState(false);\n\n const {\n billingAccounts,\n currentAccount,\n paymentMethods,\n activeSubscriptions,\n hasActiveSubscription,\n recommendedAddons,\n isLoading,\n error,\n refetchAll,\n } = useBillingOverviewData(selectedAccountId, productId);\n\n const currentAccountId = currentAccount?.id;\n const isLoadingAddons = isLoading;\n\n const setSelectedAccountId = useCallback(\n (accountId: string | null) => {\n setSelectedAccountIdState(accountId);\n setStoredBillingAccountId(orgId, accountId);\n },\n [orgId]\n );\n\n // Addon cart store for add to cart functionality\n const { addToCart, isInCart, getCartItem, updateQuantity, removeFromCart } = useAddonCartStore();\n\n const {\n createBillingAccount,\n setBillingAddress,\n setDefaultPaymentMethod,\n deletePaymentMethod,\n isCreatingAccount,\n } = useDashboardMutations();\n\n // Reset subscription selector when account changes or subscriptions change\n useEffect(() => {\n setSelectedSubscriptionIndex(0);\n setIsSubscriptionSelectorOpen(false);\n }, [currentAccountId, activeSubscriptions.length]);\n\n useEffect(() => {\n if (selectedAccountId && billingAccounts.length > 0) {\n const accountExists = billingAccounts.some((account) => account.id === selectedAccountId);\n if (!accountExists) {\n setSelectedAccountId(null);\n }\n }\n }, [billingAccounts, selectedAccountId, setSelectedAccountId]);\n\n useEffect(() => {\n if (!selectedAccountId && billingAccounts.length > 0) {\n const defaultAccount =\n billingAccounts.find((account) => account.isDefault) ?? billingAccounts[0];\n setSelectedAccountId(defaultAccount.id);\n }\n }, [billingAccounts, selectedAccountId, setSelectedAccountId]);\n\n // Derive selected subscription from active subscriptions\n const selectedSubscription =\n activeSubscriptions[selectedSubscriptionIndex] || activeSubscriptions[0] || null;\n\n // Helper for navigation - properly joins basePath and path\n const navigateTo = useCallback(\n (path: string) => {\n // Handle path joining to avoid double slashes (e.g., / + /plans = //plans)\n let fullPath = path;\n if (basePath && basePath !== '/') {\n // Remove trailing slash from basePath and leading slash from path if needed\n const base = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;\n const suffix = path.startsWith('/') ? path : `/${path}`;\n fullPath = `${base}${suffix}`;\n }\n navigate(fullPath);\n },\n [navigate, basePath]\n );\n\n // Handlers\n const handleCreateAccount = useCallback(\n async (\n input: CreateBillingAccountInput,\n address?: Omit<SetBillingAddressInput, 'billingAccountId'>\n ) => {\n setCreateError(null);\n try {\n const newAccount = await createBillingAccount(input);\n\n // If address data provided, set the billing address\n if (address && newAccount.id) {\n await setBillingAddress({\n billingAccountId: newAccount.id,\n ...address,\n });\n }\n\n setIsCreateModalOpen(false);\n setSelectedAccountId(newAccount.id);\n emit('billing.billing_account.created', {\n route: '/billing/overview',\n entityId: newAccount.id,\n source: 'overview',\n });\n await refetchAll();\n } catch (err) {\n setCreateError(err instanceof Error ? err.message : 'Failed to create billing account');\n }\n },\n [createBillingAccount, emit, refetchAll, setBillingAddress, setSelectedAccountId]\n );\n\n const handleAddPaymentMethod = useCallback(() => {\n setIsAddPaymentModalOpen(true);\n }, []);\n\n // Helper to refetch the current account data\n const refetchCurrentAccount = useCallback(async () => {\n await refetchAll();\n }, [refetchAll]);\n\n const handlePaymentMethodAdded = useCallback(async () => {\n emit('billing.payment_method.added', {\n route: '/billing/overview',\n entityId: currentAccountId,\n source: 'overview',\n });\n await refetchCurrentAccount();\n }, [currentAccountId, emit, refetchCurrentAccount]);\n\n const handleSetDefaultPaymentMethod = useCallback(\n async (id: string) => {\n if (!currentAccountId) return;\n await setDefaultPaymentMethod(id, currentAccountId);\n emit('billing.payment_method.default_set', {\n route: '/billing/overview',\n entityId: id,\n source: 'overview',\n });\n await refetchCurrentAccount();\n },\n [currentAccountId, emit, setDefaultPaymentMethod, refetchCurrentAccount]\n );\n\n const handleDeletePaymentMethod = useCallback(\n async (id: string) => {\n if (!currentAccountId) return;\n await deletePaymentMethod(id, currentAccountId);\n emit('billing.payment_method.deleted', {\n route: '/billing/overview',\n entityId: id,\n source: 'overview',\n });\n await refetchCurrentAccount();\n },\n [currentAccountId, deletePaymentMethod, emit, refetchCurrentAccount]\n );\n\n const handleSelectAccount = useCallback(\n (account: BillingAccount) => {\n setSelectedAccountId(account.id);\n setIsAccountSelectorOpen(false);\n },\n [setSelectedAccountId]\n );\n\n const handleRefresh = useCallback(async () => {\n await refetchAll();\n }, [refetchAll]);\n\n // Handler for adding addon to cart\n const handleAddToCart = useCallback(\n (addon: Addon) => {\n addToCart(addon);\n },\n [addToCart]\n );\n\n // Handler to check if addon is in cart\n const handleIsInCart = useCallback(\n (addonId: string) => {\n return isInCart(addonId);\n },\n [isInCart]\n );\n\n // Handler to get cart quantity for addon\n const handleGetCartQuantity = useCallback(\n (addonId: string) => {\n const item = getCartItem(addonId);\n return item?.quantity || 0;\n },\n [getCartItem]\n );\n\n // Handler to update quantity in cart\n const handleUpdateQuantity = useCallback(\n (addonId: string, quantity: number) => {\n if (quantity <= 0) {\n removeFromCart(addonId);\n } else {\n updateQuantity(addonId, quantity);\n }\n },\n [updateQuantity, removeFromCart]\n );\n\n // Handler to remove from cart\n const handleRemoveFromCart = useCallback(\n (addonId: string) => {\n removeFromCart(addonId);\n },\n [removeFromCart]\n );\n\n // Permission check - must be after all hooks are defined\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view billing information.\" />;\n }\n\n // Error state\n if (error && isServerError(error) && !isLoading) {\n return (\n <div className=\"p-6\">\n <ServerError\n title=\"Server Unavailable\"\n message=\"Unable to load billing overview. The server might be down or experiencing issues.\"\n onRetry={handleRefresh}\n showRetry\n />\n </div>\n );\n }\n\n // Loading state\n if (isLoading && !currentAccount) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"flex flex-col items-center gap-3\">\n <Loader2 className=\"w-8 h-8 animate-spin text-primary\" />\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.overview.loadingInfo', 'Loading billing information...')}\n </p>\n </div>\n </div>\n );\n }\n\n // No billing accounts state\n if (!isLoading && billingAccounts.length === 0) {\n return (\n <div className=\"p-6\">\n <header className=\"mb-8\">\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.overview.title', 'Billing Overview')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\n 'billing.overview.emptySetupDescription',\n 'Set up billing to manage subscriptions, payments, and invoices'\n )}\n </p>\n </header>\n <EmptyState\n icon={<Building2 className=\"w-6 h-6 text-muted-foreground\" />}\n title={tr('billing.overview.emptyTitle', 'No billing account')}\n description={tr(\n 'billing.overview.emptyDescription',\n 'Create a billing account to start managing your subscriptions and payments'\n )}\n action={\n permissions.canManageBillingAccount ? (\n <button\n onClick={() => setIsCreateModalOpen(true)}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('billing.overview.createBillingAccount', 'Create Billing Account')}\n </button>\n ) : undefined\n }\n />\n\n <CreateBillingAccountModal\n isOpen={isCreateModalOpen}\n onClose={() => {\n setIsCreateModalOpen(false);\n setCreateError(null);\n }}\n onSubmit={handleCreateAccount}\n isSubmitting={isCreatingAccount}\n error={createError}\n />\n </div>\n );\n }\n\n return (\n <div className=\"p-4 sm:p-6 space-y-6 sm:space-y-8\">\n {/* Header */}\n <header className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.overview.title', 'Billing Overview')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\n 'billing.overview.description',\n 'Manage your billing accounts, subscriptions, and payment methods'\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleRefresh}\n className=\"p-2 rounded-lg border border-border hover:bg-muted text-muted-foreground hover:text-foreground transition-colors\"\n aria-label={tr('billing.overview.refresh', 'Refresh')}\n >\n <RefreshCw className={`w-4 h-4 ${isLoading ? 'animate-spin' : ''}`} />\n </button>\n {permissions.canManageBillingAccount && billingAccounts.length > 0 && (\n <button\n onClick={() => setIsCreateModalOpen(true)}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n <span className=\"hidden sm:inline\">\n {tr('billing.overview.newAccount', 'New Account')}\n </span>\n </button>\n )}\n </div>\n </header>\n\n {/* Account Selector (if multiple accounts) */}\n {billingAccounts.length > 1 && (\n <div className=\"relative\">\n <button\n onClick={() => setIsAccountSelectorOpen(!isAccountSelectorOpen)}\n className=\"w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center\">\n <Building2 className=\"w-4 h-4 text-primary\" />\n </div>\n <div className=\"text-left\">\n <p className=\"text-sm font-medium text-foreground\">\n {currentAccount?.name || tr('billing.overview.selectAccount', 'Select Account')}\n </p>\n <p className=\"text-xs text-muted-foreground\">{currentAccount?.email}</p>\n </div>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-muted-foreground transition-transform ${isAccountSelectorOpen ? 'rotate-180' : ''}`}\n />\n </button>\n\n {isAccountSelectorOpen && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setIsAccountSelectorOpen(false)} />\n <div className=\"absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto\">\n {billingAccounts.map((account) => (\n <button\n key={account.id}\n onClick={() => handleSelectAccount(account)}\n className=\"w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"w-8 h-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0\">\n <Building2 className=\"w-4 h-4 text-muted-foreground\" />\n </div>\n <div className=\"text-left min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {account.name}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">{account.email}</p>\n </div>\n </div>\n {currentAccount?.id === account.id && (\n <Check className=\"w-4 h-4 text-primary flex-shrink-0\" />\n )}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Stats Row */}\n {currentAccount && (\n <div className=\"grid grid-cols-1 xs:grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4\">\n <StatCard\n label={tr('billing.overview.stats.creditBalance', 'Credit Balance')}\n value={`${(currentAccount.creditAmount || 0).toLocaleString()} Credits`}\n icon={<Wallet className=\"w-5 h-5\" />}\n />\n <StatCard\n label={tr('billing.overview.stats.activePlans', 'Active Plans')}\n value={\n activeSubscriptions.length > 0\n ? activeSubscriptions.length === 1\n ? activeSubscriptions[0]?.plan?.name || '1 Plan'\n : `${activeSubscriptions.length} ${tr('billing.overview.stats.plansSuffix', 'Plans')}`\n : tr('billing.overview.stats.none', 'None')\n }\n icon={<RefreshCw className=\"w-5 h-5\" />}\n />\n <StatCard\n label={tr('billing.overview.stats.paymentMethods', 'Payment Methods')}\n value={paymentMethods.length}\n icon={<Building2 className=\"w-5 h-5\" />}\n />\n <StatCard\n label={tr('billing.overview.stats.paymentCurrency', 'Payment Currency')}\n value={currentAccount.currency || 'USD'}\n icon={<Building2 className=\"w-5 h-5\" />}\n />\n </div>\n )}\n\n {/* Main Content Grid */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Left Column - Billing Account & Subscription */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Billing Account Card */}\n {currentAccount && (\n <BillingAccountCard\n account={currentAccount}\n isDefault={currentAccount.isDefault ?? false}\n onEdit={() =>\n currentAccount && navigateTo(`/settings?billingAccountId=${currentAccount.id}`)\n }\n onViewTransactions={() => navigateTo(`/transactions/${currentAccount.id}`)}\n onViewCreditTransactions={() =>\n navigateTo(`/creditTransactions/${currentAccount.id}`)\n }\n />\n )}\n\n {/* Active Subscriptions */}\n <div className=\"space-y-3\">\n {/* Subscription Selector (if multiple subscriptions) */}\n {activeSubscriptions.length > 1 && (\n <div className=\"relative\">\n <button\n onClick={() => setIsSubscriptionSelectorOpen(!isSubscriptionSelectorOpen)}\n className=\"w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center\">\n <Crown className=\"w-4 h-4 text-primary\" />\n </div>\n <div className=\"text-left\">\n <p className=\"text-sm font-medium text-foreground\">\n {selectedSubscription?.plan?.name ||\n tr('billing.overview.selectSubscription', 'Select Subscription')}\n {selectedSubscription?.plan?.product?.name && (\n <span className=\"text-muted-foreground font-normal\">\n {' '}\n · {selectedSubscription.plan.product.name}\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {activeSubscriptions.length}{' '}\n {tr('billing.overview.activeSubscriptions', 'active subscriptions')}\n </p>\n </div>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-muted-foreground transition-transform ${isSubscriptionSelectorOpen ? 'rotate-180' : ''}`}\n />\n </button>\n\n {isSubscriptionSelectorOpen && (\n <>\n <div\n className=\"fixed inset-0 z-10\"\n onClick={() => setIsSubscriptionSelectorOpen(false)}\n />\n <div className=\"absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto\">\n {activeSubscriptions.map((subscription, index) => (\n <button\n key={subscription.id}\n onClick={() => {\n setSelectedSubscriptionIndex(index);\n setIsSubscriptionSelectorOpen(false);\n }}\n className=\"w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"w-8 h-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0\">\n <Crown className=\"w-4 h-4 text-muted-foreground\" />\n </div>\n <div className=\"text-left min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {subscription.plan?.name ||\n tr('billing.overview.subscription', 'Subscription')}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">\n {subscription.plan?.product?.name ||\n tr('billing.overview.unknownProduct', 'Unknown Product')}{' '}\n · {tr('billing.overview.ends', 'Ends')}{' '}\n {new Date(subscription.endDate).toLocaleDateString()}\n </p>\n </div>\n </div>\n {selectedSubscriptionIndex === index && (\n <Check className=\"w-4 h-4 text-primary flex-shrink-0\" />\n )}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Single Subscription Card */}\n <ActiveSubscriptionCard\n subscription={selectedSubscription}\n onViewDetails={() =>\n selectedSubscription &&\n navigateTo(\n withBillingAccountId(\n `/subscriptions/${selectedSubscription.id}`,\n selectedSubscription.billingAccountId ?? currentAccount?.id\n )\n )\n }\n onUpgrade={() =>\n selectedSubscription &&\n navigateTo(\n withBillingAccountId(\n `/subscriptions/${selectedSubscription.id}/upgrade`,\n selectedSubscription.billingAccountId ?? currentAccount?.id\n )\n )\n }\n onManage={() =>\n currentAccount && navigateTo(`/subscriptions?billingAccountId=${currentAccount.id}`)\n }\n onPurchasePlan={() => navigateTo('/plans')}\n />\n </div>\n\n {/* Payment Methods */}\n {currentAccount && (\n <PaymentMethodsSection\n paymentMethods={paymentMethods}\n billingAccountId={currentAccount.id}\n onAddPaymentMethod={handleAddPaymentMethod}\n onSetDefault={handleSetDefaultPaymentMethod}\n onDelete={handleDeletePaymentMethod}\n isLoading={isLoading}\n />\n )}\n </div>\n\n {/* Right Column - Quick Actions & Info */}\n <div className=\"space-y-6\">\n {/* Quick Actions */}\n <section className=\"border border-border rounded-lg bg-card p-4\">\n <h3 className=\"font-semibold text-foreground mb-4\">Quick Actions</h3>\n <div className=\"space-y-2\">\n <button\n onClick={() => currentAccount && navigateTo(`/transactions/${currentAccount.id}`)}\n disabled={!currentAccount}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <div className=\"w-8 h-8 rounded bg-status-info-bg-subtle flex items-center justify-center\">\n <Receipt className=\"w-4 h-4 text-accent-blue\" />\n </div>\n View Transactions\n </button>\n <button\n onClick={() =>\n currentAccount && navigateTo(`/creditTransactions/${currentAccount.id}`)\n }\n disabled={!currentAccount}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <div className=\"w-8 h-8 rounded bg-status-warning-bg-subtle flex items-center justify-center\">\n <Wallet className=\"w-4 h-4 text-status-warning-text\" />\n </div>\n Credit History\n </button>\n <button\n onClick={() => navigateTo('/checkout/credits')}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <div className=\"w-8 h-8 rounded bg-status-success-bg-subtle flex items-center justify-center\">\n <Coins className=\"w-4 h-4 text-status-success-text\" />\n </div>\n Purchase Credits\n </button>\n <button\n onClick={() =>\n currentAccount && navigateTo(`/usage?billingAccountId=${currentAccount.id}`)\n }\n disabled={!currentAccount}\n className=\"w-full flex items-center gap-3 px-3 py-2.5 text-sm text-left text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <div className=\"w-8 h-8 rounded bg-accent-violet-subtle flex items-center justify-center\">\n <Activity className=\"w-4 h-4 text-accent-violet\" />\n </div>\n Usage Analytics\n </button>\n </div>\n </section>\n\n {/* Get Started (if no subscription) */}\n {!hasActiveSubscription && (\n <section className=\"border border-border rounded-lg bg-gradient-to-br from-primary/5 to-primary/10 p-4\">\n <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0\">\n <Sparkles className=\"w-5 h-5 text-primary\" />\n </div>\n <div>\n <h3 className=\"font-semibold text-foreground\">Get Started</h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Choose a plan that fits your needs to unlock all features\n </p>\n </div>\n </div>\n <button\n onClick={() => navigateTo('/plans')}\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n Browse Plans\n <ArrowRight className=\"w-4 h-4\" />\n </button>\n </section>\n )}\n </div>\n </div>\n\n {/* Recommended Addons (only if has subscription) - Limited to 3 with cart support */}\n <RecommendedAddonsSection\n addons={recommendedAddons}\n hasSubscription={hasActiveSubscription}\n onViewAddon={(addonId) => navigateTo(`/addons/${addonId}`)}\n onPurchaseAddon={(addonId) => navigateTo(`/addons/${addonId}?action=purchase`)}\n onViewAllAddons={() => navigateTo('/addons')}\n onAddToCart={handleAddToCart}\n isInCart={handleIsInCart}\n getCartQuantity={handleGetCartQuantity}\n onUpdateQuantity={handleUpdateQuantity}\n onRemoveFromCart={handleRemoveFromCart}\n maxAddons={3}\n isLoading={isLoadingAddons}\n />\n\n {/* Floating Cart Drawer - shows when items are in cart */}\n <FloatingCartDrawer />\n\n {/* Create Billing Account Modal */}\n <CreateBillingAccountModal\n isOpen={isCreateModalOpen}\n onClose={() => {\n setIsCreateModalOpen(false);\n setCreateError(null);\n }}\n onSubmit={handleCreateAccount}\n isSubmitting={isCreatingAccount}\n error={createError}\n />\n\n {/* Add Payment Method Modal */}\n {currentAccount && (\n <AddPaymentMethodModal\n isOpen={isAddPaymentModalOpen}\n onClose={() => setIsAddPaymentModalOpen(false)}\n billingAccountId={currentAccount.id}\n currency={currentAccount.currency}\n country={currentAccount.billingAddresses?.[0]?.country}\n onSuccess={handlePaymentMethodAdded}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
@@ -246,9 +246,9 @@ var g = {
246
246
  ]
247
247
  }),
248
248
  /* @__PURE__ */ d("div", {
249
- className: "flex flex-wrap items-center gap-4 pb-4 border-b border-border",
249
+ className: "flex flex-col sm:flex-row flex-wrap items-stretch sm:items-center gap-3 sm:gap-4 pb-4 border-b border-border",
250
250
  children: /* @__PURE__ */ f("div", {
251
- className: "relative flex-1 min-w-[200px] max-w-md",
251
+ className: "relative flex-1 min-w-0 w-full sm:max-w-md",
252
252
  children: [/* @__PURE__ */ d("svg", {
253
253
  className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground",
254
254
  fill: "none",
@@ -1 +1 @@
1
- {"version":3,"file":"DiscountsListPage.js","names":[],"sources":["../../../../../src/billing/modules/discounts/pages/DiscountsListPage.tsx"],"sourcesContent":["/**\n * Discounts Module - Discounts List Page\n * Admin page for creating, viewing, and managing discount codes\n */\n\nimport { useMemo, useState, type FC, type FormEvent } from 'react';\nimport {\n useGetDiscountsQuery,\n useCreateDiscountMutation,\n useUpdateDiscountMutation,\n useDeleteDiscountMutation,\n} from '../../../../generated/global-operations';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied } from '../../../shared/components';\nimport { formatCurrency, formatDate } from '../../../shared/utils/format';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DiscountType = 'PERCENTAGE' | 'FIXED';\n\ninterface BillingDiscount {\n id: string;\n code: string;\n type: DiscountType;\n value: number;\n currency: string | null;\n maxUses: number | null;\n usedCount: number;\n validFrom: string | null;\n validUntil: string | null;\n metadata: Record<string, unknown> | null;\n context: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface CreateDiscountForm {\n code: string;\n type: DiscountType;\n value: string;\n currency: string;\n maxUses: string;\n validFrom: string;\n validUntil: string;\n}\n\ninterface EditDiscountForm {\n maxUses: string;\n validUntil: string;\n}\n\ntype ModalState =\n | { kind: 'closed' }\n | { kind: 'create' }\n | { kind: 'edit'; discount: BillingDiscount }\n | { kind: 'delete'; discount: BillingDiscount };\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction isExpired(discount: BillingDiscount): boolean {\n if (!discount.validUntil) return false;\n return new Date(discount.validUntil) < new Date();\n}\n\nfunction formatDiscountValue(discount: BillingDiscount): string {\n if (discount.type === 'PERCENTAGE') {\n return `${discount.value}%`;\n }\n return formatCurrency(discount.value, discount.currency ?? 'USD');\n}\n\nconst INITIAL_CREATE_FORM: CreateDiscountForm = {\n code: '',\n type: 'PERCENTAGE',\n value: '',\n currency: 'USD',\n maxUses: '',\n validFrom: '',\n validUntil: '',\n};\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const DiscountsListPage: 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 permissions = useBillingPermissions();\n\n const { data, loading, error, refetch } = useGetDiscountsQuery();\n\n const [createDiscount, { loading: isCreating }] = useCreateDiscountMutation();\n const [updateDiscount, { loading: isUpdating }] = useUpdateDiscountMutation();\n const [deleteDiscount, { loading: isDeleting }] = useDeleteDiscountMutation();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [modal, setModal] = useState<ModalState>({ kind: 'closed' });\n const [createForm, setCreateForm] = useState<CreateDiscountForm>(INITIAL_CREATE_FORM);\n const [editForm, setEditForm] = useState<EditDiscountForm>({ maxUses: '', validUntil: '' });\n const [mutationError, setMutationError] = useState<string | null>(null);\n const [selectedDiscountIds, setSelectedDiscountIds] = useState<Set<string>>(new Set());\n const [showBulkDeleteConfirm, setShowBulkDeleteConfirm] = useState(false);\n\n const discounts: BillingDiscount[] = (data?.getDiscounts ?? []) as BillingDiscount[];\n\n // Filtered discounts\n const filteredDiscounts = discounts.filter((discount: BillingDiscount) => {\n if (!searchQuery) return true;\n return discount.code.toLowerCase().includes(searchQuery.toLowerCase());\n });\n\n const selectedDiscounts = useMemo(\n () => filteredDiscounts.filter((discount) => selectedDiscountIds.has(discount.id)),\n [filteredDiscounts, selectedDiscountIds]\n );\n\n const allVisibleSelected =\n filteredDiscounts.length > 0 &&\n filteredDiscounts.every((discount) => selectedDiscountIds.has(discount.id));\n const partiallySelected =\n filteredDiscounts.some((discount) => selectedDiscountIds.has(discount.id)) &&\n !allVisibleSelected;\n\n // Permission check\n if (!permissions.canManageDiscounts) {\n return <AccessDenied message=\"You don't have permission to manage discount codes.\" />;\n }\n\n // Summary stats\n const totalDiscounts = discounts.length;\n const activeDiscounts = discounts.filter((d: BillingDiscount) => !isExpired(d)).length;\n const expiredDiscounts = discounts.filter((d: BillingDiscount) => isExpired(d)).length;\n\n // ── Modal handlers ──────────────────────────────────────────────────\n\n const openCreateModal = () => {\n setCreateForm(INITIAL_CREATE_FORM);\n setMutationError(null);\n setModal({ kind: 'create' });\n };\n\n const openEditModal = (discount: BillingDiscount) => {\n setEditForm({\n maxUses: discount.maxUses != null ? String(discount.maxUses) : '',\n validUntil: discount.validUntil\n ? new Date(discount.validUntil).toISOString().slice(0, 16)\n : '',\n });\n setMutationError(null);\n setModal({ kind: 'edit', discount });\n };\n\n const openDeleteModal = (discount: BillingDiscount) => {\n setMutationError(null);\n setModal({ kind: 'delete', discount });\n };\n\n const closeModal = () => {\n setModal({ kind: 'closed' });\n setMutationError(null);\n };\n\n // ── Mutation handlers ───────────────────────────────────────────────\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n setMutationError(null);\n\n if (!createForm.code.trim()) {\n setMutationError('Discount code is required.');\n return;\n }\n\n const valueNum = Number(createForm.value);\n if (Number.isNaN(valueNum) || valueNum <= 0) {\n setMutationError('Value must be a positive number.');\n return;\n }\n\n if (createForm.type === 'PERCENTAGE' && valueNum > 100) {\n setMutationError('Percentage value cannot exceed 100.');\n return;\n }\n\n try {\n await createDiscount({\n variables: {\n code: createForm.code.trim().toUpperCase(),\n type: createForm.type,\n value: valueNum,\n currency: createForm.type === 'FIXED' ? createForm.currency : null,\n maxUses: createForm.maxUses ? Number(createForm.maxUses) : null,\n validFrom: createForm.validFrom ? new Date(createForm.validFrom).toISOString() : null,\n validUntil: createForm.validUntil ? new Date(createForm.validUntil).toISOString() : null,\n },\n });\n await refetch();\n closeModal();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to create discount.');\n }\n };\n\n const handleUpdate = async (e: FormEvent) => {\n e.preventDefault();\n if (modal.kind !== 'edit') return;\n setMutationError(null);\n\n try {\n await updateDiscount({\n variables: {\n id: modal.discount.id,\n maxUses: editForm.maxUses ? Number(editForm.maxUses) : null,\n validUntil: editForm.validUntil ? new Date(editForm.validUntil).toISOString() : null,\n },\n });\n await refetch();\n closeModal();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to update discount.');\n }\n };\n\n const handleDelete = async () => {\n if (modal.kind !== 'delete') return;\n setMutationError(null);\n void nativeImpact('medium');\n\n try {\n await deleteDiscount({ variables: { id: modal.discount.id } });\n void nativeNotify('success');\n await refetch();\n closeModal();\n } catch (err) {\n void nativeNotify('error');\n setMutationError(err instanceof Error ? err.message : 'Failed to delete discount.');\n }\n };\n\n const handleBulkDelete = async () => {\n if (selectedDiscounts.length === 0) return;\n\n setMutationError(null);\n setShowBulkDeleteConfirm(false);\n await Promise.allSettled(\n selectedDiscounts.map((discount) => deleteDiscount({ variables: { id: discount.id } }))\n );\n await refetch();\n setSelectedDiscountIds(new Set());\n };\n\n const toggleDiscountSelection = (discountId: string, checked: boolean) => {\n setSelectedDiscountIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(discountId);\n } else {\n next.delete(discountId);\n }\n return next;\n });\n setShowBulkDeleteConfirm(false);\n };\n\n const toggleAllDiscounts = (checked: boolean) => {\n setSelectedDiscountIds((prev) => {\n const next = new Set(prev);\n filteredDiscounts.forEach((discount) => {\n if (checked) {\n next.add(discount.id);\n } else {\n next.delete(discount.id);\n }\n });\n return next;\n });\n setShowBulkDeleteConfirm(false);\n };\n\n // ── Loading state ───────────────────────────────────────────────────\n\n if (loading && discounts.length === 0) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"border border-border rounded-lg p-4 space-y-2\">\n <div className=\"h-4 w-24 bg-muted animate-pulse rounded\" />\n <div className=\"h-6 w-16 bg-muted animate-pulse rounded\" />\n </div>\n ))}\n </div>\n <div className=\"space-y-3\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"border border-border rounded-lg p-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-10 w-10 bg-muted animate-pulse rounded\" />\n <div className=\"flex-1 space-y-2\">\n <div className=\"h-4 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-48 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n // ── Error state ─────────────────────────────────────────────────────\n\n if (error) {\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=\"w-12 h-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center\">\n <svg\n className=\"w-6 h-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\">Failed to load discounts</h2>\n <p className=\"text-sm text-muted-foreground\">{error.message}</p>\n <button\n onClick={() => refetch()}\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 Try Again\n </button>\n </div>\n </div>\n );\n }\n\n // ── Main render ─────────────────────────────────────────────────────\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-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">Discount Codes</h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Create, view, and manage discount codes for billing\n </p>\n </div>\n <button\n onClick={openCreateModal}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n Create Discount\n </button>\n </div>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <div className=\"border border-border rounded-lg bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">Total Discounts</p>\n <p className=\"text-xl font-semibold text-foreground mt-1\">{totalDiscounts}</p>\n </div>\n <div className=\"border border-border rounded-lg bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">Active</p>\n <p className=\"text-xl font-semibold text-status-success-text mt-1\">{activeDiscounts}</p>\n </div>\n <div className=\"border border-border rounded-lg bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">Expired</p>\n <p className=\"text-xl font-semibold text-status-warning-text mt-1\">{expiredDiscounts}</p>\n </div>\n </div>\n\n {/* Search */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border\">\n <div className=\"relative flex-1 min-w-[200px] max-w-md\">\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 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=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search by discount code...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n </div>\n\n {filteredDiscounts.length > 0 && (\n <div className=\"flex flex-col gap-3 rounded-lg border border-border bg-card p-4 sm:flex-row sm:items-center sm:justify-between\">\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={allVisibleSelected}\n ref={(input) => {\n if (input) {\n input.indeterminate = partiallySelected && !allVisibleSelected;\n }\n }}\n onChange={(event) => toggleAllDiscounts(event.target.checked)}\n aria-label=\"Select all discounts\"\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n <span>Select all visible</span>\n </label>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n {selectedDiscountIds.size} selected\n </span>\n {selectedDiscountIds.size > 0 && (\n <button\n onClick={() => {\n setSelectedDiscountIds(new Set());\n setShowBulkDeleteConfirm(false);\n }}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n Clear selection\n </button>\n )}\n <button\n onClick={() => setShowBulkDeleteConfirm(true)}\n disabled={selectedDiscounts.length === 0 || isDeleting}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium border border-destructive/30 text-destructive rounded-md hover:bg-destructive/10 transition-colors disabled:opacity-50\"\n >\n Delete Selected{selectedDiscounts.length > 0 ? ` (${selectedDiscounts.length})` : ''}\n </button>\n </div>\n </div>\n )}\n\n {showBulkDeleteConfirm && selectedDiscounts.length > 0 && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 p-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">\n Delete {selectedDiscounts.length} selected discount\n {selectedDiscounts.length === 1 ? '' : 's'}?\n </p>\n <p className=\"text-sm text-muted-foreground\">This action cannot be undone.</p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setShowBulkDeleteConfirm(false)}\n className=\"px-3 py-2 text-sm font-medium text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n onClick={handleBulkDelete}\n disabled={isDeleting}\n className=\"inline-flex items-center gap-2 rounded-md bg-destructive px-3 py-2 text-sm font-medium text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50\"\n >\n Confirm Delete\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Discounts Table */}\n {filteredDiscounts.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 border border-dashed border-border rounded-lg\">\n <div className=\"w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-4\">\n <svg\n className=\"w-6 h-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=\"M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A2 2 0 013 12V7a4 4 0 014-4z\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-foreground\">No discount codes found</h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {searchQuery\n ? 'No discount codes match your search.'\n : 'Create your first discount code to get started.'}\n </p>\n {!searchQuery && (\n <button\n onClick={openCreateModal}\n className=\"mt-4 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Create your first discount\n </button>\n )}\n </div>\n ) : (\n <div className=\"border border-border rounded-lg overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead className=\"bg-muted/50\">\n <tr>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground w-12\">\n <input\n type=\"checkbox\"\n checked={allVisibleSelected}\n ref={(input) => {\n if (input) {\n input.indeterminate = partiallySelected && !allVisibleSelected;\n }\n }}\n onChange={(event) => toggleAllDiscounts(event.target.checked)}\n aria-label=\"Select all discounts\"\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Code\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Type\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Value\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground hidden md:table-cell\">\n Uses\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground hidden lg:table-cell\">\n Valid From\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground hidden sm:table-cell\">\n Valid Until\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Status\n </th>\n <th className=\"text-right px-4 py-3 text-sm font-medium text-muted-foreground\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {filteredDiscounts.map((discount: BillingDiscount) => (\n <DiscountRow\n key={discount.id}\n discount={discount}\n selected={selectedDiscountIds.has(discount.id)}\n onToggleSelect={toggleDiscountSelection}\n onEdit={openEditModal}\n onDelete={openDeleteModal}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n\n {/* Create Modal */}\n {modal.kind === 'create' && (\n <ModalOverlay onClose={closeModal}>\n <form onSubmit={handleCreate} className=\"space-y-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.discounts.createDiscountCode', 'Create Discount Code')}\n </h2>\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <svg\n className=\"w-5 h-5 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=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {mutationError && (\n <div className=\"p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md\">\n {mutationError}\n </div>\n )}\n\n {/* Code */}\n <div>\n <label\n htmlFor=\"create-code\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.code', 'Code')} <span className=\"text-destructive\">*</span>\n </label>\n <input\n id=\"create-code\"\n type=\"text\"\n required\n value={createForm.code}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, code: e.target.value }))}\n placeholder={tr('billing.discounts.codePlaceholder', 'e.g. SUMMER25')}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent uppercase\"\n />\n </div>\n\n {/* Type + Value row */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"create-type\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.type', 'Type')} <span className=\"text-destructive\">*</span>\n </label>\n <select\n id=\"create-type\"\n value={createForm.type}\n onChange={(e) =>\n setCreateForm((prev) => ({\n ...prev,\n type: e.target.value as DiscountType,\n }))\n }\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n >\n <option value=\"PERCENTAGE\">\n {tr('billing.discounts.typePercentage', 'Percentage')}\n </option>\n <option value=\"FIXED\">\n {tr('billing.discounts.typeFixedAmount', 'Fixed Amount')}\n </option>\n </select>\n </div>\n <div>\n <label\n htmlFor=\"create-value\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.value', 'Value')}{' '}\n <span className=\"text-destructive\">*</span>\n </label>\n <div className=\"relative\">\n <input\n id=\"create-value\"\n type=\"number\"\n required\n min=\"0.01\"\n max={createForm.type === 'PERCENTAGE' ? '100' : undefined}\n step=\"0.01\"\n value={createForm.value}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, value: e.target.value }))}\n placeholder={createForm.type === 'PERCENTAGE' ? '10' : '25.00'}\n className=\"w-full px-3 py-2 pr-8 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <span className=\"absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground\">\n {createForm.type === 'PERCENTAGE' ? '%' : createForm.currency}\n </span>\n </div>\n </div>\n </div>\n\n {/* Currency (only for FIXED) */}\n {createForm.type === 'FIXED' && (\n <div>\n <label\n htmlFor=\"create-currency\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.currency', 'Currency')}\n </label>\n <select\n id=\"create-currency\"\n value={createForm.currency}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, currency: e.target.value }))}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n >\n <option value=\"USD\">USD</option>\n <option value=\"EUR\">EUR</option>\n <option value=\"GBP\">GBP</option>\n <option value=\"INR\">INR</option>\n <option value=\"CAD\">CAD</option>\n <option value=\"AUD\">AUD</option>\n </select>\n </div>\n )}\n\n {/* Max Uses */}\n <div>\n <label\n htmlFor=\"create-max-uses\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.maxUses', 'Max Uses')}\n </label>\n <input\n id=\"create-max-uses\"\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={createForm.maxUses}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, maxUses: e.target.value }))}\n placeholder={tr('billing.discounts.unlimited', 'Unlimited')}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr('billing.discounts.unlimitedHelp', 'Leave empty for unlimited uses.')}\n </p>\n </div>\n\n {/* Valid From / Valid Until row */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"create-valid-from\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.validFrom', 'Valid From')}\n </label>\n <input\n id=\"create-valid-from\"\n type=\"datetime-local\"\n value={createForm.validFrom}\n onChange={(e) =>\n setCreateForm((prev) => ({ ...prev, validFrom: e.target.value }))\n }\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n <div>\n <label\n htmlFor=\"create-valid-until\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.validUntil', 'Valid Until')}\n </label>\n <input\n id=\"create-valid-until\"\n type=\"datetime-local\"\n value={createForm.validUntil}\n onChange={(e) =>\n setCreateForm((prev) => ({ ...prev, validUntil: e.target.value }))\n }\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-end gap-3 pt-2 border-t border-border\">\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n {tr('billing.discounts.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={isCreating}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isCreating\n ? tr('billing.discounts.creating', 'Creating...')\n : tr('billing.discounts.createDiscount', 'Create Discount')}\n </button>\n </div>\n </form>\n </ModalOverlay>\n )}\n\n {/* Edit Modal */}\n {modal.kind === 'edit' && (\n <ModalOverlay onClose={closeModal}>\n <form onSubmit={handleUpdate} className=\"space-y-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Edit Discount</h2>\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <svg\n className=\"w-5 h-5 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=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {mutationError && (\n <div className=\"p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md\">\n {mutationError}\n </div>\n )}\n\n {/* Read-only info */}\n <div className=\"p-3 bg-muted/50 border border-border rounded-md space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Code</span>\n <span className=\"font-mono font-medium text-foreground\">{modal.discount.code}</span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Type</span>\n <span className=\"text-foreground\">\n {modal.discount.type === 'PERCENTAGE' ? 'Percentage' : 'Fixed Amount'}\n </span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Value</span>\n <span className=\"text-foreground\">{formatDiscountValue(modal.discount)}</span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Used</span>\n <span className=\"text-foreground\">{modal.discount.usedCount} times</span>\n </div>\n </div>\n\n {/* Editable: Max Uses */}\n <div>\n <label\n htmlFor=\"edit-max-uses\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n Max Uses\n </label>\n <input\n id=\"edit-max-uses\"\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={editForm.maxUses}\n onChange={(e) => setEditForm((prev) => ({ ...prev, maxUses: e.target.value }))}\n placeholder=\"Unlimited\"\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">Leave empty for unlimited uses.</p>\n </div>\n\n {/* Editable: Valid Until */}\n <div>\n <label\n htmlFor=\"edit-valid-until\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n Valid Until\n </label>\n <input\n id=\"edit-valid-until\"\n type=\"datetime-local\"\n value={editForm.validUntil}\n onChange={(e) => setEditForm((prev) => ({ ...prev, validUntil: e.target.value }))}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-end gap-3 pt-2 border-t border-border\">\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={isUpdating}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isUpdating ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </form>\n </ModalOverlay>\n )}\n\n {/* Delete Confirmation Modal */}\n {modal.kind === 'delete' && (\n <ModalOverlay onClose={closeModal}>\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Delete Discount</h2>\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <svg\n className=\"w-5 h-5 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=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {mutationError && (\n <div className=\"p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md\">\n {mutationError}\n </div>\n )}\n\n <div className=\"flex items-start gap-3\">\n <div className=\"w-10 h-10 rounded-full bg-destructive/10 flex items-center justify-center shrink-0\">\n <svg\n className=\"w-5 h-5 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 <div>\n <p className=\"text-sm text-foreground\">\n Are you sure you want to delete the discount code{' '}\n <span className=\"font-mono font-semibold\">{modal.discount.code}</span>?\n </p>\n <p className=\"text-sm text-muted-foreground mt-1\">\n This action cannot be undone. The discount has been used{' '}\n <span className=\"font-medium\">{modal.discount.usedCount}</span> time\n {modal.discount.usedCount !== 1 ? 's' : ''}.\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center justify-end gap-3 pt-2 border-t border-border\">\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"px-4 py-2 text-sm font-medium bg-destructive text-destructive-foreground rounded-md hover:bg-destructive/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isDeleting ? 'Deleting...' : 'Delete Discount'}\n </button>\n </div>\n </div>\n </ModalOverlay>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Discount Row Component\n// ============================================================================\n\ninterface DiscountRowProps {\n discount: BillingDiscount;\n selected: boolean;\n onToggleSelect: (discountId: string, checked: boolean) => void;\n onEdit: (discount: BillingDiscount) => void;\n onDelete: (discount: BillingDiscount) => void;\n}\n\nconst DiscountRow: FC<DiscountRowProps> = ({\n discount,\n selected,\n onToggleSelect,\n onEdit,\n onDelete,\n}) => {\n const expired = isExpired(discount);\n\n return (\n <tr className={`hover:bg-muted/30 transition-colors ${selected ? 'bg-muted/20' : ''}`}>\n <td className=\"px-4 py-4\">\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(discount.id, event.target.checked)}\n aria-label={`Select discount ${discount.code}`}\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n </td>\n {/* Code */}\n <td className=\"px-4 py-4\">\n <span className=\"font-mono font-medium text-foreground\">{discount.code}</span>\n </td>\n\n {/* Type */}\n <td className=\"px-4 py-4\">\n <span className=\"text-sm text-muted-foreground\">\n {discount.type === 'PERCENTAGE' ? 'Percentage' : 'Fixed'}\n </span>\n </td>\n\n {/* Value */}\n <td className=\"px-4 py-4\">\n <span className=\"text-sm font-medium text-foreground\">{formatDiscountValue(discount)}</span>\n </td>\n\n {/* Uses */}\n <td className=\"px-4 py-4 hidden md:table-cell\">\n <span className=\"text-sm text-muted-foreground\">\n {discount.usedCount}\n {discount.maxUses != null ? ` / ${discount.maxUses}` : ' / \\u221E'}\n </span>\n </td>\n\n {/* Valid From */}\n <td className=\"px-4 py-4 text-sm text-muted-foreground hidden lg:table-cell\">\n {discount.validFrom ? formatDate(discount.validFrom, 'short') : '\\u2014'}\n </td>\n\n {/* Valid Until */}\n <td className=\"px-4 py-4 text-sm text-muted-foreground hidden sm:table-cell\">\n {discount.validUntil ? formatDate(discount.validUntil, 'short') : '\\u2014'}\n </td>\n\n {/* Status */}\n <td className=\"px-4 py-4\">\n {expired ? (\n <span className=\"inline-flex px-2 py-1 text-xs font-medium rounded bg-status-warning-bg-subtle text-status-warning-text\">\n Expired\n </span>\n ) : (\n <span className=\"inline-flex px-2 py-1 text-xs font-medium rounded bg-status-success-bg-subtle text-status-success-text\">\n Active\n </span>\n )}\n </td>\n\n {/* Actions */}\n <td className=\"px-4 py-4 text-right\">\n <div className=\"flex items-center justify-end gap-2\">\n <button\n onClick={() => onEdit(discount)}\n className=\"px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted rounded-md transition-colors\"\n title=\"Edit discount\"\n >\n {/* Pencil icon */}\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n </button>\n <button\n onClick={() => onDelete(discount)}\n className=\"px-3 py-1.5 text-sm font-medium text-destructive hover:bg-destructive/10 rounded-md transition-colors\"\n title=\"Delete discount\"\n >\n {/* Trash icon */}\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n </button>\n </div>\n </td>\n </tr>\n );\n};\n\n// ============================================================================\n// Modal Overlay Component\n// ============================================================================\n\ninterface ModalOverlayProps {\n onClose: () => void;\n children: React.ReactNode;\n}\n\nconst ModalOverlay: FC<ModalOverlayProps> = ({ onClose, children }) => {\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-overlay-scrim\" onClick={onClose} />\n\n {/* Dialog */}\n <div className=\"relative w-full max-w-lg max-h-[85vh] overflow-y-auto bg-card border border-border rounded-xl shadow-xl p-6 mx-4\">\n {children}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"DiscountsListPage.js","names":[],"sources":["../../../../../src/billing/modules/discounts/pages/DiscountsListPage.tsx"],"sourcesContent":["/**\n * Discounts Module - Discounts List Page\n * Admin page for creating, viewing, and managing discount codes\n */\n\nimport { useMemo, useState, type FC, type FormEvent } from 'react';\nimport {\n useGetDiscountsQuery,\n useCreateDiscountMutation,\n useUpdateDiscountMutation,\n useDeleteDiscountMutation,\n} from '../../../../generated/global-operations';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied } from '../../../shared/components';\nimport { formatCurrency, formatDate } from '../../../shared/utils/format';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DiscountType = 'PERCENTAGE' | 'FIXED';\n\ninterface BillingDiscount {\n id: string;\n code: string;\n type: DiscountType;\n value: number;\n currency: string | null;\n maxUses: number | null;\n usedCount: number;\n validFrom: string | null;\n validUntil: string | null;\n metadata: Record<string, unknown> | null;\n context: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface CreateDiscountForm {\n code: string;\n type: DiscountType;\n value: string;\n currency: string;\n maxUses: string;\n validFrom: string;\n validUntil: string;\n}\n\ninterface EditDiscountForm {\n maxUses: string;\n validUntil: string;\n}\n\ntype ModalState =\n | { kind: 'closed' }\n | { kind: 'create' }\n | { kind: 'edit'; discount: BillingDiscount }\n | { kind: 'delete'; discount: BillingDiscount };\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction isExpired(discount: BillingDiscount): boolean {\n if (!discount.validUntil) return false;\n return new Date(discount.validUntil) < new Date();\n}\n\nfunction formatDiscountValue(discount: BillingDiscount): string {\n if (discount.type === 'PERCENTAGE') {\n return `${discount.value}%`;\n }\n return formatCurrency(discount.value, discount.currency ?? 'USD');\n}\n\nconst INITIAL_CREATE_FORM: CreateDiscountForm = {\n code: '',\n type: 'PERCENTAGE',\n value: '',\n currency: 'USD',\n maxUses: '',\n validFrom: '',\n validUntil: '',\n};\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const DiscountsListPage: 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 permissions = useBillingPermissions();\n\n const { data, loading, error, refetch } = useGetDiscountsQuery();\n\n const [createDiscount, { loading: isCreating }] = useCreateDiscountMutation();\n const [updateDiscount, { loading: isUpdating }] = useUpdateDiscountMutation();\n const [deleteDiscount, { loading: isDeleting }] = useDeleteDiscountMutation();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [modal, setModal] = useState<ModalState>({ kind: 'closed' });\n const [createForm, setCreateForm] = useState<CreateDiscountForm>(INITIAL_CREATE_FORM);\n const [editForm, setEditForm] = useState<EditDiscountForm>({ maxUses: '', validUntil: '' });\n const [mutationError, setMutationError] = useState<string | null>(null);\n const [selectedDiscountIds, setSelectedDiscountIds] = useState<Set<string>>(new Set());\n const [showBulkDeleteConfirm, setShowBulkDeleteConfirm] = useState(false);\n\n const discounts: BillingDiscount[] = (data?.getDiscounts ?? []) as BillingDiscount[];\n\n // Filtered discounts\n const filteredDiscounts = discounts.filter((discount: BillingDiscount) => {\n if (!searchQuery) return true;\n return discount.code.toLowerCase().includes(searchQuery.toLowerCase());\n });\n\n const selectedDiscounts = useMemo(\n () => filteredDiscounts.filter((discount) => selectedDiscountIds.has(discount.id)),\n [filteredDiscounts, selectedDiscountIds]\n );\n\n const allVisibleSelected =\n filteredDiscounts.length > 0 &&\n filteredDiscounts.every((discount) => selectedDiscountIds.has(discount.id));\n const partiallySelected =\n filteredDiscounts.some((discount) => selectedDiscountIds.has(discount.id)) &&\n !allVisibleSelected;\n\n // Permission check\n if (!permissions.canManageDiscounts) {\n return <AccessDenied message=\"You don't have permission to manage discount codes.\" />;\n }\n\n // Summary stats\n const totalDiscounts = discounts.length;\n const activeDiscounts = discounts.filter((d: BillingDiscount) => !isExpired(d)).length;\n const expiredDiscounts = discounts.filter((d: BillingDiscount) => isExpired(d)).length;\n\n // ── Modal handlers ──────────────────────────────────────────────────\n\n const openCreateModal = () => {\n setCreateForm(INITIAL_CREATE_FORM);\n setMutationError(null);\n setModal({ kind: 'create' });\n };\n\n const openEditModal = (discount: BillingDiscount) => {\n setEditForm({\n maxUses: discount.maxUses != null ? String(discount.maxUses) : '',\n validUntil: discount.validUntil\n ? new Date(discount.validUntil).toISOString().slice(0, 16)\n : '',\n });\n setMutationError(null);\n setModal({ kind: 'edit', discount });\n };\n\n const openDeleteModal = (discount: BillingDiscount) => {\n setMutationError(null);\n setModal({ kind: 'delete', discount });\n };\n\n const closeModal = () => {\n setModal({ kind: 'closed' });\n setMutationError(null);\n };\n\n // ── Mutation handlers ───────────────────────────────────────────────\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n setMutationError(null);\n\n if (!createForm.code.trim()) {\n setMutationError('Discount code is required.');\n return;\n }\n\n const valueNum = Number(createForm.value);\n if (Number.isNaN(valueNum) || valueNum <= 0) {\n setMutationError('Value must be a positive number.');\n return;\n }\n\n if (createForm.type === 'PERCENTAGE' && valueNum > 100) {\n setMutationError('Percentage value cannot exceed 100.');\n return;\n }\n\n try {\n await createDiscount({\n variables: {\n code: createForm.code.trim().toUpperCase(),\n type: createForm.type,\n value: valueNum,\n currency: createForm.type === 'FIXED' ? createForm.currency : null,\n maxUses: createForm.maxUses ? Number(createForm.maxUses) : null,\n validFrom: createForm.validFrom ? new Date(createForm.validFrom).toISOString() : null,\n validUntil: createForm.validUntil ? new Date(createForm.validUntil).toISOString() : null,\n },\n });\n await refetch();\n closeModal();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to create discount.');\n }\n };\n\n const handleUpdate = async (e: FormEvent) => {\n e.preventDefault();\n if (modal.kind !== 'edit') return;\n setMutationError(null);\n\n try {\n await updateDiscount({\n variables: {\n id: modal.discount.id,\n maxUses: editForm.maxUses ? Number(editForm.maxUses) : null,\n validUntil: editForm.validUntil ? new Date(editForm.validUntil).toISOString() : null,\n },\n });\n await refetch();\n closeModal();\n } catch (err) {\n setMutationError(err instanceof Error ? err.message : 'Failed to update discount.');\n }\n };\n\n const handleDelete = async () => {\n if (modal.kind !== 'delete') return;\n setMutationError(null);\n void nativeImpact('medium');\n\n try {\n await deleteDiscount({ variables: { id: modal.discount.id } });\n void nativeNotify('success');\n await refetch();\n closeModal();\n } catch (err) {\n void nativeNotify('error');\n setMutationError(err instanceof Error ? err.message : 'Failed to delete discount.');\n }\n };\n\n const handleBulkDelete = async () => {\n if (selectedDiscounts.length === 0) return;\n\n setMutationError(null);\n setShowBulkDeleteConfirm(false);\n await Promise.allSettled(\n selectedDiscounts.map((discount) => deleteDiscount({ variables: { id: discount.id } }))\n );\n await refetch();\n setSelectedDiscountIds(new Set());\n };\n\n const toggleDiscountSelection = (discountId: string, checked: boolean) => {\n setSelectedDiscountIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(discountId);\n } else {\n next.delete(discountId);\n }\n return next;\n });\n setShowBulkDeleteConfirm(false);\n };\n\n const toggleAllDiscounts = (checked: boolean) => {\n setSelectedDiscountIds((prev) => {\n const next = new Set(prev);\n filteredDiscounts.forEach((discount) => {\n if (checked) {\n next.add(discount.id);\n } else {\n next.delete(discount.id);\n }\n });\n return next;\n });\n setShowBulkDeleteConfirm(false);\n };\n\n // ── Loading state ───────────────────────────────────────────────────\n\n if (loading && discounts.length === 0) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"border border-border rounded-lg p-4 space-y-2\">\n <div className=\"h-4 w-24 bg-muted animate-pulse rounded\" />\n <div className=\"h-6 w-16 bg-muted animate-pulse rounded\" />\n </div>\n ))}\n </div>\n <div className=\"space-y-3\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"border border-border rounded-lg p-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-10 w-10 bg-muted animate-pulse rounded\" />\n <div className=\"flex-1 space-y-2\">\n <div className=\"h-4 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-48 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n // ── Error state ─────────────────────────────────────────────────────\n\n if (error) {\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=\"w-12 h-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center\">\n <svg\n className=\"w-6 h-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\">Failed to load discounts</h2>\n <p className=\"text-sm text-muted-foreground\">{error.message}</p>\n <button\n onClick={() => refetch()}\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 Try Again\n </button>\n </div>\n </div>\n );\n }\n\n // ── Main render ─────────────────────────────────────────────────────\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-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">Discount Codes</h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Create, view, and manage discount codes for billing\n </p>\n </div>\n <button\n onClick={openCreateModal}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n Create Discount\n </button>\n </div>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <div className=\"border border-border rounded-lg bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">Total Discounts</p>\n <p className=\"text-xl font-semibold text-foreground mt-1\">{totalDiscounts}</p>\n </div>\n <div className=\"border border-border rounded-lg bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">Active</p>\n <p className=\"text-xl font-semibold text-status-success-text mt-1\">{activeDiscounts}</p>\n </div>\n <div className=\"border border-border rounded-lg bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">Expired</p>\n <p className=\"text-xl font-semibold text-status-warning-text mt-1\">{expiredDiscounts}</p>\n </div>\n </div>\n\n {/* Search */}\n <div className=\"flex flex-col sm:flex-row flex-wrap items-stretch sm:items-center gap-3 sm:gap-4 pb-4 border-b border-border\">\n <div className=\"relative flex-1 min-w-0 w-full sm:max-w-md\">\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 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=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search by discount code...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n </div>\n\n {filteredDiscounts.length > 0 && (\n <div className=\"flex flex-col gap-3 rounded-lg border border-border bg-card p-4 sm:flex-row sm:items-center sm:justify-between\">\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={allVisibleSelected}\n ref={(input) => {\n if (input) {\n input.indeterminate = partiallySelected && !allVisibleSelected;\n }\n }}\n onChange={(event) => toggleAllDiscounts(event.target.checked)}\n aria-label=\"Select all discounts\"\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n <span>Select all visible</span>\n </label>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n {selectedDiscountIds.size} selected\n </span>\n {selectedDiscountIds.size > 0 && (\n <button\n onClick={() => {\n setSelectedDiscountIds(new Set());\n setShowBulkDeleteConfirm(false);\n }}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n Clear selection\n </button>\n )}\n <button\n onClick={() => setShowBulkDeleteConfirm(true)}\n disabled={selectedDiscounts.length === 0 || isDeleting}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium border border-destructive/30 text-destructive rounded-md hover:bg-destructive/10 transition-colors disabled:opacity-50\"\n >\n Delete Selected{selectedDiscounts.length > 0 ? ` (${selectedDiscounts.length})` : ''}\n </button>\n </div>\n </div>\n )}\n\n {showBulkDeleteConfirm && selectedDiscounts.length > 0 && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 p-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">\n Delete {selectedDiscounts.length} selected discount\n {selectedDiscounts.length === 1 ? '' : 's'}?\n </p>\n <p className=\"text-sm text-muted-foreground\">This action cannot be undone.</p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setShowBulkDeleteConfirm(false)}\n className=\"px-3 py-2 text-sm font-medium text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n onClick={handleBulkDelete}\n disabled={isDeleting}\n className=\"inline-flex items-center gap-2 rounded-md bg-destructive px-3 py-2 text-sm font-medium text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50\"\n >\n Confirm Delete\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Discounts Table */}\n {filteredDiscounts.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 border border-dashed border-border rounded-lg\">\n <div className=\"w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-4\">\n <svg\n className=\"w-6 h-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=\"M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A2 2 0 013 12V7a4 4 0 014-4z\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-foreground\">No discount codes found</h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {searchQuery\n ? 'No discount codes match your search.'\n : 'Create your first discount code to get started.'}\n </p>\n {!searchQuery && (\n <button\n onClick={openCreateModal}\n className=\"mt-4 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Create your first discount\n </button>\n )}\n </div>\n ) : (\n <div className=\"border border-border rounded-lg overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead className=\"bg-muted/50\">\n <tr>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground w-12\">\n <input\n type=\"checkbox\"\n checked={allVisibleSelected}\n ref={(input) => {\n if (input) {\n input.indeterminate = partiallySelected && !allVisibleSelected;\n }\n }}\n onChange={(event) => toggleAllDiscounts(event.target.checked)}\n aria-label=\"Select all discounts\"\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Code\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Type\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Value\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground hidden md:table-cell\">\n Uses\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground hidden lg:table-cell\">\n Valid From\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground hidden sm:table-cell\">\n Valid Until\n </th>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-muted-foreground\">\n Status\n </th>\n <th className=\"text-right px-4 py-3 text-sm font-medium text-muted-foreground\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {filteredDiscounts.map((discount: BillingDiscount) => (\n <DiscountRow\n key={discount.id}\n discount={discount}\n selected={selectedDiscountIds.has(discount.id)}\n onToggleSelect={toggleDiscountSelection}\n onEdit={openEditModal}\n onDelete={openDeleteModal}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n\n {/* Create Modal */}\n {modal.kind === 'create' && (\n <ModalOverlay onClose={closeModal}>\n <form onSubmit={handleCreate} className=\"space-y-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.discounts.createDiscountCode', 'Create Discount Code')}\n </h2>\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <svg\n className=\"w-5 h-5 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=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {mutationError && (\n <div className=\"p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md\">\n {mutationError}\n </div>\n )}\n\n {/* Code */}\n <div>\n <label\n htmlFor=\"create-code\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.code', 'Code')} <span className=\"text-destructive\">*</span>\n </label>\n <input\n id=\"create-code\"\n type=\"text\"\n required\n value={createForm.code}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, code: e.target.value }))}\n placeholder={tr('billing.discounts.codePlaceholder', 'e.g. SUMMER25')}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent uppercase\"\n />\n </div>\n\n {/* Type + Value row */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"create-type\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.type', 'Type')} <span className=\"text-destructive\">*</span>\n </label>\n <select\n id=\"create-type\"\n value={createForm.type}\n onChange={(e) =>\n setCreateForm((prev) => ({\n ...prev,\n type: e.target.value as DiscountType,\n }))\n }\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n >\n <option value=\"PERCENTAGE\">\n {tr('billing.discounts.typePercentage', 'Percentage')}\n </option>\n <option value=\"FIXED\">\n {tr('billing.discounts.typeFixedAmount', 'Fixed Amount')}\n </option>\n </select>\n </div>\n <div>\n <label\n htmlFor=\"create-value\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.value', 'Value')}{' '}\n <span className=\"text-destructive\">*</span>\n </label>\n <div className=\"relative\">\n <input\n id=\"create-value\"\n type=\"number\"\n required\n min=\"0.01\"\n max={createForm.type === 'PERCENTAGE' ? '100' : undefined}\n step=\"0.01\"\n value={createForm.value}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, value: e.target.value }))}\n placeholder={createForm.type === 'PERCENTAGE' ? '10' : '25.00'}\n className=\"w-full px-3 py-2 pr-8 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <span className=\"absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground\">\n {createForm.type === 'PERCENTAGE' ? '%' : createForm.currency}\n </span>\n </div>\n </div>\n </div>\n\n {/* Currency (only for FIXED) */}\n {createForm.type === 'FIXED' && (\n <div>\n <label\n htmlFor=\"create-currency\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.currency', 'Currency')}\n </label>\n <select\n id=\"create-currency\"\n value={createForm.currency}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, currency: e.target.value }))}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n >\n <option value=\"USD\">USD</option>\n <option value=\"EUR\">EUR</option>\n <option value=\"GBP\">GBP</option>\n <option value=\"INR\">INR</option>\n <option value=\"CAD\">CAD</option>\n <option value=\"AUD\">AUD</option>\n </select>\n </div>\n )}\n\n {/* Max Uses */}\n <div>\n <label\n htmlFor=\"create-max-uses\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.maxUses', 'Max Uses')}\n </label>\n <input\n id=\"create-max-uses\"\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={createForm.maxUses}\n onChange={(e) => setCreateForm((prev) => ({ ...prev, maxUses: e.target.value }))}\n placeholder={tr('billing.discounts.unlimited', 'Unlimited')}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr('billing.discounts.unlimitedHelp', 'Leave empty for unlimited uses.')}\n </p>\n </div>\n\n {/* Valid From / Valid Until row */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"create-valid-from\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.validFrom', 'Valid From')}\n </label>\n <input\n id=\"create-valid-from\"\n type=\"datetime-local\"\n value={createForm.validFrom}\n onChange={(e) =>\n setCreateForm((prev) => ({ ...prev, validFrom: e.target.value }))\n }\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n <div>\n <label\n htmlFor=\"create-valid-until\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.discounts.validUntil', 'Valid Until')}\n </label>\n <input\n id=\"create-valid-until\"\n type=\"datetime-local\"\n value={createForm.validUntil}\n onChange={(e) =>\n setCreateForm((prev) => ({ ...prev, validUntil: e.target.value }))\n }\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-end gap-3 pt-2 border-t border-border\">\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n {tr('billing.discounts.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={isCreating}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isCreating\n ? tr('billing.discounts.creating', 'Creating...')\n : tr('billing.discounts.createDiscount', 'Create Discount')}\n </button>\n </div>\n </form>\n </ModalOverlay>\n )}\n\n {/* Edit Modal */}\n {modal.kind === 'edit' && (\n <ModalOverlay onClose={closeModal}>\n <form onSubmit={handleUpdate} className=\"space-y-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Edit Discount</h2>\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <svg\n className=\"w-5 h-5 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=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {mutationError && (\n <div className=\"p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md\">\n {mutationError}\n </div>\n )}\n\n {/* Read-only info */}\n <div className=\"p-3 bg-muted/50 border border-border rounded-md space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Code</span>\n <span className=\"font-mono font-medium text-foreground\">{modal.discount.code}</span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Type</span>\n <span className=\"text-foreground\">\n {modal.discount.type === 'PERCENTAGE' ? 'Percentage' : 'Fixed Amount'}\n </span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Value</span>\n <span className=\"text-foreground\">{formatDiscountValue(modal.discount)}</span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Used</span>\n <span className=\"text-foreground\">{modal.discount.usedCount} times</span>\n </div>\n </div>\n\n {/* Editable: Max Uses */}\n <div>\n <label\n htmlFor=\"edit-max-uses\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n Max Uses\n </label>\n <input\n id=\"edit-max-uses\"\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={editForm.maxUses}\n onChange={(e) => setEditForm((prev) => ({ ...prev, maxUses: e.target.value }))}\n placeholder=\"Unlimited\"\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">Leave empty for unlimited uses.</p>\n </div>\n\n {/* Editable: Valid Until */}\n <div>\n <label\n htmlFor=\"edit-valid-until\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n Valid Until\n </label>\n <input\n id=\"edit-valid-until\"\n type=\"datetime-local\"\n value={editForm.validUntil}\n onChange={(e) => setEditForm((prev) => ({ ...prev, validUntil: e.target.value }))}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-end gap-3 pt-2 border-t border-border\">\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={isUpdating}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isUpdating ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </form>\n </ModalOverlay>\n )}\n\n {/* Delete Confirmation Modal */}\n {modal.kind === 'delete' && (\n <ModalOverlay onClose={closeModal}>\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Delete Discount</h2>\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <svg\n className=\"w-5 h-5 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=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {mutationError && (\n <div className=\"p-3 text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md\">\n {mutationError}\n </div>\n )}\n\n <div className=\"flex items-start gap-3\">\n <div className=\"w-10 h-10 rounded-full bg-destructive/10 flex items-center justify-center shrink-0\">\n <svg\n className=\"w-5 h-5 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 <div>\n <p className=\"text-sm text-foreground\">\n Are you sure you want to delete the discount code{' '}\n <span className=\"font-mono font-semibold\">{modal.discount.code}</span>?\n </p>\n <p className=\"text-sm text-muted-foreground mt-1\">\n This action cannot be undone. The discount has been used{' '}\n <span className=\"font-medium\">{modal.discount.usedCount}</span> time\n {modal.discount.usedCount !== 1 ? 's' : ''}.\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center justify-end gap-3 pt-2 border-t border-border\">\n <button\n type=\"button\"\n onClick={closeModal}\n className=\"px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"px-4 py-2 text-sm font-medium bg-destructive text-destructive-foreground rounded-md hover:bg-destructive/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isDeleting ? 'Deleting...' : 'Delete Discount'}\n </button>\n </div>\n </div>\n </ModalOverlay>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Discount Row Component\n// ============================================================================\n\ninterface DiscountRowProps {\n discount: BillingDiscount;\n selected: boolean;\n onToggleSelect: (discountId: string, checked: boolean) => void;\n onEdit: (discount: BillingDiscount) => void;\n onDelete: (discount: BillingDiscount) => void;\n}\n\nconst DiscountRow: FC<DiscountRowProps> = ({\n discount,\n selected,\n onToggleSelect,\n onEdit,\n onDelete,\n}) => {\n const expired = isExpired(discount);\n\n return (\n <tr className={`hover:bg-muted/30 transition-colors ${selected ? 'bg-muted/20' : ''}`}>\n <td className=\"px-4 py-4\">\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(discount.id, event.target.checked)}\n aria-label={`Select discount ${discount.code}`}\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n </td>\n {/* Code */}\n <td className=\"px-4 py-4\">\n <span className=\"font-mono font-medium text-foreground\">{discount.code}</span>\n </td>\n\n {/* Type */}\n <td className=\"px-4 py-4\">\n <span className=\"text-sm text-muted-foreground\">\n {discount.type === 'PERCENTAGE' ? 'Percentage' : 'Fixed'}\n </span>\n </td>\n\n {/* Value */}\n <td className=\"px-4 py-4\">\n <span className=\"text-sm font-medium text-foreground\">{formatDiscountValue(discount)}</span>\n </td>\n\n {/* Uses */}\n <td className=\"px-4 py-4 hidden md:table-cell\">\n <span className=\"text-sm text-muted-foreground\">\n {discount.usedCount}\n {discount.maxUses != null ? ` / ${discount.maxUses}` : ' / \\u221E'}\n </span>\n </td>\n\n {/* Valid From */}\n <td className=\"px-4 py-4 text-sm text-muted-foreground hidden lg:table-cell\">\n {discount.validFrom ? formatDate(discount.validFrom, 'short') : '\\u2014'}\n </td>\n\n {/* Valid Until */}\n <td className=\"px-4 py-4 text-sm text-muted-foreground hidden sm:table-cell\">\n {discount.validUntil ? formatDate(discount.validUntil, 'short') : '\\u2014'}\n </td>\n\n {/* Status */}\n <td className=\"px-4 py-4\">\n {expired ? (\n <span className=\"inline-flex px-2 py-1 text-xs font-medium rounded bg-status-warning-bg-subtle text-status-warning-text\">\n Expired\n </span>\n ) : (\n <span className=\"inline-flex px-2 py-1 text-xs font-medium rounded bg-status-success-bg-subtle text-status-success-text\">\n Active\n </span>\n )}\n </td>\n\n {/* Actions */}\n <td className=\"px-4 py-4 text-right\">\n <div className=\"flex items-center justify-end gap-2\">\n <button\n onClick={() => onEdit(discount)}\n className=\"px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted rounded-md transition-colors\"\n title=\"Edit discount\"\n >\n {/* Pencil icon */}\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\"\n />\n </svg>\n </button>\n <button\n onClick={() => onDelete(discount)}\n className=\"px-3 py-1.5 text-sm font-medium text-destructive hover:bg-destructive/10 rounded-md transition-colors\"\n title=\"Delete discount\"\n >\n {/* Trash icon */}\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n </button>\n </div>\n </td>\n </tr>\n );\n};\n\n// ============================================================================\n// Modal Overlay Component\n// ============================================================================\n\ninterface ModalOverlayProps {\n onClose: () => void;\n children: React.ReactNode;\n}\n\nconst ModalOverlay: FC<ModalOverlayProps> = ({ onClose, children }) => {\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-overlay-scrim\" onClick={onClose} />\n\n {/* Dialog */}\n <div className=\"relative w-full max-w-lg max-h-[85vh] overflow-y-auto bg-card border border-border rounded-xl shadow-xl p-6 mx-4\">\n {children}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -176,7 +176,7 @@ var g = () => {
176
176
  children: e === "all" ? "All" : r(e)
177
177
  }, e))
178
178
  }), /* @__PURE__ */ m("div", {
179
- className: "relative flex-1 min-w-[200px] max-w-md",
179
+ className: "relative flex-1 min-w-0 w-full sm:max-w-md",
180
180
  children: [/* @__PURE__ */ p("svg", {
181
181
  className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground",
182
182
  fill: "none",