@burdenoff/microfe-billing 2026.821.1 → 2026.825.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingRoot.js.map +1 -1
- package/dist/billing/BillingUserRoutes.js.map +1 -1
- package/dist/billing/hooks/useBillingAccountSelection.js.map +1 -1
- package/dist/billing/hooks/useBillingEventEmitter.js.map +1 -1
- package/dist/billing/hooks/useBillingNavigate.js.map +1 -1
- package/dist/billing/hooks/useBillingPermissions.js.map +1 -1
- package/dist/billing/hooks/useDefaultBillingCurrency.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/hooks/useAddons.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/addons/store/addonCartStore.js.map +1 -1
- package/dist/billing/modules/affiliate/api.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +107 -107
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +80 -81
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useInvoices.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useRefunds.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useTransactions.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/UserRefundsPage.js +127 -127
- package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StoreShippingSection.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/useCheckout.js +0 -1
- package/dist/billing/modules/checkout/hooks/useCheckout.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/useNativeCheckout.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/usePaymentProviders.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/usePaymentStatusPolling.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/useStoreShipping.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +412 -395
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/checkout/utils/storeOrder.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/hooks/useCredits.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/hooks/useBillingOverviewData.js.map +1 -1
- package/dist/billing/modules/dashboard/hooks/useDashboard.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/api.js.map +1 -1
- package/dist/billing/modules/earnings/pages/DeveloperRevenueAdminPage.js +145 -145
- package/dist/billing/modules/earnings/pages/DeveloperRevenueAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +133 -133
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +7 -9
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +95 -95
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/constants/featuredQuotas.js.map +1 -1
- package/dist/billing/modules/plans/hooks/usePlans.js.map +1 -1
- package/dist/billing/modules/plans/hooks/useQuotas.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
- package/dist/billing/modules/quota/hooks/useQuotaTemplates.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaAssignFreePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
- package/dist/billing/modules/store/pages/StoreCheckoutPage.js +5 -6
- package/dist/billing/modules/store/pages/StoreCheckoutPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/hooks/useSubscriptions.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/hooks/useUsage.js +14 -9
- package/dist/billing/modules/usage/hooks/useUsage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +481 -453
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/providers/BillingProvider.js.map +1 -1
- package/dist/billing/shared/components/AccessDenied.js.map +1 -1
- package/dist/billing/shared/components/ActorIdentity.js.map +1 -1
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
- package/dist/billing/shared/components/EmptyState.js.map +1 -1
- package/dist/billing/shared/components/PageHeader.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/dist/billing/shared/components/StatCard.js.map +1 -1
- package/dist/billing/shared/hooks/useActorProfiles.js.map +1 -1
- package/dist/billing/shared/types/graphql.js.map +1 -1
- package/dist/billing/shared/ui/Card.js.map +1 -1
- package/dist/billing/shared/ui/MetricCard.js.map +1 -1
- package/dist/billing/shared/ui/ProgressBar.js.map +1 -1
- package/dist/billing/shared/ui/StatusPill.js.map +1 -1
- package/dist/billing/shared/utils/directBillingGraphql.js.map +1 -1
- package/dist/billing/shared/utils/error.js.map +1 -1
- package/dist/billing/shared/utils/format.js.map +1 -1
- package/dist/billing/shared/utils/gatewayGraphql.js.map +1 -1
- package/dist/billing/shared/utils/navigation.js.map +1 -1
- package/dist/billing/shared/utils/paymentTheme.js.map +1 -1
- package/dist/billing/shared/utils/planFeatureQuantity.js.map +1 -1
- package/dist/billing/shared/utils/status.js.map +1 -1
- package/dist/billing/shared/utils/tokens.js.map +1 -1
- package/dist/generated/global-operations.js +5 -1
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.js.map +1 -1
- package/dist/generated/wspace-operations.js +1 -1
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/node_modules/@capacitor/core/dist/index.js +1 -1
- package/dist/node_modules/@capacitor/core/dist/index.js.map +1 -1
- package/package.json +13 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyPriceOverridesEditor.js","names":[],"sources":["../../../../src/billing/shared/components/CurrencyPriceOverridesEditor.tsx"],"sourcesContent":["import { useState, type FC } from 'react';\n\nimport type { CurrencyPriceOverrideInput } from '../types';\n\ninterface CurrencyPriceOverridesEditorProps {\n overrides: CurrencyPriceOverrideInput[];\n onChange: (overrides: CurrencyPriceOverrideInput[]) => void;\n showPerSeatAmount?: boolean;\n}\n\nconst PRICING_CURRENCIES: { code: string; name: string; symbol: string }[] = [\n { code: 'EUR', name: 'Euro', symbol: '€' },\n { code: 'GBP', name: 'British Pound', symbol: '£' },\n { code: 'INR', name: 'Indian Rupee', symbol: '₹' },\n { code: 'AUD', name: 'Australian Dollar', symbol: 'A$' },\n { code: 'CAD', name: 'Canadian Dollar', symbol: 'C$' },\n { code: 'SGD', name: 'Singapore Dollar', symbol: 'S$' },\n { code: 'JPY', name: 'Japanese Yen', symbol: '¥' },\n { code: 'MXN', name: 'Mexican Peso', symbol: 'MX$' },\n { code: 'BRL', name: 'Brazilian Real', symbol: 'R$' },\n { code: 'CHF', name: 'Swiss Franc', symbol: 'Fr' },\n { code: 'CNY', name: 'Chinese Yuan', symbol: '¥' },\n { code: 'HKD', name: 'Hong Kong Dollar', symbol: 'HK$' },\n { code: 'NZD', name: 'New Zealand Dollar', symbol: 'NZ$' },\n { code: 'SEK', name: 'Swedish Krona', symbol: 'kr' },\n { code: 'KRW', name: 'South Korean Won', symbol: '₩' },\n { code: 'NOK', name: 'Norwegian Krone', symbol: 'kr' },\n { code: 'DKK', name: 'Danish Krone', symbol: 'kr' },\n { code: 'PLN', name: 'Polish Złoty', symbol: 'zł' },\n { code: 'THB', name: 'Thai Baht', symbol: '฿' },\n { code: 'MYR', name: 'Malaysian Ringgit', symbol: 'RM' },\n];\n\nexport const CurrencyPriceOverridesEditor: FC<CurrencyPriceOverridesEditorProps> = ({\n overrides,\n onChange,\n showPerSeatAmount = false,\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const getOverride = (currency: string): CurrencyPriceOverrideInput | undefined =>\n overrides.find((o) => o.currency === currency);\n\n const handleAmountChange = (currency: string, value: string) => {\n const trimmed = value.trim();\n const existing = overrides.filter((o) => o.currency !== currency);\n\n if (trimmed === '') {\n onChange(existing);\n return;\n }\n\n const amount = parseFloat(trimmed);\n if (isNaN(amount) || amount < 0) return;\n\n const currentOverride = getOverride(currency);\n onChange([\n ...existing,\n {\n currency,\n amount,\n ...(currentOverride?.perSeatAmount !== undefined\n ? { perSeatAmount: currentOverride.perSeatAmount }\n : {}),\n },\n ]);\n };\n\n const handlePerSeatChange = (currency: string, value: string) => {\n const trimmed = value.trim();\n const existing = overrides.filter((o) => o.currency !== currency);\n const currentOverride = getOverride(currency);\n\n if (!currentOverride) return;\n\n if (trimmed === '') {\n onChange([...existing, { currency, amount: currentOverride.amount }]);\n return;\n }\n\n const perSeatAmount = parseFloat(trimmed);\n if (isNaN(perSeatAmount) || perSeatAmount < 0) return;\n\n onChange([...existing, { ...currentOverride, perSeatAmount }]);\n };\n\n const overrideCount = overrides.length;\n\n return (\n <div className=\"border border-border-subtle rounded-lg bg-bg-surface overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setIsExpanded((v) => !v)}\n className=\"w-full p-4 border-b border-border-subtle bg-bg-sunken/30 flex items-center justify-between hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-2\">\n <h2 className=\"font-semibold text-text-primary\">Currency Price Overrides</h2>\n {overrideCount > 0 && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-action-primary-bg/10 text-primary rounded-full\">\n {overrideCount} set\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <span>\n {isExpanded ? 'Hide' : 'Show'} (leave blank to use auto-calculated exchange rates)\n </span>\n <svg\n className={`w-4 h-4 transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n </button>\n\n {isExpanded && (\n <div className=\"p-4\">\n <p className=\"text-xs text-text-secondary mb-4\">\n Set a specific price for any currency. Leave a field empty to auto-calculate from the\n USD base price using live exchange rates.\n </p>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3\">\n {PRICING_CURRENCIES.map(({ code, name, symbol }) => {\n const override = getOverride(code);\n return (\n <div key={code} className=\"space-y-1\">\n <label className=\"flex items-center gap-1 text-xs font-medium text-text-primary\">\n <span className=\"text-text-secondary\">{symbol}</span>\n <span>{code}</span>\n <span className=\"text-text-secondary font-normal truncate\">({name})</span>\n </label>\n <div className={showPerSeatAmount ? 'flex gap-1' : ''}>\n <input\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n value={override?.amount ?? ''}\n onChange={(e) => handleAmountChange(code, e.target.value)}\n placeholder=\"auto\"\n className={`px-2 py-1.5 text-sm border border-border-subtle rounded-md bg-bg-surface text-text-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-text-secondary ${\n showPerSeatAmount ? 'flex-1 min-w-0' : 'w-full'\n } ${override?.amount !== undefined ? 'border-primary/50' : ''}`}\n />\n {showPerSeatAmount && (\n <input\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n value={override?.perSeatAmount ?? ''}\n onChange={(e) => handlePerSeatChange(code, e.target.value)}\n placeholder=\"/seat\"\n disabled={!override}\n title=\"Per-seat amount (requires flat amount to be set first)\"\n className=\"flex-1 min-w-0 px-2 py-1.5 text-sm border border-border-subtle rounded-md bg-bg-surface text-text-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-text-secondary disabled:opacity-40\"\n />\n )}\n </div>\n </div>\n );\n })}\n </div>\n {overrideCount > 0 && (\n <button\n type=\"button\"\n onClick={() => onChange([])}\n className=\"mt-4 text-xs text-status-error-text hover:underline\"\n >\n Clear all overrides\n </button>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CurrencyPriceOverridesEditor.js","names":[],"sources":["../../../../src/billing/shared/components/CurrencyPriceOverridesEditor.tsx"],"sourcesContent":["import { useState, type FC } from 'react';\n\nimport type { CurrencyPriceOverrideInput } from '../types';\n\ninterface CurrencyPriceOverridesEditorProps {\n overrides: CurrencyPriceOverrideInput[];\n onChange: (overrides: CurrencyPriceOverrideInput[]) => void;\n showPerSeatAmount?: boolean;\n}\n\nconst PRICING_CURRENCIES: { code: string; name: string; symbol: string }[] = [\n { code: 'EUR', name: 'Euro', symbol: '€' },\n { code: 'GBP', name: 'British Pound', symbol: '£' },\n { code: 'INR', name: 'Indian Rupee', symbol: '₹' },\n { code: 'AUD', name: 'Australian Dollar', symbol: 'A$' },\n { code: 'CAD', name: 'Canadian Dollar', symbol: 'C$' },\n { code: 'SGD', name: 'Singapore Dollar', symbol: 'S$' },\n { code: 'JPY', name: 'Japanese Yen', symbol: '¥' },\n { code: 'MXN', name: 'Mexican Peso', symbol: 'MX$' },\n { code: 'BRL', name: 'Brazilian Real', symbol: 'R$' },\n { code: 'CHF', name: 'Swiss Franc', symbol: 'Fr' },\n { code: 'CNY', name: 'Chinese Yuan', symbol: '¥' },\n { code: 'HKD', name: 'Hong Kong Dollar', symbol: 'HK$' },\n { code: 'NZD', name: 'New Zealand Dollar', symbol: 'NZ$' },\n { code: 'SEK', name: 'Swedish Krona', symbol: 'kr' },\n { code: 'KRW', name: 'South Korean Won', symbol: '₩' },\n { code: 'NOK', name: 'Norwegian Krone', symbol: 'kr' },\n { code: 'DKK', name: 'Danish Krone', symbol: 'kr' },\n { code: 'PLN', name: 'Polish Złoty', symbol: 'zł' },\n { code: 'THB', name: 'Thai Baht', symbol: '฿' },\n { code: 'MYR', name: 'Malaysian Ringgit', symbol: 'RM' },\n];\n\nexport const CurrencyPriceOverridesEditor: FC<CurrencyPriceOverridesEditorProps> = ({\n overrides,\n onChange,\n showPerSeatAmount = false,\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const getOverride = (currency: string): CurrencyPriceOverrideInput | undefined =>\n overrides.find((o) => o.currency === currency);\n\n const handleAmountChange = (currency: string, value: string) => {\n const trimmed = value.trim();\n const existing = overrides.filter((o) => o.currency !== currency);\n\n if (trimmed === '') {\n onChange(existing);\n return;\n }\n\n const amount = parseFloat(trimmed);\n if (isNaN(amount) || amount < 0) return;\n\n const currentOverride = getOverride(currency);\n onChange([\n ...existing,\n {\n currency,\n amount,\n ...(currentOverride?.perSeatAmount !== undefined\n ? { perSeatAmount: currentOverride.perSeatAmount }\n : {}),\n },\n ]);\n };\n\n const handlePerSeatChange = (currency: string, value: string) => {\n const trimmed = value.trim();\n const existing = overrides.filter((o) => o.currency !== currency);\n const currentOverride = getOverride(currency);\n\n if (!currentOverride) return;\n\n if (trimmed === '') {\n onChange([...existing, { currency, amount: currentOverride.amount }]);\n return;\n }\n\n const perSeatAmount = parseFloat(trimmed);\n if (isNaN(perSeatAmount) || perSeatAmount < 0) return;\n\n onChange([...existing, { ...currentOverride, perSeatAmount }]);\n };\n\n const overrideCount = overrides.length;\n\n return (\n <div className=\"border border-border-subtle rounded-lg bg-bg-surface overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setIsExpanded((v) => !v)}\n className=\"w-full p-4 border-b border-border-subtle bg-bg-sunken/30 flex items-center justify-between hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-2\">\n <h2 className=\"font-semibold text-text-primary\">Currency Price Overrides</h2>\n {overrideCount > 0 && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-action-primary-bg/10 text-primary rounded-full\">\n {overrideCount} set\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <span>\n {isExpanded ? 'Hide' : 'Show'} (leave blank to use auto-calculated exchange rates)\n </span>\n <svg\n className={`w-4 h-4 transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n </button>\n\n {isExpanded && (\n <div className=\"p-4\">\n <p className=\"text-xs text-text-secondary mb-4\">\n Set a specific price for any currency. Leave a field empty to auto-calculate from the\n USD base price using live exchange rates.\n </p>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3\">\n {PRICING_CURRENCIES.map(({ code, name, symbol }) => {\n const override = getOverride(code);\n return (\n <div key={code} className=\"space-y-1\">\n <label className=\"flex items-center gap-1 text-xs font-medium text-text-primary\">\n <span className=\"text-text-secondary\">{symbol}</span>\n <span>{code}</span>\n <span className=\"text-text-secondary font-normal truncate\">({name})</span>\n </label>\n <div className={showPerSeatAmount ? 'flex gap-1' : ''}>\n <input\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n value={override?.amount ?? ''}\n onChange={(e) => handleAmountChange(code, e.target.value)}\n placeholder=\"auto\"\n className={`px-2 py-1.5 text-sm border border-border-subtle rounded-md bg-bg-surface text-text-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-text-secondary ${\n showPerSeatAmount ? 'flex-1 min-w-0' : 'w-full'\n } ${override?.amount !== undefined ? 'border-primary/50' : ''}`}\n />\n {showPerSeatAmount && (\n <input\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n value={override?.perSeatAmount ?? ''}\n onChange={(e) => handlePerSeatChange(code, e.target.value)}\n placeholder=\"/seat\"\n disabled={!override}\n title=\"Per-seat amount (requires flat amount to be set first)\"\n className=\"flex-1 min-w-0 px-2 py-1.5 text-sm border border-border-subtle rounded-md bg-bg-surface text-text-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-text-secondary disabled:opacity-40\"\n />\n )}\n </div>\n </div>\n );\n })}\n </div>\n {overrideCount > 0 && (\n <button\n type=\"button\"\n onClick={() => onChange([])}\n className=\"mt-4 text-xs text-status-error-text hover:underline\"\n >\n Clear all overrides\n </button>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.js","names":[],"sources":["../../../../src/billing/shared/components/EmptyState.tsx"],"sourcesContent":["/**\n * Shared Empty State Component\n *\n * Local wrapper around `EmptyState` from `@burdenoff/fe-libs/ui`.\n * Keeps the existing microfe-billing call sites stable while routing all\n * empty-state rendering through the canonical primitive.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { EmptyState as CanonicalEmptyState } from '@burdenoff/fe-libs/ui';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n}\n\nexport const EmptyState: FC<EmptyStateProps> = ({ icon, title, description, action }) => {\n return (\n <CanonicalEmptyState icon={icon} title={title} description={description} action={action} />\n );\n};\n"],"mappings":";;;AAkBA,IAAa,KAAmC,EAAE,SAAM,UAAO,gBAAa,gBAExE,kBAAC,GAAD;CAA2B;CAAa;CAAoB;CAAqB;
|
|
1
|
+
{"version":3,"file":"EmptyState.js","names":[],"sources":["../../../../src/billing/shared/components/EmptyState.tsx"],"sourcesContent":["/**\n * Shared Empty State Component\n *\n * Local wrapper around `EmptyState` from `@burdenoff/fe-libs/ui`.\n * Keeps the existing microfe-billing call sites stable while routing all\n * empty-state rendering through the canonical primitive.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { EmptyState as CanonicalEmptyState } from '@burdenoff/fe-libs/ui';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n}\n\nexport const EmptyState: FC<EmptyStateProps> = ({ icon, title, description, action }) => {\n return (\n <CanonicalEmptyState icon={icon} title={title} description={description} action={action} />\n );\n};\n"],"mappings":";;;AAkBA,IAAa,KAAmC,EAAE,SAAM,UAAO,gBAAa,gBAExE,kBAAC,GAAD;CAA2B;CAAa;CAAoB;CAAqB;AAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.js","names":[],"sources":["../../../../src/billing/shared/components/PageHeader.tsx"],"sourcesContent":["/**\n * Shared Page Header Component\n *\n * Local wrapper around `PageHeader` from `@burdenoff/fe-libs/chrome`.\n * Routes all billing page headers through the canonical primitive so they\n * inherit responsive layout, breadcrumb support, and one-primary-action\n * styling from the design system.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { PageHeader as CanonicalPageHeader } from '@burdenoff/fe-libs/chrome';\n\ninterface PageHeaderProps {\n title: string;\n description?: string;\n actions?: ReactNode;\n icon?: ReactNode;\n}\n\nexport const PageHeader: FC<PageHeaderProps> = ({ title, description, actions, icon }) => {\n return (\n <CanonicalPageHeader title={title} description={description} actions={actions} icon={icon} />\n );\n};\n"],"mappings":";;;AAmBA,IAAa,KAAmC,EAAE,UAAO,gBAAa,YAAS,cAE3E,kBAAC,GAAD;CAA4B;CAAoB;CAAsB;CAAe;
|
|
1
|
+
{"version":3,"file":"PageHeader.js","names":[],"sources":["../../../../src/billing/shared/components/PageHeader.tsx"],"sourcesContent":["/**\n * Shared Page Header Component\n *\n * Local wrapper around `PageHeader` from `@burdenoff/fe-libs/chrome`.\n * Routes all billing page headers through the canonical primitive so they\n * inherit responsive layout, breadcrumb support, and one-primary-action\n * styling from the design system.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { PageHeader as CanonicalPageHeader } from '@burdenoff/fe-libs/chrome';\n\ninterface PageHeaderProps {\n title: string;\n description?: string;\n actions?: ReactNode;\n icon?: ReactNode;\n}\n\nexport const PageHeader: FC<PageHeaderProps> = ({ title, description, actions, icon }) => {\n return (\n <CanonicalPageHeader title={title} description={description} actions={actions} icon={icon} />\n );\n};\n"],"mappings":";;;AAmBA,IAAa,KAAmC,EAAE,UAAO,gBAAa,YAAS,cAE3E,kBAAC,GAAD;CAA4B;CAAoB;CAAsB;CAAe;AAAO,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerError.js","names":[],"sources":["../../../../src/billing/shared/components/ServerError.tsx"],"sourcesContent":["/**\n * Shared Server Error Component\n * Displays when backend server is unavailable or returns 500 errors\n */\n\nimport type { FC } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { statusTokens } from '../utils/tokens';\n\ninterface ServerErrorProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n showRetry?: boolean;\n}\n\nexport const ServerError: FC<ServerErrorProps> = ({\n title,\n message,\n onRetry,\n showRetry = true,\n}) => {\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\n const displayTitle = title ?? tr('billing.serverError.title', 'Server Unavailable');\n const displayMessage =\n message ??\n tr(\n 'billing.serverError.message',\n \"We're having trouble connecting to the server. Please try again later.\"\n );\n const errorTokens = statusTokens.error;\n\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4 max-w-md\">\n {/* Server Icon */}\n <div\n className={`size-16 mx-auto rounded-full ${errorTokens.bg} flex items-center justify-center`}\n >\n <svg\n className={`size-8 ${errorTokens.icon}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z\"\n />\n </svg>\n </div>\n\n {/* Error Title */}\n <h2 className=\"text-xl font-semibold text-text-primary\">{displayTitle}</h2>\n\n {/* Error Message */}\n <p className=\"text-sm text-text-secondary\">{displayMessage}</p>\n\n {/* Status Indicator */}\n <div\n className={`inline-flex items-center gap-2 px-3 py-1.5 ${errorTokens.bg} rounded-full`}\n >\n <span className={`size-2 rounded-full ${errorTokens.dot} animate-pulse`} />\n <span className={`text-xs font-medium ${errorTokens.text}`}>\n {tr('billing.serverError.statusOffline', 'Server Status: Offline')}\n </span>\n </div>\n\n {/* Retry Button */}\n {showRetry && onRetry && (\n <div className=\"pt-2\">\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg hover:bg-action-primary-bgHover rounded-button transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2\"\n >\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99\"\n />\n </svg>\n {tr('billing.serverError.tryAgain', 'Try Again')}\n </button>\n </div>\n )}\n\n {/* Additional Help */}\n <p className=\"text-xs text-text-muted pt-4\">\n {tr(\n 'billing.serverError.persistHelp',\n 'If this issue persists, please contact support or check the system status page.'\n )}\n </p>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;AAgBA,IAAa,KAAqC,EAChD,UACA,YACA,YACA,eAAY,SACR;CACJ,IAAM,EAAE,SAAM,
|
|
1
|
+
{"version":3,"file":"ServerError.js","names":[],"sources":["../../../../src/billing/shared/components/ServerError.tsx"],"sourcesContent":["/**\n * Shared Server Error Component\n * Displays when backend server is unavailable or returns 500 errors\n */\n\nimport type { FC } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { statusTokens } from '../utils/tokens';\n\ninterface ServerErrorProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n showRetry?: boolean;\n}\n\nexport const ServerError: FC<ServerErrorProps> = ({\n title,\n message,\n onRetry,\n showRetry = true,\n}) => {\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\n const displayTitle = title ?? tr('billing.serverError.title', 'Server Unavailable');\n const displayMessage =\n message ??\n tr(\n 'billing.serverError.message',\n \"We're having trouble connecting to the server. Please try again later.\"\n );\n const errorTokens = statusTokens.error;\n\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4 max-w-md\">\n {/* Server Icon */}\n <div\n className={`size-16 mx-auto rounded-full ${errorTokens.bg} flex items-center justify-center`}\n >\n <svg\n className={`size-8 ${errorTokens.icon}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z\"\n />\n </svg>\n </div>\n\n {/* Error Title */}\n <h2 className=\"text-xl font-semibold text-text-primary\">{displayTitle}</h2>\n\n {/* Error Message */}\n <p className=\"text-sm text-text-secondary\">{displayMessage}</p>\n\n {/* Status Indicator */}\n <div\n className={`inline-flex items-center gap-2 px-3 py-1.5 ${errorTokens.bg} rounded-full`}\n >\n <span className={`size-2 rounded-full ${errorTokens.dot} animate-pulse`} />\n <span className={`text-xs font-medium ${errorTokens.text}`}>\n {tr('billing.serverError.statusOffline', 'Server Status: Offline')}\n </span>\n </div>\n\n {/* Retry Button */}\n {showRetry && onRetry && (\n <div className=\"pt-2\">\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg hover:bg-action-primary-bgHover rounded-button transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2\"\n >\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99\"\n />\n </svg>\n {tr('billing.serverError.tryAgain', 'Try Again')}\n </button>\n </div>\n )}\n\n {/* Additional Help */}\n <p className=\"text-xs text-text-muted pt-4\">\n {tr(\n 'billing.serverError.persistHelp',\n 'If this issue persists, please contact support or check the system status page.'\n )}\n </p>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;AAgBA,IAAa,KAAqC,EAChD,UACA,YACA,YACA,eAAY,SACR;CACJ,IAAM,EAAE,SAAM,EAAQ,GAChB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,CAAG;EACxB,OAAO,MAAe,IAAM,IAAW;CACzC,GAEM,IAAe,KAAS,EAAG,6BAA6B,oBAAoB,GAC5E,IACJ,KACA,EACE,+BACA,wEACF,GACI,IAAc,EAAa;CAEjC,OACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KACE,WAAW,gCAAgC,EAAY,GAAG;eAE1D,kBAAC,OAAD;MACE,WAAW,UAAU,EAAY;MACjC,MAAK;MACL,SAAQ;MACR,QAAO;MACP,aAAa;gBAEb,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,GAAE;MACH,CAAA;KACE,CAAA;IACF,CAAA;IAGL,kBAAC,MAAD;KAAI,WAAU;eAA2C;IAAiB,CAAA;IAG1E,kBAAC,KAAD;KAAG,WAAU;eAA+B;IAAkB,CAAA;IAG9D,kBAAC,OAAD;KACE,WAAW,8CAA8C,EAAY,GAAG;eAD1E,CAGE,kBAAC,QAAD,EAAM,WAAW,uBAAuB,EAAY,IAAI,gBAAkB,CAAA,GAC1E,kBAAC,QAAD;MAAM,WAAW,uBAAuB,EAAY;gBACjD,EAAG,qCAAqC,wBAAwB;KAC7D,CAAA,CACH;;IAGJ,KAAa,KACZ,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBAHZ,CAKE,kBAAC,OAAD;OACE,WAAU;OACV,MAAK;OACL,SAAQ;OACR,QAAO;OACP,aAAa;iBAEb,kBAAC,QAAD;QACE,eAAc;QACd,gBAAe;QACf,GAAE;OACH,CAAA;MACE,CAAA,GACJ,EAAG,gCAAgC,WAAW,CACzC;;IACL,CAAA;IAIP,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,mCACA,iFACF;IACC,CAAA;GACA;;CACF,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatCard.js","names":[],"sources":["../../../../src/billing/shared/components/StatCard.tsx"],"sourcesContent":["/**\n * Shared Stat Card Component\n * Displays a metric with label and value\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { MetricCard } from '../ui';\n\ninterface StatCardProps {\n label: string;\n value: string | number;\n icon?: ReactNode;\n trend?: {\n value: number;\n isPositive: boolean;\n };\n className?: string;\n}\n\nexport const StatCard: FC<StatCardProps> = ({ label, value, icon, trend, className = '' }) => {\n return <MetricCard label={label} value={value} icon={icon} trend={trend} className={className} />;\n};\n"],"mappings":";;;;AAmBA,IAAa,KAA+B,EAAE,UAAO,UAAO,SAAM,UAAO,eAAY,SAC5E,kBAAC,GAAD;CAAmB;CAAc;CAAa;CAAa;CAAkB;
|
|
1
|
+
{"version":3,"file":"StatCard.js","names":[],"sources":["../../../../src/billing/shared/components/StatCard.tsx"],"sourcesContent":["/**\n * Shared Stat Card Component\n * Displays a metric with label and value\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { MetricCard } from '../ui';\n\ninterface StatCardProps {\n label: string;\n value: string | number;\n icon?: ReactNode;\n trend?: {\n value: number;\n isPositive: boolean;\n };\n className?: string;\n}\n\nexport const StatCard: FC<StatCardProps> = ({ label, value, icon, trend, className = '' }) => {\n return <MetricCard label={label} value={value} icon={icon} trend={trend} className={className} />;\n};\n"],"mappings":";;;;AAmBA,IAAa,KAA+B,EAAE,UAAO,UAAO,SAAM,UAAO,eAAY,SAC5E,kBAAC,GAAD;CAAmB;CAAc;CAAa;CAAa;CAAkB;AAAY,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useActorProfiles.js","names":[],"sources":["../../../../src/billing/shared/hooks/useActorProfiles.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useBilling } from '../../providers/BillingProvider';\nimport { directBillingGraphqlRequest } from '../utils';\n\nexport interface ActorProfile {\n actorId: string;\n actorType: string;\n displayName: string;\n secondaryLabel: string;\n email?: string;\n avatarUrl?: string;\n resolved: boolean;\n}\n\nexport type ActorProfileMap = Record<string, ActorProfile>;\n\ninterface ActorInput {\n actorId: string;\n actorType: string;\n}\n\nconst USER_QUERY = `\n query ActorProfileUser($id: ID!) {\n user(id: $id) {\n id\n email\n firstName\n lastName\n name\n username\n avatar\n }\n }\n`;\n\ninterface UserResponse {\n user: {\n id: string;\n email?: string | null;\n firstName?: string | null;\n lastName?: string | null;\n name?: string | null;\n username?: string | null;\n avatar?: string | null;\n } | null;\n}\n\nfunction shortId(actorId: string): string {\n if (actorId.length <= 12) return actorId;\n return `${actorId.slice(0, 8)}…${actorId.slice(-4)}`;\n}\n\nfunction humanizeType(actorType: string): string {\n switch (actorType.toLowerCase()) {\n case 'user':\n return 'User';\n case 'app':\n return 'App';\n case 'service':\n return 'Service';\n case 'super_admin':\n return 'Super Admin';\n default:\n return actorType\n .split('_')\n .map((segment) => segment.charAt(0) + segment.slice(1).toLowerCase())\n .join(' ');\n }\n}\n\nfunction buildFallback(actor: ActorInput): ActorProfile {\n return {\n actorId: actor.actorId,\n actorType: actor.actorType,\n displayName:\n actor.actorType.toLowerCase() === 'user'\n ? `User ${shortId(actor.actorId)}`\n : humanizeType(actor.actorType),\n secondaryLabel: shortId(actor.actorId),\n resolved: false,\n };\n}\n\nconst cache = new Map<string, ActorProfile>();\nconst inflight = new Map<string, Promise<ActorProfile>>();\nconst CACHE_TTL_MS = 5 * 60 * 1000;\nconst cacheExpiresAt = new Map<string, number>();\n\nfunction cacheGet(actorId: string): ActorProfile | undefined {\n const expiresAt = cacheExpiresAt.get(actorId);\n if (!expiresAt || expiresAt < Date.now()) {\n cache.delete(actorId);\n cacheExpiresAt.delete(actorId);\n return undefined;\n }\n return cache.get(actorId);\n}\n\nfunction cacheSet(profile: ActorProfile): void {\n cache.set(profile.actorId, profile);\n cacheExpiresAt.set(profile.actorId, Date.now() + CACHE_TTL_MS);\n}\n\nexport function useActorProfiles(actors: ActorInput[]): ActorProfileMap {\n const { authToken, apiGatewayUrl, orgId } = useBilling();\n const [profileMap, setProfileMap] = useState<ActorProfileMap>(() => {\n const initial: ActorProfileMap = {};\n for (const actor of actors) {\n const cached = cacheGet(actor.actorId);\n initial[actor.actorId] = cached ?? buildFallback(actor);\n }\n return initial;\n });\n\n const actorsKey = useMemo(\n () =>\n actors\n .map((a) => `${a.actorId}|${a.actorType}`)\n .sort()\n .join(','),\n [actors]\n );\n const lastTokenRef = useRef<string | undefined>(undefined);\n\n useEffect(() => {\n let cancelled = false;\n lastTokenRef.current = authToken;\n\n async function loadOne(actor: ActorInput): Promise<ActorProfile> {\n const cached = cacheGet(actor.actorId);\n if (cached?.resolved) return cached;\n\n if (actor.actorType.toLowerCase() !== 'user') {\n const profile = buildFallback(actor);\n cacheSet(profile);\n return profile;\n }\n\n const key = actor.actorId;\n const existing = inflight.get(key);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const data = await directBillingGraphqlRequest<UserResponse>({\n apiGatewayUrl,\n authToken,\n orgId,\n query: USER_QUERY,\n variables: { id: actor.actorId },\n });\n if (!data.user) {\n const profile = buildFallback(actor);\n cacheSet(profile);\n return profile;\n }\n const u = data.user;\n const displayName =\n u.name?.trim() ||\n [u.firstName, u.lastName].filter(Boolean).join(' ').trim() ||\n u.username?.trim() ||\n u.email?.trim() ||\n `User ${shortId(actor.actorId)}`;\n const profile: ActorProfile = {\n actorId: actor.actorId,\n actorType: actor.actorType,\n displayName,\n secondaryLabel: u.email ?? shortId(actor.actorId),\n email: u.email ?? undefined,\n avatarUrl: u.avatar ?? undefined,\n resolved: true,\n };\n cacheSet(profile);\n return profile;\n } catch {\n const profile = buildFallback(actor);\n return profile;\n } finally {\n inflight.delete(key);\n }\n })();\n inflight.set(key, promise);\n return promise;\n }\n\n async function run() {\n const results = await Promise.all(actors.map(loadOne));\n if (cancelled) return;\n setProfileMap((prev) => {\n const next: ActorProfileMap = { ...prev };\n for (const profile of results) {\n next[profile.actorId] = profile;\n }\n return next;\n });\n }\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [actorsKey, authToken, apiGatewayUrl, orgId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return profileMap;\n}\n"],"mappings":";;;;;AAqBA,IAAM,IAAa;AA0BnB,SAAS,EAAQ,GAAyB;
|
|
1
|
+
{"version":3,"file":"useActorProfiles.js","names":[],"sources":["../../../../src/billing/shared/hooks/useActorProfiles.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useBilling } from '../../providers/BillingProvider';\nimport { directBillingGraphqlRequest } from '../utils';\n\nexport interface ActorProfile {\n actorId: string;\n actorType: string;\n displayName: string;\n secondaryLabel: string;\n email?: string;\n avatarUrl?: string;\n resolved: boolean;\n}\n\nexport type ActorProfileMap = Record<string, ActorProfile>;\n\ninterface ActorInput {\n actorId: string;\n actorType: string;\n}\n\nconst USER_QUERY = `\n query ActorProfileUser($id: ID!) {\n user(id: $id) {\n id\n email\n firstName\n lastName\n name\n username\n avatar\n }\n }\n`;\n\ninterface UserResponse {\n user: {\n id: string;\n email?: string | null;\n firstName?: string | null;\n lastName?: string | null;\n name?: string | null;\n username?: string | null;\n avatar?: string | null;\n } | null;\n}\n\nfunction shortId(actorId: string): string {\n if (actorId.length <= 12) return actorId;\n return `${actorId.slice(0, 8)}…${actorId.slice(-4)}`;\n}\n\nfunction humanizeType(actorType: string): string {\n switch (actorType.toLowerCase()) {\n case 'user':\n return 'User';\n case 'app':\n return 'App';\n case 'service':\n return 'Service';\n case 'super_admin':\n return 'Super Admin';\n default:\n return actorType\n .split('_')\n .map((segment) => segment.charAt(0) + segment.slice(1).toLowerCase())\n .join(' ');\n }\n}\n\nfunction buildFallback(actor: ActorInput): ActorProfile {\n return {\n actorId: actor.actorId,\n actorType: actor.actorType,\n displayName:\n actor.actorType.toLowerCase() === 'user'\n ? `User ${shortId(actor.actorId)}`\n : humanizeType(actor.actorType),\n secondaryLabel: shortId(actor.actorId),\n resolved: false,\n };\n}\n\nconst cache = new Map<string, ActorProfile>();\nconst inflight = new Map<string, Promise<ActorProfile>>();\nconst CACHE_TTL_MS = 5 * 60 * 1000;\nconst cacheExpiresAt = new Map<string, number>();\n\nfunction cacheGet(actorId: string): ActorProfile | undefined {\n const expiresAt = cacheExpiresAt.get(actorId);\n if (!expiresAt || expiresAt < Date.now()) {\n cache.delete(actorId);\n cacheExpiresAt.delete(actorId);\n return undefined;\n }\n return cache.get(actorId);\n}\n\nfunction cacheSet(profile: ActorProfile): void {\n cache.set(profile.actorId, profile);\n cacheExpiresAt.set(profile.actorId, Date.now() + CACHE_TTL_MS);\n}\n\nexport function useActorProfiles(actors: ActorInput[]): ActorProfileMap {\n const { authToken, apiGatewayUrl, orgId } = useBilling();\n const [profileMap, setProfileMap] = useState<ActorProfileMap>(() => {\n const initial: ActorProfileMap = {};\n for (const actor of actors) {\n const cached = cacheGet(actor.actorId);\n initial[actor.actorId] = cached ?? buildFallback(actor);\n }\n return initial;\n });\n\n const actorsKey = useMemo(\n () =>\n actors\n .map((a) => `${a.actorId}|${a.actorType}`)\n .sort()\n .join(','),\n [actors]\n );\n const lastTokenRef = useRef<string | undefined>(undefined);\n\n useEffect(() => {\n let cancelled = false;\n lastTokenRef.current = authToken;\n\n async function loadOne(actor: ActorInput): Promise<ActorProfile> {\n const cached = cacheGet(actor.actorId);\n if (cached?.resolved) return cached;\n\n if (actor.actorType.toLowerCase() !== 'user') {\n const profile = buildFallback(actor);\n cacheSet(profile);\n return profile;\n }\n\n const key = actor.actorId;\n const existing = inflight.get(key);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const data = await directBillingGraphqlRequest<UserResponse>({\n apiGatewayUrl,\n authToken,\n orgId,\n query: USER_QUERY,\n variables: { id: actor.actorId },\n });\n if (!data.user) {\n const profile = buildFallback(actor);\n cacheSet(profile);\n return profile;\n }\n const u = data.user;\n const displayName =\n u.name?.trim() ||\n [u.firstName, u.lastName].filter(Boolean).join(' ').trim() ||\n u.username?.trim() ||\n u.email?.trim() ||\n `User ${shortId(actor.actorId)}`;\n const profile: ActorProfile = {\n actorId: actor.actorId,\n actorType: actor.actorType,\n displayName,\n secondaryLabel: u.email ?? shortId(actor.actorId),\n email: u.email ?? undefined,\n avatarUrl: u.avatar ?? undefined,\n resolved: true,\n };\n cacheSet(profile);\n return profile;\n } catch {\n const profile = buildFallback(actor);\n return profile;\n } finally {\n inflight.delete(key);\n }\n })();\n inflight.set(key, promise);\n return promise;\n }\n\n async function run() {\n const results = await Promise.all(actors.map(loadOne));\n if (cancelled) return;\n setProfileMap((prev) => {\n const next: ActorProfileMap = { ...prev };\n for (const profile of results) {\n next[profile.actorId] = profile;\n }\n return next;\n });\n }\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [actorsKey, authToken, apiGatewayUrl, orgId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return profileMap;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.js","names":[],"sources":["../../../../src/billing/shared/types/graphql.ts"],"sourcesContent":["/**\n * GraphQL Types for Billing Module\n * Auto-generated types matching the backend billing service schema\n */\n\n// ============================================================================\n// Enums\n// ============================================================================\n\nexport enum SubscriptionStatus {\n ACTIVE = 'active',\n CANCELED = 'canceled',\n EXPIRED = 'expired',\n UPGRADED = 'upgraded',\n}\n\nexport enum InvoiceStatus {\n DRAFT = 'DRAFT',\n OPEN = 'OPEN',\n PAID = 'PAID',\n VOID = 'VOID',\n UNCOLLECTIBLE = 'UNCOLLECTIBLE',\n}\n\nexport enum PaymentStatus {\n PENDING = 'PENDING',\n SUCCEEDED = 'SUCCEEDED',\n FAILED = 'FAILED',\n CANCELED = 'CANCELED',\n REFUNDED = 'REFUNDED',\n}\n\nexport enum ChargeStatus {\n PENDING = 'PENDING',\n SUCCEEDED = 'SUCCEEDED',\n FAILED = 'FAILED',\n REFUNDED = 'REFUNDED',\n}\n\nexport enum RefundStatus {\n PENDING = 'PENDING',\n SUCCEEDED = 'SUCCEEDED',\n FAILED = 'FAILED',\n CANCELED = 'CANCELED',\n}\n\nexport enum PaymentMethodType {\n CREDIT_CARD = 'CREDIT_CARD',\n DEBIT_CARD = 'DEBIT_CARD',\n BANK_TRANSFER = 'BANK_TRANSFER',\n PAYPAL = 'PAYPAL',\n CRYPTO = 'CRYPTO',\n WALLET = 'WALLET',\n NETBANKING = 'NETBANKING',\n}\n\nexport enum PlanDuration {\n MONTHLY = 'monthly',\n YEARLY = 'yearly',\n}\n\nexport enum PricingModel {\n FLAT_RATE = 'FLAT_RATE',\n PER_SEAT = 'PER_SEAT',\n}\n\nexport enum QuotaType {\n POOLED = 'POOLED',\n PRODUCT_SPECIFIC = 'PRODUCT_SPECIFIC',\n}\n\nexport enum QuotaScope {\n WORKSPACE = 'WORKSPACE',\n GLOBAL = 'GLOBAL',\n}\n\nexport enum QuotaResetPeriod {\n NEVER = 'NEVER',\n DAILY = 'DAILY',\n MONTHLY = 'MONTHLY',\n}\n\nexport enum QuotaStatus {\n HEALTHY = 'HEALTHY',\n WARNING = 'WARNING',\n CRITICAL = 'CRITICAL',\n EXHAUSTED = 'EXHAUSTED',\n INACTIVE = 'INACTIVE',\n}\n\nexport enum TransactionType {\n PAYMENT = 'payment',\n REFUND = 'refund',\n ADJUSTMENT = 'adjustment',\n}\n\nexport enum TransactionStatus {\n PENDING = 'pending',\n SUCCESS = 'success',\n FAILED = 'failed',\n}\n\nexport enum CreditTransactionType {\n PURCHASE = 'purchase',\n USAGE = 'usage',\n ADJUSTMENT = 'adjustment',\n GRANTED = 'granted',\n}\n\nexport enum CreditTransactionStatus {\n PENDING = 'pending',\n SUCCESS = 'success',\n FAILED = 'failed',\n REFUND = 'refund',\n}\n\nexport enum EntitlementAccessType {\n FREE_ACCESS = 'FREE_ACCESS',\n DISCOUNT = 'DISCOUNT',\n}\n\nexport enum PurchaseType {\n PLAN = 'PLAN',\n ADDON = 'ADDON',\n CREDITS = 'CREDITS',\n}\n\nexport enum PaymentProviderPreference {\n AUTO = 'AUTO',\n STRIPE = 'STRIPE',\n RAZORPAY = 'RAZORPAY',\n}\n\nexport enum AnalyticsPeriod {\n LAST_7_DAYS = 'LAST_7_DAYS',\n LAST_30_DAYS = 'LAST_30_DAYS',\n LAST_90_DAYS = 'LAST_90_DAYS',\n LAST_MONTH = 'LAST_MONTH',\n CURRENT_MONTH = 'CURRENT_MONTH',\n}\n\nexport enum UsageMetricType {\n USERS = 'USERS',\n STORAGE = 'STORAGE',\n API_CALLS = 'API_CALLS',\n BANDWIDTH = 'BANDWIDTH',\n REQUESTS = 'REQUESTS',\n COMPUTE_HOURS = 'COMPUTE_HOURS',\n TRANSACTIONS = 'TRANSACTIONS',\n CUSTOM = 'CUSTOM',\n}\n\n// ============================================================================\n// Core Types\n// ============================================================================\n\nexport interface BillingAccount {\n id: string;\n orgId: string;\n name: string;\n email: string;\n billingEmail?: string;\n currency: string;\n creditAmount: number;\n stripeCustomerId?: string;\n razorpayCustomerId?: string;\n defaultPaymentMethod?: string;\n taxId?: string;\n isActive: boolean;\n isDefault?: boolean;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n subscriptions?: BillingSubscription[];\n paymentMethods?: PaymentMethod[];\n creditTransactions?: CreditTransaction[];\n quotaAssignments?: QuotaAssignment[];\n billingAddresses?: BillingAddress[];\n transactions?: Transaction[];\n}\n\nexport interface BillingAddress {\n id: string;\n billingAccountId: string;\n orgId: string;\n line1: string;\n line2?: string;\n city: string;\n state?: string;\n postalCode: string;\n country: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Plan Types\n// ============================================================================\n\nexport interface Plan {\n id: string;\n productID: string;\n name: string;\n price: number;\n currency: string;\n currencyPrices?: Record<string, number>;\n geoPricingOverrides?: GeoPricingOverrideInput[];\n duration: PlanDuration;\n pricingModel?: PricingModel;\n pricePerSeat?: number;\n minSeats?: number;\n maxSeats?: number;\n isActive: boolean;\n isPurchasable: boolean;\n features?: SubscriptionFeatures[];\n itemEntitlements?: SubscriptionEntitlement[];\n subscriptions?: BillingSubscription[];\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n product?: Product;\n}\n\nexport interface SubscriptionFeatures {\n id: string;\n planId?: string;\n addonId?: string;\n quotaId?: string;\n plan?: Plan;\n addon?: Addon;\n quota?: Quota;\n context?: Record<string, unknown>;\n}\n\nexport interface SubscriptionEntitlement {\n id: string;\n planId: string;\n itemId: string;\n accessType: EntitlementAccessType;\n discountPercentage?: number;\n plan?: Plan;\n item?: { id: string };\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Subscription Types\n// ============================================================================\n\nexport interface BillingSubscription {\n id: string;\n billingAccountId: string;\n planId: string;\n status: SubscriptionStatus;\n startDate: string;\n endDate: string;\n autoRenewal: boolean;\n recurrence: boolean;\n seatCount?: number;\n lastSeatChangeAt?: string;\n lastBillingDate?: string;\n nextBillingDate?: string;\n lastRenewalDate?: string;\n canceledAt?: string;\n canceledBy?: string;\n cancellationReason?: string;\n stripeSubscriptionId?: string;\n razorpaySubscriptionId?: string;\n paymentGateway?: string;\n assignedWorkspaceId?: string | null;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n plan?: Plan;\n billingAccount?: BillingAccount;\n addonSubscriptions?: AddonSubscription[];\n quotas?: QuotaAssignment[];\n transactions?: Transaction[];\n history?: SubscriptionHistory[];\n}\n\nexport interface SubscriptionHistory {\n id: string;\n subscriptionId: string;\n fromStatus: SubscriptionStatus;\n toStatus: SubscriptionStatus;\n reason?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n}\n\n// ============================================================================\n// Addon Types\n// ============================================================================\n\nexport interface Addon {\n id: string;\n productID: string;\n name: string;\n price: number;\n currency: string;\n currencyPrices?: Record<string, number>;\n geoPricingOverrides?: GeoPricingOverrideInput[];\n duration: PlanDuration;\n isActive: boolean;\n features?: SubscriptionFeatures[];\n addonSubscriptions?: AddonSubscription[];\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n product?: Product;\n}\n\nexport interface AddonSubscription {\n id: string;\n addonId: string;\n currentSubscriptionId: string;\n quantity: number;\n startDate: string;\n endDate: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n addon?: Addon;\n currentSubscription?: BillingSubscription;\n}\n\n// ============================================================================\n// Invoice Types\n// ============================================================================\n\nexport interface Invoice {\n id: string;\n orgId: string;\n billingAccountId?: string;\n subscriptionId?: string;\n paymentId?: string;\n invoiceNumber: string;\n status: InvoiceStatus;\n subtotal: number;\n tax: number;\n total: number;\n amountPaid: number;\n currency: string;\n dueDate?: string;\n paidAt?: string;\n gatewayInvoiceId?: string;\n invoiceUrl?: string;\n pdfUrl?: string;\n itemDescription?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n items: InvoiceItem[];\n subscription?: BillingSubscription;\n payment?: Payment;\n}\n\nexport interface InvoiceItem {\n id: string;\n invoiceId: string;\n description: string;\n quantity: number;\n unitPrice: number;\n amount: number;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\nexport interface Payment {\n id: string;\n orgId: string;\n transactionId?: string;\n amount: number;\n currency: string;\n status: PaymentStatus;\n method: PaymentMethodType;\n provider?: string;\n gatewayPaymentId?: string;\n gatewayOrderId?: string;\n failureReason?: string;\n paidAt?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n invoice?: Invoice;\n}\n\nexport interface PaymentMethod {\n id: string;\n orgId: string;\n billingAccountId?: string;\n type: PaymentMethodType;\n brand?: string;\n last4?: string;\n expiryMonth?: number;\n expiryYear?: number;\n isDefault: boolean;\n isVerified: boolean;\n verifiedAt?: string;\n stripeCustomerId?: string;\n stripePaymentMethodId?: string;\n razorpayCustomerId?: string;\n razorpayPaymentMethodId?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n billingAccount?: BillingAccount;\n transactions?: Transaction[];\n}\n\nexport interface Charge {\n id: string;\n orgId: string;\n amount: number;\n currency: string;\n status: ChargeStatus;\n description?: string;\n provider?: string;\n gatewayChargeId?: string;\n gatewayPaymentId?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n refunds: Refund[];\n}\n\nexport interface Refund {\n id: string;\n chargeId: string;\n amount: number;\n currency: string;\n status: RefundStatus;\n reason?: string;\n provider?: string;\n gatewayRefundId?: string;\n processedAt?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n charge?: Charge;\n}\n\n// ============================================================================\n// Transaction Types\n// ============================================================================\n\nexport interface Transaction {\n id: string;\n billingAccountId: string;\n amount: number;\n currency: string;\n type: TransactionType;\n status: TransactionStatus;\n description?: string;\n stripePaymentId?: string;\n razorpayPaymentId?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Credit Types\n// ============================================================================\n\nexport interface CreditTransaction {\n id: string;\n billingAccountId: string;\n productId: string;\n amount: number;\n type: CreditTransactionType;\n status: CreditTransactionStatus;\n fromType?: CreditTransactionType | null;\n payoutRequestId?: string | null;\n entityType?: string;\n entityId?: string;\n transactionId?: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n billingAccount?: BillingAccount;\n transaction?: Transaction;\n}\n\nexport interface CreditBalanceByType {\n purchased: number;\n earned: number;\n granted: number;\n withdrawable: number;\n total: number;\n}\n\nexport interface CreditNote {\n id: string;\n orgId: string;\n invoiceId?: string;\n number: string;\n amount: number;\n currency: string;\n reason?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreditRate {\n id: string;\n rateUSD: number;\n effectiveFrom: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Quota Types\n// ============================================================================\n\nexport interface Quota {\n id: string;\n name: string;\n limits: Record<string, unknown>;\n quotaType: QuotaType;\n reusable: boolean;\n resetPeriod: QuotaResetPeriod;\n isActive: boolean;\n scope?: QuotaScope;\n subscriptions?: SubscriptionFeatures[];\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface QuotaAssignment {\n id: string;\n billingAccountId?: string;\n subscriptionId?: string;\n name: string;\n limits: Record<string, unknown>;\n quotaType: QuotaType;\n reusable: boolean;\n currentUsageSum: number;\n totalUsageCount: number;\n endtime: string;\n context?: Record<string, unknown>;\n createdAt: string;\n // Relations\n billingAccount?: BillingAccount;\n subscription?: BillingSubscription;\n usages?: Usage[];\n recentUsages?: Usage[];\n usageAnalytics?: QuotaUsageAnalytics;\n}\n\nexport interface QuotaAssignmentWithAnalytics extends QuotaAssignment {\n status: QuotaStatus;\n healthScore: number;\n usagePercentage: number;\n limitLeft: number;\n analytics: QuotaUsageAnalytics;\n}\n\nexport interface QuotaAssignmentUsageSummary {\n id: string;\n name: string;\n quotaType: QuotaType;\n reusable: boolean;\n limit: number;\n limitLeft: number;\n used: number;\n usagePercentage: number;\n noLimit: boolean;\n subscriptionId?: string;\n recentUsages: Usage[];\n createdAt: string;\n endtime: string;\n}\n\n// ============================================================================\n// Usage Types\n// ============================================================================\n\nexport interface Usage {\n id: string;\n quotaAssignmentId: string;\n userId?: string;\n productId?: string;\n amount: number;\n description?: string;\n tags?: Record<string, unknown>;\n timestamp: string;\n lastUpdated: string;\n context?: Record<string, unknown>;\n // Relations\n quotaAssignment?: QuotaAssignment;\n user?: { id: string };\n}\n\nexport interface UsageRecord {\n id: string;\n orgId: string;\n subscriptionId?: string;\n metricType: UsageMetricType;\n quantity: number;\n unitCost?: number;\n totalCost?: number;\n timestamp: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n}\n\nexport interface DailyUsage {\n date: string;\n usage: number;\n count: number;\n}\n\nexport interface PeakUsage {\n peakDate: string;\n maxDailyUsage: number;\n peakHour?: number;\n}\n\nexport interface UsageTrends {\n averageDailyUsage?: number;\n growthRate?: number;\n predictedUsage?: number;\n}\n\nexport interface UsageByType {\n resourceType: string;\n usage: number;\n count: number;\n percentage: number;\n}\n\nexport interface QuotaUsageAnalytics {\n dailyUsage: DailyUsage[];\n usageByType: UsageByType[];\n peakUsage?: PeakUsage;\n trends?: UsageTrends;\n}\n\nexport interface QuotaUsageSummary {\n quotaId: string;\n quotaName: string;\n usage: number;\n limit: number;\n percentage: number;\n status: QuotaStatus;\n}\n\nexport interface UsageActivity {\n id: string;\n quotaName: string;\n amount: number;\n description: string;\n tags?: Record<string, unknown>;\n timestamp: string;\n}\n\nexport interface UsageDashboard {\n totalUsage: number;\n totalQuotas: number;\n activeQuotas: number;\n healthyQuotas: number;\n warningQuotas: number;\n criticalQuotas: number;\n exhaustedQuotas: number;\n topUsageByQuota: QuotaUsageSummary[];\n recentActivities: UsageActivity[];\n overallTrends: UsageTrends;\n}\n\nexport interface BillingAccountQuotasSummary {\n billingAccountId: string;\n totalUsage: number;\n totalLimit: number;\n pooledQuotas: QuotaAssignmentUsageSummary[];\n subscriptionQuotas: QuotaAssignmentUsageSummary[];\n}\n\n// ============================================================================\n// Other Types\n// ============================================================================\n\nexport interface Product {\n id: string;\n name: string;\n url?: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Discount {\n id: string;\n code: string;\n type: string;\n value: number;\n currency?: string;\n maxUses?: number;\n usedCount: number;\n validFrom: string;\n validUntil?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n transactions?: Transaction[];\n}\n\nexport interface TaxRate {\n id: string;\n country: string;\n state?: string;\n rate: number;\n description?: string;\n active: boolean;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BillingNotification {\n id: string;\n orgId: string;\n type: string;\n message: string;\n sentAt?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n}\n\n// ============================================================================\n// Payment Initiation Types\n// ============================================================================\n\nexport interface InitiatePaymentInput {\n billingAccountId: string;\n purchaseType: PurchaseType;\n amount: number;\n currency: string;\n planId?: string;\n addonId?: string;\n quantity?: number;\n // Multiple addons support (cart checkout)\n addonIds?: string[];\n quantities?: number[];\n creditAmount?: number;\n productId?: string;\n provider?: PaymentProviderPreference;\n // Saved card support\n paymentMethodId?: string;\n saveCard?: boolean;\n // Plan change/upgrade support\n upgradeFromSubscriptionId?: string;\n // Plan downgrade — old sub auto-renewal cancelled, runs to natural expiry\n downgradeFromSubscriptionId?: string;\n metadata?: Record<string, unknown>;\n // Auto-renewal (for plan purchases)\n autoRenew?: boolean;\n autoRenewPaymentMethodId?: string;\n}\n\nexport interface InitiatePaymentResponse {\n success: boolean;\n provider: string;\n paymentId?: string;\n clientSecret?: string;\n orderId?: string;\n razorpayKeyId?: string;\n razorpayCustomerId?: string;\n prefillName?: string;\n prefillEmail?: string;\n prefillContact?: string;\n subtotal: number;\n taxAmount: number;\n taxRate: number;\n taxType: string;\n taxBreakdown?: Record<string, unknown>;\n jurisdiction: string;\n total: number;\n currency: string;\n error?: string;\n}\n\nexport interface VerifyPaymentMethodInput {\n billingAccountId: string;\n currency: string;\n provider?: PaymentProviderPreference;\n setAsDefault?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface VerifyPaymentMethodResponse {\n success: boolean;\n provider: string;\n orderId?: string;\n razorpayKeyId?: string;\n razorpayCustomerId?: string;\n clientSecret?: string;\n amount: number;\n currency: string;\n prefillName?: string;\n prefillEmail?: string;\n prefillContact?: string;\n error?: string;\n}\n\n// ============================================================================\n// Pagination Types\n// ============================================================================\n\nexport interface PaginationInput {\n page?: number;\n limit?: number;\n offset?: number;\n cursor?: string;\n}\n\nexport interface PaginatedResponse<T> {\n items: T[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n hasMore: boolean;\n}\n\nexport interface PaginatedCreditTransactions {\n creditTransactions: CreditTransaction[];\n page: number;\n pageSize: number;\n totalCount: number;\n hasMore: boolean;\n}\n\nexport interface PaginatedQuotaAssignments {\n quotaAssignments: QuotaAssignment[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n}\n\nexport interface PaginatedQuotaAssignmentsWithAnalytics {\n quotaAssignments: QuotaAssignmentWithAnalytics[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n}\n\nexport interface PaginatedUsages {\n usages: Usage[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n}\n\n// ============================================================================\n// Input Types\n// ============================================================================\n\nexport interface CreateBillingAccountInput {\n name: string;\n email: string;\n billingEmail?: string;\n currency?: string;\n taxId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateBillingAccountInput {\n id: string;\n name?: string;\n email?: string;\n billingEmail?: string;\n currency?: string;\n taxId?: string;\n isActive?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CreatePaymentMethodInput {\n billingAccountId: string;\n type: PaymentMethodType;\n brand?: string;\n last4?: string;\n expiryMonth?: number;\n expiryYear?: number;\n isDefault?: boolean;\n stripePaymentMethodId?: string;\n razorpayPaymentMethodId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SetBillingAddressInput {\n billingAccountId: string;\n line1: string;\n line2?: string;\n city: string;\n state?: string;\n postalCode: string;\n country: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CreatePlanInput {\n productId: string;\n name: string;\n price: number;\n currency?: string;\n duration: PlanDuration;\n isPurchasable?: boolean;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface UpdatePlanInput {\n id: string;\n name?: string;\n price?: number;\n currency?: string;\n duration?: PlanDuration;\n isActive?: boolean;\n isPurchasable?: boolean;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface GeoPricingOverrideInput {\n country?: string;\n state?: string;\n region?: string;\n currency: string;\n amount?: number;\n perSeatAmount?: number;\n}\n\nexport interface CurrencyPriceOverrideInput {\n currency: string;\n amount: number;\n perSeatAmount?: number;\n}\n\nexport interface CreateAddonInput {\n productId: string;\n name: string;\n price: number;\n currency: string;\n duration: PlanDuration;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface UpdateAddonInput {\n id: string;\n name?: string;\n price?: number;\n currency?: string;\n duration?: PlanDuration;\n isActive?: boolean;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface CreateQuotaInput {\n name: string;\n limits: Record<string, unknown>;\n quotaType?: QuotaType;\n reusable: boolean;\n resetPeriod?: QuotaResetPeriod;\n context?: Record<string, unknown>;\n}\n\nexport interface UpdateQuotaInput {\n id: string;\n name?: string;\n limits?: Record<string, unknown>;\n reusable?: boolean;\n isActive: boolean;\n resetPeriod?: QuotaResetPeriod;\n context?: Record<string, unknown>;\n}\n\nexport interface SpendCreditsInput {\n billingAccountId: string;\n planId?: string;\n storeItemId?: string;\n isAnnual?: boolean;\n addOnIds?: { id: string; quantity?: number }[];\n upgradeFromSubscriptionId?: string;\n subscriptionId?: string;\n /** Seat count for PER_SEAT plans. Credits charged = pricePerSeat × seatCount. */\n seatCount?: number;\n}\n\nexport interface CancelSubscriptionInput {\n billingAccountId: string;\n subscriptionId: string;\n reason?: string;\n canceledBy?: string;\n}\n\nexport interface UpdateSubscriptionSeatsInput {\n subscriptionId: string;\n seatCount: number;\n}\n\nexport interface CreateEntitlementInput {\n planId: string;\n itemId: string;\n accessType: EntitlementAccessType;\n discountPercentage?: number;\n}\n\nexport interface UpdateEntitlementInput {\n id: string;\n accessType?: EntitlementAccessType;\n discountPercentage?: number;\n}\n\n// ============================================================================\n// Filter & Sort Types\n// ============================================================================\n\nexport interface DateRangeInput {\n from?: string;\n to?: string;\n}\n\nexport interface AmountRangeInput {\n min?: number;\n max?: number;\n}\n\nexport interface ContextFilterInput {\n orgId?: string;\n userId?: string;\n workspaceId?: string;\n organizationId?: string;\n projectId?: string;\n}\n\nexport interface ContextInput {\n orgId?: string;\n userId?: string;\n workspaceId?: string;\n organizationId?: string;\n projectId?: string;\n custom?: Record<string, unknown>;\n}\n"],"mappings":";AASA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,SAAA,UACA,EAAA,WAAA,YACA,EAAA,UAAA,WACA,EAAA,WAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,QAAA,SACA,EAAA,OAAA,QACA,EAAA,OAAA,QACA,EAAA,OAAA,QACA,EAAA,gBAAA;KACD,EAkCW,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,SAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,YAAA,aACA,EAAA,WAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,SAAA,UACA,EAAA,mBAAA;KACD,EAOW,IAAL,yBAAA,GAAA;QACL,EAAA,QAAA,SACA,EAAA,QAAA,SACA,EAAA,UAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,UAAA,WACA,EAAA,WAAA,YACA,EAAA,YAAA,aACA,EAAA,WAAA;KACD,EAQW,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,UAAA,WACA,EAAA,SAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,WAAA,YACA,EAAA,QAAA,SACA,EAAA,aAAA,cACA,EAAA,UAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,UAAA,WACA,EAAA,SAAA,UACA,EAAA,SAAA;KACD,EAaW,IAAL,yBAAA,GAAA;QACL,EAAA,OAAA,QACA,EAAA,SAAA,UACA,EAAA,WAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,cAAA,eACA,EAAA,eAAA,gBACA,EAAA,eAAA,gBACA,EAAA,aAAA,cACA,EAAA,gBAAA;KACD"}
|
|
1
|
+
{"version":3,"file":"graphql.js","names":[],"sources":["../../../../src/billing/shared/types/graphql.ts"],"sourcesContent":["/**\n * GraphQL Types for Billing Module\n * Auto-generated types matching the backend billing service schema\n */\n\n// ============================================================================\n// Enums\n// ============================================================================\n\nexport enum SubscriptionStatus {\n ACTIVE = 'active',\n CANCELED = 'canceled',\n EXPIRED = 'expired',\n UPGRADED = 'upgraded',\n}\n\nexport enum InvoiceStatus {\n DRAFT = 'DRAFT',\n OPEN = 'OPEN',\n PAID = 'PAID',\n VOID = 'VOID',\n UNCOLLECTIBLE = 'UNCOLLECTIBLE',\n}\n\nexport enum PaymentStatus {\n PENDING = 'PENDING',\n SUCCEEDED = 'SUCCEEDED',\n FAILED = 'FAILED',\n CANCELED = 'CANCELED',\n REFUNDED = 'REFUNDED',\n}\n\nexport enum ChargeStatus {\n PENDING = 'PENDING',\n SUCCEEDED = 'SUCCEEDED',\n FAILED = 'FAILED',\n REFUNDED = 'REFUNDED',\n}\n\nexport enum RefundStatus {\n PENDING = 'PENDING',\n SUCCEEDED = 'SUCCEEDED',\n FAILED = 'FAILED',\n CANCELED = 'CANCELED',\n}\n\nexport enum PaymentMethodType {\n CREDIT_CARD = 'CREDIT_CARD',\n DEBIT_CARD = 'DEBIT_CARD',\n BANK_TRANSFER = 'BANK_TRANSFER',\n PAYPAL = 'PAYPAL',\n CRYPTO = 'CRYPTO',\n WALLET = 'WALLET',\n NETBANKING = 'NETBANKING',\n}\n\nexport enum PlanDuration {\n MONTHLY = 'monthly',\n YEARLY = 'yearly',\n}\n\nexport enum PricingModel {\n FLAT_RATE = 'FLAT_RATE',\n PER_SEAT = 'PER_SEAT',\n}\n\nexport enum QuotaType {\n POOLED = 'POOLED',\n PRODUCT_SPECIFIC = 'PRODUCT_SPECIFIC',\n}\n\nexport enum QuotaScope {\n WORKSPACE = 'WORKSPACE',\n GLOBAL = 'GLOBAL',\n}\n\nexport enum QuotaResetPeriod {\n NEVER = 'NEVER',\n DAILY = 'DAILY',\n MONTHLY = 'MONTHLY',\n}\n\nexport enum QuotaStatus {\n HEALTHY = 'HEALTHY',\n WARNING = 'WARNING',\n CRITICAL = 'CRITICAL',\n EXHAUSTED = 'EXHAUSTED',\n INACTIVE = 'INACTIVE',\n}\n\nexport enum TransactionType {\n PAYMENT = 'payment',\n REFUND = 'refund',\n ADJUSTMENT = 'adjustment',\n}\n\nexport enum TransactionStatus {\n PENDING = 'pending',\n SUCCESS = 'success',\n FAILED = 'failed',\n}\n\nexport enum CreditTransactionType {\n PURCHASE = 'purchase',\n USAGE = 'usage',\n ADJUSTMENT = 'adjustment',\n GRANTED = 'granted',\n}\n\nexport enum CreditTransactionStatus {\n PENDING = 'pending',\n SUCCESS = 'success',\n FAILED = 'failed',\n REFUND = 'refund',\n}\n\nexport enum EntitlementAccessType {\n FREE_ACCESS = 'FREE_ACCESS',\n DISCOUNT = 'DISCOUNT',\n}\n\nexport enum PurchaseType {\n PLAN = 'PLAN',\n ADDON = 'ADDON',\n CREDITS = 'CREDITS',\n}\n\nexport enum PaymentProviderPreference {\n AUTO = 'AUTO',\n STRIPE = 'STRIPE',\n RAZORPAY = 'RAZORPAY',\n}\n\nexport enum AnalyticsPeriod {\n LAST_7_DAYS = 'LAST_7_DAYS',\n LAST_30_DAYS = 'LAST_30_DAYS',\n LAST_90_DAYS = 'LAST_90_DAYS',\n LAST_MONTH = 'LAST_MONTH',\n CURRENT_MONTH = 'CURRENT_MONTH',\n}\n\nexport enum UsageMetricType {\n USERS = 'USERS',\n STORAGE = 'STORAGE',\n API_CALLS = 'API_CALLS',\n BANDWIDTH = 'BANDWIDTH',\n REQUESTS = 'REQUESTS',\n COMPUTE_HOURS = 'COMPUTE_HOURS',\n TRANSACTIONS = 'TRANSACTIONS',\n CUSTOM = 'CUSTOM',\n}\n\n// ============================================================================\n// Core Types\n// ============================================================================\n\nexport interface BillingAccount {\n id: string;\n orgId: string;\n name: string;\n email: string;\n billingEmail?: string;\n currency: string;\n creditAmount: number;\n stripeCustomerId?: string;\n razorpayCustomerId?: string;\n defaultPaymentMethod?: string;\n taxId?: string;\n isActive: boolean;\n isDefault?: boolean;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n subscriptions?: BillingSubscription[];\n paymentMethods?: PaymentMethod[];\n creditTransactions?: CreditTransaction[];\n quotaAssignments?: QuotaAssignment[];\n billingAddresses?: BillingAddress[];\n transactions?: Transaction[];\n}\n\nexport interface BillingAddress {\n id: string;\n billingAccountId: string;\n orgId: string;\n line1: string;\n line2?: string;\n city: string;\n state?: string;\n postalCode: string;\n country: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Plan Types\n// ============================================================================\n\nexport interface Plan {\n id: string;\n productID: string;\n name: string;\n price: number;\n currency: string;\n currencyPrices?: Record<string, number>;\n geoPricingOverrides?: GeoPricingOverrideInput[];\n duration: PlanDuration;\n pricingModel?: PricingModel;\n pricePerSeat?: number;\n minSeats?: number;\n maxSeats?: number;\n isActive: boolean;\n isPurchasable: boolean;\n features?: SubscriptionFeatures[];\n itemEntitlements?: SubscriptionEntitlement[];\n subscriptions?: BillingSubscription[];\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n product?: Product;\n}\n\nexport interface SubscriptionFeatures {\n id: string;\n planId?: string;\n addonId?: string;\n quotaId?: string;\n plan?: Plan;\n addon?: Addon;\n quota?: Quota;\n context?: Record<string, unknown>;\n}\n\nexport interface SubscriptionEntitlement {\n id: string;\n planId: string;\n itemId: string;\n accessType: EntitlementAccessType;\n discountPercentage?: number;\n plan?: Plan;\n item?: { id: string };\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Subscription Types\n// ============================================================================\n\nexport interface BillingSubscription {\n id: string;\n billingAccountId: string;\n planId: string;\n status: SubscriptionStatus;\n startDate: string;\n endDate: string;\n autoRenewal: boolean;\n recurrence: boolean;\n seatCount?: number;\n lastSeatChangeAt?: string;\n lastBillingDate?: string;\n nextBillingDate?: string;\n lastRenewalDate?: string;\n canceledAt?: string;\n canceledBy?: string;\n cancellationReason?: string;\n stripeSubscriptionId?: string;\n razorpaySubscriptionId?: string;\n paymentGateway?: string;\n assignedWorkspaceId?: string | null;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n plan?: Plan;\n billingAccount?: BillingAccount;\n addonSubscriptions?: AddonSubscription[];\n quotas?: QuotaAssignment[];\n transactions?: Transaction[];\n history?: SubscriptionHistory[];\n}\n\nexport interface SubscriptionHistory {\n id: string;\n subscriptionId: string;\n fromStatus: SubscriptionStatus;\n toStatus: SubscriptionStatus;\n reason?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n}\n\n// ============================================================================\n// Addon Types\n// ============================================================================\n\nexport interface Addon {\n id: string;\n productID: string;\n name: string;\n price: number;\n currency: string;\n currencyPrices?: Record<string, number>;\n geoPricingOverrides?: GeoPricingOverrideInput[];\n duration: PlanDuration;\n isActive: boolean;\n features?: SubscriptionFeatures[];\n addonSubscriptions?: AddonSubscription[];\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n product?: Product;\n}\n\nexport interface AddonSubscription {\n id: string;\n addonId: string;\n currentSubscriptionId: string;\n quantity: number;\n startDate: string;\n endDate: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n addon?: Addon;\n currentSubscription?: BillingSubscription;\n}\n\n// ============================================================================\n// Invoice Types\n// ============================================================================\n\nexport interface Invoice {\n id: string;\n orgId: string;\n billingAccountId?: string;\n subscriptionId?: string;\n paymentId?: string;\n invoiceNumber: string;\n status: InvoiceStatus;\n subtotal: number;\n tax: number;\n total: number;\n amountPaid: number;\n currency: string;\n dueDate?: string;\n paidAt?: string;\n gatewayInvoiceId?: string;\n invoiceUrl?: string;\n pdfUrl?: string;\n itemDescription?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n items: InvoiceItem[];\n subscription?: BillingSubscription;\n payment?: Payment;\n}\n\nexport interface InvoiceItem {\n id: string;\n invoiceId: string;\n description: string;\n quantity: number;\n unitPrice: number;\n amount: number;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\nexport interface Payment {\n id: string;\n orgId: string;\n transactionId?: string;\n amount: number;\n currency: string;\n status: PaymentStatus;\n method: PaymentMethodType;\n provider?: string;\n gatewayPaymentId?: string;\n gatewayOrderId?: string;\n failureReason?: string;\n paidAt?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n invoice?: Invoice;\n}\n\nexport interface PaymentMethod {\n id: string;\n orgId: string;\n billingAccountId?: string;\n type: PaymentMethodType;\n brand?: string;\n last4?: string;\n expiryMonth?: number;\n expiryYear?: number;\n isDefault: boolean;\n isVerified: boolean;\n verifiedAt?: string;\n stripeCustomerId?: string;\n stripePaymentMethodId?: string;\n razorpayCustomerId?: string;\n razorpayPaymentMethodId?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n billingAccount?: BillingAccount;\n transactions?: Transaction[];\n}\n\nexport interface Charge {\n id: string;\n orgId: string;\n amount: number;\n currency: string;\n status: ChargeStatus;\n description?: string;\n provider?: string;\n gatewayChargeId?: string;\n gatewayPaymentId?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n refunds: Refund[];\n}\n\nexport interface Refund {\n id: string;\n chargeId: string;\n amount: number;\n currency: string;\n status: RefundStatus;\n reason?: string;\n provider?: string;\n gatewayRefundId?: string;\n processedAt?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n charge?: Charge;\n}\n\n// ============================================================================\n// Transaction Types\n// ============================================================================\n\nexport interface Transaction {\n id: string;\n billingAccountId: string;\n amount: number;\n currency: string;\n type: TransactionType;\n status: TransactionStatus;\n description?: string;\n stripePaymentId?: string;\n razorpayPaymentId?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Credit Types\n// ============================================================================\n\nexport interface CreditTransaction {\n id: string;\n billingAccountId: string;\n productId: string;\n amount: number;\n type: CreditTransactionType;\n status: CreditTransactionStatus;\n fromType?: CreditTransactionType | null;\n payoutRequestId?: string | null;\n entityType?: string;\n entityId?: string;\n transactionId?: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n // Relations\n billingAccount?: BillingAccount;\n transaction?: Transaction;\n}\n\nexport interface CreditBalanceByType {\n purchased: number;\n earned: number;\n granted: number;\n withdrawable: number;\n total: number;\n}\n\nexport interface CreditNote {\n id: string;\n orgId: string;\n invoiceId?: string;\n number: string;\n amount: number;\n currency: string;\n reason?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreditRate {\n id: string;\n rateUSD: number;\n effectiveFrom: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Quota Types\n// ============================================================================\n\nexport interface Quota {\n id: string;\n name: string;\n limits: Record<string, unknown>;\n quotaType: QuotaType;\n reusable: boolean;\n resetPeriod: QuotaResetPeriod;\n isActive: boolean;\n scope?: QuotaScope;\n subscriptions?: SubscriptionFeatures[];\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface QuotaAssignment {\n id: string;\n billingAccountId?: string;\n subscriptionId?: string;\n name: string;\n limits: Record<string, unknown>;\n quotaType: QuotaType;\n reusable: boolean;\n currentUsageSum: number;\n totalUsageCount: number;\n endtime: string;\n context?: Record<string, unknown>;\n createdAt: string;\n // Relations\n billingAccount?: BillingAccount;\n subscription?: BillingSubscription;\n usages?: Usage[];\n recentUsages?: Usage[];\n usageAnalytics?: QuotaUsageAnalytics;\n}\n\nexport interface QuotaAssignmentWithAnalytics extends QuotaAssignment {\n status: QuotaStatus;\n healthScore: number;\n usagePercentage: number;\n limitLeft: number;\n analytics: QuotaUsageAnalytics;\n}\n\nexport interface QuotaAssignmentUsageSummary {\n id: string;\n name: string;\n quotaType: QuotaType;\n reusable: boolean;\n limit: number;\n limitLeft: number;\n used: number;\n usagePercentage: number;\n noLimit: boolean;\n subscriptionId?: string;\n recentUsages: Usage[];\n createdAt: string;\n endtime: string;\n}\n\n// ============================================================================\n// Usage Types\n// ============================================================================\n\nexport interface Usage {\n id: string;\n quotaAssignmentId: string;\n userId?: string;\n productId?: string;\n amount: number;\n description?: string;\n tags?: Record<string, unknown>;\n timestamp: string;\n lastUpdated: string;\n context?: Record<string, unknown>;\n // Relations\n quotaAssignment?: QuotaAssignment;\n user?: { id: string };\n}\n\nexport interface UsageRecord {\n id: string;\n orgId: string;\n subscriptionId?: string;\n metricType: UsageMetricType;\n quantity: number;\n unitCost?: number;\n totalCost?: number;\n timestamp: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n}\n\nexport interface DailyUsage {\n date: string;\n usage: number;\n count: number;\n}\n\nexport interface PeakUsage {\n peakDate: string;\n maxDailyUsage: number;\n peakHour?: number;\n}\n\nexport interface UsageTrends {\n averageDailyUsage?: number;\n growthRate?: number;\n predictedUsage?: number;\n}\n\nexport interface UsageByType {\n resourceType: string;\n usage: number;\n count: number;\n percentage: number;\n}\n\nexport interface QuotaUsageAnalytics {\n dailyUsage: DailyUsage[];\n usageByType: UsageByType[];\n peakUsage?: PeakUsage;\n trends?: UsageTrends;\n}\n\nexport interface QuotaUsageSummary {\n quotaId: string;\n quotaName: string;\n usage: number;\n limit: number;\n percentage: number;\n status: QuotaStatus;\n}\n\nexport interface UsageActivity {\n id: string;\n quotaName: string;\n amount: number;\n description: string;\n tags?: Record<string, unknown>;\n timestamp: string;\n}\n\nexport interface UsageDashboard {\n totalUsage: number;\n totalQuotas: number;\n activeQuotas: number;\n healthyQuotas: number;\n warningQuotas: number;\n criticalQuotas: number;\n exhaustedQuotas: number;\n topUsageByQuota: QuotaUsageSummary[];\n recentActivities: UsageActivity[];\n overallTrends: UsageTrends;\n}\n\nexport interface BillingAccountQuotasSummary {\n billingAccountId: string;\n totalUsage: number;\n totalLimit: number;\n pooledQuotas: QuotaAssignmentUsageSummary[];\n subscriptionQuotas: QuotaAssignmentUsageSummary[];\n}\n\n// ============================================================================\n// Other Types\n// ============================================================================\n\nexport interface Product {\n id: string;\n name: string;\n url?: string;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Discount {\n id: string;\n code: string;\n type: string;\n value: number;\n currency?: string;\n maxUses?: number;\n usedCount: number;\n validFrom: string;\n validUntil?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n transactions?: Transaction[];\n}\n\nexport interface TaxRate {\n id: string;\n country: string;\n state?: string;\n rate: number;\n description?: string;\n active: boolean;\n context?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BillingNotification {\n id: string;\n orgId: string;\n type: string;\n message: string;\n sentAt?: string;\n metadata?: Record<string, unknown>;\n context?: Record<string, unknown>;\n createdAt: string;\n}\n\n// ============================================================================\n// Payment Initiation Types\n// ============================================================================\n\nexport interface InitiatePaymentInput {\n billingAccountId: string;\n purchaseType: PurchaseType;\n amount: number;\n currency: string;\n planId?: string;\n addonId?: string;\n quantity?: number;\n // Multiple addons support (cart checkout)\n addonIds?: string[];\n quantities?: number[];\n creditAmount?: number;\n productId?: string;\n provider?: PaymentProviderPreference;\n // Saved card support\n paymentMethodId?: string;\n saveCard?: boolean;\n // Plan change/upgrade support\n upgradeFromSubscriptionId?: string;\n // Plan downgrade — old sub auto-renewal cancelled, runs to natural expiry\n downgradeFromSubscriptionId?: string;\n metadata?: Record<string, unknown>;\n // Auto-renewal (for plan purchases)\n autoRenew?: boolean;\n autoRenewPaymentMethodId?: string;\n}\n\nexport interface InitiatePaymentResponse {\n success: boolean;\n provider: string;\n paymentId?: string;\n clientSecret?: string;\n orderId?: string;\n razorpayKeyId?: string;\n razorpayCustomerId?: string;\n prefillName?: string;\n prefillEmail?: string;\n prefillContact?: string;\n subtotal: number;\n taxAmount: number;\n taxRate: number;\n taxType: string;\n taxBreakdown?: Record<string, unknown>;\n jurisdiction: string;\n total: number;\n currency: string;\n error?: string;\n}\n\nexport interface VerifyPaymentMethodInput {\n billingAccountId: string;\n currency: string;\n provider?: PaymentProviderPreference;\n setAsDefault?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface VerifyPaymentMethodResponse {\n success: boolean;\n provider: string;\n orderId?: string;\n razorpayKeyId?: string;\n razorpayCustomerId?: string;\n clientSecret?: string;\n amount: number;\n currency: string;\n prefillName?: string;\n prefillEmail?: string;\n prefillContact?: string;\n error?: string;\n}\n\n// ============================================================================\n// Pagination Types\n// ============================================================================\n\nexport interface PaginationInput {\n page?: number;\n limit?: number;\n offset?: number;\n cursor?: string;\n}\n\nexport interface PaginatedResponse<T> {\n items: T[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n hasMore: boolean;\n}\n\nexport interface PaginatedCreditTransactions {\n creditTransactions: CreditTransaction[];\n page: number;\n pageSize: number;\n totalCount: number;\n hasMore: boolean;\n}\n\nexport interface PaginatedQuotaAssignments {\n quotaAssignments: QuotaAssignment[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n}\n\nexport interface PaginatedQuotaAssignmentsWithAnalytics {\n quotaAssignments: QuotaAssignmentWithAnalytics[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n}\n\nexport interface PaginatedUsages {\n usages: Usage[];\n page: number;\n pageSize: number;\n totalCount: number;\n totalPages: number;\n}\n\n// ============================================================================\n// Input Types\n// ============================================================================\n\nexport interface CreateBillingAccountInput {\n name: string;\n email: string;\n billingEmail?: string;\n currency?: string;\n taxId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateBillingAccountInput {\n id: string;\n name?: string;\n email?: string;\n billingEmail?: string;\n currency?: string;\n taxId?: string;\n isActive?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CreatePaymentMethodInput {\n billingAccountId: string;\n type: PaymentMethodType;\n brand?: string;\n last4?: string;\n expiryMonth?: number;\n expiryYear?: number;\n isDefault?: boolean;\n stripePaymentMethodId?: string;\n razorpayPaymentMethodId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SetBillingAddressInput {\n billingAccountId: string;\n line1: string;\n line2?: string;\n city: string;\n state?: string;\n postalCode: string;\n country: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CreatePlanInput {\n productId: string;\n name: string;\n price: number;\n currency?: string;\n duration: PlanDuration;\n isPurchasable?: boolean;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface UpdatePlanInput {\n id: string;\n name?: string;\n price?: number;\n currency?: string;\n duration?: PlanDuration;\n isActive?: boolean;\n isPurchasable?: boolean;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface GeoPricingOverrideInput {\n country?: string;\n state?: string;\n region?: string;\n currency: string;\n amount?: number;\n perSeatAmount?: number;\n}\n\nexport interface CurrencyPriceOverrideInput {\n currency: string;\n amount: number;\n perSeatAmount?: number;\n}\n\nexport interface CreateAddonInput {\n productId: string;\n name: string;\n price: number;\n currency: string;\n duration: PlanDuration;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface UpdateAddonInput {\n id: string;\n name?: string;\n price?: number;\n currency?: string;\n duration?: PlanDuration;\n isActive?: boolean;\n quotas: { quotaId: string; quantity: number }[];\n geoPricingOverrides?: GeoPricingOverrideInput[];\n currencyPriceOverrides?: CurrencyPriceOverrideInput[];\n}\n\nexport interface CreateQuotaInput {\n name: string;\n limits: Record<string, unknown>;\n quotaType?: QuotaType;\n reusable: boolean;\n resetPeriod?: QuotaResetPeriod;\n context?: Record<string, unknown>;\n}\n\nexport interface UpdateQuotaInput {\n id: string;\n name?: string;\n limits?: Record<string, unknown>;\n reusable?: boolean;\n isActive: boolean;\n resetPeriod?: QuotaResetPeriod;\n context?: Record<string, unknown>;\n}\n\nexport interface SpendCreditsInput {\n billingAccountId: string;\n planId?: string;\n storeItemId?: string;\n isAnnual?: boolean;\n addOnIds?: { id: string; quantity?: number }[];\n upgradeFromSubscriptionId?: string;\n subscriptionId?: string;\n /** Seat count for PER_SEAT plans. Credits charged = pricePerSeat × seatCount. */\n seatCount?: number;\n}\n\nexport interface CancelSubscriptionInput {\n billingAccountId: string;\n subscriptionId: string;\n reason?: string;\n canceledBy?: string;\n}\n\nexport interface UpdateSubscriptionSeatsInput {\n subscriptionId: string;\n seatCount: number;\n}\n\nexport interface CreateEntitlementInput {\n planId: string;\n itemId: string;\n accessType: EntitlementAccessType;\n discountPercentage?: number;\n}\n\nexport interface UpdateEntitlementInput {\n id: string;\n accessType?: EntitlementAccessType;\n discountPercentage?: number;\n}\n\n// ============================================================================\n// Filter & Sort Types\n// ============================================================================\n\nexport interface DateRangeInput {\n from?: string;\n to?: string;\n}\n\nexport interface AmountRangeInput {\n min?: number;\n max?: number;\n}\n\nexport interface ContextFilterInput {\n orgId?: string;\n userId?: string;\n workspaceId?: string;\n organizationId?: string;\n projectId?: string;\n}\n\nexport interface ContextInput {\n orgId?: string;\n userId?: string;\n workspaceId?: string;\n organizationId?: string;\n projectId?: string;\n custom?: Record<string, unknown>;\n}\n"],"mappings":";AASA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,SAAA,UACA,EAAA,WAAA,YACA,EAAA,UAAA,WACA,EAAA,WAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,QAAA,SACA,EAAA,OAAA,QACA,EAAA,OAAA,QACA,EAAA,OAAA,QACA,EAAA,gBAAA;AACF,EAAA,CAAA,CAAA,GAkCY,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,SAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,YAAA,aACA,EAAA,WAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,SAAA,UACA,EAAA,mBAAA;AACF,EAAA,CAAA,CAAA,GAOY,IAAL,yBAAA,GAAA;QACL,EAAA,QAAA,SACA,EAAA,QAAA,SACA,EAAA,UAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,UAAA,WACA,EAAA,WAAA,YACA,EAAA,YAAA,aACA,EAAA,WAAA;AACF,EAAA,CAAA,CAAA,GAQY,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,UAAA,WACA,EAAA,SAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,WAAA,YACA,EAAA,QAAA,SACA,EAAA,aAAA,cACA,EAAA,UAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,UAAA,WACA,EAAA,SAAA,UACA,EAAA,SAAA;AACF,EAAA,CAAA,CAAA,GAaY,IAAL,yBAAA,GAAA;QACL,EAAA,OAAA,QACA,EAAA,SAAA,UACA,EAAA,WAAA;AACF,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACL,EAAA,cAAA,eACA,EAAA,eAAA,gBACA,EAAA,eAAA,gBACA,EAAA,aAAA,cACA,EAAA,gBAAA;AACF,EAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.js","names":[],"sources":["../../../../src/billing/shared/ui/Card.tsx"],"sourcesContent":["/**\n * Boff UI — Card primitive\n *\n * The workhorse surface for the billing MFE. Renders the canonical Boff UI\n * card recipe: `rounded-card border border-border-subtle bg-bg-surface\n * shadow-elevation-1`. Set `interactive` for the hover-lift treatment and\n * `selected` for the accent-soft selected state.\n *\n * Visual-only primitive — no business logic.\n */\n\nimport type { ElementType, ReactNode } from 'react';\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\n\ninterface CardProps {\n children: ReactNode;\n className?: string;\n /** Apply hover lift + stronger border/elevation (use for clickable cards). */\n interactive?: boolean;\n /** Apply the accent-soft selected ring/wash. */\n selected?: boolean;\n /** Render as a different element (e.g. 'section', 'article'). Defaults to 'div'. */\n as?: ElementType;\n onClick?: () => void;\n /** Passthrough for data-tour and other data-* hooks. */\n [key: `data-${string}`]: string | undefined;\n}\n\nexport function Card({\n children,\n className,\n interactive = false,\n selected = false,\n as,\n onClick,\n ...rest\n}: CardProps) {\n const Component = as ?? 'div';\n return (\n <Component\n onClick={onClick}\n className={cn(\n 'rounded-card border border-border-seam bg-bg-surface shadow-elevation-1',\n interactive &&\n 'transition-[box-shadow,transform] duration-200 ease-[var(--motion-easing-out)] shadow-[var(--shadow-pop)] hover:shadow-elevation-2 [@media(hover:none)]:',\n selected && 'ring-1 ring-[var(--color-focus-ring)] border-border-strong',\n onClick && 'cursor-pointer text-left',\n className\n )}\n {...rest}\n >\n {children}\n </Component>\n );\n}\n"],"mappings":";;;AA4BA,SAAgB,EAAK,EACnB,aACA,cACA,iBAAc,IACd,cAAW,IACX,OACA,YACA,GAAG,KACS;
|
|
1
|
+
{"version":3,"file":"Card.js","names":[],"sources":["../../../../src/billing/shared/ui/Card.tsx"],"sourcesContent":["/**\n * Boff UI — Card primitive\n *\n * The workhorse surface for the billing MFE. Renders the canonical Boff UI\n * card recipe: `rounded-card border border-border-subtle bg-bg-surface\n * shadow-elevation-1`. Set `interactive` for the hover-lift treatment and\n * `selected` for the accent-soft selected state.\n *\n * Visual-only primitive — no business logic.\n */\n\nimport type { ElementType, ReactNode } from 'react';\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\n\ninterface CardProps {\n children: ReactNode;\n className?: string;\n /** Apply hover lift + stronger border/elevation (use for clickable cards). */\n interactive?: boolean;\n /** Apply the accent-soft selected ring/wash. */\n selected?: boolean;\n /** Render as a different element (e.g. 'section', 'article'). Defaults to 'div'. */\n as?: ElementType;\n onClick?: () => void;\n /** Passthrough for data-tour and other data-* hooks. */\n [key: `data-${string}`]: string | undefined;\n}\n\nexport function Card({\n children,\n className,\n interactive = false,\n selected = false,\n as,\n onClick,\n ...rest\n}: CardProps) {\n const Component = as ?? 'div';\n return (\n <Component\n onClick={onClick}\n className={cn(\n 'rounded-card border border-border-seam bg-bg-surface shadow-elevation-1',\n interactive &&\n 'transition-[box-shadow,transform] duration-200 ease-[var(--motion-easing-out)] shadow-[var(--shadow-pop)] hover:shadow-elevation-2 [@media(hover:none)]:',\n selected && 'ring-1 ring-[var(--color-focus-ring)] border-border-strong',\n onClick && 'cursor-pointer text-left',\n className\n )}\n {...rest}\n >\n {children}\n </Component>\n );\n}\n"],"mappings":";;;AA4BA,SAAgB,EAAK,EACnB,aACA,cACA,iBAAc,IACd,cAAW,IACX,OACA,YACA,GAAG,KACS;CAEZ,OACE,kBAFgB,KAAM,OAEtB;EACW;EACT,WAAW,EACT,2EACA,KACE,4JACF,KAAY,8DACZ,KAAW,4BACX,CACF;EACA,GAAI;EAEH;CACQ,CAAA;AAEf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetricCard.js","names":[],"sources":["../../../../src/billing/shared/ui/MetricCard.tsx"],"sourcesContent":["/**\n * Boff UI — MetricCard primitive\n *\n * Stat/metric card following the Boff UI recipe: small muted label, large\n * tabular-nums value, optional trend, and an optional icon in an accent-soft\n * tile. One question per card. Can render as a button when `onClick` is\n * provided (used by the usage dashboard's filterable stats).\n *\n * Visual-only primitive.\n */\n\nimport type { ReactNode } from 'react';\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\ninterface MetricCardTrend {\n value: number;\n isPositive: boolean;\n}\n\ninterface MetricCardProps {\n label: ReactNode;\n value: ReactNode;\n icon?: ReactNode;\n trend?: MetricCardTrend;\n /** When provided, renders an interactive button (with selected ring when active). */\n onClick?: () => void;\n isActive?: boolean;\n className?: string;\n /** Passthrough for data-tour and other data-* hooks. */\n [key: `data-${string}`]: string | undefined;\n}\n\nexport function MetricCard({\n label,\n value,\n icon,\n trend,\n onClick,\n isActive = false,\n className,\n ...rest\n}: MetricCardProps) {\n const base = cn(\n 'p-5 text-left',\n onClick &&\n 'w-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n isActive && 'ring-1 ring-[var(--color-focus-ring)] border-border-strong',\n className\n );\n\n const inner = (\n <>\n <div className=\"flex items-start justify-between gap-3\">\n <p className=\"text-sm text-text-secondary\">{label}</p>\n {icon && (\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {icon}\n </span>\n )}\n </div>\n <p className=\"mt-2 text-2xl font-semibold tabular-nums text-text-primary\">{value}</p>\n {trend && (\n <p\n className={cn(\n 'mt-1 text-xs font-medium tabular-nums',\n trend.isPositive ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {trend.isPositive ? '+' : ''}\n {trend.value}%\n </p>\n )}\n </>\n );\n\n if (onClick) {\n return (\n <GlassCard\n treatment=\"metric\"\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick();\n }\n }}\n className={cn(base, 'cursor-pointer')}\n {...rest}\n >\n {inner}\n </GlassCard>\n );\n }\n\n return (\n <GlassCard treatment=\"metric\" className={base} {...rest}>\n {inner}\n </GlassCard>\n );\n}\n"],"mappings":";;;;AAiCA,SAAgB,EAAW,EACzB,UACA,UACA,SACA,UACA,YACA,cAAW,IACX,cACA,GAAG,KACe;CAClB,IAAM,IAAO,EACX,iBACA,KACE,uGACF,KAAY,8DACZ,
|
|
1
|
+
{"version":3,"file":"MetricCard.js","names":[],"sources":["../../../../src/billing/shared/ui/MetricCard.tsx"],"sourcesContent":["/**\n * Boff UI — MetricCard primitive\n *\n * Stat/metric card following the Boff UI recipe: small muted label, large\n * tabular-nums value, optional trend, and an optional icon in an accent-soft\n * tile. One question per card. Can render as a button when `onClick` is\n * provided (used by the usage dashboard's filterable stats).\n *\n * Visual-only primitive.\n */\n\nimport type { ReactNode } from 'react';\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\ninterface MetricCardTrend {\n value: number;\n isPositive: boolean;\n}\n\ninterface MetricCardProps {\n label: ReactNode;\n value: ReactNode;\n icon?: ReactNode;\n trend?: MetricCardTrend;\n /** When provided, renders an interactive button (with selected ring when active). */\n onClick?: () => void;\n isActive?: boolean;\n className?: string;\n /** Passthrough for data-tour and other data-* hooks. */\n [key: `data-${string}`]: string | undefined;\n}\n\nexport function MetricCard({\n label,\n value,\n icon,\n trend,\n onClick,\n isActive = false,\n className,\n ...rest\n}: MetricCardProps) {\n const base = cn(\n 'p-5 text-left',\n onClick &&\n 'w-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n isActive && 'ring-1 ring-[var(--color-focus-ring)] border-border-strong',\n className\n );\n\n const inner = (\n <>\n <div className=\"flex items-start justify-between gap-3\">\n <p className=\"text-sm text-text-secondary\">{label}</p>\n {icon && (\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {icon}\n </span>\n )}\n </div>\n <p className=\"mt-2 text-2xl font-semibold tabular-nums text-text-primary\">{value}</p>\n {trend && (\n <p\n className={cn(\n 'mt-1 text-xs font-medium tabular-nums',\n trend.isPositive ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {trend.isPositive ? '+' : ''}\n {trend.value}%\n </p>\n )}\n </>\n );\n\n if (onClick) {\n return (\n <GlassCard\n treatment=\"metric\"\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick();\n }\n }}\n className={cn(base, 'cursor-pointer')}\n {...rest}\n >\n {inner}\n </GlassCard>\n );\n }\n\n return (\n <GlassCard treatment=\"metric\" className={base} {...rest}>\n {inner}\n </GlassCard>\n );\n}\n"],"mappings":";;;;AAiCA,SAAgB,EAAW,EACzB,UACA,UACA,SACA,UACA,YACA,cAAW,IACX,cACA,GAAG,KACe;CAClB,IAAM,IAAO,EACX,iBACA,KACE,uGACF,KAAY,8DACZ,CACF,GAEM,IACJ,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IAAG,WAAU;cAA+B;GAAS,CAAA,GACpD,KACC,kBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,CAEL;;EACL,kBAAC,KAAD;GAAG,WAAU;aAA8D;EAAS,CAAA;EACnF,KACC,kBAAC,KAAD;GACE,WAAW,EACT,yCACA,EAAM,aAAa,6BAA6B,wBAClD;aAJF;IAMG,EAAM,aAAa,MAAM;IACzB,EAAM;IAAM;GACZ;;CAEL,EAAA,CAAA;CAwBJ,OArBI,IAEA,kBAAC,GAAD;EACE,WAAU;EACV,MAAK;EACL,UAAU;EACD;EACT,YAAY,MAAM;GAChB,CAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,eAAe,GACjB,EAAQ;EAEZ;EACA,WAAW,EAAG,GAAM,gBAAgB;EACpC,GAAI;YAEH;CACQ,CAAA,IAKb,kBAAC,GAAD;EAAW,WAAU;EAAS,WAAW;EAAM,GAAI;YAChD;CACQ,CAAA;AAEf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressBar.js","names":[],"sources":["../../../../src/billing/shared/ui/ProgressBar.tsx"],"sourcesContent":["/**\n * Boff UI — ProgressBar primitive\n *\n * Quota / usage progress bar with status-driven fill colors. Track uses the\n * sunken surface; the fill maps the billing `SemanticStatus` palette to the\n * canonical status tokens. Clamps the value to 0-100.\n *\n * Visual-only primitive.\n */\n\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\nimport type { SemanticStatus } from '../utils/tokens';\n\nconst FILL_TONE: Record<SemanticStatus, string> = {\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n error: 'bg-status-error-bg',\n info: 'bg-status-info-bg',\n neutral: 'bg-text-muted',\n primary: 'bg-action-primary-bg',\n};\n\ninterface ProgressBarProps {\n /** Percentage 0-100. */\n value: number;\n /** Status tone for the fill color. Defaults to a neutral/primary fill. */\n status?: SemanticStatus;\n /** Bar height: sm = h-1.5, md = h-2.5. */\n size?: 'sm' | 'md';\n className?: string;\n /** Accessible label for the progress meter. */\n 'aria-label'?: string;\n}\n\nexport function ProgressBar({\n value,\n status = 'primary',\n size = 'md',\n className,\n 'aria-label': ariaLabel,\n}: ProgressBarProps) {\n const clamped = Math.min(100, Math.max(0, value));\n return (\n <div\n className={cn(\n 'w-full overflow-hidden rounded-full bg-bg-sunken',\n size === 'sm' ? 'h-1.5' : 'h-2.5',\n className\n )}\n role=\"progressbar\"\n aria-valuenow={Math.round(clamped)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n >\n <div\n className={cn(\n 'h-full rounded-full transition-all duration-300 ease-[var(--motion-easing-out)]',\n FILL_TONE[status]\n )}\n style={{ width: `${clamped}%` }}\n />\n </div>\n );\n}\n"],"mappings":";;;AAaA,IAAM,IAA4C;CAChD,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;
|
|
1
|
+
{"version":3,"file":"ProgressBar.js","names":[],"sources":["../../../../src/billing/shared/ui/ProgressBar.tsx"],"sourcesContent":["/**\n * Boff UI — ProgressBar primitive\n *\n * Quota / usage progress bar with status-driven fill colors. Track uses the\n * sunken surface; the fill maps the billing `SemanticStatus` palette to the\n * canonical status tokens. Clamps the value to 0-100.\n *\n * Visual-only primitive.\n */\n\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\nimport type { SemanticStatus } from '../utils/tokens';\n\nconst FILL_TONE: Record<SemanticStatus, string> = {\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n error: 'bg-status-error-bg',\n info: 'bg-status-info-bg',\n neutral: 'bg-text-muted',\n primary: 'bg-action-primary-bg',\n};\n\ninterface ProgressBarProps {\n /** Percentage 0-100. */\n value: number;\n /** Status tone for the fill color. Defaults to a neutral/primary fill. */\n status?: SemanticStatus;\n /** Bar height: sm = h-1.5, md = h-2.5. */\n size?: 'sm' | 'md';\n className?: string;\n /** Accessible label for the progress meter. */\n 'aria-label'?: string;\n}\n\nexport function ProgressBar({\n value,\n status = 'primary',\n size = 'md',\n className,\n 'aria-label': ariaLabel,\n}: ProgressBarProps) {\n const clamped = Math.min(100, Math.max(0, value));\n return (\n <div\n className={cn(\n 'w-full overflow-hidden rounded-full bg-bg-sunken',\n size === 'sm' ? 'h-1.5' : 'h-2.5',\n className\n )}\n role=\"progressbar\"\n aria-valuenow={Math.round(clamped)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n >\n <div\n className={cn(\n 'h-full rounded-full transition-all duration-300 ease-[var(--motion-easing-out)]',\n FILL_TONE[status]\n )}\n style={{ width: `${clamped}%` }}\n />\n </div>\n );\n}\n"],"mappings":";;;AAaA,IAAM,IAA4C;CAChD,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX;AAcA,SAAgB,EAAY,EAC1B,UACA,YAAS,WACT,UAAO,MACP,cACA,cAAc,KACK;CACnB,IAAM,IAAU,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,CAAK,CAAC;CAChD,OACE,kBAAC,OAAD;EACE,WAAW,EACT,oDACA,MAAS,OAAO,UAAU,SAC1B,CACF;EACA,MAAK;EACL,iBAAe,KAAK,MAAM,CAAO;EACjC,iBAAe;EACf,iBAAe;EACf,cAAY;YAEZ,kBAAC,OAAD;GACE,WAAW,EACT,mFACA,EAAU,EACZ;GACA,OAAO,EAAE,OAAO,GAAG,EAAQ,GAAG;EAC/B,CAAA;CACE,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusPill.js","names":[],"sources":["../../../../src/billing/shared/ui/StatusPill.tsx"],"sourcesContent":["/**\n * Boff UI — StatusPill primitive\n *\n * Subtle status badge following the Boff UI recipe\n * (
|
|
1
|
+
{"version":3,"file":"StatusPill.js","names":[],"sources":["../../../../src/billing/shared/ui/StatusPill.tsx"],"sourcesContent":["/**\n * Boff UI — StatusPill primitive\n *\n * Subtle status badge following the Boff UI recipe\n * (semantic status background and foreground utilities, neutral =\n * `bg-bg-sunken text-text-secondary`). Always keeps the text label and an\n * optional dot — never color-only. Maps the billing module's existing\n * `SemanticStatus` palette to the canonical tokens.\n *\n * Visual-only primitive.\n */\n\nimport type { ReactNode } from 'react';\nimport { cn } from '@burdenoff/fe-libs/shared/utils';\nimport type { SemanticStatus } from '../utils/tokens';\n\nconst PILL_TONE: Record<SemanticStatus, string> = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n info: 'bg-status-info-bg-subtle text-status-info-text',\n neutral: 'bg-bg-sunken text-text-secondary',\n primary: 'bg-[var(--color-accent-soft)] text-text-link',\n};\n\nconst DOT_TONE: Record<SemanticStatus, string> = {\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n error: 'bg-status-error-bg',\n info: 'bg-status-info-bg',\n neutral: 'bg-text-muted',\n primary: 'bg-action-primary-bg',\n};\n\ninterface StatusPillProps {\n status: SemanticStatus;\n children: ReactNode;\n /** Show a leading status dot. */\n dot?: boolean;\n /** Pulse the dot (e.g. live / offline indicators). */\n pulse?: boolean;\n className?: string;\n}\n\nexport function StatusPill({\n status,\n children,\n dot = false,\n pulse = false,\n className,\n}: StatusPillProps) {\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n PILL_TONE[status],\n className\n )}\n >\n {dot && (\n <span\n className={cn(\n 'size-1.5 rounded-full',\n DOT_TONE[status],\n pulse && 'motion-safe:animate-vc-glow-pulse'\n )}\n />\n )}\n {children}\n </span>\n );\n}\n"],"mappings":";;;AAgBA,IAAM,IAA4C;CAChD,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX,GAEM,IAA2C;CAC/C,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX;AAYA,SAAgB,EAAW,EACzB,WACA,aACA,SAAM,IACN,WAAQ,IACR,gBACkB;CAClB,OACE,kBAAC,QAAD;EACE,WAAW,EACT,mFACA,EAAU,IACV,CACF;YALF,CAOG,KACC,kBAAC,QAAD,EACE,WAAW,EACT,yBACA,EAAS,IACT,KAAS,mCACX,EACD,CAAA,GAEF,CACG;;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directBillingGraphql.js","names":[],"sources":["../../../../src/billing/shared/utils/directBillingGraphql.ts"],"sourcesContent":["import { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql/fetch';\n\nimport {\n normalizeGlobalGatewayBaseUrl,\n toGraphqlQuery,\n type GatewayGraphqlDocument,\n} from './gatewayGraphql';\n\ninterface DirectBillingGraphqlRequestOptions<TVariables> {\n apiGatewayUrl?: string;\n authToken?: string;\n orgId?: string;\n query: GatewayGraphqlDocument;\n variables?: TVariables;\n}\n\nexport function resolveDirectBillingGraphqlUrl(apiGatewayUrl?: string): string | undefined {\n return normalizeGlobalGatewayBaseUrl(apiGatewayUrl, ['localhost:4012', '/billing-graphql']);\n}\n\nexport async function directBillingGraphqlRequest<TData, TVariables = Record<string, unknown>>(\n options: DirectBillingGraphqlRequestOptions<TVariables>\n): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'global',\n baseUrl: resolveDirectBillingGraphqlUrl(options.apiGatewayUrl),\n authToken: options.authToken,\n organizationId: options.orgId,\n query: toGraphqlQuery(options.query),\n variables: options.variables as Record<string, unknown> | undefined,\n });\n\n if (response.errors?.length || !response.data) {\n throw new Error(response.errors?.[0]?.message || 'Billing GraphQL request failed');\n }\n\n return response.data;\n}\n"],"mappings":";;;AAgBA,SAAgB,EAA+B,GAA4C;
|
|
1
|
+
{"version":3,"file":"directBillingGraphql.js","names":[],"sources":["../../../../src/billing/shared/utils/directBillingGraphql.ts"],"sourcesContent":["import { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql/fetch';\n\nimport {\n normalizeGlobalGatewayBaseUrl,\n toGraphqlQuery,\n type GatewayGraphqlDocument,\n} from './gatewayGraphql';\n\ninterface DirectBillingGraphqlRequestOptions<TVariables> {\n apiGatewayUrl?: string;\n authToken?: string;\n orgId?: string;\n query: GatewayGraphqlDocument;\n variables?: TVariables;\n}\n\nexport function resolveDirectBillingGraphqlUrl(apiGatewayUrl?: string): string | undefined {\n return normalizeGlobalGatewayBaseUrl(apiGatewayUrl, ['localhost:4012', '/billing-graphql']);\n}\n\nexport async function directBillingGraphqlRequest<TData, TVariables = Record<string, unknown>>(\n options: DirectBillingGraphqlRequestOptions<TVariables>\n): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'global',\n baseUrl: resolveDirectBillingGraphqlUrl(options.apiGatewayUrl),\n authToken: options.authToken,\n organizationId: options.orgId,\n query: toGraphqlQuery(options.query),\n variables: options.variables as Record<string, unknown> | undefined,\n });\n\n if (response.errors?.length || !response.data) {\n throw new Error(response.errors?.[0]?.message || 'Billing GraphQL request failed');\n }\n\n return response.data;\n}\n"],"mappings":";;;AAgBA,SAAgB,EAA+B,GAA4C;CACzF,OAAO,EAA8B,GAAe,CAAC,kBAAkB,kBAAkB,CAAC;AAC5F;AAEA,eAAsB,EACpB,GACgB;CAChB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT,SAAS,EAA+B,EAAQ,aAAa;EAC7D,WAAW,EAAQ;EACnB,gBAAgB,EAAQ;EACxB,OAAO,EAAe,EAAQ,KAAK;EACnC,WAAW,EAAQ;CACrB,CAAC;CAED,IAAI,EAAS,QAAQ,UAAU,CAAC,EAAS,MACvC,MAAU,MAAM,EAAS,SAAS,IAAI,WAAW,gCAAgC;CAGnF,OAAO,EAAS;AAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","names":[],"sources":["../../../../src/billing/shared/utils/error.ts"],"sourcesContent":["/**\n * Error Handling Utilities\n */\n\n/**\n * GraphQL error type with network error support\n * Compatible with Apollo Client 4.x error shape\n */\ninterface GraphQLError extends Error {\n networkError?: {\n statusCode?: number;\n message?: string;\n } | null;\n graphQLErrors?: Array<{ message: string }>;\n}\n\n/**\n * Check if an Apollo error is a server error (5xx status)\n */\nexport function isServerError(error: GraphQLError | Error | undefined | null): boolean {\n if (!error) return false;\n\n // Check if it's an Apollo error with network error\n if ('networkError' in error && error.networkError) {\n const networkError = error.networkError as { statusCode?: number; message?: string };\n\n // Check for 5xx status codes\n if (networkError.statusCode && networkError.statusCode >= 500) {\n return true;\n }\n\n // Check for common network error messages\n const message = networkError.message?.toLowerCase() || '';\n if (\n message.includes('failed to fetch') ||\n message.includes('network request failed') ||\n message.includes('econnrefused') ||\n message.includes('server error') ||\n message.includes('502') ||\n message.includes('503') ||\n message.includes('504')\n ) {\n return true;\n }\n }\n\n // Check error message for 500 errors\n const errorMessage = error.message?.toLowerCase() || '';\n if (\n errorMessage.includes('500') ||\n errorMessage.includes('internal server error') ||\n errorMessage.includes('service unavailable') ||\n errorMessage.includes('bad gateway') ||\n errorMessage.includes('gateway timeout')\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if an error is a network connectivity issue\n */\nexport function isNetworkError(error: GraphQLError | Error | undefined | null): boolean {\n if (!error) return false;\n\n if ('networkError' in error && error.networkError) {\n const message = (error.networkError as { message?: string }).message?.toLowerCase() || '';\n return (\n message.includes('failed to fetch') ||\n message.includes('network request failed') ||\n message.includes('econnrefused') ||\n message.includes('networkerror')\n );\n }\n\n return false;\n}\n\n/**\n * Get a user-friendly error message\n */\nexport function getErrorMessage(error: GraphQLError | Error | undefined | null): string {\n if (!error) return 'An unexpected error occurred.';\n\n if (isServerError(error)) {\n return 'The server is currently unavailable. Please try again later.';\n }\n\n if (isNetworkError(error)) {\n return 'Unable to connect to the server. Please check your internet connection.';\n }\n\n // Return the actual error message if it's user-friendly enough\n if (error.message && !error.message.includes('GraphQL')) {\n return error.message;\n }\n\n return 'Something went wrong. Please try again.';\n}\n"],"mappings":";AAmBA,SAAgB,EAAc,GAAyD;
|
|
1
|
+
{"version":3,"file":"error.js","names":[],"sources":["../../../../src/billing/shared/utils/error.ts"],"sourcesContent":["/**\n * Error Handling Utilities\n */\n\n/**\n * GraphQL error type with network error support\n * Compatible with Apollo Client 4.x error shape\n */\ninterface GraphQLError extends Error {\n networkError?: {\n statusCode?: number;\n message?: string;\n } | null;\n graphQLErrors?: Array<{ message: string }>;\n}\n\n/**\n * Check if an Apollo error is a server error (5xx status)\n */\nexport function isServerError(error: GraphQLError | Error | undefined | null): boolean {\n if (!error) return false;\n\n // Check if it's an Apollo error with network error\n if ('networkError' in error && error.networkError) {\n const networkError = error.networkError as { statusCode?: number; message?: string };\n\n // Check for 5xx status codes\n if (networkError.statusCode && networkError.statusCode >= 500) {\n return true;\n }\n\n // Check for common network error messages\n const message = networkError.message?.toLowerCase() || '';\n if (\n message.includes('failed to fetch') ||\n message.includes('network request failed') ||\n message.includes('econnrefused') ||\n message.includes('server error') ||\n message.includes('502') ||\n message.includes('503') ||\n message.includes('504')\n ) {\n return true;\n }\n }\n\n // Check error message for 500 errors\n const errorMessage = error.message?.toLowerCase() || '';\n if (\n errorMessage.includes('500') ||\n errorMessage.includes('internal server error') ||\n errorMessage.includes('service unavailable') ||\n errorMessage.includes('bad gateway') ||\n errorMessage.includes('gateway timeout')\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if an error is a network connectivity issue\n */\nexport function isNetworkError(error: GraphQLError | Error | undefined | null): boolean {\n if (!error) return false;\n\n if ('networkError' in error && error.networkError) {\n const message = (error.networkError as { message?: string }).message?.toLowerCase() || '';\n return (\n message.includes('failed to fetch') ||\n message.includes('network request failed') ||\n message.includes('econnrefused') ||\n message.includes('networkerror')\n );\n }\n\n return false;\n}\n\n/**\n * Get a user-friendly error message\n */\nexport function getErrorMessage(error: GraphQLError | Error | undefined | null): string {\n if (!error) return 'An unexpected error occurred.';\n\n if (isServerError(error)) {\n return 'The server is currently unavailable. Please try again later.';\n }\n\n if (isNetworkError(error)) {\n return 'Unable to connect to the server. Please check your internet connection.';\n }\n\n // Return the actual error message if it's user-friendly enough\n if (error.message && !error.message.includes('GraphQL')) {\n return error.message;\n }\n\n return 'Something went wrong. Please try again.';\n}\n"],"mappings":";AAmBA,SAAgB,EAAc,GAAyD;CACrF,IAAI,CAAC,GAAO,OAAO;CAGnB,IAAI,kBAAkB,KAAS,EAAM,cAAc;EACjD,IAAM,IAAe,EAAM;EAG3B,IAAI,EAAa,cAAc,EAAa,cAAc,KACxD,OAAO;EAIT,IAAM,IAAU,EAAa,SAAS,YAAY,KAAK;EACvD,IACE,EAAQ,SAAS,iBAAiB,KAClC,EAAQ,SAAS,wBAAwB,KACzC,EAAQ,SAAS,cAAc,KAC/B,EAAQ,SAAS,cAAc,KAC/B,EAAQ,SAAS,KAAK,KACtB,EAAQ,SAAS,KAAK,KACtB,EAAQ,SAAS,KAAK,GAEtB,OAAO;CAEX;CAGA,IAAM,IAAe,EAAM,SAAS,YAAY,KAAK;CAWrD,OAVA,GACE,EAAa,SAAS,KAAK,KAC3B,EAAa,SAAS,uBAAuB,KAC7C,EAAa,SAAS,qBAAqB,KAC3C,EAAa,SAAS,aAAa,KACnC,EAAa,SAAS,iBAAiB;AAM3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","names":[],"sources":["../../../../src/billing/shared/utils/format.ts"],"sourcesContent":["/**\n * Formatting utilities for the billing module\n *\n * Re-exports common formatting utilities from fe-libs and adds billing-specific ones.\n */\n\nimport {\n SubscriptionStatus,\n InvoiceStatus,\n PaymentStatus,\n ChargeStatus,\n QuotaStatus,\n PlanDuration,\n PaymentMethodType,\n TransactionType,\n CreditTransactionType,\n} from '../types';\n\n// Re-export common formatting utilities from fe-libs\nexport {\n formatCurrency as formatCurrencyBase,\n formatCurrencyCompact as formatCurrencyCompactBase,\n formatDate,\n formatDateTime,\n formatRelativeTime,\n formatDuration,\n formatNumber,\n formatPercentage,\n formatBytes,\n formatCompactNumber,\n} from '@burdenoff/fe-libs/shared/utils';\n\n// Import for internal use\nimport {\n formatCurrency as formatCurrencyBase,\n formatCurrencyCompact as formatCurrencyCompactBase,\n formatBytes,\n} from '@burdenoff/fe-libs/shared/utils';\n\n// ============================================================================\n// Billing-specific Currency Formatting (handles CREDITS)\n// ============================================================================\n\nexport function formatCurrency(amount: number, currency = 'USD', locale = 'en-US'): string {\n // Handle CREDITS specially - credits are not a real currency\n if (currency.toUpperCase() === 'CREDITS') {\n return formatCredits(amount);\n }\n return formatCurrencyBase(amount, currency, locale);\n}\n\n/**\n * Format credits as \"X Credits\" or \"X.XX Credits\"\n * Credits are always displayed as a unit count, not as currency\n */\nexport function formatCredits(amount: number): string {\n // For whole numbers, show without decimals\n if (Number.isInteger(amount)) {\n return `${amount.toLocaleString()} Credits`;\n }\n // For fractional credits, show up to 2 decimals\n return `${amount.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 2 })} Credits`;\n}\n\nexport function formatCurrencyCompact(amount: number, currency = 'USD'): string {\n if (currency.toUpperCase() === 'CREDITS') {\n return formatCredits(amount);\n }\n return formatCurrencyCompactBase(amount, currency);\n}\n\n// ============================================================================\n// Status Formatting\n// ============================================================================\n\nexport function formatSubscriptionStatus(status: SubscriptionStatus): string {\n const labels: Record<SubscriptionStatus, string> = {\n [SubscriptionStatus.ACTIVE]: 'Active',\n [SubscriptionStatus.CANCELED]: 'Canceled',\n [SubscriptionStatus.EXPIRED]: 'Expired',\n [SubscriptionStatus.UPGRADED]: 'Upgraded',\n };\n return labels[status] || status;\n}\n\nexport function formatInvoiceStatus(status: InvoiceStatus): string {\n const labels: Record<InvoiceStatus, string> = {\n [InvoiceStatus.DRAFT]: 'Draft',\n [InvoiceStatus.OPEN]: 'Open',\n [InvoiceStatus.PAID]: 'Paid',\n [InvoiceStatus.VOID]: 'Void',\n [InvoiceStatus.UNCOLLECTIBLE]: 'Uncollectible',\n };\n return labels[status] || status;\n}\n\nexport function formatPaymentStatus(status: PaymentStatus): string {\n const labels: Record<PaymentStatus, string> = {\n [PaymentStatus.PENDING]: 'Pending',\n [PaymentStatus.SUCCEEDED]: 'Succeeded',\n [PaymentStatus.FAILED]: 'Failed',\n [PaymentStatus.CANCELED]: 'Canceled',\n [PaymentStatus.REFUNDED]: 'Refunded',\n };\n return labels[status] || status;\n}\n\nexport function formatChargeStatus(status: ChargeStatus): string {\n const labels: Record<ChargeStatus, string> = {\n [ChargeStatus.PENDING]: 'Pending',\n [ChargeStatus.SUCCEEDED]: 'Succeeded',\n [ChargeStatus.FAILED]: 'Failed',\n [ChargeStatus.REFUNDED]: 'Refunded',\n };\n return labels[status] || status;\n}\n\nexport function formatQuotaStatus(status: QuotaStatus): string {\n const labels: Record<QuotaStatus, string> = {\n [QuotaStatus.HEALTHY]: 'Healthy',\n [QuotaStatus.WARNING]: 'Warning',\n [QuotaStatus.CRITICAL]: 'Critical',\n [QuotaStatus.EXHAUSTED]: 'Exhausted',\n [QuotaStatus.INACTIVE]: 'Inactive',\n };\n return labels[status] || status;\n}\n\n// ============================================================================\n// Plan & Duration Formatting\n// ============================================================================\n\nexport function formatPlanDuration(duration: PlanDuration): string {\n const labels: Record<PlanDuration, string> = {\n [PlanDuration.MONTHLY]: 'month',\n [PlanDuration.YEARLY]: 'year',\n };\n return labels[duration] || duration;\n}\n\nexport function formatPlanDurationLabel(duration: PlanDuration): string {\n const labels: Record<PlanDuration, string> = {\n [PlanDuration.MONTHLY]: 'Monthly',\n [PlanDuration.YEARLY]: 'Yearly',\n };\n return labels[duration] || duration;\n}\n\nexport function formatPlanPrice(price: number, currency: string, duration: PlanDuration): string {\n return `${formatCurrency(price, currency)}/${formatPlanDuration(duration)}`;\n}\n\n// ============================================================================\n// Payment Method Formatting\n// ============================================================================\n\nexport function formatPaymentMethodType(type: PaymentMethodType): string {\n const labels: Record<PaymentMethodType, string> = {\n [PaymentMethodType.CREDIT_CARD]: 'Credit Card',\n [PaymentMethodType.DEBIT_CARD]: 'Debit Card',\n [PaymentMethodType.BANK_TRANSFER]: 'Bank Transfer',\n [PaymentMethodType.PAYPAL]: 'PayPal',\n [PaymentMethodType.CRYPTO]: 'Cryptocurrency',\n [PaymentMethodType.WALLET]: 'Wallet',\n [PaymentMethodType.NETBANKING]: 'Netbanking',\n };\n return labels[type] || type;\n}\n\nexport function formatCardBrand(brand?: string): string {\n if (!brand) return 'Card';\n return brand.charAt(0).toUpperCase() + brand.slice(1).toLowerCase();\n}\n\nexport function formatCardNumber(last4?: string): string {\n if (!last4) return '****';\n return `•••• ${last4}`;\n}\n\nexport function formatCardExpiry(month?: number, year?: number): string {\n if (!month || !year) return '';\n return `${month.toString().padStart(2, '0')}/${year.toString().slice(-2)}`;\n}\n\n// ============================================================================\n// Transaction Formatting\n// ============================================================================\n\nexport function formatTransactionType(type: TransactionType): string {\n const labels: Record<TransactionType, string> = {\n [TransactionType.PAYMENT]: 'Payment',\n [TransactionType.REFUND]: 'Refund',\n [TransactionType.ADJUSTMENT]: 'Adjustment',\n };\n return labels[type] || type;\n}\n\nexport function formatCreditTransactionType(type: CreditTransactionType): string {\n const labels: Record<CreditTransactionType, string> = {\n [CreditTransactionType.PURCHASE]: 'Purchase',\n [CreditTransactionType.USAGE]: 'Usage',\n [CreditTransactionType.ADJUSTMENT]: 'Earned',\n [CreditTransactionType.GRANTED]: 'Granted',\n };\n return labels[type] || type;\n}\n\n// ============================================================================\n// Text Formatting\n// ============================================================================\n\nexport function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return `${text.slice(0, maxLength - 3)}...`;\n}\n\nexport function capitalizeFirst(text: string): string {\n if (!text) return '';\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n}\n\nexport function formatInvoiceNumber(number: string): string {\n return `#${number}`;\n}\n\n// ============================================================================\n// Quota Value Formatting\n// ============================================================================\n\n/**\n * Format a quota's total value for display, unit-aware. Byte-denominated\n * quotas (storage, upload caps) render as MB/GB via formatBytes instead of a\n * raw byte count — everything else falls back to a plain localized number.\n */\nexport function formatQuotaValue(value: number, unit?: string): string {\n if (unit === 'bytes') return formatBytes(value);\n return value.toLocaleString();\n}\n"],"mappings":";;;AA2CA,SAAgB,EAAe,GAAgB,IAAW,OAAO,IAAS,SAAiB;
|
|
1
|
+
{"version":3,"file":"format.js","names":[],"sources":["../../../../src/billing/shared/utils/format.ts"],"sourcesContent":["/**\n * Formatting utilities for the billing module\n *\n * Re-exports common formatting utilities from fe-libs and adds billing-specific ones.\n */\n\nimport {\n SubscriptionStatus,\n InvoiceStatus,\n PaymentStatus,\n ChargeStatus,\n QuotaStatus,\n PlanDuration,\n PaymentMethodType,\n TransactionType,\n CreditTransactionType,\n} from '../types';\n\n// Re-export common formatting utilities from fe-libs\nexport {\n formatCurrency as formatCurrencyBase,\n formatCurrencyCompact as formatCurrencyCompactBase,\n formatDate,\n formatDateTime,\n formatRelativeTime,\n formatDuration,\n formatNumber,\n formatPercentage,\n formatBytes,\n formatCompactNumber,\n} from '@burdenoff/fe-libs/shared/utils';\n\n// Import for internal use\nimport {\n formatCurrency as formatCurrencyBase,\n formatCurrencyCompact as formatCurrencyCompactBase,\n formatBytes,\n} from '@burdenoff/fe-libs/shared/utils';\n\n// ============================================================================\n// Billing-specific Currency Formatting (handles CREDITS)\n// ============================================================================\n\nexport function formatCurrency(amount: number, currency = 'USD', locale = 'en-US'): string {\n // Handle CREDITS specially - credits are not a real currency\n if (currency.toUpperCase() === 'CREDITS') {\n return formatCredits(amount);\n }\n return formatCurrencyBase(amount, currency, locale);\n}\n\n/**\n * Format credits as \"X Credits\" or \"X.XX Credits\"\n * Credits are always displayed as a unit count, not as currency\n */\nexport function formatCredits(amount: number): string {\n // For whole numbers, show without decimals\n if (Number.isInteger(amount)) {\n return `${amount.toLocaleString()} Credits`;\n }\n // For fractional credits, show up to 2 decimals\n return `${amount.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 2 })} Credits`;\n}\n\nexport function formatCurrencyCompact(amount: number, currency = 'USD'): string {\n if (currency.toUpperCase() === 'CREDITS') {\n return formatCredits(amount);\n }\n return formatCurrencyCompactBase(amount, currency);\n}\n\n// ============================================================================\n// Status Formatting\n// ============================================================================\n\nexport function formatSubscriptionStatus(status: SubscriptionStatus): string {\n const labels: Record<SubscriptionStatus, string> = {\n [SubscriptionStatus.ACTIVE]: 'Active',\n [SubscriptionStatus.CANCELED]: 'Canceled',\n [SubscriptionStatus.EXPIRED]: 'Expired',\n [SubscriptionStatus.UPGRADED]: 'Upgraded',\n };\n return labels[status] || status;\n}\n\nexport function formatInvoiceStatus(status: InvoiceStatus): string {\n const labels: Record<InvoiceStatus, string> = {\n [InvoiceStatus.DRAFT]: 'Draft',\n [InvoiceStatus.OPEN]: 'Open',\n [InvoiceStatus.PAID]: 'Paid',\n [InvoiceStatus.VOID]: 'Void',\n [InvoiceStatus.UNCOLLECTIBLE]: 'Uncollectible',\n };\n return labels[status] || status;\n}\n\nexport function formatPaymentStatus(status: PaymentStatus): string {\n const labels: Record<PaymentStatus, string> = {\n [PaymentStatus.PENDING]: 'Pending',\n [PaymentStatus.SUCCEEDED]: 'Succeeded',\n [PaymentStatus.FAILED]: 'Failed',\n [PaymentStatus.CANCELED]: 'Canceled',\n [PaymentStatus.REFUNDED]: 'Refunded',\n };\n return labels[status] || status;\n}\n\nexport function formatChargeStatus(status: ChargeStatus): string {\n const labels: Record<ChargeStatus, string> = {\n [ChargeStatus.PENDING]: 'Pending',\n [ChargeStatus.SUCCEEDED]: 'Succeeded',\n [ChargeStatus.FAILED]: 'Failed',\n [ChargeStatus.REFUNDED]: 'Refunded',\n };\n return labels[status] || status;\n}\n\nexport function formatQuotaStatus(status: QuotaStatus): string {\n const labels: Record<QuotaStatus, string> = {\n [QuotaStatus.HEALTHY]: 'Healthy',\n [QuotaStatus.WARNING]: 'Warning',\n [QuotaStatus.CRITICAL]: 'Critical',\n [QuotaStatus.EXHAUSTED]: 'Exhausted',\n [QuotaStatus.INACTIVE]: 'Inactive',\n };\n return labels[status] || status;\n}\n\n// ============================================================================\n// Plan & Duration Formatting\n// ============================================================================\n\nexport function formatPlanDuration(duration: PlanDuration): string {\n const labels: Record<PlanDuration, string> = {\n [PlanDuration.MONTHLY]: 'month',\n [PlanDuration.YEARLY]: 'year',\n };\n return labels[duration] || duration;\n}\n\nexport function formatPlanDurationLabel(duration: PlanDuration): string {\n const labels: Record<PlanDuration, string> = {\n [PlanDuration.MONTHLY]: 'Monthly',\n [PlanDuration.YEARLY]: 'Yearly',\n };\n return labels[duration] || duration;\n}\n\nexport function formatPlanPrice(price: number, currency: string, duration: PlanDuration): string {\n return `${formatCurrency(price, currency)}/${formatPlanDuration(duration)}`;\n}\n\n// ============================================================================\n// Payment Method Formatting\n// ============================================================================\n\nexport function formatPaymentMethodType(type: PaymentMethodType): string {\n const labels: Record<PaymentMethodType, string> = {\n [PaymentMethodType.CREDIT_CARD]: 'Credit Card',\n [PaymentMethodType.DEBIT_CARD]: 'Debit Card',\n [PaymentMethodType.BANK_TRANSFER]: 'Bank Transfer',\n [PaymentMethodType.PAYPAL]: 'PayPal',\n [PaymentMethodType.CRYPTO]: 'Cryptocurrency',\n [PaymentMethodType.WALLET]: 'Wallet',\n [PaymentMethodType.NETBANKING]: 'Netbanking',\n };\n return labels[type] || type;\n}\n\nexport function formatCardBrand(brand?: string): string {\n if (!brand) return 'Card';\n return brand.charAt(0).toUpperCase() + brand.slice(1).toLowerCase();\n}\n\nexport function formatCardNumber(last4?: string): string {\n if (!last4) return '****';\n return `•••• ${last4}`;\n}\n\nexport function formatCardExpiry(month?: number, year?: number): string {\n if (!month || !year) return '';\n return `${month.toString().padStart(2, '0')}/${year.toString().slice(-2)}`;\n}\n\n// ============================================================================\n// Transaction Formatting\n// ============================================================================\n\nexport function formatTransactionType(type: TransactionType): string {\n const labels: Record<TransactionType, string> = {\n [TransactionType.PAYMENT]: 'Payment',\n [TransactionType.REFUND]: 'Refund',\n [TransactionType.ADJUSTMENT]: 'Adjustment',\n };\n return labels[type] || type;\n}\n\nexport function formatCreditTransactionType(type: CreditTransactionType): string {\n const labels: Record<CreditTransactionType, string> = {\n [CreditTransactionType.PURCHASE]: 'Purchase',\n [CreditTransactionType.USAGE]: 'Usage',\n [CreditTransactionType.ADJUSTMENT]: 'Earned',\n [CreditTransactionType.GRANTED]: 'Granted',\n };\n return labels[type] || type;\n}\n\n// ============================================================================\n// Text Formatting\n// ============================================================================\n\nexport function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return `${text.slice(0, maxLength - 3)}...`;\n}\n\nexport function capitalizeFirst(text: string): string {\n if (!text) return '';\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n}\n\nexport function formatInvoiceNumber(number: string): string {\n return `#${number}`;\n}\n\n// ============================================================================\n// Quota Value Formatting\n// ============================================================================\n\n/**\n * Format a quota's total value for display, unit-aware. Byte-denominated\n * quotas (storage, upload caps) render as MB/GB via formatBytes instead of a\n * raw byte count — everything else falls back to a plain localized number.\n */\nexport function formatQuotaValue(value: number, unit?: string): string {\n if (unit === 'bytes') return formatBytes(value);\n return value.toLocaleString();\n}\n"],"mappings":";;;AA2CA,SAAgB,EAAe,GAAgB,IAAW,OAAO,IAAS,SAAiB;CAKzF,OAHI,EAAS,YAAY,MAAM,YACtB,EAAc,CAAM,IAEtB,EAAmB,GAAQ,GAAU,CAAM;AACpD;AAMA,SAAgB,EAAc,GAAwB;CAMpD,OAJI,OAAO,UAAU,CAAM,IAClB,GAAG,EAAO,eAAe,EAAE,YAG7B,GAAG,EAAO,eAAe,KAAA,GAAW;EAAE,uBAAuB;EAAG,uBAAuB;CAAE,CAAC,EAAE;AACrG;AAaA,SAAgB,EAAyB,GAAoC;CAO3E,OAAO;GALJ,EAAmB,SAAS;GAC5B,EAAmB,WAAW;GAC9B,EAAmB,UAAU;GAC7B,EAAmB,WAAW;CAE1B,EAAO,MAAW;AAC3B;AAEA,SAAgB,EAAoB,GAA+B;CAQjE,OAAO;GANJ,EAAc,QAAQ;GACtB,EAAc,OAAO;GACrB,EAAc,OAAO;GACrB,EAAc,OAAO;GACrB,EAAc,gBAAgB;CAE1B,EAAO,MAAW;AAC3B;AAsCA,SAAgB,EAAmB,GAAgC;CAKjE,OAAO;GAHJ,EAAa,UAAU;GACvB,EAAa,SAAS;CAElB,EAAO,MAAa;AAC7B;AAEA,SAAgB,EAAwB,GAAgC;CAKtE,OAAO;GAHJ,EAAa,UAAU;GACvB,EAAa,SAAS;CAElB,EAAO,MAAa;AAC7B;AAmDA,SAAgB,EAA4B,GAAqC;CAO/E,OAAO;GALJ,EAAsB,WAAW;GACjC,EAAsB,QAAQ;GAC9B,EAAsB,aAAa;GACnC,EAAsB,UAAU;CAE5B,EAAO,MAAS;AACzB;AAgBA,SAAgB,EAAoB,GAAwB;CAC1D,OAAO,IAAI;AACb;AAWA,SAAgB,EAAiB,GAAe,GAAuB;CAErE,OADI,MAAS,UAAgB,EAAY,CAAK,IACvC,EAAM,eAAe;AAC9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gatewayGraphql.js","names":[],"sources":["../../../../src/billing/shared/utils/gatewayGraphql.ts"],"sourcesContent":["import { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql/fetch';\nimport { print, type DocumentNode } from 'graphql';\n\nexport type GatewayGraphqlDocument = string | DocumentNode;\n\nexport function toGraphqlQuery(query: GatewayGraphqlDocument): string {\n return typeof query === 'string' ? query : print(query);\n}\n\ninterface GatewayGraphqlRequestOptions<TVariables> {\n apiGatewayUrl?: string;\n authToken?: string;\n orgId?: string;\n query: GatewayGraphqlDocument;\n variables?: TVariables;\n}\n\nconst GLOBAL_GRAPHQL_PATH = '/global/graphql';\n\nexport function normalizeGlobalGatewayBaseUrl(\n apiGatewayUrl?: string,\n legacyDirectEndpoints: string[] = []\n): string | undefined {\n const trimmedUrl = apiGatewayUrl?.trim();\n\n if (!trimmedUrl || trimmedUrl.startsWith('/')) {\n return undefined;\n }\n\n if (legacyDirectEndpoints.some((endpoint) => trimmedUrl.includes(endpoint))) {\n return undefined;\n }\n\n if (trimmedUrl.endsWith(GLOBAL_GRAPHQL_PATH)) {\n return trimmedUrl.slice(0, -GLOBAL_GRAPHQL_PATH.length) || undefined;\n }\n\n return trimmedUrl;\n}\n\nexport async function gatewayGraphqlRequest<TData, TVariables = Record<string, unknown>>(\n options: GatewayGraphqlRequestOptions<TVariables>\n): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'global',\n baseUrl: normalizeGlobalGatewayBaseUrl(options.apiGatewayUrl),\n authToken: options.authToken,\n organizationId: options.orgId,\n query: toGraphqlQuery(options.query),\n variables: options.variables as Record<string, unknown> | undefined,\n });\n\n if (response.errors?.length || !response.data) {\n throw new Error(response.errors?.[0]?.message || 'Gateway GraphQL request failed');\n }\n\n return response.data;\n}\n"],"mappings":";;;AAKA,SAAgB,EAAe,GAAuC;
|
|
1
|
+
{"version":3,"file":"gatewayGraphql.js","names":[],"sources":["../../../../src/billing/shared/utils/gatewayGraphql.ts"],"sourcesContent":["import { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql/fetch';\nimport { print, type DocumentNode } from 'graphql';\n\nexport type GatewayGraphqlDocument = string | DocumentNode;\n\nexport function toGraphqlQuery(query: GatewayGraphqlDocument): string {\n return typeof query === 'string' ? query : print(query);\n}\n\ninterface GatewayGraphqlRequestOptions<TVariables> {\n apiGatewayUrl?: string;\n authToken?: string;\n orgId?: string;\n query: GatewayGraphqlDocument;\n variables?: TVariables;\n}\n\nconst GLOBAL_GRAPHQL_PATH = '/global/graphql';\n\nexport function normalizeGlobalGatewayBaseUrl(\n apiGatewayUrl?: string,\n legacyDirectEndpoints: string[] = []\n): string | undefined {\n const trimmedUrl = apiGatewayUrl?.trim();\n\n if (!trimmedUrl || trimmedUrl.startsWith('/')) {\n return undefined;\n }\n\n if (legacyDirectEndpoints.some((endpoint) => trimmedUrl.includes(endpoint))) {\n return undefined;\n }\n\n if (trimmedUrl.endsWith(GLOBAL_GRAPHQL_PATH)) {\n return trimmedUrl.slice(0, -GLOBAL_GRAPHQL_PATH.length) || undefined;\n }\n\n return trimmedUrl;\n}\n\nexport async function gatewayGraphqlRequest<TData, TVariables = Record<string, unknown>>(\n options: GatewayGraphqlRequestOptions<TVariables>\n): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'global',\n baseUrl: normalizeGlobalGatewayBaseUrl(options.apiGatewayUrl),\n authToken: options.authToken,\n organizationId: options.orgId,\n query: toGraphqlQuery(options.query),\n variables: options.variables as Record<string, unknown> | undefined,\n });\n\n if (response.errors?.length || !response.data) {\n throw new Error(response.errors?.[0]?.message || 'Gateway GraphQL request failed');\n }\n\n return response.data;\n}\n"],"mappings":";;;AAKA,SAAgB,EAAe,GAAuC;CACpE,OAAO,OAAO,KAAU,WAAW,IAAQ,EAAM,CAAK;AACxD;AAUA,IAAM,IAAsB;AAE5B,SAAgB,EACd,GACA,IAAkC,CAAC,GACf;CACpB,IAAM,IAAa,GAAe,KAAK;CAEnC,OAAC,KAAc,EAAW,WAAW,GAAG,MAIxC,GAAsB,MAAM,MAAa,EAAW,SAAS,CAAQ,CAAC,GAQ1E,OAJI,EAAW,SAAS,CAAmB,IAClC,EAAW,MAAM,GAAG,GAA2B,KAAK,KAAA,IAGtD;AACT;AAEA,eAAsB,EACpB,GACgB;CAChB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT,SAAS,EAA8B,EAAQ,aAAa;EAC5D,WAAW,EAAQ;EACnB,gBAAgB,EAAQ;EACxB,OAAO,EAAe,EAAQ,KAAK;EACnC,WAAW,EAAQ;CACrB,CAAC;CAED,IAAI,EAAS,QAAQ,UAAU,CAAC,EAAS,MACvC,MAAU,MAAM,EAAS,SAAS,IAAI,WAAW,gCAAgC;CAGnF,OAAO,EAAS;AAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","names":[],"sources":["../../../../src/billing/shared/utils/navigation.ts"],"sourcesContent":["export function withBillingAccountId(path: string, billingAccountId?: string | null): string {\n if (!billingAccountId) return path;\n\n const separator = path.includes('?') ? '&' : '?';\n return `${path}${separator}billingAccountId=${encodeURIComponent(billingAccountId)}`;\n}\n"],"mappings":";AAAA,SAAgB,EAAqB,GAAc,GAA0C;
|
|
1
|
+
{"version":3,"file":"navigation.js","names":[],"sources":["../../../../src/billing/shared/utils/navigation.ts"],"sourcesContent":["export function withBillingAccountId(path: string, billingAccountId?: string | null): string {\n if (!billingAccountId) return path;\n\n const separator = path.includes('?') ? '&' : '?';\n return `${path}${separator}billingAccountId=${encodeURIComponent(billingAccountId)}`;\n}\n"],"mappings":";AAAA,SAAgB,EAAqB,GAAc,GAA0C;CAI3F,OAHK,IAGE,GAAG,IADQ,EAAK,SAAS,GAAG,IAAI,MAAM,IAClB,mBAAmB,mBAAmB,CAAgB,MAHnD;AAIhC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paymentTheme.js","names":[],"sources":["../../../../src/billing/shared/utils/paymentTheme.ts"],"sourcesContent":["/**\n * Utilities for adapting third-party payment widgets to the current semantic theme.\n */\n\ninterface PaymentThemePalette {\n textColor?: string;\n placeholderColor?: string;\n mutedColor?: string;\n errorColor?: string;\n primaryColor?: string;\n}\n\nfunction readCssVar(name: string): string | undefined {\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n const value = window.getComputedStyle(document.documentElement).getPropertyValue(name).trim();\n return value || undefined;\n}\n\nexport function getPaymentThemePalette(): PaymentThemePalette {\n return {\n textColor: readCssVar('--color-text-primary'),\n placeholderColor: readCssVar('--color-text-placeholder'),\n mutedColor: readCssVar('--color-text-secondary'),\n errorColor: readCssVar('--color-status-error-bg'),\n primaryColor: readCssVar('--color-action-primary-bg'),\n };\n}\n\nexport function getStripeCardElementStyle(fontFamily = 'Inter, system-ui, sans-serif') {\n const palette = getPaymentThemePalette();\n\n const base: Record<string, unknown> = {\n fontSize: '16px',\n fontFamily,\n };\n\n if (palette.textColor) {\n base.color = palette.textColor;\n }\n\n if (palette.placeholderColor) {\n base['::placeholder'] = { color: palette.placeholderColor };\n }\n\n if (palette.mutedColor) {\n base.iconColor = palette.mutedColor;\n }\n\n const invalid: Record<string, unknown> = {};\n\n if (palette.errorColor) {\n invalid.color = palette.errorColor;\n invalid.iconColor = palette.errorColor;\n }\n\n return {\n base,\n invalid,\n };\n}\n\nexport function getPaymentProviderThemeColor(): string | undefined {\n return getPaymentThemePalette().primaryColor;\n}\n"],"mappings":";AAYA,SAAS,EAAW,GAAkC;
|
|
1
|
+
{"version":3,"file":"paymentTheme.js","names":[],"sources":["../../../../src/billing/shared/utils/paymentTheme.ts"],"sourcesContent":["/**\n * Utilities for adapting third-party payment widgets to the current semantic theme.\n */\n\ninterface PaymentThemePalette {\n textColor?: string;\n placeholderColor?: string;\n mutedColor?: string;\n errorColor?: string;\n primaryColor?: string;\n}\n\nfunction readCssVar(name: string): string | undefined {\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n const value = window.getComputedStyle(document.documentElement).getPropertyValue(name).trim();\n return value || undefined;\n}\n\nexport function getPaymentThemePalette(): PaymentThemePalette {\n return {\n textColor: readCssVar('--color-text-primary'),\n placeholderColor: readCssVar('--color-text-placeholder'),\n mutedColor: readCssVar('--color-text-secondary'),\n errorColor: readCssVar('--color-status-error-bg'),\n primaryColor: readCssVar('--color-action-primary-bg'),\n };\n}\n\nexport function getStripeCardElementStyle(fontFamily = 'Inter, system-ui, sans-serif') {\n const palette = getPaymentThemePalette();\n\n const base: Record<string, unknown> = {\n fontSize: '16px',\n fontFamily,\n };\n\n if (palette.textColor) {\n base.color = palette.textColor;\n }\n\n if (palette.placeholderColor) {\n base['::placeholder'] = { color: palette.placeholderColor };\n }\n\n if (palette.mutedColor) {\n base.iconColor = palette.mutedColor;\n }\n\n const invalid: Record<string, unknown> = {};\n\n if (palette.errorColor) {\n invalid.color = palette.errorColor;\n invalid.iconColor = palette.errorColor;\n }\n\n return {\n base,\n invalid,\n };\n}\n\nexport function getPaymentProviderThemeColor(): string | undefined {\n return getPaymentThemePalette().primaryColor;\n}\n"],"mappings":";AAYA,SAAS,EAAW,GAAkC;CAChD,aAAO,SAAW,MAKtB,OADc,OAAO,iBAAiB,SAAS,eAAe,EAAE,iBAAiB,CAAI,EAAE,KAChF,KAAS,KAAA;AAClB;AAEA,SAAgB,IAA8C;CAC5D,OAAO;EACL,WAAW,EAAW,sBAAsB;EAC5C,kBAAkB,EAAW,0BAA0B;EACvD,YAAY,EAAW,wBAAwB;EAC/C,YAAY,EAAW,yBAAyB;EAChD,cAAc,EAAW,2BAA2B;CACtD;AACF;AAEA,SAAgB,EAA0B,IAAa,gCAAgC;CACrF,IAAM,IAAU,EAAuB,GAEjC,IAAgC;EACpC,UAAU;EACV;CACF;CAUA,AARI,EAAQ,cACV,EAAK,QAAQ,EAAQ,YAGnB,EAAQ,qBACV,EAAK,mBAAmB,EAAE,OAAO,EAAQ,iBAAiB,IAGxD,EAAQ,eACV,EAAK,YAAY,EAAQ;CAG3B,IAAM,IAAmC,CAAC;CAO1C,OALI,EAAQ,eACV,EAAQ,QAAQ,EAAQ,YACxB,EAAQ,YAAY,EAAQ,aAGvB;EACL;EACA;CACF;AACF;AAEA,SAAgB,IAAmD;CACjE,OAAO,EAAuB,EAAE;AAClC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planFeatureQuantity.js","names":[],"sources":["../../../../src/billing/shared/utils/planFeatureQuantity.ts"],"sourcesContent":["/**\n * Source of truth for \"how big is this quota on this plan\":\n * 1. Per-plan override stored on the SubscriptionFeature row's\n * `context.quantity` (autoseed + post-OSS-release createPlan path).\n * 2. Fall back to the catalog default `quota.limits.value` for plans that\n * pre-date per-plan overrides (only the autoseeded Free plan today).\n */\ntype FeatureLike = {\n context?: unknown;\n quota?: { name?: string | null; limits?: unknown; context?: unknown } | null;\n};\n\nexport function getPlanFeatureQuantity(feature: FeatureLike): number {\n const ctx = feature.context as { quantity?: number } | null | undefined;\n if (ctx && typeof ctx.quantity === 'number') return ctx.quantity;\n\n const limits = feature.quota?.limits as { value?: number } | null | undefined;\n return typeof limits?.value === 'number' ? limits.value : 0;\n}\n\n/**\n * The unit a quota's quantity is denominated in (e.g. \"bytes\", \"days\",\n * \"workflows\"), as seeded on the SubscriptionFeature row's `context.unit`.\n * Used to render byte-denominated quotas (storage, uploads) as MB/GB instead\n * of a raw byte count — see formatQuotaValue in format.ts.\n */\nexport function getPlanFeatureUnit(feature: FeatureLike): string | undefined {\n const ctx = feature.context as { unit?: string } | null | undefined;\n return typeof ctx?.unit === 'string' ? ctx.unit : undefined;\n}\n\n// Trailing name segments that describe the unit/cadence, not the quota\n// itself (e.g. \"fluidgrids.storage.bytes\" → the \"bytes\" segment). Stripped\n// by humanizeQuotaName so the fallback label doesn't end in a redundant\n// technical word.\nconst NAME_SUFFIX_STOPWORDS = new Set([\n 'count',\n 'bytes',\n 'days',\n 'seconds',\n 'hours',\n 'monthly',\n 'daily',\n 'concurrent',\n]);\n\n/**\n * Best-effort human label for a quota that has no seeded `displayName`\n * (older rows only — every quota seeded since BOFF-3058 carries one). Turns\n * \"fluidgrids.scheduled_triggers.count\" into \"Scheduled Triggers\": drops the\n * leading product/boundary segment and a trailing unit/cadence stopword,\n * then title-cases the rest.\n */\nexport function humanizeQuotaName(name: string): string {\n const segments = name.split('.').filter(Boolean);\n const withoutBoundary = segments.length > 1 ? segments.slice(1) : segments;\n const last = withoutBoundary[withoutBoundary.length - 1];\n const meaningful =\n withoutBoundary.length > 1 && last && NAME_SUFFIX_STOPWORDS.has(last)\n ? withoutBoundary.slice(0, -1)\n : withoutBoundary;\n\n const words = meaningful.join(' ').replace(/_/g, ' ').trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return name;\n return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');\n}\n\n/**\n * The name to show a user for a quota: prefers the curated `displayName`\n * seeded on Quota.context (e.g. \"Storage\", \"Team Members\"); falls back to a\n * humanized version of the raw dotted identifier for any quota seeded before\n * displayName was added to the catalog.\n */\nexport function getQuotaDisplayName(feature: FeatureLike): string {\n const quotaContext = feature.quota?.context as { displayName?: string } | null | undefined;\n if (quotaContext && typeof quotaContext.displayName === 'string' && quotaContext.displayName) {\n return quotaContext.displayName;\n }\n\n const rawName = feature.quota?.name;\n return rawName ? humanizeQuotaName(rawName) : 'Unknown Quota';\n}\n"],"mappings":";AAYA,SAAgB,EAAuB,GAA8B;CACnE,IAAM,IAAM,EAAQ;
|
|
1
|
+
{"version":3,"file":"planFeatureQuantity.js","names":[],"sources":["../../../../src/billing/shared/utils/planFeatureQuantity.ts"],"sourcesContent":["/**\n * Source of truth for \"how big is this quota on this plan\":\n * 1. Per-plan override stored on the SubscriptionFeature row's\n * `context.quantity` (autoseed + post-OSS-release createPlan path).\n * 2. Fall back to the catalog default `quota.limits.value` for plans that\n * pre-date per-plan overrides (only the autoseeded Free plan today).\n */\ntype FeatureLike = {\n context?: unknown;\n quota?: { name?: string | null; limits?: unknown; context?: unknown } | null;\n};\n\nexport function getPlanFeatureQuantity(feature: FeatureLike): number {\n const ctx = feature.context as { quantity?: number } | null | undefined;\n if (ctx && typeof ctx.quantity === 'number') return ctx.quantity;\n\n const limits = feature.quota?.limits as { value?: number } | null | undefined;\n return typeof limits?.value === 'number' ? limits.value : 0;\n}\n\n/**\n * The unit a quota's quantity is denominated in (e.g. \"bytes\", \"days\",\n * \"workflows\"), as seeded on the SubscriptionFeature row's `context.unit`.\n * Used to render byte-denominated quotas (storage, uploads) as MB/GB instead\n * of a raw byte count — see formatQuotaValue in format.ts.\n */\nexport function getPlanFeatureUnit(feature: FeatureLike): string | undefined {\n const ctx = feature.context as { unit?: string } | null | undefined;\n return typeof ctx?.unit === 'string' ? ctx.unit : undefined;\n}\n\n// Trailing name segments that describe the unit/cadence, not the quota\n// itself (e.g. \"fluidgrids.storage.bytes\" → the \"bytes\" segment). Stripped\n// by humanizeQuotaName so the fallback label doesn't end in a redundant\n// technical word.\nconst NAME_SUFFIX_STOPWORDS = new Set([\n 'count',\n 'bytes',\n 'days',\n 'seconds',\n 'hours',\n 'monthly',\n 'daily',\n 'concurrent',\n]);\n\n/**\n * Best-effort human label for a quota that has no seeded `displayName`\n * (older rows only — every quota seeded since BOFF-3058 carries one). Turns\n * \"fluidgrids.scheduled_triggers.count\" into \"Scheduled Triggers\": drops the\n * leading product/boundary segment and a trailing unit/cadence stopword,\n * then title-cases the rest.\n */\nexport function humanizeQuotaName(name: string): string {\n const segments = name.split('.').filter(Boolean);\n const withoutBoundary = segments.length > 1 ? segments.slice(1) : segments;\n const last = withoutBoundary[withoutBoundary.length - 1];\n const meaningful =\n withoutBoundary.length > 1 && last && NAME_SUFFIX_STOPWORDS.has(last)\n ? withoutBoundary.slice(0, -1)\n : withoutBoundary;\n\n const words = meaningful.join(' ').replace(/_/g, ' ').trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return name;\n return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');\n}\n\n/**\n * The name to show a user for a quota: prefers the curated `displayName`\n * seeded on Quota.context (e.g. \"Storage\", \"Team Members\"); falls back to a\n * humanized version of the raw dotted identifier for any quota seeded before\n * displayName was added to the catalog.\n */\nexport function getQuotaDisplayName(feature: FeatureLike): string {\n const quotaContext = feature.quota?.context as { displayName?: string } | null | undefined;\n if (quotaContext && typeof quotaContext.displayName === 'string' && quotaContext.displayName) {\n return quotaContext.displayName;\n }\n\n const rawName = feature.quota?.name;\n return rawName ? humanizeQuotaName(rawName) : 'Unknown Quota';\n}\n"],"mappings":";AAYA,SAAgB,EAAuB,GAA8B;CACnE,IAAM,IAAM,EAAQ;CACpB,IAAI,KAAO,OAAO,EAAI,YAAa,UAAU,OAAO,EAAI;CAExD,IAAM,IAAS,EAAQ,OAAO;CAC9B,OAAO,OAAO,GAAQ,SAAU,WAAW,EAAO,QAAQ;AAC5D;AAQA,SAAgB,EAAmB,GAA0C;CAC3E,IAAM,IAAM,EAAQ;CACpB,OAAO,OAAO,GAAK,QAAS,WAAW,EAAI,OAAO,KAAA;AACpD;AAMA,IAAM,IAAwB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AASD,SAAgB,EAAkB,GAAsB;CACtD,IAAM,IAAW,EAAK,MAAM,GAAG,EAAE,OAAO,OAAO,GACzC,IAAkB,EAAS,SAAS,IAAI,EAAS,MAAM,CAAC,IAAI,GAC5D,IAAO,EAAgB,EAAgB,SAAS,IAMhD,KAJJ,EAAgB,SAAS,KAAK,KAAQ,EAAsB,IAAI,CAAI,IAChE,EAAgB,MAAM,GAAG,EAAE,IAC3B,GAEmB,KAAK,GAAG,EAAE,QAAQ,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;CAExF,OADI,EAAM,WAAW,IAAU,IACxB,EAAM,KAAK,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG;AAC1E;AAQA,SAAgB,EAAoB,GAA8B;CAChE,IAAM,IAAe,EAAQ,OAAO;CACpC,IAAI,KAAgB,OAAO,EAAa,eAAgB,YAAY,EAAa,aAC/E,OAAO,EAAa;CAGtB,IAAM,IAAU,EAAQ,OAAO;CAC/B,OAAO,IAAU,EAAkB,CAAO,IAAI;AAChD"}
|