@burdenoff/microfe-subscriberbot 2026.626.1 → 2026.628.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/index.js +4 -4
  2. package/dist/subscriberbot/SubscriberBotRoot.js +61 -133
  3. package/dist/subscriberbot/SubscriberBotRoot.js.map +1 -1
  4. package/dist/subscriberbot/SubscriberBotRoutes.js +56 -187
  5. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  6. package/dist/subscriberbot/components/StateViews.js +49 -0
  7. package/dist/subscriberbot/components/StateViews.js.map +1 -0
  8. package/dist/subscriberbot/components/StatusBadge.js +45 -47
  9. package/dist/subscriberbot/components/StatusBadge.js.map +1 -1
  10. package/dist/subscriberbot/context/SubscriberBotContext.js +22 -30
  11. package/dist/subscriberbot/context/SubscriberBotContext.js.map +1 -1
  12. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +342 -195
  13. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  14. package/dist/subscriberbot/index.js +1 -1
  15. package/dist/subscriberbot/pages/DashboardPage.js +269 -0
  16. package/dist/subscriberbot/pages/DashboardPage.js.map +1 -0
  17. package/dist/subscriberbot/pages/InboxPage.js +186 -0
  18. package/dist/subscriberbot/pages/InboxPage.js.map +1 -0
  19. package/dist/subscriberbot/pages/InvoicesPage.js +211 -0
  20. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -0
  21. package/dist/subscriberbot/pages/WorkflowsPage.js +236 -0
  22. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -0
  23. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +160 -0
  24. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -0
  25. package/dist/subscriberbot/pages/agents/AgentNewPage.js +140 -0
  26. package/dist/subscriberbot/pages/agents/AgentNewPage.js.map +1 -0
  27. package/dist/subscriberbot/pages/agents/AgentsListPage.js +178 -0
  28. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -0
  29. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +179 -0
  30. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -0
  31. package/dist/subscriberbot/pages/providers/ProviderNewPage.js +185 -0
  32. package/dist/subscriberbot/pages/providers/ProviderNewPage.js.map +1 -0
  33. package/dist/subscriberbot/pages/providers/ProvidersListPage.js +254 -0
  34. package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -0
  35. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +306 -0
  36. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -0
  37. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +253 -0
  38. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -0
  39. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +248 -0
  40. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -0
  41. package/dist/subscriberbot/utils/formatters.js +50 -32
  42. package/dist/subscriberbot/utils/formatters.js.map +1 -1
  43. package/package.json +1 -1
  44. package/dist/subscriberbot/components/InvestmentCard.js +0 -97
  45. package/dist/subscriberbot/components/InvestmentCard.js.map +0 -1
  46. package/dist/subscriberbot/components/RatingDisplay.js +0 -35
  47. package/dist/subscriberbot/components/RatingDisplay.js.map +0 -1
  48. package/dist/subscriberbot/mocks/data.js +0 -1517
  49. package/dist/subscriberbot/mocks/data.js.map +0 -1
  50. package/dist/subscriberbot/mocks/users.js +0 -34
  51. package/dist/subscriberbot/mocks/users.js.map +0 -1
  52. package/dist/subscriberbot/pages/HomePage.js +0 -930
  53. package/dist/subscriberbot/pages/HomePage.js.map +0 -1
  54. package/dist/subscriberbot/pages/admin/AdminAnalyticsPage.js +0 -651
  55. package/dist/subscriberbot/pages/admin/AdminAnalyticsPage.js.map +0 -1
  56. package/dist/subscriberbot/pages/admin/AdminDashboard.js +0 -679
  57. package/dist/subscriberbot/pages/admin/AdminDashboard.js.map +0 -1
  58. package/dist/subscriberbot/pages/admin/AdminFinancialPage.js +0 -427
  59. package/dist/subscriberbot/pages/admin/AdminFinancialPage.js.map +0 -1
  60. package/dist/subscriberbot/pages/admin/AdminOrdersPage.js +0 -665
  61. package/dist/subscriberbot/pages/admin/AdminOrdersPage.js.map +0 -1
  62. package/dist/subscriberbot/pages/admin/AdminProfilePage.js +0 -261
  63. package/dist/subscriberbot/pages/admin/AdminProfilePage.js.map +0 -1
  64. package/dist/subscriberbot/pages/admin/AdminSettingsPage.js +0 -654
  65. package/dist/subscriberbot/pages/admin/AdminSettingsPage.js.map +0 -1
  66. package/dist/subscriberbot/pages/admin/CartManagementPage.js +0 -874
  67. package/dist/subscriberbot/pages/admin/CartManagementPage.js.map +0 -1
  68. package/dist/subscriberbot/pages/admin/UserManagementPage.js +0 -898
  69. package/dist/subscriberbot/pages/admin/UserManagementPage.js.map +0 -1
  70. package/dist/subscriberbot/pages/cart-owner/AnalyticsDashboard.js +0 -839
  71. package/dist/subscriberbot/pages/cart-owner/AnalyticsDashboard.js.map +0 -1
  72. package/dist/subscriberbot/pages/cart-owner/BusinessSettingsPage.js +0 -705
  73. package/dist/subscriberbot/pages/cart-owner/BusinessSettingsPage.js.map +0 -1
  74. package/dist/subscriberbot/pages/cart-owner/CartOwnerDashboard.js +0 -802
  75. package/dist/subscriberbot/pages/cart-owner/CartOwnerDashboard.js.map +0 -1
  76. package/dist/subscriberbot/pages/cart-owner/CartOwnerProfilePage.js +0 -891
  77. package/dist/subscriberbot/pages/cart-owner/CartOwnerProfilePage.js.map +0 -1
  78. package/dist/subscriberbot/pages/cart-owner/CartServiceConfigPage.js +0 -633
  79. package/dist/subscriberbot/pages/cart-owner/CartServiceConfigPage.js.map +0 -1
  80. package/dist/subscriberbot/pages/cart-owner/InventoryManagementPage.js +0 -910
  81. package/dist/subscriberbot/pages/cart-owner/InventoryManagementPage.js.map +0 -1
  82. package/dist/subscriberbot/pages/cart-owner/OrderManagementPage.js +0 -879
  83. package/dist/subscriberbot/pages/cart-owner/OrderManagementPage.js.map +0 -1
  84. package/dist/subscriberbot/pages/cart-owner/StaffManagementPage.js +0 -838
  85. package/dist/subscriberbot/pages/cart-owner/StaffManagementPage.js.map +0 -1
  86. package/dist/subscriberbot/pages/common/HelpSupportPage.js +0 -1323
  87. package/dist/subscriberbot/pages/common/HelpSupportPage.js.map +0 -1
  88. package/dist/subscriberbot/pages/common/NotificationCenterPage.js +0 -672
  89. package/dist/subscriberbot/pages/common/NotificationCenterPage.js.map +0 -1
  90. package/dist/subscriberbot/pages/common/SettingsPage.js +0 -973
  91. package/dist/subscriberbot/pages/common/SettingsPage.js.map +0 -1
  92. package/dist/subscriberbot/pages/customer/BookingDetailsPage.js +0 -626
  93. package/dist/subscriberbot/pages/customer/BookingDetailsPage.js.map +0 -1
  94. package/dist/subscriberbot/pages/customer/CartDetailPage.js +0 -654
  95. package/dist/subscriberbot/pages/customer/CartDetailPage.js.map +0 -1
  96. package/dist/subscriberbot/pages/customer/CartDiscoveryPage.js +0 -555
  97. package/dist/subscriberbot/pages/customer/CartDiscoveryPage.js.map +0 -1
  98. package/dist/subscriberbot/pages/customer/CheckoutPage.js +0 -529
  99. package/dist/subscriberbot/pages/customer/CheckoutPage.js.map +0 -1
  100. package/dist/subscriberbot/pages/customer/CustomerDashboard.js +0 -532
  101. package/dist/subscriberbot/pages/customer/CustomerDashboard.js.map +0 -1
  102. package/dist/subscriberbot/pages/customer/CustomerProfilePage.js +0 -630
  103. package/dist/subscriberbot/pages/customer/CustomerProfilePage.js.map +0 -1
  104. package/dist/subscriberbot/pages/customer/DirectServiceBookingPage.js +0 -633
  105. package/dist/subscriberbot/pages/customer/DirectServiceBookingPage.js.map +0 -1
  106. package/dist/subscriberbot/pages/customer/FavoritesPage.js +0 -484
  107. package/dist/subscriberbot/pages/customer/FavoritesPage.js.map +0 -1
  108. package/dist/subscriberbot/pages/customer/OrderHistoryPage.js +0 -446
  109. package/dist/subscriberbot/pages/customer/OrderHistoryPage.js.map +0 -1
  110. package/dist/subscriberbot/pages/customer/OrderTrackingPage.js +0 -394
  111. package/dist/subscriberbot/pages/customer/OrderTrackingPage.js.map +0 -1
  112. package/dist/subscriberbot/pages/customer/PaymentMethodsPage.js +0 -495
  113. package/dist/subscriberbot/pages/customer/PaymentMethodsPage.js.map +0 -1
  114. package/dist/subscriberbot/pages/customer/ReviewsPage.js +0 -613
  115. package/dist/subscriberbot/pages/customer/ReviewsPage.js.map +0 -1
  116. package/dist/subscriberbot/pages/customer/SavedAddressesPage.js +0 -450
  117. package/dist/subscriberbot/pages/customer/SavedAddressesPage.js.map +0 -1
  118. package/dist/subscriberbot/pages/investor/InvestmentDetailsPage.js +0 -886
  119. package/dist/subscriberbot/pages/investor/InvestmentDetailsPage.js.map +0 -1
  120. package/dist/subscriberbot/pages/investor/InvestmentOpportunitiesPage.js +0 -947
  121. package/dist/subscriberbot/pages/investor/InvestmentOpportunitiesPage.js.map +0 -1
  122. package/dist/subscriberbot/pages/investor/InvestorAnalyticsPage.js +0 -687
  123. package/dist/subscriberbot/pages/investor/InvestorAnalyticsPage.js.map +0 -1
  124. package/dist/subscriberbot/pages/investor/InvestorDashboard.js +0 -451
  125. package/dist/subscriberbot/pages/investor/InvestorDashboard.js.map +0 -1
  126. package/dist/subscriberbot/pages/investor/InvestorInvestmentsPage.js +0 -406
  127. package/dist/subscriberbot/pages/investor/InvestorInvestmentsPage.js.map +0 -1
  128. package/dist/subscriberbot/pages/investor/InvestorPortfolioPage.js +0 -575
  129. package/dist/subscriberbot/pages/investor/InvestorPortfolioPage.js.map +0 -1
  130. package/dist/subscriberbot/pages/investor/InvestorProfilePage.js +0 -1070
  131. package/dist/subscriberbot/pages/investor/InvestorProfilePage.js.map +0 -1
  132. package/dist/subscriberbot/pages/worker/TaskDetailsPage.js +0 -535
  133. package/dist/subscriberbot/pages/worker/TaskDetailsPage.js.map +0 -1
  134. package/dist/subscriberbot/pages/worker/WorkerDashboard.js +0 -666
  135. package/dist/subscriberbot/pages/worker/WorkerDashboard.js.map +0 -1
  136. package/dist/subscriberbot/pages/worker/WorkerOrdersPage.js +0 -681
  137. package/dist/subscriberbot/pages/worker/WorkerOrdersPage.js.map +0 -1
  138. package/dist/subscriberbot/pages/worker/WorkerProfilePage.js +0 -692
  139. package/dist/subscriberbot/pages/worker/WorkerProfilePage.js.map +0 -1
  140. package/dist/subscriberbot/pages/worker/WorkerSchedulePage.js +0 -588
  141. package/dist/subscriberbot/pages/worker/WorkerSchedulePage.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useSubscriberBotApi.js","names":[],"sources":["../../../src/subscriberbot/hooks/useSubscriberBotApi.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useSubscriberBot } from '../context';\nimport type {\n MockCart,\n MockOrder,\n InvestmentOpportunity,\n Investment,\n DashboardStats,\n AdminAnalytics,\n WorkerTask,\n} from '../types';\n\nconst subscriberbotQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n\n return response.data;\n};\n\n// ============================================================================\n// Service Providers (Carts)\n// ============================================================================\n\nexport const useProviders = (query?: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'providers', query],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listServiceProviders: any[] }>(\n `query Providers($filter: SubscriberBotProviderFilterInput) {\n listServiceProviders(filter: $filter, limit: 200) {\n id name slug category status rating totalRatings averageOrderValue serviceTypes location businessHours createdAt\n }\n }`,\n {\n filter: query\n ? {\n query,\n }\n : undefined,\n },\n apiGatewayUrl\n );\n\n return result.listServiceProviders.map((p) => ({\n ...p,\n image: `https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?w=400`, // Placeholder\n images: [`https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?w=400`],\n isOpen: p.status === 'ACTIVE' || p.status === 'VERIFIED',\n isVerified: p.status === 'VERIFIED',\n distance: 0.5, // Mock\n estimatedTime: 20, // Mock\n createdAt: p.createdAt,\n })) as MockCart[];\n },\n });\n};\n\nexport const useOfferings = (providerId?: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'offerings', providerId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listOfferings: any[] }>(\n `query Offerings($providerId: String) {\n listOfferings(providerId: $providerId, limit: 300) {\n id providerId kind name slug category description price originalPrice stock durationMinutes serviceType tags isAvailable metadata media\n }\n }`,\n { providerId },\n apiGatewayUrl\n );\n return result.listOfferings;\n },\n enabled: Boolean(providerId),\n });\n};\n\n// ============================================================================\n// Orders\n// ============================================================================\n\nexport const useOrders = (input: { providerId?: string; customerId?: string } = {}) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'orders', input.providerId, input.customerId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listOrders: any[] }>(\n `query Orders($providerId: String, $customerId: String) {\n listOrders(providerId: $providerId, customerId: $customerId, limit: 200) {\n id orderNumber providerId customerId status paymentStatus fulfillmentType subtotal tax deliveryFee discount total notes timeline paymentMethod deliveryAddress createdAt\n provider { name }\n items { id offeringId name quantity unitPrice totalPrice customizations }\n }\n }`,\n input,\n apiGatewayUrl\n );\n\n return result.listOrders.map((o) => ({\n id: o.id,\n cartId: o.providerId,\n cartName: o.provider?.name || 'Unknown Cart',\n cartImage: `https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?w=100`, // Placeholder\n items: o.items.map((i: any) => ({\n id: i.id,\n name: i.name,\n quantity: i.quantity,\n price: i.unitPrice,\n customizations: i.customizations,\n })),\n total: o.total,\n subtotal: o.subtotal,\n taxes: o.tax,\n deliveryFee: o.deliveryFee,\n discount: o.discount,\n status: o.status.toLowerCase(),\n orderDate: o.createdAt,\n deliveryAddress: o.deliveryAddress,\n paymentMethod: o.paymentMethod || 'Cash',\n paymentStatus: o.paymentStatus.toLowerCase(),\n timeline: o.timeline || [],\n })) as MockOrder[];\n },\n });\n};\n\n// ============================================================================\n// Analytics & Stats\n// ============================================================================\n\nexport const useDashboardStats = () => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'dashboard-stats'],\n queryFn: async () => {\n const result = await subscriberbotQuery<{\n subscriberbotDashboardStats: DashboardStats;\n }>(\n `query DashboardStats { subscriberbotDashboardStats { totalOrders totalRevenue activeProviders activeCustomers avgRating pendingOrders } }`,\n {},\n apiGatewayUrl\n );\n return result.subscriberbotDashboardStats;\n },\n });\n};\n\nexport const useAdminAnalytics = () => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'admin-analytics'],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ subscriberbotAdminAnalytics: AdminAnalytics }>(\n `query AdminAnalytics { subscriberbotAdminAnalytics { revenueByCategory orderTrends topProviders customerGrowth categoryDistribution } }`,\n {},\n apiGatewayUrl\n );\n return result.subscriberbotAdminAnalytics;\n },\n });\n};\n\n// ============================================================================\n// Investments\n// ============================================================================\n\nexport const useInvestmentOpportunities = () => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'investment-opportunities'],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listInvestmentOpportunities: any[] }>(\n `query Opportunities {\n listInvestmentOpportunities(limit: 200) {\n id providerId title description targetAmount raisedAmount minimumInvestment expectedReturnsPct lockInMonths riskLevel status expiresAt terms businessMetrics createdAt\n provider { name }\n }\n }`,\n {},\n apiGatewayUrl\n );\n\n return result.listInvestmentOpportunities.map((o) => ({\n id: o.id,\n cartId: o.providerId,\n cartName: o.provider?.name || 'Unknown Cart',\n businessOwner: 'Owner', // Mock\n targetAmount: o.targetAmount,\n raisedAmount: o.raisedAmount,\n minimumInvestment: o.minimumInvestment,\n expectedReturns: o.expectedReturnsPct,\n investmentPeriod: o.lockInMonths,\n riskLevel: o.riskLevel.toLowerCase(),\n description: o.description,\n businessPlan: '',\n financialProjections: [],\n documents: [],\n investors: [],\n status: o.status.toLowerCase(),\n createdAt: o.createdAt,\n expiresAt: o.expiresAt,\n })) as InvestmentOpportunity[];\n },\n });\n};\n\nexport const useInvestments = (investorId: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'investments', investorId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listInvestments: any[] }>(\n `query Investments($investorId: String!) {\n listInvestments(investorId: $investorId) {\n id opportunityId amount currentValue expectedReturnsPct status investedAt maturedAt realizedReturns\n opportunity { provider { name } }\n }\n }`,\n { investorId },\n apiGatewayUrl\n );\n\n return result.listInvestments.map((i) => ({\n id: i.id,\n opportunityId: i.opportunityId,\n cartName: i.opportunity?.provider?.name || 'Unknown Cart',\n investedAmount: i.amount,\n currentValue: i.currentValue,\n returns: i.realizedReturns,\n returnsPercentage: i.expectedReturnsPct,\n investmentDate: i.investedAt,\n status: i.status.toLowerCase(),\n })) as Investment[];\n },\n enabled: Boolean(investorId),\n });\n};\n\n// ============================================================================\n// Workers & Tasks\n// ============================================================================\n\nexport const useWorkerTasks = (workerId: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'worker-tasks', workerId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listWorkerTasks: any[] }>(\n `query WorkerTasks($workerId: String!) {\n listWorkerTasks(workerId: $workerId, limit: 100) {\n id orderId providerId type description priority status assignedAt dueAt completedAt customerName customerPhone earnings distance notes\n provider { name }\n order { deliveryAddress }\n }\n }`,\n { workerId },\n apiGatewayUrl\n );\n\n return result.listWorkerTasks.map((t) => ({\n id: t.id,\n orderId: t.orderId,\n cartId: t.providerId,\n cartName: t.provider?.name || 'Unknown Cart',\n type: t.type.toLowerCase(),\n description: t.description,\n priority: t.priority.toLowerCase(),\n status: t.status.toLowerCase(),\n assignedAt: t.assignedAt,\n dueAt: t.dueAt,\n completedAt: t.completedAt,\n customerName: t.customerName,\n customerPhone: t.customerPhone,\n deliveryAddress: t.order?.deliveryAddress,\n earnings: t.earnings,\n distance: t.distance,\n notes: t.notes,\n })) as WorkerTask[];\n },\n enabled: Boolean(workerId),\n });\n};\n\nexport const useWorkerStats = (workerId: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'worker-stats', workerId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ subscriberbotWorkerStats: any }>(\n `query WorkerStats($workerId: String!) {\n subscriberbotWorkerStats(workerId: $workerId) {\n totalDeliveries totalEarnings averageRating completionRate todayTasks todayEarnings\n }\n }`,\n { workerId },\n apiGatewayUrl\n );\n return result.subscriberbotWorkerStats;\n },\n enabled: Boolean(workerId),\n });\n};\n\nexport const useWorkerSchedules = (workerId: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'worker-schedules', workerId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listWorkerSchedules: any[] }>(\n `query WorkerSchedules($workerId: String!) {\n listWorkerSchedules(workerId: $workerId) {\n id date startTime endTime providerId status tasksCompleted totalEarnings\n provider { name }\n }\n }`,\n { workerId },\n apiGatewayUrl\n );\n\n return result.listWorkerSchedules.map((s) => ({\n id: s.id,\n date: s.date,\n startTime: s.startTime,\n endTime: s.endTime,\n cartId: s.providerId,\n cartName: s.provider?.name || 'Unknown Cart',\n status: s.status.toLowerCase(),\n tasksCompleted: s.tasksCompleted,\n totalEarnings: s.totalEarnings,\n }));\n },\n enabled: Boolean(workerId),\n });\n};\n\n// ============================================================================\n// Reviews\n// ============================================================================\n\nexport const useReviews = (providerId: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: ['subscriberbot', 'reviews', providerId],\n queryFn: async () => {\n const result = await subscriberbotQuery<{ listReviews: any[] }>(\n `query Reviews($providerId: String!) {\n listReviews(providerId: $providerId) {\n id providerId customerId rating review response createdAt updatedAt\n }\n }`,\n { providerId },\n apiGatewayUrl\n );\n return result.listReviews;\n },\n enabled: Boolean(providerId),\n });\n};\n\n// ============================================================================\n// Mutations\n// ============================================================================\n\nexport const usePlaceOrder = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n\n return useMutation({\n mutationFn: async (input: Record<string, unknown>) => {\n const result = await subscriberbotQuery<{ placeOrder: any }>(\n `mutation PlaceOrder($input: SubscriberBotPlaceOrderInput!) {\n placeOrder(input: $input) {\n id orderNumber status total createdAt\n }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.placeOrder;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'orders'] });\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'dashboard-stats'] });\n },\n });\n};\n\nexport const useCreateProvider = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n\n return useMutation({\n mutationFn: async (input: Record<string, unknown>) => {\n const result = await subscriberbotQuery<{ subscriberbotCreateServiceProvider: any }>(\n `mutation CreateProvider($input: SubscriberBotCreateServiceProviderInput!) {\n subscriberbotCreateServiceProvider(input: $input) {\n id name slug status category location rating\n }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.subscriberbotCreateServiceProvider;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'providers'] });\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'dashboard-stats'] });\n },\n });\n};\n\nexport const useUpdateWorkerTaskStatus = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n\n return useMutation({\n mutationFn: async ({ taskId, status }: { taskId: string; status: string }) => {\n const result = await subscriberbotQuery<{ subscriberbotUpdateWorkerTaskStatus: any }>(\n `mutation UpdateTaskStatus($taskId: String!, $status: SubscriberBotWorkerTaskStatus!) {\n subscriberbotUpdateWorkerTaskStatus(taskId: $taskId, status: $status) {\n id status\n }\n }`,\n { taskId, status },\n apiGatewayUrl\n );\n return result.subscriberbotUpdateWorkerTaskStatus;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'worker-tasks'] });\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'worker-stats'] });\n },\n });\n};\n\nexport const useWorkerClockInOut = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n\n return useMutation({\n mutationFn: async ({\n workerId,\n action,\n }: {\n workerId: string;\n action: 'CLOCK_IN' | 'CLOCK_OUT';\n }) => {\n const result = await subscriberbotQuery<{ subscriberbotWorkerClockInOut: any }>(\n `mutation ClockInOut($workerId: String!, $action: SubscriberBotClockAction!) {\n subscriberbotWorkerClockInOut(workerId: $workerId, action: $action) {\n success message\n }\n }`,\n { workerId, action },\n apiGatewayUrl\n );\n return result.subscriberbotWorkerClockInOut;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: ['subscriberbot', 'worker-schedules'] });\n },\n });\n};\n\n// ============================================================================\n// Main Hook\n// ============================================================================\n\nexport const useSubscriberBotApi = () => {\n const { currentUser } = useSubscriberBot();\n const providers = useProviders();\n const orders = useOrders({ customerId: currentUser?.id });\n const dashboardStats = useDashboardStats();\n const investmentOpportunities = useInvestmentOpportunities();\n const investments = useInvestments(currentUser?.id || '');\n\n return useMemo(\n () => ({\n providers,\n orders,\n dashboardStats,\n investmentOpportunities,\n investments,\n }),\n [providers, orders, dashboardStats, investmentOpportunities, investments]\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useSubscriberBotApi.js","names":[],"sources":["../../../src/subscriberbot/hooks/useSubscriberBotApi.ts"],"sourcesContent":["/**\n * SubscriberBot API hooks\n * @module subscriberbot/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-subscriberbot-svc`\n * federated GraphQL contract (the `Sub*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })`\n * — the same pattern the workspace MFEs use; the host shell supplies the\n * gateway base URL + a workspace-scoped token.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useSubscriberBot } from '../context';\nimport type {\n PaginationInput,\n SubAgentKind,\n SubAgentStatus,\n SubAiAgent,\n SubAsset,\n SubCommunicationChannel,\n SubConnection,\n SubCreateAgentInput,\n SubCreateProviderInput,\n SubCreateRelationshipInput,\n SubCreateWorkflowInput,\n SubEntitlement,\n SubInboxMessage,\n SubInvoice,\n SubInvoiceStatus,\n SubMessageCategory,\n SubPaymentInstrument,\n SubPlan,\n SubProvider,\n SubProviderCategory,\n SubProviderStatus,\n SubRelationship,\n SubRelationshipKind,\n SubRelationshipStatus,\n SubRenewalEvent,\n SubWorkflow,\n SubWorkflowStatus,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\nconst subQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n relationships: ['subscriberbot', 'relationships'] as const,\n relationship: (id: string) => ['subscriberbot', 'relationship', id] as const,\n providers: ['subscriberbot', 'providers'] as const,\n provider: (id: string) => ['subscriberbot', 'provider', id] as const,\n plans: ['subscriberbot', 'plans'] as const,\n inbox: ['subscriberbot', 'inbox'] as const,\n invoices: ['subscriberbot', 'invoices'] as const,\n paymentInstruments: ['subscriberbot', 'payment-instruments'] as const,\n channels: ['subscriberbot', 'channels'] as const,\n agents: ['subscriberbot', 'agents'] as const,\n agent: (id: string) => ['subscriberbot', 'agent', id] as const,\n workflows: ['subscriberbot', 'workflows'] as const,\n renewals: ['subscriberbot', 'renewals'] as const,\n assets: ['subscriberbot', 'assets'] as const,\n entitlements: ['subscriberbot', 'entitlements'] as const,\n} as const;\n\n// ============================================================================\n// Reusable gql field selections (kept inline-string for codegen-free strictness)\n// ============================================================================\n\nconst PROVIDER_FIELDS = `\n id name slug category status description industry region language websiteUrl\n logoFileId tags churnRiskScore vendorHealthScore workspaceId createdAt updatedAt\n`;\n\nconst PLAN_FIELDS = `\n id name description providerId amount currency interval features isActive\n workspaceId createdAt updatedAt\n`;\n\nconst RELATIONSHIP_FIELDS = `\n id label kind status amount currency interval autoRenew discoverySource notes\n tags healthScore ownerId providerId planId startedAt renewsAt trialEndsAt\n cancelledAt workspaceId createdAt updatedAt\n`;\n\nconst INBOX_FIELDS = `\n id subject preview category categoryConfidence channelId relationshipId\n externalId actionRequired isRead receivedAt workspaceId createdAt updatedAt\n`;\n\nconst INVOICE_FIELDS = `\n id number relationshipId status currency subtotal taxAmount total issueDate\n dueDate paidAt paymentInstrumentId workspaceId createdAt updatedAt\n`;\n\nconst AGENT_FIELDS = `\n id name description kind status ownerId lastRunAt workspaceId createdAt updatedAt\n`;\n\nconst WORKFLOW_FIELDS = `\n id name description triggerEvent status runCount lastRunAt workspaceId\n createdAt updatedAt\n`;\n\n// ============================================================================\n// Relationships (the core domain object)\n// ============================================================================\n\nexport interface RelationshipListFilters {\n kind?: SubRelationshipKind;\n status?: SubRelationshipStatus;\n providerId?: string;\n ownerId?: string;\n pagination?: PaginationInput;\n}\n\nexport const useRelationships = (filters: RelationshipListFilters = {}) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.relationships, filters],\n queryFn: async () => {\n const result = await subQuery<{\n subListRelationships: SubConnection<SubRelationship>;\n }>(\n `query SubRelationships(\n $kind: SubRelationshipKind\n $status: SubRelationshipStatus\n $providerId: ID\n $ownerId: ID\n $pagination: PaginationInput\n ) {\n subListRelationships(\n kind: $kind\n status: $status\n providerId: $providerId\n ownerId: $ownerId\n pagination: $pagination\n ) {\n items {\n ${RELATIONSHIP_FIELDS}\n provider { id name category status logoFileId }\n plan { id name amount currency interval }\n }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n kind: filters.kind,\n status: filters.status,\n providerId: filters.providerId,\n ownerId: filters.ownerId,\n pagination: filters.pagination ?? { limit: 50, offset: 0 },\n },\n apiGatewayUrl\n );\n return result.subListRelationships;\n },\n });\n};\n\nexport const useRelationship = (id: string | undefined) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: KEY.relationship(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await subQuery<{ subRelationship: SubRelationship | null }>(\n `query SubRelationship($id: ID!) {\n subRelationship(id: $id) {\n ${RELATIONSHIP_FIELDS}\n provider { ${PROVIDER_FIELDS} }\n plan { ${PLAN_FIELDS} }\n entitlements {\n id name description type relationshipId quota used unit isActive\n workspaceId createdAt updatedAt\n }\n assets {\n id name type relationshipId secretRef expiresAt workspaceId\n createdAt updatedAt file { id }\n }\n renewalEvents {\n id relationshipId eventType occursAt amount currency detail\n notified workspaceId createdAt updatedAt\n }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subRelationship;\n },\n });\n};\n\nexport const useCreateRelationship = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (input: SubCreateRelationshipInput) => {\n const result = await subQuery<{ subCreateRelationship: SubRelationship }>(\n `mutation SubCreateRelationship($input: SubCreateRelationshipInput!) {\n subCreateRelationship(input: $input) { ${RELATIONSHIP_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.subCreateRelationship;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.relationships });\n },\n });\n};\n\nexport const useTransitionRelationship = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: SubRelationshipStatus }) => {\n const result = await subQuery<{ subTransitionRelationship: SubRelationship }>(\n `mutation SubTransitionRelationship($id: ID!, $status: SubRelationshipStatus!) {\n subTransitionRelationship(id: $id, status: $status) { ${RELATIONSHIP_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.subTransitionRelationship;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: KEY.relationships });\n void queryClient.invalidateQueries({ queryKey: KEY.relationship(data.id) });\n },\n });\n};\n\nexport const useCancelRelationship = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await subQuery<{ subCancelRelationship: SubRelationship }>(\n `mutation SubCancelRelationship($id: ID!) {\n subCancelRelationship(id: $id) { ${RELATIONSHIP_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subCancelRelationship;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: KEY.relationships });\n void queryClient.invalidateQueries({ queryKey: KEY.relationship(data.id) });\n },\n });\n};\n\nexport const useRenewalEvents = (\n args: { relationshipId?: string; upcomingOnly?: boolean } = {}\n) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.renewals, args],\n queryFn: async () => {\n const result = await subQuery<{ subListRenewalEvents: SubRenewalEvent[] }>(\n `query SubRenewalEvents($relationshipId: ID, $upcomingOnly: Boolean) {\n subListRenewalEvents(relationshipId: $relationshipId, upcomingOnly: $upcomingOnly) {\n id relationshipId eventType occursAt amount currency detail notified\n workspaceId createdAt updatedAt\n }\n }`,\n { relationshipId: args.relationshipId, upcomingOnly: args.upcomingOnly },\n apiGatewayUrl\n );\n return result.subListRenewalEvents;\n },\n });\n};\n\nexport const useEntitlements = (relationshipId: string | undefined) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.entitlements, relationshipId],\n enabled: Boolean(relationshipId),\n queryFn: async () => {\n const result = await subQuery<{ subListEntitlements: SubEntitlement[] }>(\n `query SubEntitlements($relationshipId: ID!) {\n subListEntitlements(relationshipId: $relationshipId) {\n id name description type relationshipId quota used unit isActive\n workspaceId createdAt updatedAt\n }\n }`,\n { relationshipId },\n apiGatewayUrl\n );\n return result.subListEntitlements;\n },\n });\n};\n\nexport const useAssets = (relationshipId: string | undefined) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.assets, relationshipId],\n enabled: Boolean(relationshipId),\n queryFn: async () => {\n const result = await subQuery<{ subListAssets: SubAsset[] }>(\n `query SubAssets($relationshipId: ID!) {\n subListAssets(relationshipId: $relationshipId) {\n id name type relationshipId secretRef expiresAt workspaceId\n createdAt updatedAt file { id }\n }\n }`,\n { relationshipId },\n apiGatewayUrl\n );\n return result.subListAssets;\n },\n });\n};\n\n// ============================================================================\n// Providers (the global discovery registry)\n// ============================================================================\n\nexport interface ProviderListFilters {\n category?: SubProviderCategory;\n status?: SubProviderStatus;\n search?: string;\n pagination?: PaginationInput;\n}\n\nexport const useProviders = (filters: ProviderListFilters = {}) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.providers, filters],\n queryFn: async () => {\n const result = await subQuery<{ subListProviders: SubConnection<SubProvider> }>(\n `query SubProviders(\n $category: SubProviderCategory\n $status: SubProviderStatus\n $search: String\n $pagination: PaginationInput\n ) {\n subListProviders(\n category: $category\n status: $status\n search: $search\n pagination: $pagination\n ) {\n items { ${PROVIDER_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n category: filters.category,\n status: filters.status,\n search: filters.search,\n pagination: filters.pagination ?? { limit: 50, offset: 0 },\n },\n apiGatewayUrl\n );\n return result.subListProviders;\n },\n });\n};\n\nexport const useProvider = (id: string | undefined) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: KEY.provider(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await subQuery<{ subProvider: SubProvider | null }>(\n `query SubProvider($id: ID!) {\n subProvider(id: $id) {\n ${PROVIDER_FIELDS}\n plans { ${PLAN_FIELDS} }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subProvider;\n },\n });\n};\n\nexport const useCreateProvider = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (input: SubCreateProviderInput) => {\n const result = await subQuery<{ subCreateProvider: SubProvider }>(\n `mutation SubCreateProvider($input: SubCreateProviderInput!) {\n subCreateProvider(input: $input) { ${PROVIDER_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.subCreateProvider;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.providers });\n },\n });\n};\n\nexport const usePlans = (providerId: string | undefined) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.plans, providerId],\n enabled: Boolean(providerId),\n queryFn: async () => {\n const result = await subQuery<{ subListPlans: SubPlan[] }>(\n `query SubPlans($providerId: ID) {\n subListPlans(providerId: $providerId) { ${PLAN_FIELDS} }\n }`,\n { providerId },\n apiGatewayUrl\n );\n return result.subListPlans;\n },\n });\n};\n\n// ============================================================================\n// Universal Inbox\n// ============================================================================\n\nexport interface InboxListFilters {\n category?: SubMessageCategory;\n channelId?: string;\n relationshipId?: string;\n unreadOnly?: boolean;\n pagination?: PaginationInput;\n}\n\nexport const useInboxMessages = (filters: InboxListFilters = {}) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.inbox, filters],\n queryFn: async () => {\n const result = await subQuery<{\n subListInboxMessages: SubConnection<SubInboxMessage>;\n }>(\n `query SubInboxMessages(\n $category: SubMessageCategory\n $channelId: ID\n $relationshipId: ID\n $unreadOnly: Boolean\n $pagination: PaginationInput\n ) {\n subListInboxMessages(\n category: $category\n channelId: $channelId\n relationshipId: $relationshipId\n unreadOnly: $unreadOnly\n pagination: $pagination\n ) {\n items { ${INBOX_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n category: filters.category,\n channelId: filters.channelId,\n relationshipId: filters.relationshipId,\n unreadOnly: filters.unreadOnly,\n pagination: filters.pagination ?? { limit: 50, offset: 0 },\n },\n apiGatewayUrl\n );\n return result.subListInboxMessages;\n },\n });\n};\n\nexport const useMarkMessageRead = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await subQuery<{ subMarkMessageRead: SubInboxMessage }>(\n `mutation SubMarkMessageRead($id: ID!) {\n subMarkMessageRead(id: $id) { ${INBOX_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subMarkMessageRead;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.inbox });\n },\n });\n};\n\n// ============================================================================\n// Invoices (Universal Billing Layer)\n// ============================================================================\n\nexport interface InvoiceListFilters {\n status?: SubInvoiceStatus;\n relationshipId?: string;\n pagination?: PaginationInput;\n}\n\nexport const useInvoices = (filters: InvoiceListFilters = {}) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.invoices, filters],\n queryFn: async () => {\n const result = await subQuery<{ subListInvoices: SubConnection<SubInvoice> }>(\n `query SubInvoices(\n $status: SubInvoiceStatus\n $relationshipId: ID\n $pagination: PaginationInput\n ) {\n subListInvoices(\n status: $status\n relationshipId: $relationshipId\n pagination: $pagination\n ) {\n items { ${INVOICE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n {\n status: filters.status,\n relationshipId: filters.relationshipId,\n pagination: filters.pagination ?? { limit: 50, offset: 0 },\n },\n apiGatewayUrl\n );\n return result.subListInvoices;\n },\n });\n};\n\nexport const useMarkInvoicePaid = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await subQuery<{ subMarkInvoicePaid: SubInvoice }>(\n `mutation SubMarkInvoicePaid($id: ID!) {\n subMarkInvoicePaid(id: $id) { ${INVOICE_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subMarkInvoicePaid;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.invoices });\n },\n });\n};\n\n// ============================================================================\n// Payment instruments & communication channels\n// ============================================================================\n\nexport const usePaymentInstruments = (ownerId?: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.paymentInstruments, ownerId],\n queryFn: async () => {\n const result = await subQuery<{ subListPaymentInstruments: SubPaymentInstrument[] }>(\n `query SubPaymentInstruments($ownerId: ID) {\n subListPaymentInstruments(ownerId: $ownerId) {\n id label type status brand last4 expiryMonth expiryYear isDefault\n ownerId workspaceId createdAt updatedAt\n }\n }`,\n { ownerId },\n apiGatewayUrl\n );\n return result.subListPaymentInstruments;\n },\n });\n};\n\nexport const useChannels = (ownerId?: string) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.channels, ownerId],\n queryFn: async () => {\n const result = await subQuery<{ subListChannels: SubCommunicationChannel[] }>(\n `query SubChannels($ownerId: ID) {\n subListChannels(ownerId: $ownerId) {\n id label type status address ingestEnabled ownerId verifiedAt\n workspaceId createdAt updatedAt\n }\n }`,\n { ownerId },\n apiGatewayUrl\n );\n return result.subListChannels;\n },\n });\n};\n\n// ============================================================================\n// AI Agents & workflows (automation)\n// ============================================================================\n\nexport interface AgentListFilters {\n kind?: SubAgentKind;\n status?: SubAgentStatus;\n ownerId?: string;\n}\n\nexport const useAgents = (filters: AgentListFilters = {}) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.agents, filters],\n queryFn: async () => {\n const result = await subQuery<{ subListAgents: SubAiAgent[] }>(\n `query SubAgents($kind: SubAgentKind, $status: SubAgentStatus, $ownerId: ID) {\n subListAgents(kind: $kind, status: $status, ownerId: $ownerId) {\n ${AGENT_FIELDS}\n }\n }`,\n { kind: filters.kind, status: filters.status, ownerId: filters.ownerId },\n apiGatewayUrl\n );\n return result.subListAgents;\n },\n });\n};\n\nexport const useAgent = (id: string | undefined) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: KEY.agent(id ?? ''),\n enabled: Boolean(id),\n queryFn: async () => {\n const result = await subQuery<{ subAgent: SubAiAgent | null }>(\n `query SubAgent($id: ID!) {\n subAgent(id: $id) {\n ${AGENT_FIELDS}\n policies {\n id name description action agentId isEnabled triggerCount\n lastTriggeredAt workspaceId createdAt updatedAt\n }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subAgent;\n },\n });\n};\n\nexport const useCreateAgent = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (input: SubCreateAgentInput) => {\n const result = await subQuery<{ subCreateAgent: SubAiAgent }>(\n `mutation SubCreateAgent($input: SubCreateAgentInput!) {\n subCreateAgent(input: $input) { ${AGENT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.subCreateAgent;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.agents });\n },\n });\n};\n\nexport const useSetAgentStatus = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: SubAgentStatus }) => {\n const result = await subQuery<{ subSetAgentStatus: SubAiAgent }>(\n `mutation SubSetAgentStatus($id: ID!, $status: SubAgentStatus!) {\n subSetAgentStatus(id: $id, status: $status) { ${AGENT_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.subSetAgentStatus;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: KEY.agents });\n void queryClient.invalidateQueries({ queryKey: KEY.agent(data.id) });\n },\n });\n};\n\nexport const useWorkflows = (status?: SubWorkflowStatus) => {\n const { apiGatewayUrl } = useSubscriberBot();\n return useQuery({\n queryKey: [...KEY.workflows, status],\n queryFn: async () => {\n const result = await subQuery<{ subListWorkflows: SubWorkflow[] }>(\n `query SubWorkflows($status: SubWorkflowStatus) {\n subListWorkflows(status: $status) { ${WORKFLOW_FIELDS} }\n }`,\n { status },\n apiGatewayUrl\n );\n return result.subListWorkflows;\n },\n });\n};\n\nexport const useCreateWorkflow = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (input: SubCreateWorkflowInput) => {\n const result = await subQuery<{ subCreateWorkflow: SubWorkflow }>(\n `mutation SubCreateWorkflow($input: SubCreateWorkflowInput!) {\n subCreateWorkflow(input: $input) { ${WORKFLOW_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.subCreateWorkflow;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.workflows });\n },\n });\n};\n\nexport const useActivateWorkflow = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useSubscriberBot();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await subQuery<{ subActivateWorkflow: SubWorkflow }>(\n `mutation SubActivateWorkflow($id: ID!) {\n subActivateWorkflow(id: $id) { ${WORKFLOW_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.subActivateWorkflow;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: KEY.workflows });\n },\n });\n};\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import "./context/SubscriberBotContext.js";
2
2
  import "./utils/cn.js";
3
- import "./context/index.js";
4
3
  import "./utils/formatters.js";
4
+ import "./context/index.js";
5
5
  import "./SubscriberBotRoot.js";
6
6
  import "./store/subscriberbotStore.js";
7
7
  import "./store/index.js";
@@ -0,0 +1,269 @@
1
+ import { useSubscriberBot as e } from "../context/SubscriberBotContext.js";
2
+ import { PageLayout as t } from "../components/PageLayout.js";
3
+ import { MetricsCard as n } from "../components/MetricsCard.js";
4
+ import { formatCurrency as r, formatEnumLabel as i, formatRelativeTime as a } from "../utils/formatters.js";
5
+ import { StatusBadge as o } from "../components/StatusBadge.js";
6
+ import { EmptyState as s } from "../components/EmptyState.js";
7
+ import { ErrorView as c, LoadingView as l, Section as u } from "../components/StateViews.js";
8
+ import { useInboxMessages as d, useInvoices as f, useRelationships as p, useRenewalEvents as m } from "../hooks/useSubscriberBotApi.js";
9
+ import { useMemo as h } from "react";
10
+ import { AlertTriangle as g, ArrowRight as _, Bot as v, CalendarClock as y, Inbox as b, Repeat2 as x, Sparkles as S, Wallet as C } from "lucide-react";
11
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
12
+ import { PagePurpose as E } from "@burdenoff/fe-libs/ui";
13
+ //#region src/subscriberbot/pages/DashboardPage.tsx
14
+ var D = {
15
+ DAILY: 30,
16
+ WEEKLY: 4.345,
17
+ MONTHLY: 1,
18
+ QUARTERLY: 1 / 3,
19
+ YEARLY: 1 / 12,
20
+ LIFETIME: 0,
21
+ FREE: 0,
22
+ USAGE_BASED: 1
23
+ };
24
+ function O() {
25
+ let { navigateTo: O, currentUser: k } = e(), A = p({ pagination: {
26
+ limit: 100,
27
+ offset: 0
28
+ } }), j = f({ pagination: {
29
+ limit: 50,
30
+ offset: 0
31
+ } }), M = d({ pagination: {
32
+ limit: 50,
33
+ offset: 0
34
+ } }), N = m({ upcomingOnly: !0 }), P = h(() => A.data?.items ?? [], [A.data]), F = h(() => j.data?.items ?? [], [j.data]), I = h(() => M.data?.items ?? [], [M.data]), L = N.data ?? [], R = h(() => {
35
+ let e = P.filter((e) => e.status === "ACTIVE" || e.status === "TRIAL"), t = e.reduce((e, t) => e + t.amount * (D[t.interval] ?? 1), 0), n = P.filter((e) => e.status === "TRIAL").length, r = P.filter((e) => e.status === "PAST_DUE").length, i = e[0]?.currency ?? "USD", a = I.filter((e) => e.actionRequired && !e.isRead).length, o = F.filter((e) => e.status === "ISSUED" || e.status === "OVERDUE" || e.status === "FAILED"), s = o.reduce((e, t) => e + t.total, 0);
36
+ return {
37
+ activeCount: e.length,
38
+ monthlySpend: t,
39
+ primaryCurrency: i,
40
+ trials: n,
41
+ pastDue: r,
42
+ unreadActionRequired: a,
43
+ openInvoiceCount: o.length,
44
+ openInvoiceTotal: s
45
+ };
46
+ }, [
47
+ P,
48
+ I,
49
+ F
50
+ ]), z = h(() => {
51
+ let e = /* @__PURE__ */ new Map();
52
+ return P.forEach((t) => e.set(t.status, (e.get(t.status) ?? 0) + 1)), Array.from(e.entries()).sort((e, t) => t[1] - e[1]);
53
+ }, [P]), B = A.isLoading || j.isLoading || M.isLoading || N.isLoading, V = A.isError && j.isError && M.isError && N.isError;
54
+ if (B) return /* @__PURE__ */ w(t, {
55
+ title: "Overview",
56
+ description: "Your recurring digital relationships at a glance",
57
+ children: /* @__PURE__ */ w(l, { label: "Loading your subscription portfolio…" })
58
+ });
59
+ if (V) return /* @__PURE__ */ w(t, {
60
+ title: "Overview",
61
+ description: "Your recurring digital relationships at a glance",
62
+ children: /* @__PURE__ */ w(c, {
63
+ message: "We couldn't reach the Subscriber Bot service. Please try again.",
64
+ onRetry: () => {
65
+ A.refetch(), j.refetch(), M.refetch(), N.refetch();
66
+ }
67
+ })
68
+ });
69
+ let H = k?.firstName || k?.name?.split(" ")[0];
70
+ return /* @__PURE__ */ T(t, {
71
+ title: H ? `Welcome back, ${H}` : "Overview",
72
+ description: "Everything you pay for on repeat — in one intelligent console.",
73
+ children: [
74
+ /* @__PURE__ */ w(E, {
75
+ className: "mb-6",
76
+ children: "Subscriber Bot is your system of record for every recurring digital relationship. See total recurring spend, what renews next, what needs action, and what to optimize — all from real data across your providers."
77
+ }),
78
+ /* @__PURE__ */ T("div", {
79
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
80
+ children: [
81
+ /* @__PURE__ */ w(n, {
82
+ featured: !0,
83
+ icon: /* @__PURE__ */ w(C, {}),
84
+ value: r(R.monthlySpend, R.primaryCurrency, { maximumFractionDigits: 0 }),
85
+ label: "Recurring spend / month"
86
+ }),
87
+ /* @__PURE__ */ w(n, {
88
+ icon: /* @__PURE__ */ w(x, {}),
89
+ value: R.activeCount,
90
+ label: "Active relationships"
91
+ }),
92
+ /* @__PURE__ */ w(n, {
93
+ icon: /* @__PURE__ */ w(y, {}),
94
+ value: L.length,
95
+ label: "Upcoming renewals"
96
+ }),
97
+ /* @__PURE__ */ w(n, {
98
+ icon: /* @__PURE__ */ w(g, {}),
99
+ value: R.unreadActionRequired,
100
+ label: "Need your action"
101
+ })
102
+ ]
103
+ }),
104
+ /* @__PURE__ */ w("div", {
105
+ className: "mt-6 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
106
+ children: [
107
+ {
108
+ label: "Add a relationship",
109
+ description: "Track a new subscription",
110
+ icon: /* @__PURE__ */ w(x, { className: "h-5 w-5" }),
111
+ path: "/relationships/new"
112
+ },
113
+ {
114
+ label: "Discover providers",
115
+ description: "Browse the registry",
116
+ icon: /* @__PURE__ */ w(S, { className: "h-5 w-5" }),
117
+ path: "/providers"
118
+ },
119
+ {
120
+ label: "Open inbox",
121
+ description: "Merged communications",
122
+ icon: /* @__PURE__ */ w(b, { className: "h-5 w-5" }),
123
+ path: "/inbox"
124
+ },
125
+ {
126
+ label: "Configure agents",
127
+ description: "Automate your portfolio",
128
+ icon: /* @__PURE__ */ w(v, { className: "h-5 w-5" }),
129
+ path: "/agents"
130
+ }
131
+ ].map((e) => /* @__PURE__ */ T("button", {
132
+ type: "button",
133
+ onClick: () => O(e.path),
134
+ className: "flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4 text-left transition-shadow hover:shadow-md",
135
+ children: [
136
+ /* @__PURE__ */ w("span", {
137
+ className: "flex size-10 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
138
+ children: e.icon
139
+ }),
140
+ /* @__PURE__ */ T("span", {
141
+ className: "min-w-0 flex-1",
142
+ children: [/* @__PURE__ */ w("span", {
143
+ className: "block text-sm font-medium text-text-primary",
144
+ children: e.label
145
+ }), /* @__PURE__ */ w("span", {
146
+ className: "block text-xs text-text-secondary",
147
+ children: e.description
148
+ })]
149
+ }),
150
+ /* @__PURE__ */ w(_, { className: "h-4 w-4 shrink-0 text-text-secondary" })
151
+ ]
152
+ }, e.path))
153
+ }),
154
+ /* @__PURE__ */ T("div", {
155
+ className: "grid grid-cols-1 gap-8 lg:grid-cols-2",
156
+ children: [/* @__PURE__ */ w(u, {
157
+ title: "Upcoming renewals",
158
+ description: "What's charging next",
159
+ action: /* @__PURE__ */ w("button", {
160
+ type: "button",
161
+ onClick: () => O("/relationships"),
162
+ className: "text-sm font-medium text-text-link hover:underline",
163
+ children: "View all"
164
+ }),
165
+ children: L.length === 0 ? /* @__PURE__ */ w(s, {
166
+ illustration: "empty-calendar",
167
+ title: "No upcoming renewals",
168
+ description: "Renewals you track will appear here ahead of time."
169
+ }) : /* @__PURE__ */ w("div", {
170
+ className: "divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface",
171
+ children: L.slice(0, 6).map((e) => /* @__PURE__ */ T("button", {
172
+ type: "button",
173
+ onClick: () => O(`/relationships/${e.relationshipId}`),
174
+ className: "flex w-full items-center justify-between gap-3 p-3 text-left hover:bg-bg-sunken",
175
+ children: [/* @__PURE__ */ T("div", {
176
+ className: "min-w-0",
177
+ children: [/* @__PURE__ */ w("p", {
178
+ className: "truncate text-sm font-medium text-text-primary",
179
+ children: i(e.eventType)
180
+ }), /* @__PURE__ */ T("p", {
181
+ className: "text-xs text-text-secondary",
182
+ children: [a(e.occursAt), e.detail ? ` · ${e.detail}` : ""]
183
+ })]
184
+ }), e.amount != null && /* @__PURE__ */ w("span", {
185
+ className: "shrink-0 text-sm font-semibold tabular-nums text-text-primary",
186
+ children: r(e.amount, e.currency ?? R.primaryCurrency)
187
+ })]
188
+ }, e.id))
189
+ })
190
+ }), /* @__PURE__ */ w(u, {
191
+ title: "Needs your attention",
192
+ description: "Required actions from the Universal Inbox",
193
+ action: /* @__PURE__ */ w("button", {
194
+ type: "button",
195
+ onClick: () => O("/inbox"),
196
+ className: "text-sm font-medium text-text-link hover:underline",
197
+ children: "Open inbox"
198
+ }),
199
+ children: I.filter((e) => e.actionRequired).length === 0 ? /* @__PURE__ */ w(s, {
200
+ illustration: "empty-inbox",
201
+ title: "You're all caught up",
202
+ description: "Required actions across all your channels will surface here."
203
+ }) : /* @__PURE__ */ w("div", {
204
+ className: "divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface",
205
+ children: I.filter((e) => e.actionRequired).slice(0, 6).map((e) => /* @__PURE__ */ T("button", {
206
+ type: "button",
207
+ onClick: () => O("/inbox"),
208
+ className: "flex w-full items-start justify-between gap-3 p-3 text-left hover:bg-bg-sunken",
209
+ children: [/* @__PURE__ */ T("div", {
210
+ className: "min-w-0",
211
+ children: [/* @__PURE__ */ w("p", {
212
+ className: "truncate text-sm font-medium text-text-primary",
213
+ children: e.subject || "(no subject)"
214
+ }), e.preview && /* @__PURE__ */ w("p", {
215
+ className: "truncate text-xs text-text-secondary",
216
+ children: e.preview
217
+ })]
218
+ }), /* @__PURE__ */ w(o, {
219
+ status: e.category,
220
+ className: "shrink-0"
221
+ })]
222
+ }, e.id))
223
+ })
224
+ })]
225
+ }),
226
+ /* @__PURE__ */ w(u, {
227
+ title: "Portfolio by lifecycle",
228
+ description: "Where your relationships stand",
229
+ children: z.length === 0 ? /* @__PURE__ */ w(s, {
230
+ illustration: "empty-data",
231
+ title: "No relationships yet",
232
+ description: "Add your first subscription to see your portfolio breakdown.",
233
+ action: /* @__PURE__ */ w("button", {
234
+ type: "button",
235
+ onClick: () => O("/relationships/new"),
236
+ className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
237
+ children: "Add relationship"
238
+ })
239
+ }) : /* @__PURE__ */ T("div", {
240
+ className: "flex flex-wrap gap-3",
241
+ children: [z.map(([e, t]) => /* @__PURE__ */ T("div", {
242
+ className: "flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-4 py-3",
243
+ children: [/* @__PURE__ */ w(o, { status: e }), /* @__PURE__ */ w("span", {
244
+ className: "text-lg font-semibold tabular-nums text-text-primary",
245
+ children: t
246
+ })]
247
+ }, e)), R.openInvoiceCount > 0 && /* @__PURE__ */ w("div", {
248
+ className: "flex items-center gap-2 rounded-lg border border-status-warning-text/30 bg-status-warning-bg-subtle px-4 py-3",
249
+ children: /* @__PURE__ */ T("span", {
250
+ className: "text-sm font-medium text-status-warning-text",
251
+ children: [
252
+ R.openInvoiceCount,
253
+ " open invoice",
254
+ R.openInvoiceCount === 1 ? "" : "s",
255
+ " ·",
256
+ " ",
257
+ r(R.openInvoiceTotal, R.primaryCurrency)
258
+ ]
259
+ })
260
+ })]
261
+ })
262
+ })
263
+ ]
264
+ });
265
+ }
266
+ //#endregion
267
+ export { O as DashboardPage };
268
+
269
+ //# sourceMappingURL=DashboardPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/subscriberbot/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard / Overview\n * @module subscriberbot/pages\n *\n * The Subscriber Bot landing page: a single view of every recurring digital\n * relationship — total recurring spend, lifecycle breakdown, upcoming\n * renewals, the action-required inbox, and outstanding invoices. Every number\n * is computed from real data returned by `wspace-subscriberbot-svc`.\n */\n\nimport { useMemo } from 'react';\nimport {\n Repeat2,\n Wallet,\n CalendarClock,\n Inbox,\n AlertTriangle,\n ArrowRight,\n Sparkles,\n Bot,\n} from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { EmptyState } from '../components/EmptyState';\nimport { LoadingView, ErrorView, Section } from '../components/StateViews';\nimport { useSubscriberBot } from '../context/SubscriberBotContext';\nimport {\n useRelationships,\n useInvoices,\n useInboxMessages,\n useRenewalEvents,\n} from '../hooks/useSubscriberBotApi';\nimport { formatCurrency, formatRelativeTime, formatEnumLabel } from '../utils/formatters';\nimport type { SubBillingInterval } from '../types';\n\n// Normalize any billing interval to an approximate monthly multiplier so we can\n// express total recurring spend as one comparable \"per month\" number.\nconst MONTHLY_FACTOR: Record<SubBillingInterval, number> = {\n DAILY: 30,\n WEEKLY: 4.345,\n MONTHLY: 1,\n QUARTERLY: 1 / 3,\n YEARLY: 1 / 12,\n LIFETIME: 0,\n FREE: 0,\n USAGE_BASED: 1,\n};\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useSubscriberBot();\n\n const relationshipsQ = useRelationships({ pagination: { limit: 100, offset: 0 } });\n const invoicesQ = useInvoices({ pagination: { limit: 50, offset: 0 } });\n const inboxQ = useInboxMessages({ pagination: { limit: 50, offset: 0 } });\n const renewalsQ = useRenewalEvents({ upcomingOnly: true });\n\n const relationships = useMemo(\n () => relationshipsQ.data?.items ?? [],\n [relationshipsQ.data]\n );\n const invoices = useMemo(() => invoicesQ.data?.items ?? [], [invoicesQ.data]);\n const messages = useMemo(() => inboxQ.data?.items ?? [], [inboxQ.data]);\n const renewals = renewalsQ.data ?? [];\n\n const stats = useMemo(() => {\n const active = relationships.filter((r) => r.status === 'ACTIVE' || r.status === 'TRIAL');\n const monthlySpend = active.reduce(\n (sum, r) => sum + r.amount * (MONTHLY_FACTOR[r.interval] ?? 1),\n 0\n );\n const trials = relationships.filter((r) => r.status === 'TRIAL').length;\n const pastDue = relationships.filter((r) => r.status === 'PAST_DUE').length;\n const primaryCurrency = active[0]?.currency ?? 'USD';\n const unreadActionRequired = messages.filter((m) => m.actionRequired && !m.isRead).length;\n const openInvoices = invoices.filter(\n (i) => i.status === 'ISSUED' || i.status === 'OVERDUE' || i.status === 'FAILED'\n );\n const openInvoiceTotal = openInvoices.reduce((sum, i) => sum + i.total, 0);\n\n return {\n activeCount: active.length,\n monthlySpend,\n primaryCurrency,\n trials,\n pastDue,\n unreadActionRequired,\n openInvoiceCount: openInvoices.length,\n openInvoiceTotal,\n };\n }, [relationships, messages, invoices]);\n\n const statusBreakdown = useMemo(() => {\n const counts = new Map<string, number>();\n relationships.forEach((r) => counts.set(r.status, (counts.get(r.status) ?? 0) + 1));\n return Array.from(counts.entries()).sort((a, b) => b[1] - a[1]);\n }, [relationships]);\n\n const isLoading =\n relationshipsQ.isLoading || invoicesQ.isLoading || inboxQ.isLoading || renewalsQ.isLoading;\n const isError =\n relationshipsQ.isError && invoicesQ.isError && inboxQ.isError && renewalsQ.isError;\n\n if (isLoading) {\n return (\n <PageLayout title=\"Overview\" description=\"Your recurring digital relationships at a glance\">\n <LoadingView label=\"Loading your subscription portfolio…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Overview\" description=\"Your recurring digital relationships at a glance\">\n <ErrorView\n message=\"We couldn't reach the Subscriber Bot service. Please try again.\"\n onRetry={() => {\n void relationshipsQ.refetch();\n void invoicesQ.refetch();\n void inboxQ.refetch();\n void renewalsQ.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name?.split(' ')[0];\n\n return (\n <PageLayout\n title={greetingName ? `Welcome back, ${greetingName}` : 'Overview'}\n description=\"Everything you pay for on repeat — in one intelligent console.\"\n >\n <PagePurpose className=\"mb-6\">\n Subscriber Bot is your system of record for every recurring digital relationship. See total\n recurring spend, what renews next, what needs action, and what to optimize — all from real\n data across your providers.\n </PagePurpose>\n\n {/* KPI tiles */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Wallet />}\n value={formatCurrency(stats.monthlySpend, stats.primaryCurrency, {\n maximumFractionDigits: 0,\n })}\n label=\"Recurring spend / month\"\n />\n <MetricsCard\n icon={<Repeat2 />}\n value={stats.activeCount}\n label=\"Active relationships\"\n />\n <MetricsCard\n icon={<CalendarClock />}\n value={renewals.length}\n label=\"Upcoming renewals\"\n />\n <MetricsCard\n icon={<AlertTriangle />}\n value={stats.unreadActionRequired}\n label=\"Need your action\"\n />\n </div>\n\n {/* Quick actions */}\n <div className=\"mt-6 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n {[\n {\n label: 'Add a relationship',\n description: 'Track a new subscription',\n icon: <Repeat2 className=\"h-5 w-5\" />,\n path: '/relationships/new',\n },\n {\n label: 'Discover providers',\n description: 'Browse the registry',\n icon: <Sparkles className=\"h-5 w-5\" />,\n path: '/providers',\n },\n {\n label: 'Open inbox',\n description: 'Merged communications',\n icon: <Inbox className=\"h-5 w-5\" />,\n path: '/inbox',\n },\n {\n label: 'Configure agents',\n description: 'Automate your portfolio',\n icon: <Bot className=\"h-5 w-5\" />,\n path: '/agents',\n },\n ].map((qa) => (\n <button\n key={qa.path}\n type=\"button\"\n onClick={() => navigateTo(qa.path)}\n className=\"flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4 text-left transition-shadow hover:shadow-md\"\n >\n <span className=\"flex size-10 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {qa.icon}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-medium text-text-primary\">{qa.label}</span>\n <span className=\"block text-xs text-text-secondary\">{qa.description}</span>\n </span>\n <ArrowRight className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n </button>\n ))}\n </div>\n\n <div className=\"grid grid-cols-1 gap-8 lg:grid-cols-2\">\n {/* Upcoming renewals */}\n <Section\n title=\"Upcoming renewals\"\n description=\"What's charging next\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n View all\n </button>\n }\n >\n {renewals.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n title=\"No upcoming renewals\"\n description=\"Renewals you track will appear here ahead of time.\"\n />\n ) : (\n <div className=\"divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface\">\n {renewals.slice(0, 6).map((event) => (\n <button\n key={event.id}\n type=\"button\"\n onClick={() => navigateTo(`/relationships/${event.relationshipId}`)}\n className=\"flex w-full items-center justify-between gap-3 p-3 text-left hover:bg-bg-sunken\"\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {formatEnumLabel(event.eventType)}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {formatRelativeTime(event.occursAt)}\n {event.detail ? ` · ${event.detail}` : ''}\n </p>\n </div>\n {event.amount != null && (\n <span className=\"shrink-0 text-sm font-semibold tabular-nums text-text-primary\">\n {formatCurrency(event.amount, event.currency ?? stats.primaryCurrency)}\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n </Section>\n\n {/* Action-required inbox */}\n <Section\n title=\"Needs your attention\"\n description=\"Required actions from the Universal Inbox\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/inbox')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n Open inbox\n </button>\n }\n >\n {messages.filter((m) => m.actionRequired).length === 0 ? (\n <EmptyState\n illustration=\"empty-inbox\"\n title=\"You're all caught up\"\n description=\"Required actions across all your channels will surface here.\"\n />\n ) : (\n <div className=\"divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface\">\n {messages\n .filter((m) => m.actionRequired)\n .slice(0, 6)\n .map((message) => (\n <button\n key={message.id}\n type=\"button\"\n onClick={() => navigateTo('/inbox')}\n className=\"flex w-full items-start justify-between gap-3 p-3 text-left hover:bg-bg-sunken\"\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {message.subject || '(no subject)'}\n </p>\n {message.preview && (\n <p className=\"truncate text-xs text-text-secondary\">{message.preview}</p>\n )}\n </div>\n <StatusBadge status={message.category} className=\"shrink-0\" />\n </button>\n ))}\n </div>\n )}\n </Section>\n </div>\n\n {/* Lifecycle breakdown */}\n <Section title=\"Portfolio by lifecycle\" description=\"Where your relationships stand\">\n {statusBreakdown.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No relationships yet\"\n description=\"Add your first subscription to see your portfolio breakdown.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Add relationship\n </button>\n }\n />\n ) : (\n <div className=\"flex flex-wrap gap-3\">\n {statusBreakdown.map(([status, count]) => (\n <div\n key={status}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-4 py-3\"\n >\n <StatusBadge status={status} />\n <span className=\"text-lg font-semibold tabular-nums text-text-primary\">{count}</span>\n </div>\n ))}\n {stats.openInvoiceCount > 0 && (\n <div className=\"flex items-center gap-2 rounded-lg border border-status-warning-text/30 bg-status-warning-bg-subtle px-4 py-3\">\n <span className=\"text-sm font-medium text-status-warning-text\">\n {stats.openInvoiceCount} open invoice{stats.openInvoiceCount !== 1 ? 's' : ''} ·{' '}\n {formatCurrency(stats.openInvoiceTotal, stats.primaryCurrency)}\n </span>\n </div>\n )}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAuCA,IAAM,IAAqD;CACzD,OAAO;CACP,QAAQ;CACR,SAAS;CACT,WAAW,IAAI;CACf,QAAQ,IAAI;CACZ,UAAU;CACV,MAAM;CACN,aAAa;CACd;AAED,SAAgB,IAAgB;CAC9B,IAAM,EAAE,eAAY,mBAAgB,GAAkB,EAEhD,IAAiB,EAAiB,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAC5E,IAAY,EAAY,EAAE,YAAY;EAAE,OAAO;EAAI,QAAQ;EAAG,EAAE,CAAC,EACjE,IAAS,EAAiB,EAAE,YAAY;EAAE,OAAO;EAAI,QAAQ;EAAG,EAAE,CAAC,EACnE,IAAY,EAAiB,EAAE,cAAc,IAAM,CAAC,EAEpD,IAAgB,QACd,EAAe,MAAM,SAAS,EAAE,EACtC,CAAC,EAAe,KAAK,CACtB,EACK,IAAW,QAAc,EAAU,MAAM,SAAS,EAAE,EAAE,CAAC,EAAU,KAAK,CAAC,EACvE,IAAW,QAAc,EAAO,MAAM,SAAS,EAAE,EAAE,CAAC,EAAO,KAAK,CAAC,EACjE,IAAW,EAAU,QAAQ,EAAE,EAE/B,IAAQ,QAAc;EAC1B,IAAM,IAAS,EAAc,QAAQ,MAAM,EAAE,WAAW,YAAY,EAAE,WAAW,QAAQ,EACnF,IAAe,EAAO,QACzB,GAAK,MAAM,IAAM,EAAE,UAAU,EAAe,EAAE,aAAa,IAC5D,EACD,EACK,IAAS,EAAc,QAAQ,MAAM,EAAE,WAAW,QAAQ,CAAC,QAC3D,IAAU,EAAc,QAAQ,MAAM,EAAE,WAAW,WAAW,CAAC,QAC/D,IAAkB,EAAO,IAAI,YAAY,OACzC,IAAuB,EAAS,QAAQ,MAAM,EAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC,QAC7E,IAAe,EAAS,QAC3B,MAAM,EAAE,WAAW,YAAY,EAAE,WAAW,aAAa,EAAE,WAAW,SACxE,EACK,IAAmB,EAAa,QAAQ,GAAK,MAAM,IAAM,EAAE,OAAO,EAAE;AAE1E,SAAO;GACL,aAAa,EAAO;GACpB;GACA;GACA;GACA;GACA;GACA,kBAAkB,EAAa;GAC/B;GACD;IACA;EAAC;EAAe;EAAU;EAAS,CAAC,EAEjC,IAAkB,QAAc;EACpC,IAAM,oBAAS,IAAI,KAAqB;AAExC,SADA,EAAc,SAAS,MAAM,EAAO,IAAI,EAAE,SAAS,EAAO,IAAI,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,EAC5E,MAAM,KAAK,EAAO,SAAS,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG;IAC9D,CAAC,EAAc,CAAC,EAEb,IACJ,EAAe,aAAa,EAAU,aAAa,EAAO,aAAa,EAAU,WAC7E,IACJ,EAAe,WAAW,EAAU,WAAW,EAAO,WAAW,EAAU;AAE7E,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;YACvC,kBAAC,GAAD,EAAa,OAAM,wCAAyC,CAAA;EACjD,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;YACvC,kBAAC,GAAD;GACE,SAAQ;GACR,eAAe;AAIR,IAHA,EAAe,SAAS,EACxB,EAAU,SAAS,EACnB,EAAO,SAAS,EAChB,EAAU,SAAS;;GAE1B,CAAA;EACS,CAAA;CAIjB,IAAM,IAAe,GAAa,aAAa,GAAa,MAAM,MAAM,IAAI,CAAC;AAE7E,QACE,kBAAC,GAAD;EACE,OAAO,IAAe,iBAAiB,MAAiB;EACxD,aAAY;YAFd;GAIE,kBAAC,GAAD;IAAa,WAAU;cAAO;IAIhB,CAAA;GAGd,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,UAAA;MACA,MAAM,kBAAC,GAAD,EAAU,CAAA;MAChB,OAAO,EAAe,EAAM,cAAc,EAAM,iBAAiB,EAC/D,uBAAuB,GACxB,CAAC;MACF,OAAM;MACN,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAW,CAAA;MACjB,OAAO,EAAM;MACb,OAAM;MACN,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAiB,CAAA;MACvB,OAAO,EAAS;MAChB,OAAM;MACN,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAiB,CAAA;MACvB,OAAO,EAAM;MACb,OAAM;MACN,CAAA;KACE;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ;KACC;MACE,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;MACrC,MAAM;MACP;KACD;MACE,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;MACtC,MAAM;MACP;KACD;MACE,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,MAAM;MACP;KACD;MACE,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA;MACjC,MAAM;MACP;KACF,CAAC,KAAK,MACL,kBAAC,UAAD;KAEE,MAAK;KACL,eAAe,EAAW,EAAG,KAAK;KAClC,WAAU;eAJZ;MAME,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAG;OACC,CAAA;MACP,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,QAAD;QAAM,WAAU;kBAA+C,EAAG;QAAa,CAAA,EAC/E,kBAAC,QAAD;QAAM,WAAU;kBAAqC,EAAG;QAAmB,CAAA,CACtE;;MACP,kBAAC,GAAD,EAAY,WAAU,wCAAyC,CAAA;MACxD;OAbF,EAAG,KAaD,CACT;IACE,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,iBAAiB;MAC3C,WAAU;gBACX;MAEQ,CAAA;eAGV,EAAS,WAAW,IACnB,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA,GAEF,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAS,MAAM,GAAG,EAAE,CAAC,KAAK,MACzB,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAW,kBAAkB,EAAM,iBAAiB;OACnE,WAAU;iBAJZ,CAME,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAgB,EAAM,UAAU;SAC/B,CAAA,EACJ,kBAAC,KAAD;SAAG,WAAU;mBAAb,CACG,EAAmB,EAAM,SAAS,EAClC,EAAM,SAAS,MAAM,EAAM,WAAW,GACrC;WACA;WACL,EAAM,UAAU,QACf,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAe,EAAM,QAAQ,EAAM,YAAY,EAAM,gBAAgB;QACjE,CAAA,CAEF;SAnBF,EAAM,GAmBJ,CACT;MACE,CAAA;KAEA,CAAA,EAGV,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,SAAS;MACnC,WAAU;gBACX;MAEQ,CAAA;eAGV,EAAS,QAAQ,MAAM,EAAE,eAAe,CAAC,WAAW,IACnD,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA,GAEF,kBAAC,OAAD;MAAK,WAAU;gBACZ,EACE,QAAQ,MAAM,EAAE,eAAe,CAC/B,MAAM,GAAG,EAAE,CACX,KAAK,MACJ,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAW,SAAS;OACnC,WAAU;iBAJZ,CAME,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAQ,WAAW;SAClB,CAAA,EACH,EAAQ,WACP,kBAAC,KAAD;SAAG,WAAU;mBAAwC,EAAQ;SAAY,CAAA,CAEvE;WACN,kBAAC,GAAD;QAAa,QAAQ,EAAQ;QAAU,WAAU;QAAa,CAAA,CACvD;SAdF,EAAQ,GAcN,CACT;MACA,CAAA;KAEA,CAAA,CACN;;GAGN,kBAAC,GAAD;IAAS,OAAM;IAAyB,aAAY;cACjD,EAAgB,WAAW,IAC1B,kBAAC,GAAD;KACE,cAAa;KACb,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,qBAAqB;MAC/C,WAAU;gBACX;MAEQ,CAAA;KAEX,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAgB,KAAK,CAAC,GAAQ,OAC7B,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,GAAD,EAAqB,WAAU,CAAA,EAC/B,kBAAC,QAAD;OAAM,WAAU;iBAAwD;OAAa,CAAA,CACjF;QALC,EAKD,CACN,EACD,EAAM,mBAAmB,KACxB,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACG,EAAM;QAAiB;QAAc,EAAM,qBAAqB,IAAU,KAAN;QAAS;QAAG;QAChF,EAAe,EAAM,kBAAkB,EAAM,gBAAgB;QACzD;;MACH,CAAA,CAEJ;;IAEA,CAAA;GACC"}
@@ -0,0 +1,186 @@
1
+ import { useSubscriberBot as e } from "../context/SubscriberBotContext.js";
2
+ import { cn as t } from "../utils/cn.js";
3
+ import { PageLayout as n } from "../components/PageLayout.js";
4
+ import { formatRelativeTime as r } from "../utils/formatters.js";
5
+ import { StatusBadge as i } from "../components/StatusBadge.js";
6
+ import { EmptyState as a } from "../components/EmptyState.js";
7
+ import { ErrorView as o, LoadingView as s } from "../components/StateViews.js";
8
+ import { useInboxMessages as c, useMarkMessageRead as l } from "../hooks/useSubscriberBotApi.js";
9
+ import { useState as u } from "react";
10
+ import { AlertTriangle as d, Inbox as f, Mail as p, MailOpen as m } from "lucide-react";
11
+ import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
12
+ import { PagePurpose as v } from "@burdenoff/fe-libs/ui";
13
+ //#region src/subscriberbot/pages/InboxPage.tsx
14
+ var y = 25, b = [
15
+ {
16
+ value: "",
17
+ label: "All categories"
18
+ },
19
+ {
20
+ value: "BILLING",
21
+ label: "Billing"
22
+ },
23
+ {
24
+ value: "RENEWAL",
25
+ label: "Renewals"
26
+ },
27
+ {
28
+ value: "REQUIRED_ACTION",
29
+ label: "Required actions"
30
+ },
31
+ {
32
+ value: "SECURITY_ALERT",
33
+ label: "Security alerts"
34
+ },
35
+ {
36
+ value: "PRODUCT_UPDATE",
37
+ label: "Product updates"
38
+ },
39
+ {
40
+ value: "MARKETING",
41
+ label: "Marketing"
42
+ },
43
+ {
44
+ value: "OTHER",
45
+ label: "Other"
46
+ }
47
+ ];
48
+ function x() {
49
+ let { navigateTo: x } = e(), [S, C] = u(0), [w, T] = u(""), [E, D] = u(!1), { data: O, isLoading: k, isError: A, refetch: j, isFetching: M } = c({
50
+ category: w || void 0,
51
+ unreadOnly: E || void 0,
52
+ pagination: {
53
+ limit: y,
54
+ offset: S * y
55
+ }
56
+ }), N = l(), P = O?.items ?? [], F = O?.pageInfo.hasMore ?? !1;
57
+ return /* @__PURE__ */ _(n, {
58
+ title: "Universal Inbox",
59
+ description: "Every subscription communication, merged and categorized",
60
+ children: [
61
+ /* @__PURE__ */ g(v, {
62
+ className: "mb-4",
63
+ children: "Subscription communication is noisy and scattered. The Universal Inbox merges every channel a provider uses and uses AI to categorize each message so you never miss a renewal, required action or security notice."
64
+ }),
65
+ /* @__PURE__ */ _("div", {
66
+ className: "flex flex-wrap items-center gap-3",
67
+ children: [/* @__PURE__ */ g("select", {
68
+ value: w,
69
+ onChange: (e) => {
70
+ T(e.target.value), C(0);
71
+ },
72
+ className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
73
+ children: b.map((e) => /* @__PURE__ */ g("option", {
74
+ value: e.value,
75
+ children: e.label
76
+ }, e.value))
77
+ }), /* @__PURE__ */ _("label", {
78
+ className: "flex items-center gap-2 text-sm text-text-primary",
79
+ children: [/* @__PURE__ */ g("input", {
80
+ type: "checkbox",
81
+ checked: E,
82
+ onChange: (e) => {
83
+ D(e.target.checked), C(0);
84
+ },
85
+ className: "size-4 rounded border-border-subtle"
86
+ }), "Unread only"]
87
+ })]
88
+ }),
89
+ k ? /* @__PURE__ */ g(s, { label: "Loading inbox…" }) : A ? /* @__PURE__ */ g(o, {
90
+ message: "Could not load the inbox.",
91
+ onRetry: () => void j()
92
+ }) : P.length === 0 ? /* @__PURE__ */ g("div", {
93
+ className: "mt-6",
94
+ children: /* @__PURE__ */ g(a, {
95
+ illustration: "empty-inbox",
96
+ icon: /* @__PURE__ */ g(f, { className: "h-12 w-12" }),
97
+ title: "Inbox is empty",
98
+ description: E || w ? "No messages match these filters." : "Merged subscription communications will appear here once channels start ingesting."
99
+ })
100
+ }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", {
101
+ className: "mt-6 divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface",
102
+ children: P.map((e) => /* @__PURE__ */ _("div", {
103
+ className: t("flex items-start gap-3 p-4", !e.isRead && "bg-accent-wash"),
104
+ children: [
105
+ /* @__PURE__ */ g("span", {
106
+ className: "mt-0.5 shrink-0 text-text-secondary",
107
+ children: e.isRead ? /* @__PURE__ */ g(m, { className: "h-4 w-4" }) : /* @__PURE__ */ g(p, { className: "h-4 w-4 text-text-link" })
108
+ }),
109
+ /* @__PURE__ */ _("div", {
110
+ className: "min-w-0 flex-1",
111
+ children: [
112
+ /* @__PURE__ */ _("div", {
113
+ className: "flex items-center gap-2",
114
+ children: [/* @__PURE__ */ g("p", {
115
+ className: t("truncate text-sm", e.isRead ? "font-normal text-text-primary" : "font-semibold text-text-primary"),
116
+ children: e.subject || "(no subject)"
117
+ }), e.actionRequired && /* @__PURE__ */ _("span", {
118
+ title: "Action required",
119
+ className: "inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-[10px] font-medium text-status-warning-text",
120
+ children: [/* @__PURE__ */ g(d, { className: "h-3 w-3" }), " Action"]
121
+ })]
122
+ }),
123
+ e.preview && /* @__PURE__ */ g("p", {
124
+ className: "mt-0.5 line-clamp-2 text-xs text-text-secondary",
125
+ children: e.preview
126
+ }),
127
+ /* @__PURE__ */ _("div", {
128
+ className: "mt-1.5 flex flex-wrap items-center gap-2",
129
+ children: [
130
+ /* @__PURE__ */ g(i, { status: e.category }),
131
+ /* @__PURE__ */ g("span", {
132
+ className: "text-xs text-text-secondary",
133
+ children: r(e.receivedAt)
134
+ }),
135
+ e.relationshipId && /* @__PURE__ */ g("button", {
136
+ type: "button",
137
+ onClick: () => x(`/relationships/${e.relationshipId}`),
138
+ className: "text-xs font-medium text-text-link hover:underline",
139
+ children: "View relationship"
140
+ })
141
+ ]
142
+ })
143
+ ]
144
+ }),
145
+ !e.isRead && /* @__PURE__ */ g("button", {
146
+ type: "button",
147
+ disabled: N.isPending,
148
+ onClick: () => N.mutate(e.id),
149
+ className: "shrink-0 rounded-lg border border-border-subtle px-2.5 py-1 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50",
150
+ children: "Mark read"
151
+ })
152
+ ]
153
+ }, e.id))
154
+ }), /* @__PURE__ */ _("div", {
155
+ className: "mt-4 flex items-center justify-between",
156
+ children: [/* @__PURE__ */ _("p", {
157
+ className: "text-xs text-text-secondary",
158
+ children: [
159
+ "Page ",
160
+ S + 1,
161
+ M ? " · refreshing…" : ""
162
+ ]
163
+ }), /* @__PURE__ */ _("div", {
164
+ className: "flex gap-2",
165
+ children: [/* @__PURE__ */ g("button", {
166
+ type: "button",
167
+ disabled: S === 0,
168
+ onClick: () => C((e) => Math.max(0, e - 1)),
169
+ className: t("rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium", S === 0 ? "cursor-not-allowed text-text-secondary opacity-50" : "text-text-primary hover:bg-bg-sunken"),
170
+ children: "Previous"
171
+ }), /* @__PURE__ */ g("button", {
172
+ type: "button",
173
+ disabled: !F,
174
+ onClick: () => C((e) => e + 1),
175
+ className: t("rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium", F ? "text-text-primary hover:bg-bg-sunken" : "cursor-not-allowed text-text-secondary opacity-50"),
176
+ children: "Next"
177
+ })]
178
+ })]
179
+ })] })
180
+ ]
181
+ });
182
+ }
183
+ //#endregion
184
+ export { x as InboxPage };
185
+
186
+ //# sourceMappingURL=InboxPage.js.map