@withpotter/lib 0.13.0-next.78 → 0.13.0-next.80
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/admin-api.d.ts
CHANGED
|
@@ -143,6 +143,16 @@ export interface PlatformCockpit {
|
|
|
143
143
|
/** @deprecated adds currencies together; use `lifetimeGmvByCurrency`. */
|
|
144
144
|
lifetimeGmv: number;
|
|
145
145
|
lifetimeGmvByCurrency?: CurrencyAmount[];
|
|
146
|
+
/**
|
|
147
|
+
* Platform fees collected on card payments, one row per currency. Absent
|
|
148
|
+
* until the api serves it; the Overview shows no card without it.
|
|
149
|
+
*/
|
|
150
|
+
gatewayFeesByCurrency?: CurrencyAmount[];
|
|
151
|
+
/**
|
|
152
|
+
* Wallets whose business passed KYC / KYB. Absent until the api serves
|
|
153
|
+
* it; the Overview shows no card without it.
|
|
154
|
+
*/
|
|
155
|
+
verifiedWallets?: number;
|
|
146
156
|
};
|
|
147
157
|
sparklines: {
|
|
148
158
|
tenants: number[];
|
package/dist/admin-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/admin-api.ts"],"sourcesContent":["import {\n apiFetch,\n type DashboardStats,\n type FinanceAnalytics,\n type Transaction,\n} from './api';\n\nexport type {\n AccountRow,\n AccountsPage,\n AccountTenantRow,\n AccountSession,\n AccountStage,\n AccountKycStatus,\n TenantTeamMember,\n AccountsAnalytics,\n} from './admin-account-types';\nimport type {\n AccountRow,\n AccountSession,\n AccountStage,\n AccountsPage,\n AccountTenantRow,\n TenantTeamMember,\n AccountsAnalytics,\n} from './admin-account-types';\nimport type { TenantSetup } from './admin-tenant-setup-types';\nimport type { CountryFields } from './admin-country-api';\nimport { tenantsQuery, type TenantListParams } from './admin-tenants-query';\nimport type { AccountOfficer } from './admin-account-officer-api';\nimport type {\n CurrencyAmount,\n CurrencyGmvKpi,\n CurrencyOverdue,\n CurrencyPerformance,\n CurrencyRevenueGmv,\n CurrencyRevenueQuality,\n CurrencySeries,\n CurrencySettlementSummary,\n CurrencyTopTenants,\n CurrencyTotals,\n FinanceByCurrency,\n TenantCurrencyMetrics,\n} from './admin-currency-types';\nexport type * from './admin-currency-types';\n\nexport type { DashboardStats, FinanceAnalytics, Transaction } from './api';\n\n/** A merchant's finance dashboard as the admin API sends it: per currency too. */\nexport type AdminFinanceAnalytics = FinanceAnalytics & FinanceByCurrency;\n\nexport interface TenantTransactionsPage {\n transactions: Transaction[];\n pagination: {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n };\n}\n\n// ============================================\n// PLATFORM ADMIN API (growth cockpit)\n// Cross-tenant aggregates — admin/superadmin only.\n// ============================================\n\nexport interface PlatformOverview {\n tenants: { total: number; active: number; new30d: number; new7d: number };\n accounts: { total: number; new30d: number };\n orders: { total: number; gmv: number; gmv30d: number };\n subscriptions: { active: number; trialing: number };\n growth: { tenantSeries: Array<{ date: string; count: number }> };\n}\n\nexport interface TenantsAnalytics {\n range: { startDate: string; endDate: string };\n totals: {\n tenants: number;\n accounts: number;\n avgTenantsPerAccount: number;\n activeRate: number;\n gmv: number;\n orders: number;\n aov: number;\n gmvInRange: number;\n ordersInRange: number;\n newTenantsInRange: number;\n };\n statusBreakdown: Array<{ status: string; count: number }>;\n industryBreakdown: Array<{ industry: string; count: number }>;\n onboardingSeries: Array<{ date: string; count: number }>;\n performanceSeries: Array<{ date: string; gmv: number; orders: number }>;\n /** Absent until the matching api deploy lands — guard with `?? []`. */\n previousOnboardingSeries?: Array<{ date: string; count: number }>;\n previousPerformanceSeries?: Array<{\n date: string;\n gmv: number;\n orders: number;\n }>;\n topTenants: Array<{\n id: string;\n businessName: string;\n slug: string;\n gmv: number;\n orders: number;\n }>;\n /** @deprecated adds currencies together, not converted. */\n baseCurrency: string;\n /** @deprecated never convert with these. */\n rates: Record<string, number>;\n currencies?: string[];\n totalsByCurrency?: CurrencyTotals[];\n performanceSeriesByCurrency?: CurrencySeries[];\n topTenantsByCurrency?: CurrencyTopTenants[];\n}\n\nexport interface CockpitKpi {\n current: number;\n previous: number;\n pct: number | null;\n}\n\ninterface AttentionTenantRef {\n id: string;\n businessName: string;\n slug: string;\n}\n\nexport interface PlatformCockpit {\n range: { startDate: string; endDate: string };\n // Base currency all monetary figures are expressed in (USD). `rates` maps a\n // currency code to its rate-to-USD, so the client can render figures in a\n // chosen display currency by dividing a USD amount by the target's rate.\n baseCurrency: string;\n rates: Record<string, number>;\n /** Currencies with money in this payload, A→Z. */\n currencies?: string[];\n topTenantsByCurrency?: CurrencyTopTenants[];\n kpis: {\n newTenants: CockpitKpi;\n newAccounts: CockpitKpi;\n /** @deprecated adds currencies together; use `gmvByCurrency`. */\n gmv: CockpitKpi;\n orders: CockpitKpi;\n gmvByCurrency?: CurrencyGmvKpi[];\n };\n totals: {\n totalTenants: number;\n activeTenants: number;\n totalAccounts: number;\n activeSubscriptions: number;\n trialingSubscriptions: number;\n /** @deprecated adds currencies together; use `lifetimeGmvByCurrency`. */\n lifetimeGmv: number;\n lifetimeGmvByCurrency?: CurrencyAmount[];\n };\n sparklines: {\n tenants: number[];\n accounts: number[];\n gmv: number[];\n orders: number[];\n };\n statusBreakdown: Array<{ status: string; count: number }>;\n industryBreakdown: Array<{ industry: string; count: number }>;\n topTenants: Array<{\n id: string;\n businessName: string;\n slug: string;\n gmv: number;\n orders: number;\n }>;\n health?: {\n mrr: number;\n newMrr: number;\n churnedMrr: number;\n netNewMrr: number;\n grossMrrChurnPct: number;\n grossRevenueRetentionPct: number;\n newLogos: number;\n churnedLogos: number;\n netNewLogos: number;\n logoChurnPct: number;\n activePayingLogos: number;\n gmvConcentrationTop10Pct: number;\n };\n performance?: {\n takeRatePct: number | null;\n annualizedGmvRunRate: number;\n gmvPerActiveTenant: number;\n revenuePerActiveTenant: number;\n transactingTenants: number;\n transactingTenantRatePct: number;\n gmvGrowthPct: number | null;\n ordersGrowthPct: number | null;\n netNewLogos: number;\n byCurrency?: CurrencyPerformance[];\n };\n verticals?: Array<{\n industry: string;\n tenants: number;\n gmv: number;\n orders: number;\n aov: number;\n gmvGrowthPct: number | null;\n share: number;\n }>;\n /** GMV/orders across every service Box offers (sell-products, event-tickets, …). */\n salesByService?: Array<{\n service: string;\n merchants: number;\n gmv: number;\n orders: number;\n aov: number;\n gmvGrowthPct: number | null;\n share: number;\n }>;\n activation?: {\n funnel: Array<{ stage: string; count: number }>;\n medianDaysToFirstOrder: number | null;\n activationRatePct: number;\n orderConversionPct: number;\n };\n accounts?: {\n total: number;\n active: number;\n suspended: number;\n verified: number;\n unverifiedEmail: number;\n neverLoggedIn: number;\n dormant: number;\n new: number;\n };\n trend: {\n performanceSeries: Array<{ date: string; gmv: number; orders: number }>;\n onboardingSeries: Array<{ date: string; count: number }>;\n /** Absent until the matching api deploy lands — guard with `?? []`. */\n previousPerformanceSeries?: Array<{\n date: string;\n gmv: number;\n orders: number;\n }>;\n previousOnboardingSeries?: Array<{ date: string; count: number }>;\n performanceSeriesByCurrency?: CurrencySeries[];\n };\n attention: {\n /**\n * Feeds whose query failed; their counts are placeholders, not zeros.\n * Absent when talking to an API that predates this field.\n */\n unavailable?: Array<\n 'needsReview' | 'dormantTenants' | 'overdueInvoices' | 'failedSettlements'\n >;\n trialsEndingSoon: Array<\n AttentionTenantRef & { trialEndsAt: string; daysLeft: number }\n >;\n needsReview: Array<\n AttentionTenantRef & { status: string; createdAt: string }\n >;\n dormantTenants: Array<AttentionTenantRef & { createdAt: string }>;\n overdueInvoices: {\n count: number;\n /** @deprecated adds currencies together; use `totalByCurrency`. */\n total: number;\n totalByCurrency?: CurrencyOverdue[];\n sample: Array<{\n id: string;\n invoiceNumber: string;\n tenantId: string;\n tenantName: string;\n customerName: string | null;\n amountDue: number;\n currency: string;\n dueDate: string | null;\n }>;\n };\n failedSettlements: {\n count: number;\n sample: Array<{\n id: string;\n tenantId: string;\n tenantName: string;\n netAmount: number;\n currency: string;\n createdAt: string;\n }>;\n };\n };\n}\n\nexport interface PlatformRevenue {\n range: { startDate: string; endDate: string };\n currency: string;\n recurring: {\n /** False when no billing source feeds the figures below (all are 0). */\n tracked?: boolean;\n mrr: number;\n arr: number;\n arpa: number;\n activeSubscriptions: number;\n trialingSubscriptions: number;\n pastDueSubscriptions: number;\n nonRenewingSubscriptions: number;\n cancelledSubscriptions: number;\n newInRange: number;\n churnedInRange: number;\n planBreakdown: Array<{\n planId: string;\n name: string;\n interval: string;\n subscribers: number;\n mrr: number;\n }>;\n };\n gmv: {\n lifetime: number;\n inRange: number;\n ordersInRange: number;\n aov: number;\n series: Array<{ date: string; gmv: number; orders: number }>;\n topTenants: Array<{\n id: string;\n businessName: string;\n slug: string;\n gmv: number;\n orders: number;\n }>;\n };\n quality?: {\n quickRatio: number | null;\n nrrPct: number | null;\n expansionMrr: number;\n contractionMrr: number;\n mrrChurnRatePct: number | null;\n logoChurnRatePct: number | null;\n grossGmv: number;\n refundedGmv: number;\n netGmv: number;\n refundRatePct: number;\n refundedOrders: number;\n cohorts: Array<{\n cohort: string;\n size: number;\n retention: Array<number | null>;\n }>;\n gmvByCurrency?: CurrencyRevenueQuality[];\n };\n /** @deprecated never convert with these. */\n rates: Record<string, number>;\n currencies?: string[];\n gmvByCurrency?: CurrencyRevenueGmv[];\n}\n\nexport type TenantStatus = 'active' | 'suspended' | 'pending' | 'deleted';\n\nexport interface TenantRow extends CountryFields {\n id: string;\n slug: string;\n businessName: string;\n status: TenantStatus;\n industryKey: string | null;\n createdAt: string;\n /** The business's contact email (absent on older APIs). */\n email?: string | null;\n phone?: string | null;\n /** The owner's sign-in email. */\n ownerEmail?: string | null;\n /** @deprecated adds currencies together; use `gmvByCurrency`. */\n gmv: number;\n gmvByCurrency?: CurrencyAmount[];\n /** The merchant's account officer (absent on older APIs). */\n accountOfficer?: Pick<AccountOfficer, 'id' | 'name'> | null;\n}\n\nexport interface TenantsPage {\n rows: TenantRow[];\n total: number;\n page: number;\n pageSize: number;\n}\n\nexport interface TenantActivityOrder {\n id: string;\n orderNumber: string;\n total: number;\n currency: string;\n status: string;\n paymentStatus: string;\n customerEmail: string;\n customerName: string | null;\n createdAt: string;\n}\n\nexport interface TenantDetail extends TenantSetup {\n /** Who runs the workspace and how to reach it (absent on older APIs). */\n contact?: { email: string | null; phone: string | null };\n owner?: TenantTeamMember | null;\n team?: TenantTeamMember[];\n /** The admin in charge of this merchant (absent on older APIs). */\n accountOfficer?: AccountOfficer | null;\n id: string;\n slug: string;\n businessName: string;\n status: TenantStatus;\n industryKey: string | null;\n customDomain: string | null;\n createdAt: string;\n chargeBearer: 'merchant' | 'customer';\n currency: string;\n metrics: {\n totalOrders: number;\n paidOrders: number;\n pendingOrders: number;\n gmv: number;\n gmv30d: number;\n gmv7d: number;\n aov: number;\n totalCustomers: number;\n subscriptionStatus: string | null;\n window: {\n startDate: string;\n endDate: string;\n gmv: number;\n orders: number;\n paidOrders: number;\n aov: number;\n customers: number;\n };\n byCurrency?: TenantCurrencyMetrics[];\n };\n /** Currencies with paid orders, A→Z. */\n currencies?: string[];\n revenueSeries: Array<{ date: string; amount: number }>;\n revenueSeriesByCurrency?: Array<{\n currency: string;\n series: Array<{ date: string; amount: number }>;\n }>;\n recentOrders: TenantActivityOrder[];\n}\n\n// ---- Iteration 3: tenant cockpit domains ----\n\nexport interface TenantCustomer {\n id: string;\n email: string;\n phone: string | null;\n name: string | null;\n type: string;\n source: string | null;\n status: string;\n emailVerified: boolean;\n totalOrders: number;\n totalSpent: number;\n lastOrderAt: string | null;\n createdAt: string;\n}\n\nexport interface TenantCustomersPage {\n members: TenantCustomer[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface TenantProduct {\n id: string;\n type: string;\n slug: string;\n title: string;\n category: string | null;\n tags: string[];\n featured: boolean;\n isActive: boolean;\n image?: { url: string } | null;\n price: number | null;\n compareAtPrice: number | null;\n currency: string | null;\n trackInventory: boolean;\n quantity: number | null;\n reserved: number | null;\n lowStockThreshold: number | null;\n createdAt: string;\n}\n\nexport interface TenantProductStats {\n total: number;\n active: number;\n featured: number;\n lowStock: number;\n outOfStock: number;\n}\n\nexport interface TenantProductsData {\n items: TenantProduct[];\n total: number;\n stats: TenantProductStats;\n}\n\nexport interface ProductRef {\n id: string;\n title: string;\n}\n\nexport interface SellerRow {\n id: string;\n title: string;\n units: number;\n revenue: number;\n}\n\nexport interface CategorySlice {\n category: string;\n count: number;\n value: number;\n}\n\nexport interface ProductInsights {\n currency: string;\n totalProducts: number;\n activeProducts: number;\n featuredProducts: number;\n lowStock: number;\n outOfStock: number;\n trackedProducts: number;\n catalogValue: number;\n inventoryValue: number;\n inventoryAtRiskValue: number;\n avgPrice: number;\n medianPrice: number;\n totalUnitsSold: number;\n totalRevenue: number;\n pctEverSold: number;\n deadStock: number;\n newestProduct: (ProductRef & { createdAt: string }) | null;\n lastUpdatedProduct: (ProductRef & { updatedAt: string }) | null;\n categories: CategorySlice[];\n bestSellers: SellerRow[];\n worstSellers: SellerRow[];\n featuredSellThrough: {\n featuredTotal: number;\n featuredSold: number;\n featuredUnits: number;\n nonFeaturedTotal: number;\n nonFeaturedSold: number;\n nonFeaturedUnits: number;\n };\n unitsSeries: Array<{ date: string; count: number }>;\n}\n\nexport interface SpenderRow {\n id: string;\n name: string | null;\n email: string;\n totalSpent: number;\n totalOrders: number;\n}\n\nexport interface BreakdownSlice {\n label: string;\n count: number;\n}\n\nexport interface CustomerInsights {\n currency: string;\n totalCustomers: number;\n newCustomers30d: number;\n payingCustomers: number;\n repeatCustomers: number;\n repeatRate: number;\n dormantCustomers: number;\n marketingOptInRate: number;\n lifetimeValue: number;\n avgSpendPerCustomer: number;\n avgOrdersPerCustomer: number;\n avgOrderValue: number;\n topSpenders: SpenderRow[];\n bySource: BreakdownSlice[];\n byType: BreakdownSlice[];\n signupsSeries: Array<{ date: string; count: number }>;\n}\n\nexport interface TenantInvoice {\n id: string;\n invoiceNumber: string;\n status: string;\n customerEmail: string | null;\n customerName: string | null;\n total: number;\n amountPaid: number;\n amountDue: number;\n currency: string;\n dueDate: string | null;\n createdAt: string;\n}\n\nexport interface TenantInvoiceStats {\n draft: number;\n sent: number;\n paid: number;\n overdue: number;\n cancelled: number;\n total: number;\n totalRevenue: number;\n totalOutstanding: number;\n}\n\nexport interface TenantInvoicesData {\n invoices: TenantInvoice[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n stats: TenantInvoiceStats;\n}\n\nexport interface TenantLoyaltyProgram {\n id: string;\n name: string;\n pointsName: string;\n pointsPerCurrency: number;\n currencyPerPoint: number;\n isActive: boolean;\n tiers?: Array<{ id: string; name: string; threshold: number }>;\n earnRules?: Array<{ id: string; name: string; points: number }>;\n}\n\nexport interface TenantLoyaltyStats {\n totalMembers: number;\n totalPointsIssued: number;\n totalPointsRedeemed: number;\n activeMembers: number;\n programActive: boolean;\n}\n\nexport interface TenantLoyaltyData {\n program: TenantLoyaltyProgram | null;\n stats: TenantLoyaltyStats;\n}\n\nexport interface TenantDiscount {\n id: string;\n name: string;\n code: string;\n discountType: string;\n value: number;\n maxDiscountAmount: number | null;\n startsAt: string | null;\n endsAt: string | null;\n usageLimit: number | null;\n usageCount: number;\n status: string;\n autoApply: boolean;\n isValid: boolean;\n isExpired: boolean;\n createdAt: string;\n}\n\nexport interface TenantDiscountsPage {\n discounts: TenantDiscount[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface TenantSettlement {\n id: string;\n grossAmount: number;\n paystackFee: number;\n platformFee: number;\n netAmount: number;\n currency: string;\n status: string;\n settlementType: string;\n bankAccount?: { bankName: string; accountNumber: string } | null;\n settledAt: string | null;\n createdAt: string;\n}\n\nexport interface TenantSettlementSummary {\n totalSettled: number;\n totalPending: number;\n totalFailed: number;\n count: number;\n platformFeesCollected: number;\n currency: string;\n currencies?: string[];\n byCurrency?: CurrencySettlementSummary[];\n}\n\nexport interface TenantBankAccount {\n id: string;\n bankCode: string;\n bankName: string;\n accountNumber: string;\n accountName: string;\n splitPercentage: number | null;\n status: string;\n isDefault: boolean;\n /** Paystack subaccount code (ACCT_…). */\n subaccountCode?: string | null;\n failureReason?: string | null;\n createdAt: string;\n}\n\nexport interface TenantSettlementsData {\n settlements: TenantSettlement[];\n total: number;\n page: number;\n limit: number;\n summary: TenantSettlementSummary;\n bankAccounts: TenantBankAccount[];\n}\n\nexport interface TenantSubscriptionPlan {\n id: string;\n name: string;\n interval: string;\n amount: number;\n currency: string;\n}\n\nexport interface TenantSubscription {\n id: string;\n planId: string;\n customerId: string;\n customerEmail: string;\n status: string;\n amount: number;\n currency: string;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n nextPaymentDate: string | null;\n cancelledAt: string | null;\n paymentsCount: number;\n createdAt: string;\n plan?: TenantSubscriptionPlan | null;\n customer?: { id: string; name: string | null; email: string } | null;\n}\n\nexport interface TenantSubscriptionStats {\n totalActive: number;\n totalNonRenewing: number;\n totalCancelled: number;\n monthlyRecurringRevenue: number;\n}\n\nexport interface TenantSubscriptionsData {\n subscriptions: TenantSubscription[];\n total: number;\n page: number;\n limit: number;\n stats: TenantSubscriptionStats;\n}\n\nexport interface AdminsAnalytics {\n range: { startDate: string; endDate: string };\n totals: {\n admins: number;\n active: number;\n suspended: number;\n superadmins: number;\n standardAdmins: number;\n neverLoggedIn: number;\n activeInRange: number;\n actionsInRange: number;\n };\n roleBreakdown: Array<{ role: string; count: number }>;\n statusBreakdown: Array<{ status: string; count: number }>;\n activitySeries: Array<{ date: string; count: number }>;\n topActions: Array<{ action: string; count: number }>;\n recentActivity: Array<{\n id: string;\n adminEmail: string | null;\n action: string;\n targetType: string | null;\n createdAt: string;\n }>;\n}\n\nexport interface AdminSession {\n id: string;\n email: string;\n name: string | null;\n role: 'admin' | 'superadmin';\n permissions: string[];\n mustChangePassword: boolean;\n}\n\nexport interface AdminLoginCodeRequired {\n codeRequired: true;\n challengeId: string;\n /** The address the code went to, masked: `a***@gmail.com`. */\n sentTo: string;\n}\n\nexport type AdminLoginAnswer =\n | AdminLoginCodeRequired\n | {\n codeRequired?: undefined;\n mustChangePassword: boolean;\n admin: Omit<AdminSession, 'permissions'>;\n };\n\nexport const platformAdminApi = {\n /**\n * Password step. A box that emails sign-in codes answers `codeRequired` and\n * sets no session yet; finish with `verifyLoginCode`.\n */\n login: (email: string, password: string) =>\n apiFetch<AdminLoginAnswer>('/platform-admin/v1/auth/login', {\n method: 'POST',\n body: JSON.stringify({ email, password }),\n }),\n verifyLoginCode: (challengeId: string, code: string) =>\n apiFetch<{\n mustChangePassword: boolean;\n admin: Omit<AdminSession, 'permissions'>;\n }>('/platform-admin/v1/auth/login/verify', {\n method: 'POST',\n body: JSON.stringify({ challengeId, code }),\n }),\n resendLoginCode: (challengeId: string) =>\n apiFetch<AdminLoginCodeRequired>('/platform-admin/v1/auth/login/resend', {\n method: 'POST',\n body: JSON.stringify({ challengeId }),\n }),\n logout: () =>\n apiFetch<{ success: boolean }>('/platform-admin/v1/auth/logout', {\n method: 'POST',\n }),\n me: () => apiFetch<AdminSession>('/platform-admin/v1/auth/me'),\n changePassword: (currentPassword: string, newPassword: string) =>\n apiFetch<{ success: boolean }>('/platform-admin/v1/auth/change-password', {\n method: 'POST',\n body: JSON.stringify({ currentPassword, newPassword }),\n }),\n overview: () => apiFetch<PlatformOverview>('/platform-admin/v1/overview'),\n cockpit: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<PlatformCockpit>(\n `/platform-admin/v1/overview/cockpit${q ? `?${q}` : ''}`,\n );\n },\n revenue: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<PlatformRevenue>(\n `/platform-admin/v1/overview/revenue${q ? `?${q}` : ''}`,\n );\n },\n tenantsAnalytics: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<TenantsAnalytics>(\n `/platform-admin/v1/overview/tenants-analytics${q ? `?${q}` : ''}`,\n );\n },\n tenants: (params: TenantListParams = {}) =>\n apiFetch<TenantsPage>(`/platform-admin/v1/tenants${tenantsQuery(params)}`),\n tenant: (\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n if (range.endDate) qs.set('endDate', range.endDate);\n const query = qs.toString();\n return apiFetch<TenantDetail>(\n `/platform-admin/v1/tenants/${id}${query ? `?${query}` : ''}`,\n );\n },\n tenantAnalytics: (\n id: string,\n range: { startDate?: string; endDate?: string; limit?: number } = {},\n ) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n if (range.endDate) qs.set('endDate', range.endDate);\n if (range.limit) qs.set('limit', String(range.limit));\n const query = qs.toString();\n return apiFetch<DashboardStats>(\n `/platform-admin/v1/tenants/${id}/analytics${query ? `?${query}` : ''}`,\n );\n },\n tenantFinance: (\n id: string,\n range: { startDate?: string; endDate?: string; period?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n if (range.endDate) qs.set('endDate', range.endDate);\n if (range.period) qs.set('period', range.period);\n const query = qs.toString();\n return apiFetch<AdminFinanceAnalytics>(\n `/platform-admin/v1/tenants/${id}/finance${query ? `?${query}` : ''}`,\n );\n },\n tenantTransactions: (\n id: string,\n params: {\n status?: string;\n type?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.type) qs.set('type', params.type);\n if (params.search) qs.set('search', params.search);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantTransactionsPage>(\n `/platform-admin/v1/tenants/${id}/transactions${\n query ? `?${query}` : ''\n }`,\n );\n },\n tenantCustomers: (\n id: string,\n params: {\n search?: string;\n type?: string;\n status?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.search) qs.set('search', params.search);\n if (params.type) qs.set('type', params.type);\n if (params.status) qs.set('status', params.status);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantCustomersPage>(\n `/platform-admin/v1/tenants/${id}/customers${query ? `?${query}` : ''}`,\n );\n },\n tenantProducts: (\n id: string,\n params: { type?: string; search?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.type) qs.set('type', params.type);\n if (params.search) qs.set('search', params.search);\n const query = qs.toString();\n return apiFetch<TenantProductsData>(\n `/platform-admin/v1/tenants/${id}/products${query ? `?${query}` : ''}`,\n );\n },\n tenantProductInsights: (id: string, range: { startDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n const query = qs.toString();\n return apiFetch<ProductInsights>(\n `/platform-admin/v1/tenants/${id}/products/insights${\n query ? `?${query}` : ''\n }`,\n );\n },\n tenantCustomerInsights: (id: string, range: { startDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n const query = qs.toString();\n return apiFetch<CustomerInsights>(\n `/platform-admin/v1/tenants/${id}/customers/insights${\n query ? `?${query}` : ''\n }`,\n );\n },\n tenantInvoices: (\n id: string,\n params: {\n status?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.search) qs.set('search', params.search);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantInvoicesData>(\n `/platform-admin/v1/tenants/${id}/invoices${query ? `?${query}` : ''}`,\n );\n },\n tenantLoyalty: (id: string) =>\n apiFetch<TenantLoyaltyData>(`/platform-admin/v1/tenants/${id}/loyalty`),\n tenantDiscounts: (\n id: string,\n params: {\n status?: string;\n discountType?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.discountType) qs.set('discountType', params.discountType);\n if (params.search) qs.set('search', params.search);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantDiscountsPage>(\n `/platform-admin/v1/tenants/${id}/discounts${query ? `?${query}` : ''}`,\n );\n },\n tenantSettlements: (\n id: string,\n params: {\n page?: number;\n limit?: number;\n startDate?: string;\n endDate?: string;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const query = qs.toString();\n return apiFetch<TenantSettlementsData>(\n `/platform-admin/v1/tenants/${id}/settlements${query ? `?${query}` : ''}`,\n );\n },\n tenantSubscriptions: (\n id: string,\n params: {\n status?: string;\n planId?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.planId) qs.set('planId', params.planId);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantSubscriptionsData>(\n `/platform-admin/v1/tenants/${id}/subscriptions${\n query ? `?${query}` : ''\n }`,\n );\n },\n setTenantStatus: (id: string, status: TenantStatus) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/tenants/${id}/status`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n }),\n accounts: (\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n joinedFrom?: string;\n joinedTo?: string;\n stage?: AccountStage;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.page) qs.set('page', String(params.page));\n if (params.pageSize) qs.set('pageSize', String(params.pageSize));\n if (params.search) qs.set('search', params.search);\n if (params.joinedFrom) qs.set('joinedFrom', params.joinedFrom);\n if (params.joinedTo) qs.set('joinedTo', params.joinedTo);\n if (params.stage) qs.set('stage', params.stage);\n const query = qs.toString();\n return apiFetch<AccountsPage>(\n `/platform-admin/v1/accounts${query ? `?${query}` : ''}`,\n );\n },\n accountsAnalytics: (\n params: { startDate?: string; endDate?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<AccountsAnalytics>(\n `/platform-admin/v1/accounts/analytics${q ? `?${q}` : ''}`,\n );\n },\n setAccountStatus: (id: string, status: string) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/accounts/${id}/status`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n }),\n verifyAccount: (id: string) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/accounts/${id}/verify`, {\n method: 'POST',\n }),\n accountSessions: (id: string) =>\n apiFetch<AccountSession[]>(`/platform-admin/v1/accounts/${id}/sessions`),\n accountTenants: (id: string) =>\n apiFetch<AccountTenantRow[]>(`/platform-admin/v1/accounts/${id}/tenants`),\n impersonateAccount: (id: string) =>\n apiFetch<{ success: boolean }>(\n `/platform-admin/v1/accounts/${id}/impersonate`,\n { method: 'POST' },\n ),\n admins: () => apiFetch<AdminRow[]>('/platform-admin/v1/admins'),\n adminsAnalytics: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<AdminsAnalytics>(\n `/platform-admin/v1/admins/analytics${q ? `?${q}` : ''}`,\n );\n },\n adminPermissions: () =>\n apiFetch<string[]>('/platform-admin/v1/admins/permissions'),\n inviteAdmin: (\n email: string,\n role: 'admin' | 'superadmin',\n permissions: string[] = [],\n roleIds: string[] = [],\n ) =>\n apiFetch<{ email: string; tempPassword: string }>(\n '/platform-admin/v1/admins',\n {\n method: 'POST',\n body: JSON.stringify({ email, role, permissions, roleIds }),\n },\n ),\n setAdminStatus: (id: string, status: 'active' | 'suspended') =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/admins/${id}/status`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n }),\n setAdminPermissions: (id: string, permissions: string[]) =>\n apiFetch<{ success: boolean }>(\n `/platform-admin/v1/admins/${id}/permissions`,\n { method: 'PATCH', body: JSON.stringify({ permissions }) },\n ),\n setAdminRoles: (id: string, roleIds: string[]) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/admins/${id}/roles`, {\n method: 'PATCH',\n body: JSON.stringify({ roleIds }),\n }),\n resetAdminPassword: (id: string) =>\n apiFetch<{ tempPassword: string }>(\n `/platform-admin/v1/admins/${id}/reset-password`,\n { method: 'POST' },\n ),\n roles: () => apiFetch<RoleRow[]>('/platform-admin/v1/roles'),\n createRole: (name: string, permissions: string[], description?: string) =>\n apiFetch<RoleRow>('/platform-admin/v1/roles', {\n method: 'POST',\n body: JSON.stringify({ name, permissions, description }),\n }),\n updateRole: (\n id: string,\n data: { name?: string; permissions?: string[]; description?: string },\n ) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/roles/${id}`, {\n method: 'PATCH',\n body: JSON.stringify(data),\n }),\n deleteRole: (id: string) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/roles/${id}`, {\n method: 'DELETE',\n }),\n audit: (\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n action?: string;\n adminEmail?: string;\n from?: string;\n to?: string;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.page) qs.set('page', String(params.page));\n if (params.pageSize) qs.set('pageSize', String(params.pageSize));\n if (params.search) qs.set('search', params.search);\n if (params.action) qs.set('action', params.action);\n if (params.adminEmail) qs.set('adminEmail', params.adminEmail);\n if (params.from) qs.set('from', params.from);\n if (params.to) qs.set('to', params.to);\n const q = qs.toString();\n return apiFetch<AuditPage>(`/platform-admin/v1/audit${q ? `?${q}` : ''}`);\n },\n auditAnalytics: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<AuditAnalytics>(\n `/platform-admin/v1/audit/analytics${q ? `?${q}` : ''}`,\n );\n },\n};\n\nexport interface AdminRow {\n id: string;\n email: string;\n name: string | null;\n role: 'admin' | 'superadmin';\n status: 'active' | 'suspended';\n permissions: string[];\n roleIds: string[];\n mustChangePassword: boolean;\n lastLoginAt: string | null;\n createdAt: string;\n}\n\nexport interface RoleRow {\n id: string;\n key: string;\n name: string;\n description: string | null;\n permissions: string[];\n isSystem: boolean;\n assignedCount: number;\n}\n\nexport interface AuditRow {\n id: string;\n /** Who did it, by name. Absent from an engine that does not send it, or when the admin has none. */\n adminName?: string | null;\n adminEmail: string | null;\n action: string;\n targetType: string | null;\n targetId: string | null;\n metadata: Record<string, unknown>;\n ipAddress: string | null;\n /** The browser or tool the action came from. Absent from an engine that does not send it. */\n userAgent?: string | null;\n createdAt: string;\n}\n\nexport interface AuditPage {\n rows: AuditRow[];\n total: number;\n page: number;\n pageSize: number;\n}\nexport interface AuditAnalytics {\n range: { startDate: string; endDate: string };\n totals: {\n actions: number;\n activeAdmins: number;\n actionTypes: number;\n topAction: string | null;\n };\n actionSeries: Array<{ date: string; count: number }>;\n actionBreakdown: Array<{ action: string; count: number }>;\n adminBreakdown: Array<{ adminEmail: string; count: number }>;\n targetBreakdown: Array<{ targetType: string; count: number }>;\n}\n"],"mappings":"AAAA;AAAA,EACE;AAAA,OAIK;AAuBP,SAAS,oBAA2C;AAwwB7C,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK9B,OAAO,CAAC,OAAe,aACrB,SAA2B,iCAAiC;AAAA,IAC1D,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,EAC1C,CAAC;AAAA,EACH,iBAAiB,CAAC,aAAqB,SACrC,SAGG,wCAAwC;AAAA,IACzC,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,aAAa,KAAK,CAAC;AAAA,EAC5C,CAAC;AAAA,EACH,iBAAiB,CAAC,gBAChB,SAAiC,wCAAwC;AAAA,IACvE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,YAAY,CAAC;AAAA,EACtC,CAAC;AAAA,EACH,QAAQ,MACN,SAA+B,kCAAkC;AAAA,IAC/D,QAAQ;AAAA,EACV,CAAC;AAAA,EACH,IAAI,MAAM,SAAuB,4BAA4B;AAAA,EAC7D,gBAAgB,CAAC,iBAAyB,gBACxC,SAA+B,2CAA2C;AAAA,IACxE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,iBAAiB,YAAY,CAAC;AAAA,EACvD,CAAC;AAAA,EACH,UAAU,MAAM,SAA2B,6BAA6B;AAAA,EACxE,SAAS,CAAC,SAAmD,CAAC,MAAM;AAClE,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO;AAAA,MACL,sCAAsC,IAAI,IAAI,CAAC,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EACA,SAAS,CAAC,SAAmD,CAAC,MAAM;AAClE,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO;AAAA,MACL,sCAAsC,IAAI,IAAI,CAAC,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EACA,kBAAkB,CAAC,SAAmD,CAAC,MAAM;AAC3E,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO;AAAA,MACL,gDAAgD,IAAI,IAAI,CAAC,KAAK,EAAE;AAAA,IAClE;AAAA,EACF;AAAA,EACA,SAAS,CAAC,SAA2B,CAAC,MACpC,SAAsB,6BAA6B,aAAa,MAAM,CAAC,EAAE;AAAA,EAC3E,QAAQ,CACN,IACA,QAAkD,CAAC,MAChD;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,MAAM,UAAW,IAAG,IAAI,aAAa,MAAM,SAAS;AACxD,QAAI,MAAM,QAAS,IAAG,IAAI,WAAW,MAAM,OAAO;AAClD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,GAAG,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,iBAAiB,CACf,IACA,QAAkE,CAAC,MAChE;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,MAAM,UAAW,IAAG,IAAI,aAAa,MAAM,SAAS;AACxD,QAAI,MAAM,QAAS,IAAG,IAAI,WAAW,MAAM,OAAO;AAClD,QAAI,MAAM,MAAO,IAAG,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACpD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,aAAa,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACvE;AAAA,EACF;AAAA,EACA,eAAe,CACb,IACA,QAAmE,CAAC,MACjE;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,MAAM,UAAW,IAAG,IAAI,aAAa,MAAM,SAAS;AACxD,QAAI,MAAM,QAAS,IAAG,IAAI,WAAW,MAAM,OAAO;AAClD,QAAI,MAAM,OAAQ,IAAG,IAAI,UAAU,MAAM,MAAM;AAC/C,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,WAAW,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACrE;AAAA,EACF;AAAA,EACA,oBAAoB,CAClB,IACA,SAMI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,IAAI;AAC3C,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AACtD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,gBAC9B,QAAQ,IAAI,KAAK,KAAK,EACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,iBAAiB,CACf,IACA,SAMI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,IAAI;AAC3C,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AACtD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,aAAa,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACvE;AAAA,EACF;AAAA,EACA,gBAAgB,CACd,IACA,SAA6C,CAAC,MAC3C;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,IAAI;AAC3C,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,YAAY,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACtE;AAAA,EACF;AAAA,EACA,uBAAuB,CAAC,IAAY,QAAgC,CAAC,MAAM;AACzE,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,MAAM,UAAW,IAAG,IAAI,aAAa,MAAM,SAAS;AACxD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,qBAC9B,QAAQ,IAAI,KAAK,KAAK,EACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,wBAAwB,CAAC,IAAY,QAAgC,CAAC,MAAM;AAC1E,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,MAAM,UAAW,IAAG,IAAI,aAAa,MAAM,SAAS;AACxD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,sBAC9B,QAAQ,IAAI,KAAK,KAAK,EACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,gBAAgB,CACd,IACA,SAKI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AACtD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,YAAY,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACtE;AAAA,EACF;AAAA,EACA,eAAe,CAAC,OACd,SAA4B,8BAA8B,EAAE,UAAU;AAAA,EACxE,iBAAiB,CACf,IACA,SAMI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,aAAc,IAAG,IAAI,gBAAgB,OAAO,YAAY;AACnE,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AACtD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,aAAa,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACvE;AAAA,EACF;AAAA,EACA,mBAAmB,CACjB,IACA,SAKI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AACtD,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,eAAe,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACzE;AAAA,EACF;AAAA,EACA,qBAAqB,CACnB,IACA,SAKI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AACtD,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,EAAE,iBAC9B,QAAQ,IAAI,KAAK,KAAK,EACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,iBAAiB,CAAC,IAAY,WAC5B,SAA+B,8BAA8B,EAAE,WAAW;AAAA,IACxE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,EACjC,CAAC;AAAA,EACH,UAAU,CACR,SAOI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,SAAU,IAAG,IAAI,YAAY,OAAO,OAAO,QAAQ,CAAC;AAC/D,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,WAAY,IAAG,IAAI,cAAc,OAAO,UAAU;AAC7D,QAAI,OAAO,SAAU,IAAG,IAAI,YAAY,OAAO,QAAQ;AACvD,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,KAAK;AAC9C,UAAM,QAAQ,GAAG,SAAS;AAC1B,WAAO;AAAA,MACL,8BAA8B,QAAQ,IAAI,KAAK,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EACA,mBAAmB,CACjB,SAAmD,CAAC,MACjD;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO;AAAA,MACL,wCAAwC,IAAI,IAAI,CAAC,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AAAA,EACA,kBAAkB,CAAC,IAAY,WAC7B,SAA+B,+BAA+B,EAAE,WAAW;AAAA,IACzE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,EACjC,CAAC;AAAA,EACH,eAAe,CAAC,OACd,SAA+B,+BAA+B,EAAE,WAAW;AAAA,IACzE,QAAQ;AAAA,EACV,CAAC;AAAA,EACH,iBAAiB,CAAC,OAChB,SAA2B,+BAA+B,EAAE,WAAW;AAAA,EACzE,gBAAgB,CAAC,OACf,SAA6B,+BAA+B,EAAE,UAAU;AAAA,EAC1E,oBAAoB,CAAC,OACnB;AAAA,IACE,+BAA+B,EAAE;AAAA,IACjC,EAAE,QAAQ,OAAO;AAAA,EACnB;AAAA,EACF,QAAQ,MAAM,SAAqB,2BAA2B;AAAA,EAC9D,iBAAiB,CAAC,SAAmD,CAAC,MAAM;AAC1E,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO;AAAA,MACL,sCAAsC,IAAI,IAAI,CAAC,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EACA,kBAAkB,MAChB,SAAmB,uCAAuC;AAAA,EAC5D,aAAa,CACX,OACA,MACA,cAAwB,CAAC,GACzB,UAAoB,CAAC,MAErB;AAAA,IACE;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,OAAO,MAAM,aAAa,QAAQ,CAAC;AAAA,IAC5D;AAAA,EACF;AAAA,EACF,gBAAgB,CAAC,IAAY,WAC3B,SAA+B,6BAA6B,EAAE,WAAW;AAAA,IACvE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,EACjC,CAAC;AAAA,EACH,qBAAqB,CAAC,IAAY,gBAChC;AAAA,IACE,6BAA6B,EAAE;AAAA,IAC/B,EAAE,QAAQ,SAAS,MAAM,KAAK,UAAU,EAAE,YAAY,CAAC,EAAE;AAAA,EAC3D;AAAA,EACF,eAAe,CAAC,IAAY,YAC1B,SAA+B,6BAA6B,EAAE,UAAU;AAAA,IACtE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,EAClC,CAAC;AAAA,EACH,oBAAoB,CAAC,OACnB;AAAA,IACE,6BAA6B,EAAE;AAAA,IAC/B,EAAE,QAAQ,OAAO;AAAA,EACnB;AAAA,EACF,OAAO,MAAM,SAAoB,0BAA0B;AAAA,EAC3D,YAAY,CAAC,MAAc,aAAuB,gBAChD,SAAkB,4BAA4B;AAAA,IAC5C,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,MAAM,aAAa,YAAY,CAAC;AAAA,EACzD,CAAC;AAAA,EACH,YAAY,CACV,IACA,SAEA,SAA+B,4BAA4B,EAAE,IAAI;AAAA,IAC/D,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AAAA,EACH,YAAY,CAAC,OACX,SAA+B,4BAA4B,EAAE,IAAI;AAAA,IAC/D,QAAQ;AAAA,EACV,CAAC;AAAA,EACH,OAAO,CACL,SAQI,CAAC,MACF;AACH,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,OAAO,IAAI,CAAC;AACnD,QAAI,OAAO,SAAU,IAAG,IAAI,YAAY,OAAO,OAAO,QAAQ,CAAC;AAC/D,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,OAAQ,IAAG,IAAI,UAAU,OAAO,MAAM;AACjD,QAAI,OAAO,WAAY,IAAG,IAAI,cAAc,OAAO,UAAU;AAC7D,QAAI,OAAO,KAAM,IAAG,IAAI,QAAQ,OAAO,IAAI;AAC3C,QAAI,OAAO,GAAI,IAAG,IAAI,MAAM,OAAO,EAAE;AACrC,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO,SAAoB,2BAA2B,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE;AAAA,EAC1E;AAAA,EACA,gBAAgB,CAAC,SAAmD,CAAC,MAAM;AACzE,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,UAAW,IAAG,IAAI,aAAa,OAAO,SAAS;AAC1D,QAAI,OAAO,QAAS,IAAG,IAAI,WAAW,OAAO,OAAO;AACpD,UAAM,IAAI,GAAG,SAAS;AACtB,WAAO;AAAA,MACL,qCAAqC,IAAI,IAAI,CAAC,KAAK,EAAE;AAAA,IACvD;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/admin-api.ts"],"sourcesContent":["import {\n apiFetch,\n type DashboardStats,\n type FinanceAnalytics,\n type Transaction,\n} from './api';\n\nexport type {\n AccountRow,\n AccountsPage,\n AccountTenantRow,\n AccountSession,\n AccountStage,\n AccountKycStatus,\n TenantTeamMember,\n AccountsAnalytics,\n} from './admin-account-types';\nimport type {\n AccountRow,\n AccountSession,\n AccountStage,\n AccountsPage,\n AccountTenantRow,\n TenantTeamMember,\n AccountsAnalytics,\n} from './admin-account-types';\nimport type { TenantSetup } from './admin-tenant-setup-types';\nimport type { CountryFields } from './admin-country-api';\nimport { tenantsQuery, type TenantListParams } from './admin-tenants-query';\nimport type { AccountOfficer } from './admin-account-officer-api';\nimport type {\n CurrencyAmount,\n CurrencyGmvKpi,\n CurrencyOverdue,\n CurrencyPerformance,\n CurrencyRevenueGmv,\n CurrencyRevenueQuality,\n CurrencySeries,\n CurrencySettlementSummary,\n CurrencyTopTenants,\n CurrencyTotals,\n FinanceByCurrency,\n TenantCurrencyMetrics,\n} from './admin-currency-types';\nexport type * from './admin-currency-types';\n\nexport type { DashboardStats, FinanceAnalytics, Transaction } from './api';\n\n/** A merchant's finance dashboard as the admin API sends it: per currency too. */\nexport type AdminFinanceAnalytics = FinanceAnalytics & FinanceByCurrency;\n\nexport interface TenantTransactionsPage {\n transactions: Transaction[];\n pagination: {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n };\n}\n\n// ============================================\n// PLATFORM ADMIN API (growth cockpit)\n// Cross-tenant aggregates — admin/superadmin only.\n// ============================================\n\nexport interface PlatformOverview {\n tenants: { total: number; active: number; new30d: number; new7d: number };\n accounts: { total: number; new30d: number };\n orders: { total: number; gmv: number; gmv30d: number };\n subscriptions: { active: number; trialing: number };\n growth: { tenantSeries: Array<{ date: string; count: number }> };\n}\n\nexport interface TenantsAnalytics {\n range: { startDate: string; endDate: string };\n totals: {\n tenants: number;\n accounts: number;\n avgTenantsPerAccount: number;\n activeRate: number;\n gmv: number;\n orders: number;\n aov: number;\n gmvInRange: number;\n ordersInRange: number;\n newTenantsInRange: number;\n };\n statusBreakdown: Array<{ status: string; count: number }>;\n industryBreakdown: Array<{ industry: string; count: number }>;\n onboardingSeries: Array<{ date: string; count: number }>;\n performanceSeries: Array<{ date: string; gmv: number; orders: number }>;\n /** Absent until the matching api deploy lands — guard with `?? []`. */\n previousOnboardingSeries?: Array<{ date: string; count: number }>;\n previousPerformanceSeries?: Array<{\n date: string;\n gmv: number;\n orders: number;\n }>;\n topTenants: Array<{\n id: string;\n businessName: string;\n slug: string;\n gmv: number;\n orders: number;\n }>;\n /** @deprecated adds currencies together, not converted. */\n baseCurrency: string;\n /** @deprecated never convert with these. */\n rates: Record<string, number>;\n currencies?: string[];\n totalsByCurrency?: CurrencyTotals[];\n performanceSeriesByCurrency?: CurrencySeries[];\n topTenantsByCurrency?: CurrencyTopTenants[];\n}\n\nexport interface CockpitKpi {\n current: number;\n previous: number;\n pct: number | null;\n}\n\ninterface AttentionTenantRef {\n id: string;\n businessName: string;\n slug: string;\n}\n\nexport interface PlatformCockpit {\n range: { startDate: string; endDate: string };\n // Base currency all monetary figures are expressed in (USD). `rates` maps a\n // currency code to its rate-to-USD, so the client can render figures in a\n // chosen display currency by dividing a USD amount by the target's rate.\n baseCurrency: string;\n rates: Record<string, number>;\n /** Currencies with money in this payload, A→Z. */\n currencies?: string[];\n topTenantsByCurrency?: CurrencyTopTenants[];\n kpis: {\n newTenants: CockpitKpi;\n newAccounts: CockpitKpi;\n /** @deprecated adds currencies together; use `gmvByCurrency`. */\n gmv: CockpitKpi;\n orders: CockpitKpi;\n gmvByCurrency?: CurrencyGmvKpi[];\n };\n totals: {\n totalTenants: number;\n activeTenants: number;\n totalAccounts: number;\n activeSubscriptions: number;\n trialingSubscriptions: number;\n /** @deprecated adds currencies together; use `lifetimeGmvByCurrency`. */\n lifetimeGmv: number;\n lifetimeGmvByCurrency?: CurrencyAmount[];\n /**\n * Platform fees collected on card payments, one row per currency. Absent\n * until the api serves it; the Overview shows no card without it.\n */\n gatewayFeesByCurrency?: CurrencyAmount[];\n /**\n * Wallets whose business passed KYC / KYB. Absent until the api serves\n * it; the Overview shows no card without it.\n */\n verifiedWallets?: number;\n };\n sparklines: {\n tenants: number[];\n accounts: number[];\n gmv: number[];\n orders: number[];\n };\n statusBreakdown: Array<{ status: string; count: number }>;\n industryBreakdown: Array<{ industry: string; count: number }>;\n topTenants: Array<{\n id: string;\n businessName: string;\n slug: string;\n gmv: number;\n orders: number;\n }>;\n health?: {\n mrr: number;\n newMrr: number;\n churnedMrr: number;\n netNewMrr: number;\n grossMrrChurnPct: number;\n grossRevenueRetentionPct: number;\n newLogos: number;\n churnedLogos: number;\n netNewLogos: number;\n logoChurnPct: number;\n activePayingLogos: number;\n gmvConcentrationTop10Pct: number;\n };\n performance?: {\n takeRatePct: number | null;\n annualizedGmvRunRate: number;\n gmvPerActiveTenant: number;\n revenuePerActiveTenant: number;\n transactingTenants: number;\n transactingTenantRatePct: number;\n gmvGrowthPct: number | null;\n ordersGrowthPct: number | null;\n netNewLogos: number;\n byCurrency?: CurrencyPerformance[];\n };\n verticals?: Array<{\n industry: string;\n tenants: number;\n gmv: number;\n orders: number;\n aov: number;\n gmvGrowthPct: number | null;\n share: number;\n }>;\n /** GMV/orders across every service Box offers (sell-products, event-tickets, …). */\n salesByService?: Array<{\n service: string;\n merchants: number;\n gmv: number;\n orders: number;\n aov: number;\n gmvGrowthPct: number | null;\n share: number;\n }>;\n activation?: {\n funnel: Array<{ stage: string; count: number }>;\n medianDaysToFirstOrder: number | null;\n activationRatePct: number;\n orderConversionPct: number;\n };\n accounts?: {\n total: number;\n active: number;\n suspended: number;\n verified: number;\n unverifiedEmail: number;\n neverLoggedIn: number;\n dormant: number;\n new: number;\n };\n trend: {\n performanceSeries: Array<{ date: string; gmv: number; orders: number }>;\n onboardingSeries: Array<{ date: string; count: number }>;\n /** Absent until the matching api deploy lands — guard with `?? []`. */\n previousPerformanceSeries?: Array<{\n date: string;\n gmv: number;\n orders: number;\n }>;\n previousOnboardingSeries?: Array<{ date: string; count: number }>;\n performanceSeriesByCurrency?: CurrencySeries[];\n };\n attention: {\n /**\n * Feeds whose query failed; their counts are placeholders, not zeros.\n * Absent when talking to an API that predates this field.\n */\n unavailable?: Array<\n 'needsReview' | 'dormantTenants' | 'overdueInvoices' | 'failedSettlements'\n >;\n trialsEndingSoon: Array<\n AttentionTenantRef & { trialEndsAt: string; daysLeft: number }\n >;\n needsReview: Array<\n AttentionTenantRef & { status: string; createdAt: string }\n >;\n dormantTenants: Array<AttentionTenantRef & { createdAt: string }>;\n overdueInvoices: {\n count: number;\n /** @deprecated adds currencies together; use `totalByCurrency`. */\n total: number;\n totalByCurrency?: CurrencyOverdue[];\n sample: Array<{\n id: string;\n invoiceNumber: string;\n tenantId: string;\n tenantName: string;\n customerName: string | null;\n amountDue: number;\n currency: string;\n dueDate: string | null;\n }>;\n };\n failedSettlements: {\n count: number;\n sample: Array<{\n id: string;\n tenantId: string;\n tenantName: string;\n netAmount: number;\n currency: string;\n createdAt: string;\n }>;\n };\n };\n}\n\nexport interface PlatformRevenue {\n range: { startDate: string; endDate: string };\n currency: string;\n recurring: {\n /** False when no billing source feeds the figures below (all are 0). */\n tracked?: boolean;\n mrr: number;\n arr: number;\n arpa: number;\n activeSubscriptions: number;\n trialingSubscriptions: number;\n pastDueSubscriptions: number;\n nonRenewingSubscriptions: number;\n cancelledSubscriptions: number;\n newInRange: number;\n churnedInRange: number;\n planBreakdown: Array<{\n planId: string;\n name: string;\n interval: string;\n subscribers: number;\n mrr: number;\n }>;\n };\n gmv: {\n lifetime: number;\n inRange: number;\n ordersInRange: number;\n aov: number;\n series: Array<{ date: string; gmv: number; orders: number }>;\n topTenants: Array<{\n id: string;\n businessName: string;\n slug: string;\n gmv: number;\n orders: number;\n }>;\n };\n quality?: {\n quickRatio: number | null;\n nrrPct: number | null;\n expansionMrr: number;\n contractionMrr: number;\n mrrChurnRatePct: number | null;\n logoChurnRatePct: number | null;\n grossGmv: number;\n refundedGmv: number;\n netGmv: number;\n refundRatePct: number;\n refundedOrders: number;\n cohorts: Array<{\n cohort: string;\n size: number;\n retention: Array<number | null>;\n }>;\n gmvByCurrency?: CurrencyRevenueQuality[];\n };\n /** @deprecated never convert with these. */\n rates: Record<string, number>;\n currencies?: string[];\n gmvByCurrency?: CurrencyRevenueGmv[];\n}\n\nexport type TenantStatus = 'active' | 'suspended' | 'pending' | 'deleted';\n\nexport interface TenantRow extends CountryFields {\n id: string;\n slug: string;\n businessName: string;\n status: TenantStatus;\n industryKey: string | null;\n createdAt: string;\n /** The business's contact email (absent on older APIs). */\n email?: string | null;\n phone?: string | null;\n /** The owner's sign-in email. */\n ownerEmail?: string | null;\n /** @deprecated adds currencies together; use `gmvByCurrency`. */\n gmv: number;\n gmvByCurrency?: CurrencyAmount[];\n /** The merchant's account officer (absent on older APIs). */\n accountOfficer?: Pick<AccountOfficer, 'id' | 'name'> | null;\n}\n\nexport interface TenantsPage {\n rows: TenantRow[];\n total: number;\n page: number;\n pageSize: number;\n}\n\nexport interface TenantActivityOrder {\n id: string;\n orderNumber: string;\n total: number;\n currency: string;\n status: string;\n paymentStatus: string;\n customerEmail: string;\n customerName: string | null;\n createdAt: string;\n}\n\nexport interface TenantDetail extends TenantSetup {\n /** Who runs the workspace and how to reach it (absent on older APIs). */\n contact?: { email: string | null; phone: string | null };\n owner?: TenantTeamMember | null;\n team?: TenantTeamMember[];\n /** The admin in charge of this merchant (absent on older APIs). */\n accountOfficer?: AccountOfficer | null;\n id: string;\n slug: string;\n businessName: string;\n status: TenantStatus;\n industryKey: string | null;\n customDomain: string | null;\n createdAt: string;\n chargeBearer: 'merchant' | 'customer';\n currency: string;\n metrics: {\n totalOrders: number;\n paidOrders: number;\n pendingOrders: number;\n gmv: number;\n gmv30d: number;\n gmv7d: number;\n aov: number;\n totalCustomers: number;\n subscriptionStatus: string | null;\n window: {\n startDate: string;\n endDate: string;\n gmv: number;\n orders: number;\n paidOrders: number;\n aov: number;\n customers: number;\n };\n byCurrency?: TenantCurrencyMetrics[];\n };\n /** Currencies with paid orders, A→Z. */\n currencies?: string[];\n revenueSeries: Array<{ date: string; amount: number }>;\n revenueSeriesByCurrency?: Array<{\n currency: string;\n series: Array<{ date: string; amount: number }>;\n }>;\n recentOrders: TenantActivityOrder[];\n}\n\n// ---- Iteration 3: tenant cockpit domains ----\n\nexport interface TenantCustomer {\n id: string;\n email: string;\n phone: string | null;\n name: string | null;\n type: string;\n source: string | null;\n status: string;\n emailVerified: boolean;\n totalOrders: number;\n totalSpent: number;\n lastOrderAt: string | null;\n createdAt: string;\n}\n\nexport interface TenantCustomersPage {\n members: TenantCustomer[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface TenantProduct {\n id: string;\n type: string;\n slug: string;\n title: string;\n category: string | null;\n tags: string[];\n featured: boolean;\n isActive: boolean;\n image?: { url: string } | null;\n price: number | null;\n compareAtPrice: number | null;\n currency: string | null;\n trackInventory: boolean;\n quantity: number | null;\n reserved: number | null;\n lowStockThreshold: number | null;\n createdAt: string;\n}\n\nexport interface TenantProductStats {\n total: number;\n active: number;\n featured: number;\n lowStock: number;\n outOfStock: number;\n}\n\nexport interface TenantProductsData {\n items: TenantProduct[];\n total: number;\n stats: TenantProductStats;\n}\n\nexport interface ProductRef {\n id: string;\n title: string;\n}\n\nexport interface SellerRow {\n id: string;\n title: string;\n units: number;\n revenue: number;\n}\n\nexport interface CategorySlice {\n category: string;\n count: number;\n value: number;\n}\n\nexport interface ProductInsights {\n currency: string;\n totalProducts: number;\n activeProducts: number;\n featuredProducts: number;\n lowStock: number;\n outOfStock: number;\n trackedProducts: number;\n catalogValue: number;\n inventoryValue: number;\n inventoryAtRiskValue: number;\n avgPrice: number;\n medianPrice: number;\n totalUnitsSold: number;\n totalRevenue: number;\n pctEverSold: number;\n deadStock: number;\n newestProduct: (ProductRef & { createdAt: string }) | null;\n lastUpdatedProduct: (ProductRef & { updatedAt: string }) | null;\n categories: CategorySlice[];\n bestSellers: SellerRow[];\n worstSellers: SellerRow[];\n featuredSellThrough: {\n featuredTotal: number;\n featuredSold: number;\n featuredUnits: number;\n nonFeaturedTotal: number;\n nonFeaturedSold: number;\n nonFeaturedUnits: number;\n };\n unitsSeries: Array<{ date: string; count: number }>;\n}\n\nexport interface SpenderRow {\n id: string;\n name: string | null;\n email: string;\n totalSpent: number;\n totalOrders: number;\n}\n\nexport interface BreakdownSlice {\n label: string;\n count: number;\n}\n\nexport interface CustomerInsights {\n currency: string;\n totalCustomers: number;\n newCustomers30d: number;\n payingCustomers: number;\n repeatCustomers: number;\n repeatRate: number;\n dormantCustomers: number;\n marketingOptInRate: number;\n lifetimeValue: number;\n avgSpendPerCustomer: number;\n avgOrdersPerCustomer: number;\n avgOrderValue: number;\n topSpenders: SpenderRow[];\n bySource: BreakdownSlice[];\n byType: BreakdownSlice[];\n signupsSeries: Array<{ date: string; count: number }>;\n}\n\nexport interface TenantInvoice {\n id: string;\n invoiceNumber: string;\n status: string;\n customerEmail: string | null;\n customerName: string | null;\n total: number;\n amountPaid: number;\n amountDue: number;\n currency: string;\n dueDate: string | null;\n createdAt: string;\n}\n\nexport interface TenantInvoiceStats {\n draft: number;\n sent: number;\n paid: number;\n overdue: number;\n cancelled: number;\n total: number;\n totalRevenue: number;\n totalOutstanding: number;\n}\n\nexport interface TenantInvoicesData {\n invoices: TenantInvoice[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n stats: TenantInvoiceStats;\n}\n\nexport interface TenantLoyaltyProgram {\n id: string;\n name: string;\n pointsName: string;\n pointsPerCurrency: number;\n currencyPerPoint: number;\n isActive: boolean;\n tiers?: Array<{ id: string; name: string; threshold: number }>;\n earnRules?: Array<{ id: string; name: string; points: number }>;\n}\n\nexport interface TenantLoyaltyStats {\n totalMembers: number;\n totalPointsIssued: number;\n totalPointsRedeemed: number;\n activeMembers: number;\n programActive: boolean;\n}\n\nexport interface TenantLoyaltyData {\n program: TenantLoyaltyProgram | null;\n stats: TenantLoyaltyStats;\n}\n\nexport interface TenantDiscount {\n id: string;\n name: string;\n code: string;\n discountType: string;\n value: number;\n maxDiscountAmount: number | null;\n startsAt: string | null;\n endsAt: string | null;\n usageLimit: number | null;\n usageCount: number;\n status: string;\n autoApply: boolean;\n isValid: boolean;\n isExpired: boolean;\n createdAt: string;\n}\n\nexport interface TenantDiscountsPage {\n discounts: TenantDiscount[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface TenantSettlement {\n id: string;\n grossAmount: number;\n paystackFee: number;\n platformFee: number;\n netAmount: number;\n currency: string;\n status: string;\n settlementType: string;\n bankAccount?: { bankName: string; accountNumber: string } | null;\n settledAt: string | null;\n createdAt: string;\n}\n\nexport interface TenantSettlementSummary {\n totalSettled: number;\n totalPending: number;\n totalFailed: number;\n count: number;\n platformFeesCollected: number;\n currency: string;\n currencies?: string[];\n byCurrency?: CurrencySettlementSummary[];\n}\n\nexport interface TenantBankAccount {\n id: string;\n bankCode: string;\n bankName: string;\n accountNumber: string;\n accountName: string;\n splitPercentage: number | null;\n status: string;\n isDefault: boolean;\n /** Paystack subaccount code (ACCT_…). */\n subaccountCode?: string | null;\n failureReason?: string | null;\n createdAt: string;\n}\n\nexport interface TenantSettlementsData {\n settlements: TenantSettlement[];\n total: number;\n page: number;\n limit: number;\n summary: TenantSettlementSummary;\n bankAccounts: TenantBankAccount[];\n}\n\nexport interface TenantSubscriptionPlan {\n id: string;\n name: string;\n interval: string;\n amount: number;\n currency: string;\n}\n\nexport interface TenantSubscription {\n id: string;\n planId: string;\n customerId: string;\n customerEmail: string;\n status: string;\n amount: number;\n currency: string;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n nextPaymentDate: string | null;\n cancelledAt: string | null;\n paymentsCount: number;\n createdAt: string;\n plan?: TenantSubscriptionPlan | null;\n customer?: { id: string; name: string | null; email: string } | null;\n}\n\nexport interface TenantSubscriptionStats {\n totalActive: number;\n totalNonRenewing: number;\n totalCancelled: number;\n monthlyRecurringRevenue: number;\n}\n\nexport interface TenantSubscriptionsData {\n subscriptions: TenantSubscription[];\n total: number;\n page: number;\n limit: number;\n stats: TenantSubscriptionStats;\n}\n\nexport interface AdminsAnalytics {\n range: { startDate: string; endDate: string };\n totals: {\n admins: number;\n active: number;\n suspended: number;\n superadmins: number;\n standardAdmins: number;\n neverLoggedIn: number;\n activeInRange: number;\n actionsInRange: number;\n };\n roleBreakdown: Array<{ role: string; count: number }>;\n statusBreakdown: Array<{ status: string; count: number }>;\n activitySeries: Array<{ date: string; count: number }>;\n topActions: Array<{ action: string; count: number }>;\n recentActivity: Array<{\n id: string;\n adminEmail: string | null;\n action: string;\n targetType: string | null;\n createdAt: string;\n }>;\n}\n\nexport interface AdminSession {\n id: string;\n email: string;\n name: string | null;\n role: 'admin' | 'superadmin';\n permissions: string[];\n mustChangePassword: boolean;\n}\n\nexport interface AdminLoginCodeRequired {\n codeRequired: true;\n challengeId: string;\n /** The address the code went to, masked: `a***@gmail.com`. */\n sentTo: string;\n}\n\nexport type AdminLoginAnswer =\n | AdminLoginCodeRequired\n | {\n codeRequired?: undefined;\n mustChangePassword: boolean;\n admin: Omit<AdminSession, 'permissions'>;\n };\n\nexport const platformAdminApi = {\n /**\n * Password step. A box that emails sign-in codes answers `codeRequired` and\n * sets no session yet; finish with `verifyLoginCode`.\n */\n login: (email: string, password: string) =>\n apiFetch<AdminLoginAnswer>('/platform-admin/v1/auth/login', {\n method: 'POST',\n body: JSON.stringify({ email, password }),\n }),\n verifyLoginCode: (challengeId: string, code: string) =>\n apiFetch<{\n mustChangePassword: boolean;\n admin: Omit<AdminSession, 'permissions'>;\n }>('/platform-admin/v1/auth/login/verify', {\n method: 'POST',\n body: JSON.stringify({ challengeId, code }),\n }),\n resendLoginCode: (challengeId: string) =>\n apiFetch<AdminLoginCodeRequired>('/platform-admin/v1/auth/login/resend', {\n method: 'POST',\n body: JSON.stringify({ challengeId }),\n }),\n logout: () =>\n apiFetch<{ success: boolean }>('/platform-admin/v1/auth/logout', {\n method: 'POST',\n }),\n me: () => apiFetch<AdminSession>('/platform-admin/v1/auth/me'),\n changePassword: (currentPassword: string, newPassword: string) =>\n apiFetch<{ success: boolean }>('/platform-admin/v1/auth/change-password', {\n method: 'POST',\n body: JSON.stringify({ currentPassword, newPassword }),\n }),\n overview: () => apiFetch<PlatformOverview>('/platform-admin/v1/overview'),\n cockpit: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<PlatformCockpit>(\n `/platform-admin/v1/overview/cockpit${q ? `?${q}` : ''}`,\n );\n },\n revenue: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<PlatformRevenue>(\n `/platform-admin/v1/overview/revenue${q ? `?${q}` : ''}`,\n );\n },\n tenantsAnalytics: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<TenantsAnalytics>(\n `/platform-admin/v1/overview/tenants-analytics${q ? `?${q}` : ''}`,\n );\n },\n tenants: (params: TenantListParams = {}) =>\n apiFetch<TenantsPage>(`/platform-admin/v1/tenants${tenantsQuery(params)}`),\n tenant: (\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n if (range.endDate) qs.set('endDate', range.endDate);\n const query = qs.toString();\n return apiFetch<TenantDetail>(\n `/platform-admin/v1/tenants/${id}${query ? `?${query}` : ''}`,\n );\n },\n tenantAnalytics: (\n id: string,\n range: { startDate?: string; endDate?: string; limit?: number } = {},\n ) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n if (range.endDate) qs.set('endDate', range.endDate);\n if (range.limit) qs.set('limit', String(range.limit));\n const query = qs.toString();\n return apiFetch<DashboardStats>(\n `/platform-admin/v1/tenants/${id}/analytics${query ? `?${query}` : ''}`,\n );\n },\n tenantFinance: (\n id: string,\n range: { startDate?: string; endDate?: string; period?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n if (range.endDate) qs.set('endDate', range.endDate);\n if (range.period) qs.set('period', range.period);\n const query = qs.toString();\n return apiFetch<AdminFinanceAnalytics>(\n `/platform-admin/v1/tenants/${id}/finance${query ? `?${query}` : ''}`,\n );\n },\n tenantTransactions: (\n id: string,\n params: {\n status?: string;\n type?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.type) qs.set('type', params.type);\n if (params.search) qs.set('search', params.search);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantTransactionsPage>(\n `/platform-admin/v1/tenants/${id}/transactions${\n query ? `?${query}` : ''\n }`,\n );\n },\n tenantCustomers: (\n id: string,\n params: {\n search?: string;\n type?: string;\n status?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.search) qs.set('search', params.search);\n if (params.type) qs.set('type', params.type);\n if (params.status) qs.set('status', params.status);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantCustomersPage>(\n `/platform-admin/v1/tenants/${id}/customers${query ? `?${query}` : ''}`,\n );\n },\n tenantProducts: (\n id: string,\n params: { type?: string; search?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.type) qs.set('type', params.type);\n if (params.search) qs.set('search', params.search);\n const query = qs.toString();\n return apiFetch<TenantProductsData>(\n `/platform-admin/v1/tenants/${id}/products${query ? `?${query}` : ''}`,\n );\n },\n tenantProductInsights: (id: string, range: { startDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n const query = qs.toString();\n return apiFetch<ProductInsights>(\n `/platform-admin/v1/tenants/${id}/products/insights${\n query ? `?${query}` : ''\n }`,\n );\n },\n tenantCustomerInsights: (id: string, range: { startDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (range.startDate) qs.set('startDate', range.startDate);\n const query = qs.toString();\n return apiFetch<CustomerInsights>(\n `/platform-admin/v1/tenants/${id}/customers/insights${\n query ? `?${query}` : ''\n }`,\n );\n },\n tenantInvoices: (\n id: string,\n params: {\n status?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.search) qs.set('search', params.search);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantInvoicesData>(\n `/platform-admin/v1/tenants/${id}/invoices${query ? `?${query}` : ''}`,\n );\n },\n tenantLoyalty: (id: string) =>\n apiFetch<TenantLoyaltyData>(`/platform-admin/v1/tenants/${id}/loyalty`),\n tenantDiscounts: (\n id: string,\n params: {\n status?: string;\n discountType?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.discountType) qs.set('discountType', params.discountType);\n if (params.search) qs.set('search', params.search);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantDiscountsPage>(\n `/platform-admin/v1/tenants/${id}/discounts${query ? `?${query}` : ''}`,\n );\n },\n tenantSettlements: (\n id: string,\n params: {\n page?: number;\n limit?: number;\n startDate?: string;\n endDate?: string;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const query = qs.toString();\n return apiFetch<TenantSettlementsData>(\n `/platform-admin/v1/tenants/${id}/settlements${query ? `?${query}` : ''}`,\n );\n },\n tenantSubscriptions: (\n id: string,\n params: {\n status?: string;\n planId?: string;\n page?: number;\n limit?: number;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.status) qs.set('status', params.status);\n if (params.planId) qs.set('planId', params.planId);\n if (params.page) qs.set('page', String(params.page));\n if (params.limit) qs.set('limit', String(params.limit));\n const query = qs.toString();\n return apiFetch<TenantSubscriptionsData>(\n `/platform-admin/v1/tenants/${id}/subscriptions${\n query ? `?${query}` : ''\n }`,\n );\n },\n setTenantStatus: (id: string, status: TenantStatus) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/tenants/${id}/status`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n }),\n accounts: (\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n joinedFrom?: string;\n joinedTo?: string;\n stage?: AccountStage;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.page) qs.set('page', String(params.page));\n if (params.pageSize) qs.set('pageSize', String(params.pageSize));\n if (params.search) qs.set('search', params.search);\n if (params.joinedFrom) qs.set('joinedFrom', params.joinedFrom);\n if (params.joinedTo) qs.set('joinedTo', params.joinedTo);\n if (params.stage) qs.set('stage', params.stage);\n const query = qs.toString();\n return apiFetch<AccountsPage>(\n `/platform-admin/v1/accounts${query ? `?${query}` : ''}`,\n );\n },\n accountsAnalytics: (\n params: { startDate?: string; endDate?: string } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<AccountsAnalytics>(\n `/platform-admin/v1/accounts/analytics${q ? `?${q}` : ''}`,\n );\n },\n setAccountStatus: (id: string, status: string) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/accounts/${id}/status`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n }),\n verifyAccount: (id: string) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/accounts/${id}/verify`, {\n method: 'POST',\n }),\n accountSessions: (id: string) =>\n apiFetch<AccountSession[]>(`/platform-admin/v1/accounts/${id}/sessions`),\n accountTenants: (id: string) =>\n apiFetch<AccountTenantRow[]>(`/platform-admin/v1/accounts/${id}/tenants`),\n impersonateAccount: (id: string) =>\n apiFetch<{ success: boolean }>(\n `/platform-admin/v1/accounts/${id}/impersonate`,\n { method: 'POST' },\n ),\n admins: () => apiFetch<AdminRow[]>('/platform-admin/v1/admins'),\n adminsAnalytics: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<AdminsAnalytics>(\n `/platform-admin/v1/admins/analytics${q ? `?${q}` : ''}`,\n );\n },\n adminPermissions: () =>\n apiFetch<string[]>('/platform-admin/v1/admins/permissions'),\n inviteAdmin: (\n email: string,\n role: 'admin' | 'superadmin',\n permissions: string[] = [],\n roleIds: string[] = [],\n ) =>\n apiFetch<{ email: string; tempPassword: string }>(\n '/platform-admin/v1/admins',\n {\n method: 'POST',\n body: JSON.stringify({ email, role, permissions, roleIds }),\n },\n ),\n setAdminStatus: (id: string, status: 'active' | 'suspended') =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/admins/${id}/status`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n }),\n setAdminPermissions: (id: string, permissions: string[]) =>\n apiFetch<{ success: boolean }>(\n `/platform-admin/v1/admins/${id}/permissions`,\n { method: 'PATCH', body: JSON.stringify({ permissions }) },\n ),\n setAdminRoles: (id: string, roleIds: string[]) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/admins/${id}/roles`, {\n method: 'PATCH',\n body: JSON.stringify({ roleIds }),\n }),\n resetAdminPassword: (id: string) =>\n apiFetch<{ tempPassword: string }>(\n `/platform-admin/v1/admins/${id}/reset-password`,\n { method: 'POST' },\n ),\n roles: () => apiFetch<RoleRow[]>('/platform-admin/v1/roles'),\n createRole: (name: string, permissions: string[], description?: string) =>\n apiFetch<RoleRow>('/platform-admin/v1/roles', {\n method: 'POST',\n body: JSON.stringify({ name, permissions, description }),\n }),\n updateRole: (\n id: string,\n data: { name?: string; permissions?: string[]; description?: string },\n ) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/roles/${id}`, {\n method: 'PATCH',\n body: JSON.stringify(data),\n }),\n deleteRole: (id: string) =>\n apiFetch<{ success: boolean }>(`/platform-admin/v1/roles/${id}`, {\n method: 'DELETE',\n }),\n audit: (\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n action?: string;\n adminEmail?: string;\n from?: string;\n to?: string;\n } = {},\n ) => {\n const qs = new URLSearchParams();\n if (params.page) qs.set('page', String(params.page));\n if (params.pageSize) qs.set('pageSize', String(params.pageSize));\n if (params.search) qs.set('search', params.search);\n if (params.action) qs.set('action', params.action);\n if (params.adminEmail) qs.set('adminEmail', params.adminEmail);\n if (params.from) qs.set('from', params.from);\n if (params.to) qs.set('to', params.to);\n const q = qs.toString();\n return apiFetch<AuditPage>(`/platform-admin/v1/audit${q ? `?${q}` : ''}`);\n },\n auditAnalytics: (params: { startDate?: string; endDate?: string } = {}) => {\n const qs = new URLSearchParams();\n if (params.startDate) qs.set('startDate', params.startDate);\n if (params.endDate) qs.set('endDate', params.endDate);\n const q = qs.toString();\n return apiFetch<AuditAnalytics>(\n `/platform-admin/v1/audit/analytics${q ? `?${q}` : ''}`,\n );\n },\n};\n\nexport interface AdminRow {\n id: string;\n email: string;\n name: string | null;\n role: 'admin' | 'superadmin';\n status: 'active' | 'suspended';\n permissions: string[];\n roleIds: string[];\n mustChangePassword: boolean;\n lastLoginAt: string | null;\n createdAt: string;\n}\n\nexport interface RoleRow {\n id: string;\n key: string;\n name: string;\n description: string | null;\n permissions: string[];\n isSystem: boolean;\n assignedCount: number;\n}\n\nexport interface AuditRow {\n id: string;\n /** Who did it, by name. Absent from an engine that does not send it, or when the admin has none. */\n adminName?: string | null;\n adminEmail: string | null;\n action: string;\n targetType: string | null;\n targetId: string | null;\n metadata: Record<string, unknown>;\n ipAddress: string | null;\n /** The browser or tool the action came from. Absent from an engine that does not send it. */\n userAgent?: string | null;\n createdAt: string;\n}\n\nexport interface AuditPage {\n rows: AuditRow[];\n total: number;\n page: number;\n pageSize: number;\n}\nexport interface AuditAnalytics {\n range: { startDate: string; endDate: string };\n totals: {\n actions: number;\n activeAdmins: number;\n actionTypes: number;\n topAction: string | null;\n };\n actionSeries: Array<{ date: string; count: number }>;\n actionBreakdown: Array<{ action: string; count: number }>;\n adminBreakdown: Array<{ adminEmail: string; count: number }>;\n targetBreakdown: Array<{ targetType: string; count: number }>;\n}\n"],"mappings":"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","names":[]}
|
package/dist/timeline-copy.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare function productUpdated(itemTitle: string, contentType: string):
|
|
|
17
17
|
description: string;
|
|
18
18
|
emoji: string;
|
|
19
19
|
};
|
|
20
|
-
export declare function orderPlaced(customerName: string, orderNumber: string, formattedTotal: string, industryKey?: string | null): {
|
|
20
|
+
export declare function orderPlaced(customerName: string, orderNumber: string, formattedTotal: string, industryKey?: string | null, isPaid?: boolean): {
|
|
21
21
|
title: string;
|
|
22
22
|
description: string;
|
|
23
23
|
emoji: string;
|
package/dist/timeline-copy.js
CHANGED
|
@@ -17,8 +17,12 @@ const ORDER_VERB = {
|
|
|
17
17
|
hospitality: "booked",
|
|
18
18
|
events: "purchased tickets for"
|
|
19
19
|
};
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const UNPAID_ORDER_VERB = {
|
|
21
|
+
events: "started a ticket order for"
|
|
22
|
+
};
|
|
23
|
+
function orderPlaced(customerName, orderNumber, formattedTotal, industryKey, isPaid = true) {
|
|
24
|
+
const verbs = isPaid ? ORDER_VERB : { ...ORDER_VERB, ...UNPAID_ORDER_VERB };
|
|
25
|
+
const verb = industryKey && verbs[industryKey] || "placed an order";
|
|
22
26
|
return {
|
|
23
27
|
title: `${customerName} ${verb}`,
|
|
24
28
|
description: `${orderNumber} \u2022 ${formattedTotal}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/timeline-copy.ts"],"sourcesContent":["/**\n * Timeline copy/messaging for the dashboard activity feed.\n *\n * All user-facing strings for the \"What's happening\" timeline live here\n * so we can iterate on tone, A/B test, or add i18n without touching\n * component logic.\n *\n * Each generator receives contextual data and returns { title, description }.\n */\n\n// ─── Product / Content ──────────────────────────────────────────────\n\nexport function productAdded(itemTitle: string, contentType: string) {\n return {\n title: `${itemTitle} is now live`,\n description: `New ${contentType.toLowerCase()} added to your store`,\n emoji: '📦',\n };\n}\n\nexport function productUpdated(itemTitle: string, contentType: string) {\n return {\n title: `${itemTitle} was updated`,\n description: `You updated your ${contentType.toLowerCase()}`,\n emoji: '🔄',\n };\n}\n\n// ─── Orders ─────────────────────────────────────────────────────────\n\nconst ORDER_VERB: Record<string, string> = {\n food: 'ordered',\n hospitality: 'booked',\n events: 'purchased tickets for',\n};\n\nexport function orderPlaced(\n customerName: string,\n orderNumber: string,\n formattedTotal: string,\n industryKey?: string | null,\n) {\n const verb = (industryKey &&
|
|
1
|
+
{"version":3,"sources":["../src/timeline-copy.ts"],"sourcesContent":["/**\n * Timeline copy/messaging for the dashboard activity feed.\n *\n * All user-facing strings for the \"What's happening\" timeline live here\n * so we can iterate on tone, A/B test, or add i18n without touching\n * component logic.\n *\n * Each generator receives contextual data and returns { title, description }.\n */\n\n// ─── Product / Content ──────────────────────────────────────────────\n\nexport function productAdded(itemTitle: string, contentType: string) {\n return {\n title: `${itemTitle} is now live`,\n description: `New ${contentType.toLowerCase()} added to your store`,\n emoji: '📦',\n };\n}\n\nexport function productUpdated(itemTitle: string, contentType: string) {\n return {\n title: `${itemTitle} was updated`,\n description: `You updated your ${contentType.toLowerCase()}`,\n emoji: '🔄',\n };\n}\n\n// ─── Orders ─────────────────────────────────────────────────────────\n\nconst ORDER_VERB: Record<string, string> = {\n food: 'ordered',\n hospitality: 'booked',\n events: 'purchased tickets for',\n};\n\n// A ticket is only bought once it is paid. An unpaid ticket order is a checkout\n// that was started, and calling it a purchase puts money on the feed that is\n// not in the wallet.\nconst UNPAID_ORDER_VERB: Record<string, string> = {\n events: 'started a ticket order for',\n};\n\nexport function orderPlaced(\n customerName: string,\n orderNumber: string,\n formattedTotal: string,\n industryKey?: string | null,\n isPaid = true,\n) {\n const verbs = isPaid ? ORDER_VERB : { ...ORDER_VERB, ...UNPAID_ORDER_VERB };\n const verb = (industryKey && verbs[industryKey]) || 'placed an order';\n return {\n title: `${customerName} ${verb}`,\n description: `${orderNumber} • ${formattedTotal}`,\n emoji: '🛍️',\n };\n}\n\nexport function orderCompleted(customerName: string, orderNumber: string) {\n return {\n title: `${orderNumber} is fulfilled`,\n description: `${customerName}'s order is complete`,\n emoji: '✅',\n };\n}\n\n// ─── Customers / Members ────────────────────────────────────────────\n\nconst BOOKABLE_INDUSTRIES = new Set([\n 'beauty',\n 'wellness',\n 'professional',\n 'fitness',\n]);\n\nexport function memberSignup(\n name: string,\n email: string,\n industryKey?: string | null,\n) {\n const verb =\n industryKey && BOOKABLE_INDUSTRIES.has(industryKey)\n ? 'became a client'\n : 'joined your store';\n return {\n title: `${name} ${verb}`,\n description: email,\n emoji: '👤',\n };\n}\n\nexport function memberConverted(name: string, email: string) {\n return {\n title: `${name} just became a customer`,\n description: `Converted from guest · ${email}`,\n emoji: '🎉',\n };\n}\n\n// ─── Subscriptions ──────────────────────────────────────────────────\n\nexport function subscriptionCreated(\n name: string,\n planName: string,\n formattedAmount: string,\n) {\n return {\n title: `${name} subscribed to ${planName}`,\n description: `Recurring revenue: ${formattedAmount}/month`,\n emoji: '💳',\n };\n}\n\n// ─── Invoices ───────────────────────────────────────────────────────\n\nexport function invoicePaid(\n customerName: string,\n invoiceNumber: string,\n formattedAmount: string,\n) {\n return {\n title: `${customerName} paid invoice ${invoiceNumber}`,\n description: `Payment received: ${formattedAmount}`,\n emoji: '💰',\n };\n}\n\nexport function invoiceSent(\n customerName: string,\n invoiceNumber: string,\n formattedAmount: string,\n) {\n return {\n title: `Invoice ${invoiceNumber} sent to ${customerName}`,\n description: `Amount due: ${formattedAmount}`,\n emoji: '📨',\n };\n}\n\n// ─── Empty state ────────────────────────────────────────────────────\n\nconst INDUSTRY_EMPTY_TIMELINE: Record<\n string,\n { heading: string; subtext: string }\n> = {\n retail: {\n heading: 'Nothing here yet',\n subtext: 'Orders, signups, and updates will show up here as they happen.',\n },\n beauty: {\n heading: 'Nothing here yet',\n subtext: 'Appointments, bookings, and client activity will show up here.',\n },\n wellness: {\n heading: 'Nothing here yet',\n subtext: 'Appointments, bookings, and client activity will show up here.',\n },\n hospitality: {\n heading: 'Nothing here yet',\n subtext: 'Reservations, guest check-ins, and updates will show up here.',\n },\n food: {\n heading: 'Nothing here yet',\n subtext: 'Orders and customer activity will show up here as they happen.',\n },\n fitness: {\n heading: 'Nothing here yet',\n subtext: 'Class sign-ups, member activity, and updates will show up here.',\n },\n professional: {\n heading: 'Nothing here yet',\n subtext: 'Appointments, bookings, and client activity will show up here.',\n },\n creative: {\n heading: 'Nothing here yet',\n subtext: 'Bookings, orders, and client activity will show up here.',\n },\n events: {\n heading: 'Nothing here yet',\n subtext:\n 'Ticket sales, attendee activity, and event updates will show up here.',\n },\n};\n\nexport const emptyTimeline = {\n heading: 'Nothing here yet',\n subtext: 'Orders, signups, and updates will show up here as they happen.',\n};\n\nexport function getEmptyTimeline(industryKey: string | null) {\n if (industryKey && INDUSTRY_EMPTY_TIMELINE[industryKey]) {\n return INDUSTRY_EMPTY_TIMELINE[industryKey];\n }\n return emptyTimeline;\n}\n\n// ─── Feed chrome ────────────────────────────────────────────────────\n\n// Curly apostrophe, matching every other apostrophe in the product's copy.\nexport const feedHeader = 'What’s happening';\n\nexport function showMoreLabel(remaining: number) {\n return `Show ${remaining} more`;\n}\n\nexport const showLessLabel = 'Show less';\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED