@open-mercato/core 0.6.7-develop.6758.1.697eade236 → 0.6.7-develop.6768.1.9d2c4efc43

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 (269) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/api_keys/backend/api-keys/page.js +2 -1
  3. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  4. package/dist/modules/api_keys/extension-points.js +16 -0
  5. package/dist/modules/api_keys/extension-points.js.map +7 -0
  6. package/dist/modules/audit_logs/components/AccessLogsTable.js +2 -1
  7. package/dist/modules/audit_logs/components/AccessLogsTable.js.map +2 -2
  8. package/dist/modules/audit_logs/components/AuditLogsActions.js +2 -1
  9. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  10. package/dist/modules/audit_logs/extension-points.js +14 -0
  11. package/dist/modules/audit_logs/extension-points.js.map +7 -0
  12. package/dist/modules/auth/backend/roles/page.js +2 -1
  13. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  14. package/dist/modules/auth/backend/users/page.js +2 -1
  15. package/dist/modules/auth/backend/users/page.js.map +2 -2
  16. package/dist/modules/auth/extension-points.js +21 -0
  17. package/dist/modules/auth/extension-points.js.map +7 -0
  18. package/dist/modules/auth/frontend/login.js +5 -1
  19. package/dist/modules/auth/frontend/login.js.map +2 -2
  20. package/dist/modules/business_rules/backend/rules/page.js +2 -1
  21. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  22. package/dist/modules/business_rules/events.js +13 -0
  23. package/dist/modules/business_rules/events.js.map +7 -0
  24. package/dist/modules/business_rules/extension-points.js +13 -0
  25. package/dist/modules/business_rules/extension-points.js.map +7 -0
  26. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +2 -1
  27. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  28. package/dist/modules/catalog/backend/catalog/products/create/page.js +2 -1
  29. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  30. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -1
  31. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  32. package/dist/modules/catalog/components/products/ProductsDataTable.js +3 -2
  33. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  34. package/dist/modules/catalog/events.js +1 -0
  35. package/dist/modules/catalog/events.js.map +2 -2
  36. package/dist/modules/catalog/extension-points.js +27 -0
  37. package/dist/modules/catalog/extension-points.js.map +7 -0
  38. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +2 -1
  39. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  40. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +3 -2
  41. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
  42. package/dist/modules/communication_channels/extension-points.js +20 -0
  43. package/dist/modules/communication_channels/extension-points.js.map +7 -0
  44. package/dist/modules/configs/backend/config/system-status/page.js +2 -1
  45. package/dist/modules/configs/backend/config/system-status/page.js.map +2 -2
  46. package/dist/modules/configs/extension-points.js +18 -0
  47. package/dist/modules/configs/extension-points.js.map +7 -0
  48. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  49. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  50. package/dist/modules/currencies/backend/exchange-rates/page.js +2 -1
  51. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  52. package/dist/modules/currencies/extension-points.js +14 -0
  53. package/dist/modules/currencies/extension-points.js.map +7 -0
  54. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +2 -1
  55. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  56. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +2 -1
  57. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  58. package/dist/modules/customer_accounts/extension-points.js +14 -0
  59. package/dist/modules/customer_accounts/extension-points.js.map +7 -0
  60. package/dist/modules/customers/api/deals/summary/route.js +9 -115
  61. package/dist/modules/customers/api/deals/summary/route.js.map +2 -2
  62. package/dist/modules/customers/backend/customers/companies/[id]/page.js +2 -1
  63. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  64. package/dist/modules/customers/backend/customers/companies/page.js +2 -1
  65. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  66. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +5 -4
  67. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  68. package/dist/modules/customers/backend/customers/deals/[id]/page.js +5 -4
  69. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  70. package/dist/modules/customers/backend/customers/deals/page.js +2 -1
  71. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  72. package/dist/modules/customers/backend/customers/people/[id]/page.js +2 -1
  73. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  74. package/dist/modules/customers/backend/customers/people/page.js +2 -1
  75. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  76. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +5 -4
  77. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  78. package/dist/modules/customers/components/CustomerTodosTable.js +2 -1
  79. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  80. package/dist/modules/customers/extension-points.js +42 -0
  81. package/dist/modules/customers/extension-points.js.map +7 -0
  82. package/dist/modules/customers/lib/calendar/format.js +8 -4
  83. package/dist/modules/customers/lib/calendar/format.js.map +2 -2
  84. package/dist/modules/customers/lib/dealsSummaryQueries.js +144 -0
  85. package/dist/modules/customers/lib/dealsSummaryQueries.js.map +7 -0
  86. package/dist/modules/data_sync/backend/data-sync/page.js +2 -1
  87. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  88. package/dist/modules/data_sync/extension-points.js +13 -0
  89. package/dist/modules/data_sync/extension-points.js.map +7 -0
  90. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  91. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  92. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  93. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  94. package/dist/modules/directory/extension-points.js +14 -0
  95. package/dist/modules/directory/extension-points.js.map +7 -0
  96. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +5 -1
  97. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  98. package/dist/modules/entities/components/SystemEntitiesTable.js +2 -1
  99. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  100. package/dist/modules/entities/components/UserEntitiesTable.js +2 -1
  101. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  102. package/dist/modules/entities/extension-points.js +21 -0
  103. package/dist/modules/entities/extension-points.js.map +7 -0
  104. package/dist/modules/integrations/backend/integrations/[id]/page.js +2 -4
  105. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  106. package/dist/modules/integrations/extension-points.js +30 -0
  107. package/dist/modules/integrations/extension-points.js.map +7 -0
  108. package/dist/modules/messages/components/ComposeMessagePageClient.js +2 -1
  109. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +2 -2
  110. package/dist/modules/messages/components/MessageDetailPageClient.js +3 -2
  111. package/dist/modules/messages/components/MessageDetailPageClient.js.map +2 -2
  112. package/dist/modules/messages/components/MessagesInboxPageClient.js +2 -1
  113. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  114. package/dist/modules/messages/extension-points.js +16 -0
  115. package/dist/modules/messages/extension-points.js.map +7 -0
  116. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -2
  117. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  118. package/dist/modules/payment_gateways/extension-points.js +19 -0
  119. package/dist/modules/payment_gateways/extension-points.js.map +7 -0
  120. package/dist/modules/portal/extension-points.js +32 -0
  121. package/dist/modules/portal/extension-points.js.map +7 -0
  122. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +3 -3
  123. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
  124. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +3 -3
  125. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
  126. package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -3
  127. package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
  128. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +3 -3
  129. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
  130. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +3 -3
  131. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +2 -2
  132. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +3 -3
  133. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
  134. package/dist/modules/query_index/components/QueryIndexesTable.js +2 -1
  135. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  136. package/dist/modules/query_index/events.js +20 -0
  137. package/dist/modules/query_index/events.js.map +7 -0
  138. package/dist/modules/query_index/extension-points.js +13 -0
  139. package/dist/modules/query_index/extension-points.js.map +7 -0
  140. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -1
  141. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  142. package/dist/modules/resources/backend/resources/resources/page.js +2 -1
  143. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  144. package/dist/modules/resources/extension-points.js +14 -0
  145. package/dist/modules/resources/extension-points.js.map +7 -0
  146. package/dist/modules/sales/backend/sales/documents/[id]/page.js +11 -3
  147. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  148. package/dist/modules/sales/components/documents/ItemsSection.js +2 -1
  149. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  150. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -1
  151. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  152. package/dist/modules/sales/events.js +1 -0
  153. package/dist/modules/sales/events.js.map +2 -2
  154. package/dist/modules/sales/extension-points.js +36 -0
  155. package/dist/modules/sales/extension-points.js.map +7 -0
  156. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +5 -4
  157. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
  158. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +4 -3
  159. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  160. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +3 -2
  161. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
  162. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +3 -2
  163. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
  164. package/dist/modules/wms/components/backend/WmsLotsListPage.js +2 -1
  165. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  166. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +3 -2
  167. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
  168. package/dist/modules/wms/extension-points.js +26 -0
  169. package/dist/modules/wms/extension-points.js.map +7 -0
  170. package/dist/modules/workflows/backend/definitions/page.js +2 -1
  171. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  172. package/dist/modules/workflows/backend/instances/page.js +2 -1
  173. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  174. package/dist/modules/workflows/backend/tasks/page.js +2 -1
  175. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  176. package/dist/modules/workflows/events.js +1 -0
  177. package/dist/modules/workflows/events.js.map +2 -2
  178. package/dist/modules/workflows/extension-points.js +15 -0
  179. package/dist/modules/workflows/extension-points.js.map +7 -0
  180. package/package.json +7 -7
  181. package/src/modules/api_keys/backend/api-keys/page.tsx +2 -1
  182. package/src/modules/api_keys/extension-points.ts +13 -0
  183. package/src/modules/audit_logs/components/AccessLogsTable.tsx +2 -1
  184. package/src/modules/audit_logs/components/AuditLogsActions.tsx +2 -1
  185. package/src/modules/audit_logs/extension-points.ts +11 -0
  186. package/src/modules/auth/backend/roles/page.tsx +2 -1
  187. package/src/modules/auth/backend/users/page.tsx +2 -1
  188. package/src/modules/auth/extension-points.ts +18 -0
  189. package/src/modules/auth/frontend/login.tsx +5 -1
  190. package/src/modules/business_rules/backend/rules/page.tsx +2 -1
  191. package/src/modules/business_rules/events.ts +10 -0
  192. package/src/modules/business_rules/extension-points.ts +10 -0
  193. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2 -1
  194. package/src/modules/catalog/backend/catalog/products/create/page.tsx +2 -1
  195. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -1
  196. package/src/modules/catalog/components/products/ProductsDataTable.tsx +3 -2
  197. package/src/modules/catalog/events.ts +1 -0
  198. package/src/modules/catalog/extension-points.ts +24 -0
  199. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +2 -1
  200. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +3 -2
  201. package/src/modules/communication_channels/extension-points.ts +17 -0
  202. package/src/modules/configs/backend/config/system-status/page.tsx +2 -1
  203. package/src/modules/configs/extension-points.ts +15 -0
  204. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  205. package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -1
  206. package/src/modules/currencies/extension-points.ts +11 -0
  207. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +2 -1
  208. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +2 -1
  209. package/src/modules/customer_accounts/extension-points.ts +11 -0
  210. package/src/modules/customers/api/deals/summary/route.ts +10 -158
  211. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +2 -1
  212. package/src/modules/customers/backend/customers/companies/page.tsx +2 -1
  213. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +5 -4
  214. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +5 -4
  215. package/src/modules/customers/backend/customers/deals/page.tsx +2 -1
  216. package/src/modules/customers/backend/customers/people/[id]/page.tsx +2 -1
  217. package/src/modules/customers/backend/customers/people/page.tsx +2 -1
  218. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +5 -4
  219. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -1
  220. package/src/modules/customers/extension-points.ts +40 -0
  221. package/src/modules/customers/lib/calendar/format.ts +10 -4
  222. package/src/modules/customers/lib/dealsSummaryQueries.ts +211 -0
  223. package/src/modules/data_sync/backend/data-sync/page.tsx +2 -1
  224. package/src/modules/data_sync/extension-points.ts +10 -0
  225. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -1
  226. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -1
  227. package/src/modules/directory/extension-points.ts +11 -0
  228. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +5 -1
  229. package/src/modules/entities/components/SystemEntitiesTable.tsx +2 -1
  230. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -1
  231. package/src/modules/entities/extension-points.ts +18 -0
  232. package/src/modules/integrations/backend/integrations/[id]/page.tsx +2 -2
  233. package/src/modules/integrations/extension-points.ts +27 -0
  234. package/src/modules/messages/components/ComposeMessagePageClient.tsx +2 -1
  235. package/src/modules/messages/components/MessageDetailPageClient.tsx +3 -2
  236. package/src/modules/messages/components/MessagesInboxPageClient.tsx +2 -1
  237. package/src/modules/messages/extension-points.ts +13 -0
  238. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +3 -2
  239. package/src/modules/payment_gateways/extension-points.ts +16 -0
  240. package/src/modules/portal/extension-points.ts +30 -0
  241. package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +3 -3
  242. package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +3 -3
  243. package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +3 -3
  244. package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +3 -3
  245. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +4 -4
  246. package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +3 -3
  247. package/src/modules/query_index/components/QueryIndexesTable.tsx +2 -1
  248. package/src/modules/query_index/events.ts +17 -0
  249. package/src/modules/query_index/extension-points.ts +10 -0
  250. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -1
  251. package/src/modules/resources/backend/resources/resources/page.tsx +2 -1
  252. package/src/modules/resources/extension-points.ts +11 -0
  253. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +11 -3
  254. package/src/modules/sales/components/documents/ItemsSection.tsx +2 -1
  255. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +6 -1
  256. package/src/modules/sales/events.ts +1 -0
  257. package/src/modules/sales/extension-points.ts +33 -0
  258. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +5 -4
  259. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +4 -3
  260. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +3 -2
  261. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +3 -2
  262. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -1
  263. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +3 -2
  264. package/src/modules/wms/extension-points.ts +23 -0
  265. package/src/modules/workflows/backend/definitions/page.tsx +2 -1
  266. package/src/modules/workflows/backend/instances/page.tsx +2 -1
  267. package/src/modules/workflows/backend/tasks/page.tsx +2 -1
  268. package/src/modules/workflows/events.ts +1 -0
  269. package/src/modules/workflows/extension-points.ts +12 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/api/deals/summary/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager as CoreEntityManager } from '@mikro-orm/core'\nimport type { EntityManager as PgEntityManager } from '@mikro-orm/postgresql'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { ExchangeRateService, RateResult } from '@open-mercato/core/modules/currencies/services/exchangeRateService'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { fetchStuckDealIds } from '../../../lib/stuckDeals'\nimport { resolveDealsOrganizationIds } from '../../../lib/dealsOrganizationScope'\nimport { resolveOptionalBaseCurrencyCode } from '../../../lib/optionalBaseCurrency'\nimport {\n computeDelta,\n convertSumsToBase,\n getPreviousQuarterWindow,\n getQuarterWindow,\n getTrailingMonths,\n type CurrencySum,\n type Delta,\n} from '../../../lib/dealsMetrics'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.deals.view'] },\n}\n\nconst OPEN_STATUSES = ['open', 'in_progress'] as const\nconst TRAILING_MONTHS = 6\nconst TOP_OWNERS = 5\n\nconst deltaSchema = z.object({\n value: z.number(),\n direction: z.enum(['up', 'down', 'unchanged']),\n})\n\nconst stageBreakdownSchema = z.object({\n stage: z.string().nullable(),\n count: z.number(),\n value: z.number(),\n})\n\nconst ownerCountSchema = z.object({\n id: z.string(),\n count: z.number(),\n})\n\nconst winRatePointSchema = z.object({\n period: z.string(),\n rate: z.number(),\n})\n\nconst summaryResponseSchema = z.object({\n baseCurrencyCode: z.string().nullable(),\n convertedAll: z.boolean(),\n missingRateCurrencies: z.array(z.string()),\n pipelineValue: z.object({\n value: z.number(),\n delta: deltaSchema,\n stages: z.array(stageBreakdownSchema),\n }),\n activeDeals: z.object({\n value: z.number(),\n delta: deltaSchema,\n ownersCount: z.number(),\n needAttention: z.number(),\n owners: z.array(ownerCountSchema),\n ownersOverflow: z.number(),\n }),\n wonThisQuarter: z.object({\n value: z.number(),\n delta: deltaSchema,\n dealsClosed: z.number(),\n avgDeal: z.number(),\n }),\n winRate: z.object({\n value: z.number(),\n deltaPp: z.number(),\n direction: z.enum(['up', 'down', 'unchanged']),\n previousValue: z.number(),\n series: z.array(winRatePointSchema),\n }),\n})\n\nexport type DealsSummaryResponse = z.infer<typeof summaryResponseSchema>\n\nconst summaryErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Deals KPI summary',\n methods: {\n GET: {\n summary: 'Pipeline KPI metrics with period-over-period deltas for the deals list',\n description:\n 'Returns the four list-level KPI cards (pipeline value, active deals, won this quarter, win rate) with quarter-over-quarter deltas, per-stage open-pipeline breakdown, top owners, and a 6-month win-rate series. Values are converted to the tenant base currency where rates are available; partial conversions are disclosed via convertedAll/missingRateCurrencies.',\n responses: [\n { status: 200, description: 'Deals KPI summary payload', schema: summaryResponseSchema },\n ],\n errors: [\n { status: 401, description: 'Unauthorized', schema: summaryErrorSchema },\n ],\n },\n },\n}\n\ntype OpenPipelineRow = {\n stage: string | null\n currency: string | null\n total: string | number | null\n count: string | number\n owner_user_id: string | null\n}\n\ntype WindowSumRow = {\n currency: string | null\n current_total: string | number | null\n current_count: string | number\n previous_total: string | number | null\n previous_count: string | number\n}\n\ntype WinLossRow = {\n current_won: string | number\n current_lost: string | number\n previous_won: string | number\n previous_lost: string | number\n}\n\ntype WinRateMonthRow = {\n period: string\n won: string | number\n lost: string | number\n}\n\ntype OwnerCountRow = {\n owner_user_id: string | null\n count: string | number\n}\n\nfunction toNumber(value: string | number | null | undefined): number {\n const parsed = Number(value ?? 0)\n return Number.isFinite(parsed) ? parsed : 0\n}\n\nfunction winRate(won: number, lost: number): number {\n const denom = won + lost\n if (denom <= 0) return 0\n return Math.round((100 * won) / denom)\n}\n\nfunction sumsByCurrency(entries: Array<{ currency: string | null; total: number }>): CurrencySum[] {\n const byCurrency = new Map<string, number>()\n for (const entry of entries) {\n const currency = (entry.currency ?? '').toString().trim().toUpperCase()\n if (!currency) continue\n byCurrency.set(currency, (byCurrency.get(currency) ?? 0) + entry.total)\n }\n return Array.from(byCurrency.entries()).map(([currency, total]) => ({ currency, total }))\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const em = container.resolve<CoreEntityManager>('em')\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const effectiveTenantId = scope.tenantId ?? auth.tenantId\n if (!effectiveTenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const orgFilterIds = await resolveDealsOrganizationIds({ em, scope, auth, tenantId: effectiveTenantId })\n\n const today = new Date()\n const currentQuarter = getQuarterWindow(today)\n const previousQuarter = getPreviousQuarterWindow(today)\n const trailingMonths = getTrailingMonths(today, TRAILING_MONTHS)\n const seriesStart = trailingMonths[0]?.start ?? currentQuarter.start\n\n const connection = em.getConnection()\n\n const baseCurrencyCode = await resolveOptionalBaseCurrencyCode(\n container,\n effectiveTenantId,\n orgFilterIds[0],\n )\n\n const orgPlaceholders = orgFilterIds.map(() => '?').join(',')\n const scopeWhere = `tenant_id = ? AND organization_id IN (${orgPlaceholders}) AND deleted_at IS NULL`\n const scopeValues: Array<string | number | null> = [effectiveTenantId, ...orgFilterIds]\n const openPlaceholders = OPEN_STATUSES.map(() => '?').join(',')\n\n // 1) Open pipeline: per (stage, currency) sums + open-deal owner per row, so we can\n // derive pipeline value (per stage + converted total) and the open owner set in one pass.\n const openRows: OpenPipelineRow[] = await connection.execute<OpenPipelineRow[]>(\n `SELECT\n pipeline_stage AS stage,\n UPPER(COALESCE(value_currency, '')) AS currency,\n COALESCE(SUM(value_amount), 0) AS total,\n COUNT(*) AS count,\n owner_user_id\n FROM customer_deals\n WHERE ${scopeWhere} AND status IN (${openPlaceholders})\n GROUP BY pipeline_stage, UPPER(COALESCE(value_currency, '')), owner_user_id`,\n [...scopeValues, ...OPEN_STATUSES],\n )\n\n // 2) Open-deal value created in the current vs previous quarter (pipeline inflow delta).\n const inflowRows: WindowSumRow[] = await connection.execute<WindowSumRow[]>(\n `SELECT\n UPPER(COALESCE(value_currency, '')) AS currency,\n COALESCE(SUM(value_amount) FILTER (WHERE created_at >= ? AND created_at < ?), 0) AS current_total,\n COUNT(*) FILTER (WHERE created_at >= ? AND created_at < ?) AS current_count,\n COALESCE(SUM(value_amount) FILTER (WHERE created_at >= ? AND created_at < ?), 0) AS previous_total,\n COUNT(*) FILTER (WHERE created_at >= ? AND created_at < ?) AS previous_count\n FROM customer_deals\n WHERE ${scopeWhere} AND status IN (${openPlaceholders})\n GROUP BY UPPER(COALESCE(value_currency, ''))`,\n [\n currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),\n currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),\n previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),\n previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),\n ...scopeValues, ...OPEN_STATUSES,\n ],\n )\n\n // 3) Won value per currency for the current vs previous quarter (updated_at in window).\n const wonRows: WindowSumRow[] = await connection.execute<WindowSumRow[]>(\n `SELECT\n UPPER(COALESCE(value_currency, '')) AS currency,\n COALESCE(SUM(value_amount) FILTER (WHERE updated_at >= ? AND updated_at < ?), 0) AS current_total,\n COUNT(*) FILTER (WHERE updated_at >= ? AND updated_at < ?) AS current_count,\n COALESCE(SUM(value_amount) FILTER (WHERE updated_at >= ? AND updated_at < ?), 0) AS previous_total,\n COUNT(*) FILTER (WHERE updated_at >= ? AND updated_at < ?) AS previous_count\n FROM customer_deals\n WHERE ${scopeWhere} AND (status = 'win' OR closure_outcome = 'won')\n GROUP BY UPPER(COALESCE(value_currency, ''))`,\n [\n currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),\n currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),\n previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),\n previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),\n ...scopeValues,\n ],\n )\n\n // 4) Win/lost counts for the current vs previous quarter (win rate + delta-pp).\n const winLossRows: WinLossRow[] = await connection.execute<WinLossRow[]>(\n `SELECT\n COUNT(*) FILTER (WHERE (status = 'win' OR closure_outcome = 'won') AND updated_at >= ? AND updated_at < ?) AS current_won,\n COUNT(*) FILTER (WHERE (status = 'loose' OR closure_outcome = 'lost') AND updated_at >= ? AND updated_at < ?) AS current_lost,\n COUNT(*) FILTER (WHERE (status = 'win' OR closure_outcome = 'won') AND updated_at >= ? AND updated_at < ?) AS previous_won,\n COUNT(*) FILTER (WHERE (status = 'loose' OR closure_outcome = 'lost') AND updated_at >= ? AND updated_at < ?) AS previous_lost\n FROM customer_deals\n WHERE ${scopeWhere}`,\n [\n currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),\n currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),\n previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),\n previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),\n ...scopeValues,\n ],\n )\n\n // 5) Win-rate series over the trailing months (won/lost grouped by updated_at month).\n const seriesRows: WinRateMonthRow[] = await connection.execute<WinRateMonthRow[]>(\n `SELECT\n to_char(date_trunc('month', updated_at AT TIME ZONE 'UTC'), 'YYYY-MM') AS period,\n COUNT(*) FILTER (WHERE status = 'win' OR closure_outcome = 'won') AS won,\n COUNT(*) FILTER (WHERE status = 'loose' OR closure_outcome = 'lost') AS lost\n FROM customer_deals\n WHERE ${scopeWhere} AND updated_at >= ?\n GROUP BY 1`,\n [...scopeValues, seriesStart.toISOString()],\n )\n\n // Overdue open deals (id set) + stuck deals (id set) \u2192 union count for \"need attention\".\n const overdueRows: Array<{ id: string }> = await connection.execute<Array<{ id: string }>>(\n `SELECT id FROM customer_deals\n WHERE ${scopeWhere} AND status = 'open' AND expected_close_at IS NOT NULL AND expected_close_at < CURRENT_DATE`,\n [...scopeValues],\n )\n // `fetchStuckDealIds` is single-org; run it for every org in scope so multi-org callers don't\n // undercount stuck deals (the aggregates above already span every org in `orgFilterIds`).\n const stuckIdLists = await Promise.all(\n orgFilterIds.map((orgId) =>\n fetchStuckDealIds(em as unknown as PgEntityManager, orgId, effectiveTenantId)),\n )\n const stuckIdSet = new Set<string>()\n for (const list of stuckIdLists) for (const id of list) stuckIdSet.add(id)\n\n // The stuck-deal query does not filter status, so a stuck id can be a won/lost/closed deal.\n // \"Need attention\" is an active-deal metric \u2014 intersect with the open (OPEN_STATUSES) set so\n // terminal deals never inflate the count.\n let openStuckIds: string[] = []\n if (stuckIdSet.size > 0) {\n const stuckIdValues = Array.from(stuckIdSet)\n const stuckPlaceholders = stuckIdValues.map(() => '?').join(',')\n const openStuckRows: Array<{ id: string }> = await connection.execute<Array<{ id: string }>>(\n `SELECT id FROM customer_deals\n WHERE ${scopeWhere} AND status IN (${openPlaceholders}) AND id IN (${stuckPlaceholders})`,\n [...scopeValues, ...OPEN_STATUSES, ...stuckIdValues],\n )\n openStuckIds = openStuckRows.map((row) => row.id)\n }\n\n const attentionIds = new Set<string>()\n for (const row of overdueRows) attentionIds.add(row.id)\n for (const id of openStuckIds) attentionIds.add(id)\n\n // Reduce open rows: per-stage sums, distinct owners, owner counts, and a flat\n // per-currency list for the converted pipeline total.\n const stageMap = new Map<string, { stage: string | null; count: number; byCurrency: CurrencySum[] }>()\n const openOwnerCounts = new Map<string, number>()\n const openSums: Array<{ currency: string | null; total: number }> = []\n for (const row of openRows) {\n const stageKey = row.stage ?? '__null__'\n const total = toNumber(row.total)\n const count = toNumber(row.count)\n const currency = (row.currency ?? '').toString().trim().toUpperCase()\n if (!stageMap.has(stageKey)) {\n stageMap.set(stageKey, { stage: row.stage ?? null, count: 0, byCurrency: [] })\n }\n const stageAgg = stageMap.get(stageKey)!\n stageAgg.count += count\n if (currency) stageAgg.byCurrency.push({ currency, total })\n openSums.push({ currency, total })\n if (row.owner_user_id) {\n openOwnerCounts.set(row.owner_user_id, (openOwnerCounts.get(row.owner_user_id) ?? 0) + count)\n }\n }\n\n // Collect every distinct non-base currency across all metrics and fetch rates ONCE.\n const distinctCurrencies = new Set<string>()\n const collect = (entries: Array<{ currency: string | null }>) => {\n for (const entry of entries) {\n const currency = (entry.currency ?? '').toString().trim().toUpperCase()\n if (currency && currency !== baseCurrencyCode) distinctCurrencies.add(currency)\n }\n }\n collect(openSums)\n collect(inflowRows)\n collect(wonRows)\n\n let rates = new Map<string, RateResult>()\n if (baseCurrencyCode && distinctCurrencies.size > 0) {\n const exchange = container.resolve('exchangeRateService') as ExchangeRateService | undefined\n if (exchange) {\n const pairs = Array.from(distinctCurrencies).map((code) => ({\n fromCurrencyCode: code,\n toCurrencyCode: baseCurrencyCode,\n }))\n try {\n rates = await exchange.getRates({\n pairs,\n date: today,\n scope: { tenantId: effectiveTenantId, organizationId: orgFilterIds[0] },\n options: { maxDaysBack: 60, autoFetch: false },\n })\n } catch (err) {\n logger.warn('exchange-rate lookup failed; falling back to per-currency totals', { component: 'deals.summary', err })\n }\n }\n }\n\n const missingRateCurrencies = new Set<string>()\n const trackMissing = (missing: string[]) => {\n for (const code of missing) missingRateCurrencies.add(code)\n }\n let convertedAll = true\n\n // Degraded path: when there is no base currency, fall back to the dominant currency's\n // raw sum so the cards still show a number (mirrors the aggregate route's disclosure).\n const dominantCurrencyTotal = (entries: Array<{ currency: string | null; total: number }>): number => {\n const byCurrency = new Map<string, number>()\n for (const entry of entries) {\n const currency = (entry.currency ?? '').toString().trim().toUpperCase()\n if (!currency) continue\n byCurrency.set(currency, (byCurrency.get(currency) ?? 0) + entry.total)\n }\n let best = 0\n for (const total of byCurrency.values()) {\n if (Math.abs(total) > Math.abs(best)) best = total\n }\n return Math.round(best)\n }\n\n const convert = (entries: Array<{ currency: string | null; total: number }>): number => {\n if (!baseCurrencyCode) {\n convertedAll = false\n trackMissing(sumsByCurrency(entries).map((entry) => entry.currency))\n return dominantCurrencyTotal(entries)\n }\n const result = convertSumsToBase(sumsByCurrency(entries), baseCurrencyCode, rates)\n if (!result.convertedAll) convertedAll = false\n trackMissing(result.missingRateCurrencies)\n return result.total\n }\n\n // Pipeline value (open deals, converted) + per-stage converted breakdown.\n const pipelineValueTotal = convert(openSums)\n const stages = Array.from(stageMap.values()).map((stageAgg) => ({\n stage: stageAgg.stage,\n count: stageAgg.count,\n value: convert(stageAgg.byCurrency),\n }))\n\n // Pipeline inflow delta (open value created this vs previous quarter).\n const inflowCurrent = convert(inflowRows.map((row) => ({ currency: row.currency, total: toNumber(row.current_total) })))\n const inflowPrevious = convert(inflowRows.map((row) => ({ currency: row.currency, total: toNumber(row.previous_total) })))\n const pipelineDelta: Delta = computeDelta(inflowCurrent, inflowPrevious)\n\n // Active deals: count of open deals, owners, need-attention, top owners.\n const activeDealsCount = openRows.reduce((sum, row) => sum + toNumber(row.count), 0)\n const ownersCount = openOwnerCounts.size\n const inflowCurrentCount = inflowRows.reduce((sum, row) => sum + toNumber(row.current_count), 0)\n const inflowPreviousCount = inflowRows.reduce((sum, row) => sum + toNumber(row.previous_count), 0)\n const activeDelta: Delta = computeDelta(inflowCurrentCount, inflowPreviousCount)\n const sortedOwners = Array.from(openOwnerCounts.entries())\n .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n const owners = sortedOwners.slice(0, TOP_OWNERS).map(([id, count]) => ({ id, count }))\n const ownersOverflow = Math.max(0, ownersCount - owners.length)\n\n // Won this quarter.\n const wonCurrent = convert(wonRows.map((row) => ({ currency: row.currency, total: toNumber(row.current_total) })))\n const wonPrevious = convert(wonRows.map((row) => ({ currency: row.currency, total: toNumber(row.previous_total) })))\n const dealsClosed = wonRows.reduce((sum, row) => sum + toNumber(row.current_count), 0)\n const wonDelta: Delta = computeDelta(wonCurrent, wonPrevious)\n const avgDeal = dealsClosed > 0 ? Math.round(wonCurrent / dealsClosed) : 0\n\n // Win rate (current + previous quarter) and pp delta.\n const winLoss = winLossRows[0]\n const currentWon = toNumber(winLoss?.current_won)\n const currentLost = toNumber(winLoss?.current_lost)\n const previousWon = toNumber(winLoss?.previous_won)\n const previousLost = toNumber(winLoss?.previous_lost)\n const winRateValue = winRate(currentWon, currentLost)\n const winRatePrevious = winRate(previousWon, previousLost)\n const deltaPp = winRateValue - winRatePrevious\n const winRateDirection = deltaPp > 0 ? 'up' : deltaPp < 0 ? 'down' : 'unchanged'\n\n // Win-rate series over trailing months (fill missing months with 0).\n const seriesByPeriod = new Map<string, { won: number; lost: number }>()\n for (const row of seriesRows) {\n seriesByPeriod.set(row.period, { won: toNumber(row.won), lost: toNumber(row.lost) })\n }\n const series = trailingMonths.map((month) => {\n const point = seriesByPeriod.get(month.label)\n const won = point?.won ?? 0\n const lost = point?.lost ?? 0\n const denom = won + lost\n return { period: month.label, rate: denom > 0 ? won / denom : 0 }\n })\n\n const response: DealsSummaryResponse = {\n baseCurrencyCode,\n convertedAll,\n missingRateCurrencies: Array.from(missingRateCurrencies),\n pipelineValue: {\n value: pipelineValueTotal,\n delta: pipelineDelta,\n stages,\n },\n activeDeals: {\n value: activeDealsCount,\n delta: activeDelta,\n ownersCount,\n needAttention: attentionIds.size,\n owners,\n ownersOverflow,\n },\n wonThisQuarter: {\n value: wonCurrent,\n delta: wonDelta,\n dealsClosed,\n avgDeal,\n },\n winRate: {\n value: winRateValue,\n deltaPp,\n direction: winRateDirection,\n previousValue: winRatePrevious,\n series,\n },\n }\n\n return NextResponse.json(response)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager as CoreEntityManager } from '@mikro-orm/core'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { ExchangeRateService, RateResult } from '@open-mercato/core/modules/currencies/services/exchangeRateService'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { resolveDealsOrganizationIds } from '../../../lib/dealsOrganizationScope'\nimport { resolveOptionalBaseCurrencyCode } from '../../../lib/optionalBaseCurrency'\nimport { loadDealsSummaryQueryRows } from '../../../lib/dealsSummaryQueries'\nimport {\n computeDelta,\n convertSumsToBase,\n getPreviousQuarterWindow,\n getQuarterWindow,\n getTrailingMonths,\n type CurrencySum,\n type Delta,\n} from '../../../lib/dealsMetrics'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.deals.view'] },\n}\n\nconst TRAILING_MONTHS = 6\nconst TOP_OWNERS = 5\n\nconst deltaSchema = z.object({\n value: z.number(),\n direction: z.enum(['up', 'down', 'unchanged']),\n})\n\nconst stageBreakdownSchema = z.object({\n stage: z.string().nullable(),\n count: z.number(),\n value: z.number(),\n})\n\nconst ownerCountSchema = z.object({\n id: z.string(),\n count: z.number(),\n})\n\nconst winRatePointSchema = z.object({\n period: z.string(),\n rate: z.number(),\n})\n\nconst summaryResponseSchema = z.object({\n baseCurrencyCode: z.string().nullable(),\n convertedAll: z.boolean(),\n missingRateCurrencies: z.array(z.string()),\n pipelineValue: z.object({\n value: z.number(),\n delta: deltaSchema,\n stages: z.array(stageBreakdownSchema),\n }),\n activeDeals: z.object({\n value: z.number(),\n delta: deltaSchema,\n ownersCount: z.number(),\n needAttention: z.number(),\n owners: z.array(ownerCountSchema),\n ownersOverflow: z.number(),\n }),\n wonThisQuarter: z.object({\n value: z.number(),\n delta: deltaSchema,\n dealsClosed: z.number(),\n avgDeal: z.number(),\n }),\n winRate: z.object({\n value: z.number(),\n deltaPp: z.number(),\n direction: z.enum(['up', 'down', 'unchanged']),\n previousValue: z.number(),\n series: z.array(winRatePointSchema),\n }),\n})\n\nexport type DealsSummaryResponse = z.infer<typeof summaryResponseSchema>\n\nconst summaryErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Deals KPI summary',\n methods: {\n GET: {\n summary: 'Pipeline KPI metrics with period-over-period deltas for the deals list',\n description:\n 'Returns the four list-level KPI cards (pipeline value, active deals, won this quarter, win rate) with quarter-over-quarter deltas, per-stage open-pipeline breakdown, top owners, and a 6-month win-rate series. Values are converted to the tenant base currency where rates are available; partial conversions are disclosed via convertedAll/missingRateCurrencies.',\n responses: [\n { status: 200, description: 'Deals KPI summary payload', schema: summaryResponseSchema },\n ],\n errors: [\n { status: 401, description: 'Unauthorized', schema: summaryErrorSchema },\n ],\n },\n },\n}\n\nfunction toNumber(value: string | number | null | undefined): number {\n const parsed = Number(value ?? 0)\n return Number.isFinite(parsed) ? parsed : 0\n}\n\nfunction winRate(won: number, lost: number): number {\n const denom = won + lost\n if (denom <= 0) return 0\n return Math.round((100 * won) / denom)\n}\n\nfunction sumsByCurrency(entries: Array<{ currency: string | null; total: number }>): CurrencySum[] {\n const byCurrency = new Map<string, number>()\n for (const entry of entries) {\n const currency = (entry.currency ?? '').toString().trim().toUpperCase()\n if (!currency) continue\n byCurrency.set(currency, (byCurrency.get(currency) ?? 0) + entry.total)\n }\n return Array.from(byCurrency.entries()).map(([currency, total]) => ({ currency, total }))\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const em = container.resolve<CoreEntityManager>('em')\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const effectiveTenantId = scope.tenantId ?? auth.tenantId\n if (!effectiveTenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const orgFilterIds = await resolveDealsOrganizationIds({ em, scope, auth, tenantId: effectiveTenantId })\n\n const today = new Date()\n const currentQuarter = getQuarterWindow(today)\n const previousQuarter = getPreviousQuarterWindow(today)\n const trailingMonths = getTrailingMonths(today, TRAILING_MONTHS)\n const seriesStart = trailingMonths[0]?.start ?? currentQuarter.start\n\n const baseCurrencyCode = await resolveOptionalBaseCurrencyCode(\n container,\n effectiveTenantId,\n orgFilterIds[0],\n )\n\n const { openRows, inflowRows, wonRows, winLossRows, seriesRows, overdueRows, openStuckIds } =\n await loadDealsSummaryQueryRows({\n em,\n tenantId: effectiveTenantId,\n organizationIds: orgFilterIds,\n currentQuarter,\n previousQuarter,\n seriesStart,\n })\n\n const attentionIds = new Set<string>()\n for (const row of overdueRows) attentionIds.add(row.id)\n for (const id of openStuckIds) attentionIds.add(id)\n\n // Reduce open rows: per-stage sums, distinct owners, owner counts, and a flat\n // per-currency list for the converted pipeline total.\n const stageMap = new Map<string, { stage: string | null; count: number; byCurrency: CurrencySum[] }>()\n const openOwnerCounts = new Map<string, number>()\n const openSums: Array<{ currency: string | null; total: number }> = []\n for (const row of openRows) {\n const stageKey = row.stage ?? '__null__'\n const total = toNumber(row.total)\n const count = toNumber(row.count)\n const currency = (row.currency ?? '').toString().trim().toUpperCase()\n if (!stageMap.has(stageKey)) {\n stageMap.set(stageKey, { stage: row.stage ?? null, count: 0, byCurrency: [] })\n }\n const stageAgg = stageMap.get(stageKey)!\n stageAgg.count += count\n if (currency) stageAgg.byCurrency.push({ currency, total })\n openSums.push({ currency, total })\n if (row.owner_user_id) {\n openOwnerCounts.set(row.owner_user_id, (openOwnerCounts.get(row.owner_user_id) ?? 0) + count)\n }\n }\n\n // Collect every distinct non-base currency across all metrics and fetch rates ONCE.\n const distinctCurrencies = new Set<string>()\n const collect = (entries: Array<{ currency: string | null }>) => {\n for (const entry of entries) {\n const currency = (entry.currency ?? '').toString().trim().toUpperCase()\n if (currency && currency !== baseCurrencyCode) distinctCurrencies.add(currency)\n }\n }\n collect(openSums)\n collect(inflowRows)\n collect(wonRows)\n\n let rates = new Map<string, RateResult>()\n if (baseCurrencyCode && distinctCurrencies.size > 0) {\n const exchange = container.resolve('exchangeRateService') as ExchangeRateService | undefined\n if (exchange) {\n const pairs = Array.from(distinctCurrencies).map((code) => ({\n fromCurrencyCode: code,\n toCurrencyCode: baseCurrencyCode,\n }))\n try {\n rates = await exchange.getRates({\n pairs,\n date: today,\n scope: { tenantId: effectiveTenantId, organizationId: orgFilterIds[0] },\n options: { maxDaysBack: 60, autoFetch: false },\n })\n } catch (err) {\n logger.warn('exchange-rate lookup failed; falling back to per-currency totals', { component: 'deals.summary', err })\n }\n }\n }\n\n const missingRateCurrencies = new Set<string>()\n const trackMissing = (missing: string[]) => {\n for (const code of missing) missingRateCurrencies.add(code)\n }\n let convertedAll = true\n\n // Degraded path: when there is no base currency, fall back to the dominant currency's\n // raw sum so the cards still show a number (mirrors the aggregate route's disclosure).\n const dominantCurrencyTotal = (entries: Array<{ currency: string | null; total: number }>): number => {\n const byCurrency = new Map<string, number>()\n for (const entry of entries) {\n const currency = (entry.currency ?? '').toString().trim().toUpperCase()\n if (!currency) continue\n byCurrency.set(currency, (byCurrency.get(currency) ?? 0) + entry.total)\n }\n let best = 0\n for (const total of byCurrency.values()) {\n if (Math.abs(total) > Math.abs(best)) best = total\n }\n return Math.round(best)\n }\n\n const convert = (entries: Array<{ currency: string | null; total: number }>): number => {\n if (!baseCurrencyCode) {\n convertedAll = false\n trackMissing(sumsByCurrency(entries).map((entry) => entry.currency))\n return dominantCurrencyTotal(entries)\n }\n const result = convertSumsToBase(sumsByCurrency(entries), baseCurrencyCode, rates)\n if (!result.convertedAll) convertedAll = false\n trackMissing(result.missingRateCurrencies)\n return result.total\n }\n\n // Pipeline value (open deals, converted) + per-stage converted breakdown.\n const pipelineValueTotal = convert(openSums)\n const stages = Array.from(stageMap.values()).map((stageAgg) => ({\n stage: stageAgg.stage,\n count: stageAgg.count,\n value: convert(stageAgg.byCurrency),\n }))\n\n // Pipeline inflow delta (open value created this vs previous quarter).\n const inflowCurrent = convert(inflowRows.map((row) => ({ currency: row.currency, total: toNumber(row.current_total) })))\n const inflowPrevious = convert(inflowRows.map((row) => ({ currency: row.currency, total: toNumber(row.previous_total) })))\n const pipelineDelta: Delta = computeDelta(inflowCurrent, inflowPrevious)\n\n // Active deals: count of open deals, owners, need-attention, top owners.\n const activeDealsCount = openRows.reduce((sum, row) => sum + toNumber(row.count), 0)\n const ownersCount = openOwnerCounts.size\n const inflowCurrentCount = inflowRows.reduce((sum, row) => sum + toNumber(row.current_count), 0)\n const inflowPreviousCount = inflowRows.reduce((sum, row) => sum + toNumber(row.previous_count), 0)\n const activeDelta: Delta = computeDelta(inflowCurrentCount, inflowPreviousCount)\n const sortedOwners = Array.from(openOwnerCounts.entries())\n .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n const owners = sortedOwners.slice(0, TOP_OWNERS).map(([id, count]) => ({ id, count }))\n const ownersOverflow = Math.max(0, ownersCount - owners.length)\n\n // Won this quarter.\n const wonCurrent = convert(wonRows.map((row) => ({ currency: row.currency, total: toNumber(row.current_total) })))\n const wonPrevious = convert(wonRows.map((row) => ({ currency: row.currency, total: toNumber(row.previous_total) })))\n const dealsClosed = wonRows.reduce((sum, row) => sum + toNumber(row.current_count), 0)\n const wonDelta: Delta = computeDelta(wonCurrent, wonPrevious)\n const avgDeal = dealsClosed > 0 ? Math.round(wonCurrent / dealsClosed) : 0\n\n // Win rate (current + previous quarter) and pp delta.\n const winLoss = winLossRows[0]\n const currentWon = toNumber(winLoss?.current_won)\n const currentLost = toNumber(winLoss?.current_lost)\n const previousWon = toNumber(winLoss?.previous_won)\n const previousLost = toNumber(winLoss?.previous_lost)\n const winRateValue = winRate(currentWon, currentLost)\n const winRatePrevious = winRate(previousWon, previousLost)\n const deltaPp = winRateValue - winRatePrevious\n const winRateDirection = deltaPp > 0 ? 'up' : deltaPp < 0 ? 'down' : 'unchanged'\n\n // Win-rate series over trailing months (fill missing months with 0).\n const seriesByPeriod = new Map<string, { won: number; lost: number }>()\n for (const row of seriesRows) {\n seriesByPeriod.set(row.period, { won: toNumber(row.won), lost: toNumber(row.lost) })\n }\n const series = trailingMonths.map((month) => {\n const point = seriesByPeriod.get(month.label)\n const won = point?.won ?? 0\n const lost = point?.lost ?? 0\n const denom = won + lost\n return { period: month.label, rate: denom > 0 ? won / denom : 0 }\n })\n\n const response: DealsSummaryResponse = {\n baseCurrencyCode,\n convertedAll,\n missingRateCurrencies: Array.from(missingRateCurrencies),\n pipelineValue: {\n value: pipelineValueTotal,\n delta: pipelineDelta,\n stages,\n },\n activeDeals: {\n value: activeDealsCount,\n delta: activeDelta,\n ownersCount,\n needAttention: attentionIds.size,\n owners,\n ownersOverflow,\n },\n wonThisQuarter: {\n value: wonCurrent,\n delta: wonDelta,\n dealsClosed,\n avgDeal,\n },\n winRate: {\n value: winRateValue,\n deltaPp,\n direction: winRateDirection,\n previousValue: winRatePrevious,\n series,\n },\n }\n\n return NextResponse.json(response)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { extensionPoints } from "@open-mercato/core/modules/customers/extension-points";
4
5
  import Link from "next/link";
5
6
  import { useRouter, useSearchParams } from "next/navigation";
6
7
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
@@ -843,7 +844,7 @@ function CustomerCompanyDetailPage({ params }) {
843
844
  /* @__PURE__ */ jsx(
844
845
  InjectionSpot,
845
846
  {
846
- spotId: "customers.company.detail:details",
847
+ spotId: extensionPoints.hosts.companyLegacyDetails.spotId,
847
848
  context: injectionContext,
848
849
  data,
849
850
  onDataChange: (next) => setData(next)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/backend/customers/companies/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Separator } from '@open-mercato/ui/primitives/separator'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { DetailFieldsSection, type DetailFieldConfig } from '@open-mercato/ui/backend/detail'\nimport {\n ActivitiesSection,\n} from '../../../../components/detail/ActivitiesSection'\nimport {\n NotesSection,\n type CommentSummary,\n type SectionAction,\n} from '@open-mercato/ui/backend/detail'\nimport {\n TagsSection,\n type TagOption,\n} from '../../../../components/detail/TagsSection'\nimport { DealsSection } from '../../../../components/detail/DealsSection'\nimport { AddressesSection } from '../../../../components/detail/AddressesSection'\nimport { TasksSection } from '../../../../components/detail/TasksSection'\nimport { CustomDataSection } from '../../../../components/detail/CustomDataSection'\nimport { CompanyHighlights } from '../../../../components/detail/CompanyHighlights'\nimport { normalizeCustomFieldSubmitValue } from '../../../../components/detail/customFieldUtils'\nimport { InlineDictionaryEditor, renderMultilineMarkdownDisplay } from '../../../../components/detail/InlineEditors'\nimport { formatTemplate } from '../../../../components/detail/utils'\nimport { coerceDisplayName } from '../../../../lib/displayName'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport {\n CompanyPeopleSection,\n type CompanyPersonSummary,\n} from '../../../../components/detail/CompanyPeopleSection'\nimport { AnnualRevenueField } from '../../../../components/detail/AnnualRevenueField'\nimport type { ActivitySummary, DealSummary, TagSummary, TodoLinkSummary } from '../../../../components/detail/types'\nimport { renderDictionaryColor, renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { ICON_SUGGESTIONS } from '../../../../lib/dictionaries'\nimport { createCustomerNotesAdapter } from '../../../../components/detail/notesAdapter'\nimport { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '../../../../lib/markdownPreference'\nimport { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { DetailTabsLayout } from '../../../../components/detail/DetailTabsLayout'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\n\ntype CompanyOverview = {\n company: {\n id: string\n displayName: string\n description?: string | null\n ownerUserId?: string | null\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n source?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n updatedAt?: string | null\n }\n profile: {\n id: string\n legalName?: string | null\n brandName?: string | null\n domain?: string | null\n websiteUrl?: string | null\n industry?: string | null\n sizeBucket?: string | null\n annualRevenue?: string | null\n } | null\n customFields: Record<string, unknown>\n tags: TagSummary[]\n comments: CommentSummary[]\n activities: ActivitySummary[]\n deals: DealSummary[]\n todos: TodoLinkSummary[]\n people: CompanyPersonSummary[]\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\ntype SectionKey = 'notes' | 'activities' | 'deals' | 'people' | 'addresses' | 'tasks' | string\n\nexport default function CustomerCompanyDetailPage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n const notesAdapter = React.useMemo(() => createCustomerNotesAdapter(detailTranslator), [detailTranslator])\n const router = useRouter()\n const searchParams = useSearchParams()\n const initialTab = React.useMemo(() => {\n const raw = searchParams?.get('tab')\n if (raw === 'notes' || raw === 'activities' || raw === 'deals' || raw === 'people' || raw === 'addresses' || raw === 'tasks') {\n return raw\n }\n return 'notes'\n }, [searchParams])\n const [data, setData] = React.useState<CompanyOverview | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [activeTab, setActiveTab] = React.useState<SectionKey>(initialTab)\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const currentCompanyId = data?.company?.id ?? null\n const companyDisplayName = coerceDisplayName(data?.company?.displayName)\n const companyName = companyDisplayName.trim().length\n ? companyDisplayName\n : t('customers.companies.list.deleteFallbackName', 'this company')\n const translateCompanyDetail = React.useCallback(\n (key: string, fallback?: string, params?: Record<string, string | number>) => {\n const mappedKey = key.startsWith('customers.people.detail.')\n ? key.replace('customers.people.detail.', 'customers.companies.detail.')\n : key\n const adjustedFallback =\n key.startsWith('customers.people.detail.') && fallback\n ? fallback\n .replace(/\\bPerson\\b/g, 'Company')\n .replace(/\\bperson\\b/g, 'company')\n .replace(/\\bPeople\\b/g, 'Companies')\n .replace(/\\bpeople\\b/g, 'companies')\n : fallback\n const translated = t(mappedKey, params)\n if (translated !== mappedKey || mappedKey === key) return translated\n const fallbackValue = t(key, params)\n if (fallbackValue !== key) return fallbackValue\n if (!adjustedFallback) return mappedKey\n return formatTemplate(adjustedFallback, params)\n },\n [t],\n )\n const sectionLoaderLabel =\n activeTab === 'activities'\n ? t('customers.companies.detail.activities.loading', 'Loading activities\u2026')\n : activeTab === 'deals'\n ? t('customers.companies.detail.deals.loading', 'Loading deals\u2026')\n : activeTab === 'people'\n ? t('customers.companies.detail.people.loading', 'Loading people\u2026')\n : t('customers.companies.detail.sectionLoading', 'Loading\u2026')\n const mutationContextId = React.useMemo(\n () => (currentCompanyId ? `customer-company:${currentCompanyId}` : `customer-company:${id ?? 'pending'}`),\n [currentCompanyId, id],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n companyId?: string | null\n resourceKind: string\n resourceId?: string\n data: CompanyOverview | null\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const injectionContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n companyId: currentCompanyId,\n resourceKind: 'customers.company',\n resourceId: currentCompanyId ?? (id ?? undefined),\n data,\n retryLastMutation,\n }),\n [currentCompanyId, data, id, mutationContextId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {\n return runMutation({\n operation,\n mutationPayload,\n context: injectionContext,\n })\n },\n [injectionContext, runMutation],\n )\n\n const handleSectionActionChange = React.useCallback((action: SectionAction | null) => {\n setSectionAction(action)\n }, [])\n\n const handleSectionAction = React.useCallback(() => {\n if (!sectionAction || sectionAction.disabled) return\n sectionAction.onClick()\n }, [sectionAction])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n const validators = React.useMemo(() => ({\n email: (value: string) => {\n if (!value) return null\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n return emailRegex.test(value) ? null : t('customers.companies.detail.inline.emailInvalid', 'Enter a valid email address.')\n },\n phone: (value: string) => {\n if (!value) return null\n return value.length >= 3 ? null : t('customers.companies.detail.inline.phoneInvalid', 'Phone number is too short.')\n },\n displayName: (value: string) => {\n const trimmed = value.trim()\n return trimmed.length ? null : t('customers.companies.form.displayName.error', 'Company name is required.')\n },\n website: (value: string) => {\n if (!value) return null\n try {\n const url = new URL(value.trim())\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? null\n : t('customers.companies.detail.inline.websiteInvalid', 'Use a valid http(s) address.')\n } catch {\n return t('customers.companies.detail.inline.websiteInvalid', 'Use a valid http(s) address.')\n }\n },\n annualRevenue: (value: string) => {\n if (!value) return null\n const normalized = value.replace(/[, ]+/g, '')\n const amount = Number(normalized)\n if (Number.isNaN(amount) || amount < 0) {\n return t('customers.companies.detail.inline.annualRevenueInvalid', 'Enter a non-negative number.')\n }\n return null\n },\n }), [t])\n\n const { widgets: injectedTabWidgets } = useInjectionWidgets('customers.company.detail:tabs', {\n context: injectionContext,\n triggerOnLoad: true,\n })\n const injectedTabs = React.useMemo(\n () =>\n (injectedTabWidgets ?? [])\n .filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')\n .map((widget) => {\n const id = widget.placement?.groupId ?? widget.widgetId\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title\n const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0\n const render = () => (\n <widget.module.Widget\n context={injectionContext}\n data={data}\n onDataChange={(next) => setData(next as CompanyOverview)}\n />\n )\n return { id, label, priority, render }\n })\n .sort((a, b) => b.priority - a.priority),\n [data, injectedTabWidgets, injectionContext],\n )\n const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])\n\n const tabs = React.useMemo(\n () => [\n { id: 'notes' as const, label: t('customers.companies.detail.tabs.notes', 'Notes') },\n { id: 'activities' as const, label: t('customers.companies.detail.tabs.activities', 'Activities') },\n { id: 'deals' as const, label: t('customers.companies.detail.tabs.deals', 'Deals') },\n { id: 'people' as const, label: t('customers.companies.detail.tabs.people', 'People') },\n { id: 'addresses' as const, label: t('customers.companies.detail.tabs.addresses', 'Addresses') },\n { id: 'tasks' as const, label: t('customers.companies.detail.tabs.tasks', 'Tasks') },\n ...injectedTabs.map((tab) => ({ id: tab.id as SectionKey, label: tab.label })),\n ],\n [injectedTabs, t],\n )\n\n React.useEffect(() => {\n if (!id) {\n setIsNotFound(true)\n setIsLoading(false)\n return\n }\n const companyId = id\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setError(null)\n try {\n const search = new URLSearchParams()\n search.append('include', 'todos')\n search.append('include', 'people')\n const payload = await readApiResultOrThrow<CompanyOverview>(\n `/api/customers/companies/${encodeURIComponent(companyId)}?${search.toString()}`,\n undefined,\n { errorMessage: t('customers.companies.detail.error.load', 'Failed to load company.') },\n )\n if (cancelled) return\n setData(payload as CompanyOverview)\n } catch (err) {\n if (cancelled) return\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('customers.companies.detail.error.load', 'Failed to load company.')\n setError(message)\n }\n setData(null)\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [id, t])\n\n const saveCompany = React.useCallback(\n async (patch: Record<string, unknown>, apply: (prev: CompanyOverview) => CompanyOverview) => {\n if (!data) return\n const payload = { id: data.company.id, ...patch }\n const result = await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => apiCallOrThrow<{ ok?: boolean; updatedAt?: string | null }>(\n '/api/customers/companies',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: t('customers.companies.detail.inline.error', 'Unable to update company.') },\n ),\n ),\n payload,\n )\n // Refresh the optimistic-lock token so the next sequential inline edit does\n // not send a stale updatedAt and falsely 409 (#2055, default-ON locking).\n const nextUpdatedAt = result?.result?.updatedAt ?? null\n setData((prev) => {\n if (!prev) return prev\n const applied = apply(prev)\n return nextUpdatedAt\n ? { ...applied, company: { ...applied.company, updatedAt: nextUpdatedAt } }\n : applied\n })\n },\n [data, runMutationWithContext, t],\n )\n\n const updateDisplayName = React.useCallback(\n async (next: string | null) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { displayName: send },\n (prev) => ({\n ...prev,\n company: {\n ...prev.company,\n displayName: next && next.length ? next : prev.company.displayName,\n },\n })\n )\n },\n [saveCompany],\n )\n\n const updateCompanyField = React.useCallback(\n async (field: 'primaryEmail' | 'primaryPhone' | 'status' | 'lifecycleStage' | 'source', next: string | null) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { [field]: send },\n (prev) => ({\n ...prev,\n company: {\n ...prev.company,\n [field]: next && next.length ? next : null,\n },\n })\n )\n },\n [saveCompany],\n )\n\n const updateProfileField = React.useCallback(\n async (\n field: 'brandName' | 'legalName' | 'websiteUrl' | 'industry' | 'domain' | 'sizeBucket',\n next: string | null,\n ) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { [field]: send },\n (prev) => {\n if (!prev.profile) return prev\n const nextValue = next && next.length ? next : null\n return {\n ...prev,\n profile: {\n ...prev.profile,\n [field]: nextValue,\n },\n }\n }\n )\n },\n [saveCompany],\n )\n\n const submitCustomFields = React.useCallback(\n async (prefixedValues: Record<string, unknown>, { showFlash = true } = {}) => {\n if (!data) throw new Error(t('customers.companies.detail.inline.error', 'Unable to update company.'))\n const customPayload = collectCustomFieldValues(prefixedValues, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n const normalized: Record<string, unknown> = {}\n for (const [fieldId, value] of Object.entries(customPayload)) {\n normalized[`cf_${fieldId}`] = value\n }\n if (!Object.keys(customPayload).length) {\n if (showFlash) flash(t('ui.forms.flash.saveSuccess', 'Saved successfully.'), 'success')\n return\n }\n const payload = {\n id: data.company.id,\n customFields: customPayload,\n }\n let customFieldsUpdatedAt: string | null = null\n try {\n const result = await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => apiCallOrThrow<{ ok?: boolean; updatedAt?: string | null }>(\n '/api/customers/companies',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: t('customers.companies.detail.inline.error', 'Unable to update company.') },\n ),\n ),\n payload,\n )\n customFieldsUpdatedAt = result?.result?.updatedAt ?? null\n } catch (err) {\n const { message: helperMessage, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const message = helperMessage ?? t('customers.companies.detail.inline.error', 'Unable to update company.')\n const mappedErrors: Record<string, string> | undefined = fieldErrors\n ? Object.entries(fieldErrors).reduce<Record<string, string>>((acc, [key, value]) => {\n const formKey = key.startsWith('cf_') ? key : `cf_${key}`\n acc[formKey] = value\n return acc\n }, {})\n : undefined\n const error = new Error(message) as Error & { fieldErrors?: Record<string, string> }\n if (mappedErrors && Object.keys(mappedErrors).length) error.fieldErrors = mappedErrors\n throw error\n }\n setData((prev) => {\n if (!prev) return prev\n return {\n ...prev,\n company: customFieldsUpdatedAt\n ? { ...prev.company, updatedAt: customFieldsUpdatedAt }\n : prev.company,\n customFields: {\n ...prev.customFields,\n ...normalized,\n },\n }\n })\n if (showFlash) flash(t('ui.forms.flash.saveSuccess', 'Saved successfully.'), 'success')\n },\n [data, runMutationWithContext, t],\n )\n\n const handleAnnualRevenueChange = React.useCallback(\n async ({ amount, currency }: { amount: number | null; currency: string | null }) => {\n await saveCompany(\n { annualRevenue: amount ?? null },\n (prev) => {\n if (!prev.profile) return prev\n return {\n ...prev,\n profile: {\n ...prev.profile,\n annualRevenue: amount === null ? null : String(amount),\n },\n }\n }\n )\n await submitCustomFields(\n { cf_annual_revenue_currency: currency ?? null },\n { showFlash: false },\n )\n flash(t('ui.forms.flash.saveSuccess', 'Saved successfully.'), 'success')\n },\n [saveCompany, submitCustomFields, t],\n )\n\n const handleDelete = React.useCallback(async () => {\n if (!currentCompanyId) return\n const confirmed = await confirm({\n title: t('customers.companies.list.deleteConfirm', undefined, { name: companyName }),\n variant: 'destructive',\n })\n if (!confirmed) return\n setIsDeleting(true)\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => apiCallOrThrow(\n `/api/customers/companies?id=${encodeURIComponent(currentCompanyId)}`,\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n },\n { errorMessage: t('customers.companies.list.deleteError', 'Failed to delete company.') },\n ),\n ),\n { id: currentCompanyId },\n )\n flash(t('customers.companies.list.deleteSuccess', 'Company deleted.'), 'success')\n router.push('/backend/customers/companies')\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.companies.list.deleteError', 'Failed to delete company.')\n flash(message, 'error')\n } finally {\n setIsDeleting(false)\n }\n }, [companyName, confirm, currentCompanyId, router, runMutationWithContext, t])\n\n const handleTagsChange = React.useCallback((nextTags: TagOption[]) => {\n setData((prev) => (prev ? { ...prev, tags: nextTags } : prev))\n }, [])\n\n const handleCustomFieldsSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n await submitCustomFields(values)\n },\n [submitCustomFields],\n )\n\n const handleNotesLoadingChange = React.useCallback(() => {}, [])\n\n const handleActivitiesLoadingChange = React.useCallback(() => {}, [])\n\n const handleDealsLoadingChange = React.useCallback(() => {}, [])\n\n const handlePeopleLoadingChange = React.useCallback(() => {}, [])\n\n const handleAddressesLoadingChange = React.useCallback(() => {}, [])\n\n const handleTasksLoadingChange = React.useCallback(() => {}, [])\n\n const dealsScope = React.useMemo(\n () => (currentCompanyId ? ({ kind: 'company', entityId: currentCompanyId } as const) : null),\n [currentCompanyId],\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('customers.companies.detail.loading', 'Loading company\u2026')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('customers.companies.detail.error.notFound', 'Company not found.')}\n backHref=\"/backend/customers/companies\"\n backLabel={t('customers.companies.detail.actions.backToList', 'Back to companies')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data?.company?.id) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error ?? t('customers.companies.detail.error.notFound', 'Company not found.')}\n action={\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/backend/customers/companies\">\n {t('customers.companies.detail.actions.backToList', 'Back to companies')}\n </Link>\n </Button>\n }\n />\n </PageBody>\n </Page>\n )\n }\n\n const { company, profile } = data\n const companyId = company.id\n\n const annualRevenueCurrency =\n typeof data.customFields?.annual_revenue_currency === 'string'\n ? (data.customFields.annual_revenue_currency as string)\n : null\n\n const detailFields: DetailFieldConfig[] = [\n {\n key: 'displayName',\n kind: 'text',\n label: t('customers.companies.detail.fields.displayName', 'Display name'),\n value: company.displayName,\n placeholder: t('customers.companies.form.displayName.placeholder', 'Enter company name'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n validator: validators.displayName,\n onSave: updateDisplayName,\n },\n {\n key: 'legalName',\n kind: 'text',\n label: t('customers.companies.detail.fields.legalName', 'Legal name'),\n value: profile?.legalName ?? null,\n placeholder: t('customers.companies.detail.fields.legalNamePlaceholder', 'Add legal name'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('legalName', value),\n },\n {\n key: 'brandName',\n kind: 'text',\n label: t('customers.companies.detail.fields.brandName', 'Brand name'),\n value: profile?.brandName ?? null,\n placeholder: t('customers.companies.detail.fields.brandNamePlaceholder', 'Add brand name'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('brandName', value),\n },\n {\n key: 'description',\n kind: 'multiline',\n label: t('customers.companies.detail.fields.description', 'Description'),\n value: company.description ?? null,\n placeholder: t('customers.companies.detail.fields.descriptionPlaceholder', 'Describe the company'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n gridClassName: 'sm:col-span-2 xl:col-span-3',\n renderDisplay: renderMultilineMarkdownDisplay,\n onSave: async (next) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { description: send },\n (prev) => ({\n ...prev,\n company: { ...prev.company, description: next && next.length ? next : null },\n })\n )\n },\n },\n {\n key: 'lifecycleStage',\n kind: 'custom',\n label: t('customers.companies.detail.fields.lifecycleStage', 'Lifecycle stage'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <InlineDictionaryEditor\n label={t('customers.companies.detail.fields.lifecycleStage', 'Lifecycle stage')}\n value={company.lifecycleStage ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n kind=\"lifecycle-stages\"\n onSave={(next) => updateCompanyField('lifecycleStage', next)}\n selectClassName=\"h-9 w-full rounded border px-3 text-sm\"\n variant=\"muted\"\n activateOnClick\n />\n ),\n },\n {\n key: 'source',\n kind: 'custom',\n label: t('customers.companies.detail.fields.source', 'Source'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <InlineDictionaryEditor\n label={t('customers.companies.detail.fields.source', 'Source')}\n value={company.source ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n kind=\"sources\"\n onSave={(next) => updateCompanyField('source', next)}\n selectClassName=\"h-9 w-full rounded border px-3 text-sm\"\n variant=\"muted\"\n activateOnClick\n />\n ),\n },\n {\n key: 'domain',\n kind: 'text',\n label: t('customers.companies.detail.fields.domain', 'Domain'),\n value: profile?.domain ?? null,\n placeholder: t('customers.companies.detail.fields.domainPlaceholder', 'example.com'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('domain', value),\n },\n {\n key: 'industry',\n kind: 'custom',\n label: t('customers.companies.detail.fields.industry', 'Industry'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <InlineDictionaryEditor\n label={t('customers.companies.detail.fields.industry', 'Industry')}\n value={profile?.industry ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n kind=\"industries\"\n onSave={(next) => updateProfileField('industry', next)}\n selectClassName=\"h-9 w-full rounded border px-3 text-sm\"\n variant=\"muted\"\n activateOnClick\n />\n ),\n },\n {\n key: 'sizeBucket',\n kind: 'text',\n label: t('customers.companies.detail.fields.sizeBucket', 'Company size'),\n value: profile?.sizeBucket ?? null,\n placeholder: t('customers.companies.detail.fields.sizeBucketPlaceholder', 'Add size bucket'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('sizeBucket', value),\n },\n {\n key: 'annualRevenue',\n kind: 'custom',\n label: t('customers.companies.detail.fields.annualRevenue', 'Annual revenue'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <AnnualRevenueField\n label={t('customers.companies.detail.fields.annualRevenue', 'Annual revenue')}\n amount={profile?.annualRevenue ?? null}\n currency={annualRevenueCurrency}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n validator={validators.annualRevenue}\n onSave={handleAnnualRevenueChange}\n />\n ),\n },\n {\n key: 'websiteUrl',\n kind: 'text',\n label: t('customers.companies.detail.fields.website', 'Website'),\n value: profile?.websiteUrl ?? null,\n placeholder: t('customers.companies.detail.fields.websitePlaceholder', 'https://example.com'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n inputType: 'url',\n validator: validators.website,\n onSave: (value) => updateProfileField('websiteUrl', value),\n },\n ]\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-8\">\n <CompanyHighlights\n company={company}\n profile={profile ?? null}\n validators={validators}\n onDisplayNameSave={updateDisplayName}\n utilityActions={(\n <SendObjectMessageDialog\n object={{\n entityModule: 'customers',\n entityType: 'company',\n entityId: companyId,\n previewData: {\n title: company.displayName,\n subtitle: company.primaryEmail ?? undefined,\n metadata: {\n [t('customers.companies.detail.highlights.primaryPhone')]: company.primaryPhone ?? '-',\n [t('customers.companies.detail.fields.industry')]: profile?.industry ?? '-',\n },\n },\n }}\n viewHref={`/backend/customers/companies/${companyId}`}\n />\n )}\n onPrimaryEmailSave={(value) => updateCompanyField('primaryEmail', value)}\n onPrimaryPhoneSave={(value) => updateCompanyField('primaryPhone', value)}\n onStatusSave={(value) => updateCompanyField('status', value)}\n onNextInteractionSave={async (payload) => {\n await saveCompany(\n {\n nextInteraction: payload\n ? {\n at: payload.at,\n name: payload.name ?? undefined,\n refId: payload.refId ?? undefined,\n icon: payload.icon ?? undefined,\n color: payload.color ?? undefined,\n }\n : null,\n },\n (prev) => ({\n ...prev,\n company: {\n ...prev.company,\n nextInteractionAt: payload?.at ?? null,\n nextInteractionName: payload?.name ?? null,\n nextInteractionRefId: payload?.refId ?? null,\n nextInteractionIcon: payload?.icon ?? null,\n nextInteractionColor: payload?.color ?? null,\n },\n })\n )\n }}\n onDelete={handleDelete}\n isDeleting={isDeleting}\n />\n\n <DetailTabsLayout\n className=\"space-y-6\"\n tabs={tabs}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n sectionAction={sectionAction}\n onSectionAction={handleSectionAction}\n navAriaLabel={t('customers.companies.detail.tabs.label', 'Company detail sections')}\n navClassName=\"gap-4\"\n >\n {(() => {\n const injected = injectedTabMap.get(activeTab)\n if (injected) return injected()\n if (activeTab === 'notes') {\n return (\n <NotesSection\n entityId={companyId}\n emptyLabel={t('customers.companies.detail.empty.comments', 'No notes yet.')}\n viewerUserId={data.viewer?.userId ?? null}\n viewerName={data.viewer?.name ?? null}\n viewerEmail={data.viewer?.email ?? null}\n addActionLabel={t('customers.companies.detail.notes.addLabel', 'Add note')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.notes.title', 'Keep everyone in the loop'),\n actionLabel: t('customers.companies.detail.emptyState.notes.action', 'Create a note'),\n }}\n onActionChange={handleSectionActionChange}\n translator={translateCompanyDetail}\n onLoadingChange={handleNotesLoadingChange}\n dataAdapter={notesAdapter}\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n iconSuggestions={ICON_SUGGESTIONS}\n readMarkdownPreference={readMarkdownPreferenceCookie}\n writeMarkdownPreference={writeMarkdownPreferenceCookie}\n />\n )\n }\n if (activeTab === 'activities') {\n return (\n <ActivitiesSection\n entityId={companyId}\n runGuardedMutation={runMutationWithContext}\n addActionLabel={t('customers.companies.detail.activities.add', 'Log activity')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.activities.title', 'No activities logged yet'),\n actionLabel: t('customers.companies.detail.emptyState.activities.action', 'Log activity'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleActivitiesLoadingChange}\n />\n )\n }\n if (activeTab === 'deals') {\n return (\n <DealsSection\n scope={dealsScope}\n emptyLabel={t('customers.companies.detail.empty.deals', 'No deals linked to this company.')}\n addActionLabel={t('customers.companies.detail.actions.addDeal', 'Add deal')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.deals.title', 'No deals yet'),\n actionLabel: t('customers.companies.detail.emptyState.deals.action', 'Create a deal'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleDealsLoadingChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n />\n )\n }\n if (activeTab === 'people') {\n return (\n <CompanyPeopleSection\n companyId={companyId}\n initialPeople={data.people ?? []}\n addActionLabel={t('customers.companies.detail.people.add', 'Add person')}\n emptyLabel={t('customers.companies.detail.people.empty', 'No people linked to this company yet.')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.people.title', 'Build the account team'),\n actionLabel: t('customers.companies.detail.emptyState.people.action', 'Create person'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handlePeopleLoadingChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onPeopleChange={(next) => {\n setData((prev) => (prev ? { ...prev, people: next } : prev))\n }}\n />\n )\n }\n if (activeTab === 'addresses') {\n return (\n <AddressesSection\n entityId={companyId}\n emptyLabel={t('customers.companies.detail.empty.addresses', 'No addresses recorded.')}\n addActionLabel={t('customers.companies.detail.addresses.add', 'Add address')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.addresses.title', 'No addresses yet'),\n actionLabel: t('customers.companies.detail.emptyState.addresses.action', 'Add address'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleAddressesLoadingChange}\n translator={detailTranslator}\n />\n )\n }\n if (activeTab === 'tasks') {\n return (\n <TasksSection\n entityId={companyId}\n initialTasks={data.todos}\n runGuardedMutation={runMutationWithContext}\n emptyLabel={t('customers.companies.detail.empty.todos', 'No tasks linked to this company.')}\n addActionLabel={t('customers.companies.detail.tasks.add', 'Add task')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.tasks.title', 'Plan what happens next'),\n actionLabel: t('customers.companies.detail.emptyState.tasks.action', 'Create task'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleTasksLoadingChange}\n translator={translateCompanyDetail}\n entityName={companyName}\n dialogContextKey=\"customers.companies.detail.tasks.dialog.context\"\n dialogContextFallback=\"This task will be linked to {{name}}\"\n />\n )\n }\n return null\n })()}\n </DetailTabsLayout>\n\n <div className=\"space-y-6\">\n <div className=\"space-y-3\">\n <h2 className=\"text-sm font-semibold\">{t('customers.companies.detail.sections.details', 'Company details')}</h2>\n <DetailFieldsSection fields={detailFields} />\n <InjectionSpot\n spotId=\"customers.company.detail:details\"\n context={injectionContext}\n data={data}\n onDataChange={(next) => setData(next as CompanyOverview)}\n />\n </div>\n\n <CustomDataSection\n entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}\n values={data.customFields ?? {}}\n onSubmit={handleCustomFieldsSubmit}\n title={t('customers.companies.detail.sections.customFields', 'Custom fields')}\n />\n\n <TagsSection\n entityId={companyId}\n tags={data.tags}\n onChange={handleTagsChange}\n isSubmitting={false}\n />\n </div>\n\n <Separator className=\"my-4\" />\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Separator } from '@open-mercato/ui/primitives/separator'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { DetailFieldsSection, type DetailFieldConfig } from '@open-mercato/ui/backend/detail'\nimport {\n ActivitiesSection,\n} from '../../../../components/detail/ActivitiesSection'\nimport {\n NotesSection,\n type CommentSummary,\n type SectionAction,\n} from '@open-mercato/ui/backend/detail'\nimport {\n TagsSection,\n type TagOption,\n} from '../../../../components/detail/TagsSection'\nimport { DealsSection } from '../../../../components/detail/DealsSection'\nimport { AddressesSection } from '../../../../components/detail/AddressesSection'\nimport { TasksSection } from '../../../../components/detail/TasksSection'\nimport { CustomDataSection } from '../../../../components/detail/CustomDataSection'\nimport { CompanyHighlights } from '../../../../components/detail/CompanyHighlights'\nimport { normalizeCustomFieldSubmitValue } from '../../../../components/detail/customFieldUtils'\nimport { InlineDictionaryEditor, renderMultilineMarkdownDisplay } from '../../../../components/detail/InlineEditors'\nimport { formatTemplate } from '../../../../components/detail/utils'\nimport { coerceDisplayName } from '../../../../lib/displayName'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport {\n CompanyPeopleSection,\n type CompanyPersonSummary,\n} from '../../../../components/detail/CompanyPeopleSection'\nimport { AnnualRevenueField } from '../../../../components/detail/AnnualRevenueField'\nimport type { ActivitySummary, DealSummary, TagSummary, TodoLinkSummary } from '../../../../components/detail/types'\nimport { renderDictionaryColor, renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { ICON_SUGGESTIONS } from '../../../../lib/dictionaries'\nimport { createCustomerNotesAdapter } from '../../../../components/detail/notesAdapter'\nimport { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '../../../../lib/markdownPreference'\nimport { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { DetailTabsLayout } from '../../../../components/detail/DetailTabsLayout'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\n\ntype CompanyOverview = {\n company: {\n id: string\n displayName: string\n description?: string | null\n ownerUserId?: string | null\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n source?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n updatedAt?: string | null\n }\n profile: {\n id: string\n legalName?: string | null\n brandName?: string | null\n domain?: string | null\n websiteUrl?: string | null\n industry?: string | null\n sizeBucket?: string | null\n annualRevenue?: string | null\n } | null\n customFields: Record<string, unknown>\n tags: TagSummary[]\n comments: CommentSummary[]\n activities: ActivitySummary[]\n deals: DealSummary[]\n todos: TodoLinkSummary[]\n people: CompanyPersonSummary[]\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\ntype SectionKey = 'notes' | 'activities' | 'deals' | 'people' | 'addresses' | 'tasks' | string\n\nexport default function CustomerCompanyDetailPage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n const notesAdapter = React.useMemo(() => createCustomerNotesAdapter(detailTranslator), [detailTranslator])\n const router = useRouter()\n const searchParams = useSearchParams()\n const initialTab = React.useMemo(() => {\n const raw = searchParams?.get('tab')\n if (raw === 'notes' || raw === 'activities' || raw === 'deals' || raw === 'people' || raw === 'addresses' || raw === 'tasks') {\n return raw\n }\n return 'notes'\n }, [searchParams])\n const [data, setData] = React.useState<CompanyOverview | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [activeTab, setActiveTab] = React.useState<SectionKey>(initialTab)\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const currentCompanyId = data?.company?.id ?? null\n const companyDisplayName = coerceDisplayName(data?.company?.displayName)\n const companyName = companyDisplayName.trim().length\n ? companyDisplayName\n : t('customers.companies.list.deleteFallbackName', 'this company')\n const translateCompanyDetail = React.useCallback(\n (key: string, fallback?: string, params?: Record<string, string | number>) => {\n const mappedKey = key.startsWith('customers.people.detail.')\n ? key.replace('customers.people.detail.', 'customers.companies.detail.')\n : key\n const adjustedFallback =\n key.startsWith('customers.people.detail.') && fallback\n ? fallback\n .replace(/\\bPerson\\b/g, 'Company')\n .replace(/\\bperson\\b/g, 'company')\n .replace(/\\bPeople\\b/g, 'Companies')\n .replace(/\\bpeople\\b/g, 'companies')\n : fallback\n const translated = t(mappedKey, params)\n if (translated !== mappedKey || mappedKey === key) return translated\n const fallbackValue = t(key, params)\n if (fallbackValue !== key) return fallbackValue\n if (!adjustedFallback) return mappedKey\n return formatTemplate(adjustedFallback, params)\n },\n [t],\n )\n const sectionLoaderLabel =\n activeTab === 'activities'\n ? t('customers.companies.detail.activities.loading', 'Loading activities\u2026')\n : activeTab === 'deals'\n ? t('customers.companies.detail.deals.loading', 'Loading deals\u2026')\n : activeTab === 'people'\n ? t('customers.companies.detail.people.loading', 'Loading people\u2026')\n : t('customers.companies.detail.sectionLoading', 'Loading\u2026')\n const mutationContextId = React.useMemo(\n () => (currentCompanyId ? `customer-company:${currentCompanyId}` : `customer-company:${id ?? 'pending'}`),\n [currentCompanyId, id],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n companyId?: string | null\n resourceKind: string\n resourceId?: string\n data: CompanyOverview | null\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const injectionContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n companyId: currentCompanyId,\n resourceKind: 'customers.company',\n resourceId: currentCompanyId ?? (id ?? undefined),\n data,\n retryLastMutation,\n }),\n [currentCompanyId, data, id, mutationContextId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {\n return runMutation({\n operation,\n mutationPayload,\n context: injectionContext,\n })\n },\n [injectionContext, runMutation],\n )\n\n const handleSectionActionChange = React.useCallback((action: SectionAction | null) => {\n setSectionAction(action)\n }, [])\n\n const handleSectionAction = React.useCallback(() => {\n if (!sectionAction || sectionAction.disabled) return\n sectionAction.onClick()\n }, [sectionAction])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n const validators = React.useMemo(() => ({\n email: (value: string) => {\n if (!value) return null\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n return emailRegex.test(value) ? null : t('customers.companies.detail.inline.emailInvalid', 'Enter a valid email address.')\n },\n phone: (value: string) => {\n if (!value) return null\n return value.length >= 3 ? null : t('customers.companies.detail.inline.phoneInvalid', 'Phone number is too short.')\n },\n displayName: (value: string) => {\n const trimmed = value.trim()\n return trimmed.length ? null : t('customers.companies.form.displayName.error', 'Company name is required.')\n },\n website: (value: string) => {\n if (!value) return null\n try {\n const url = new URL(value.trim())\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? null\n : t('customers.companies.detail.inline.websiteInvalid', 'Use a valid http(s) address.')\n } catch {\n return t('customers.companies.detail.inline.websiteInvalid', 'Use a valid http(s) address.')\n }\n },\n annualRevenue: (value: string) => {\n if (!value) return null\n const normalized = value.replace(/[, ]+/g, '')\n const amount = Number(normalized)\n if (Number.isNaN(amount) || amount < 0) {\n return t('customers.companies.detail.inline.annualRevenueInvalid', 'Enter a non-negative number.')\n }\n return null\n },\n }), [t])\n\n const { widgets: injectedTabWidgets } = useInjectionWidgets('customers.company.detail:tabs', {\n context: injectionContext,\n triggerOnLoad: true,\n })\n const injectedTabs = React.useMemo(\n () =>\n (injectedTabWidgets ?? [])\n .filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')\n .map((widget) => {\n const id = widget.placement?.groupId ?? widget.widgetId\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title\n const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0\n const render = () => (\n <widget.module.Widget\n context={injectionContext}\n data={data}\n onDataChange={(next) => setData(next as CompanyOverview)}\n />\n )\n return { id, label, priority, render }\n })\n .sort((a, b) => b.priority - a.priority),\n [data, injectedTabWidgets, injectionContext],\n )\n const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])\n\n const tabs = React.useMemo(\n () => [\n { id: 'notes' as const, label: t('customers.companies.detail.tabs.notes', 'Notes') },\n { id: 'activities' as const, label: t('customers.companies.detail.tabs.activities', 'Activities') },\n { id: 'deals' as const, label: t('customers.companies.detail.tabs.deals', 'Deals') },\n { id: 'people' as const, label: t('customers.companies.detail.tabs.people', 'People') },\n { id: 'addresses' as const, label: t('customers.companies.detail.tabs.addresses', 'Addresses') },\n { id: 'tasks' as const, label: t('customers.companies.detail.tabs.tasks', 'Tasks') },\n ...injectedTabs.map((tab) => ({ id: tab.id as SectionKey, label: tab.label })),\n ],\n [injectedTabs, t],\n )\n\n React.useEffect(() => {\n if (!id) {\n setIsNotFound(true)\n setIsLoading(false)\n return\n }\n const companyId = id\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setError(null)\n try {\n const search = new URLSearchParams()\n search.append('include', 'todos')\n search.append('include', 'people')\n const payload = await readApiResultOrThrow<CompanyOverview>(\n `/api/customers/companies/${encodeURIComponent(companyId)}?${search.toString()}`,\n undefined,\n { errorMessage: t('customers.companies.detail.error.load', 'Failed to load company.') },\n )\n if (cancelled) return\n setData(payload as CompanyOverview)\n } catch (err) {\n if (cancelled) return\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('customers.companies.detail.error.load', 'Failed to load company.')\n setError(message)\n }\n setData(null)\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [id, t])\n\n const saveCompany = React.useCallback(\n async (patch: Record<string, unknown>, apply: (prev: CompanyOverview) => CompanyOverview) => {\n if (!data) return\n const payload = { id: data.company.id, ...patch }\n const result = await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => apiCallOrThrow<{ ok?: boolean; updatedAt?: string | null }>(\n '/api/customers/companies',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: t('customers.companies.detail.inline.error', 'Unable to update company.') },\n ),\n ),\n payload,\n )\n // Refresh the optimistic-lock token so the next sequential inline edit does\n // not send a stale updatedAt and falsely 409 (#2055, default-ON locking).\n const nextUpdatedAt = result?.result?.updatedAt ?? null\n setData((prev) => {\n if (!prev) return prev\n const applied = apply(prev)\n return nextUpdatedAt\n ? { ...applied, company: { ...applied.company, updatedAt: nextUpdatedAt } }\n : applied\n })\n },\n [data, runMutationWithContext, t],\n )\n\n const updateDisplayName = React.useCallback(\n async (next: string | null) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { displayName: send },\n (prev) => ({\n ...prev,\n company: {\n ...prev.company,\n displayName: next && next.length ? next : prev.company.displayName,\n },\n })\n )\n },\n [saveCompany],\n )\n\n const updateCompanyField = React.useCallback(\n async (field: 'primaryEmail' | 'primaryPhone' | 'status' | 'lifecycleStage' | 'source', next: string | null) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { [field]: send },\n (prev) => ({\n ...prev,\n company: {\n ...prev.company,\n [field]: next && next.length ? next : null,\n },\n })\n )\n },\n [saveCompany],\n )\n\n const updateProfileField = React.useCallback(\n async (\n field: 'brandName' | 'legalName' | 'websiteUrl' | 'industry' | 'domain' | 'sizeBucket',\n next: string | null,\n ) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { [field]: send },\n (prev) => {\n if (!prev.profile) return prev\n const nextValue = next && next.length ? next : null\n return {\n ...prev,\n profile: {\n ...prev.profile,\n [field]: nextValue,\n },\n }\n }\n )\n },\n [saveCompany],\n )\n\n const submitCustomFields = React.useCallback(\n async (prefixedValues: Record<string, unknown>, { showFlash = true } = {}) => {\n if (!data) throw new Error(t('customers.companies.detail.inline.error', 'Unable to update company.'))\n const customPayload = collectCustomFieldValues(prefixedValues, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n const normalized: Record<string, unknown> = {}\n for (const [fieldId, value] of Object.entries(customPayload)) {\n normalized[`cf_${fieldId}`] = value\n }\n if (!Object.keys(customPayload).length) {\n if (showFlash) flash(t('ui.forms.flash.saveSuccess', 'Saved successfully.'), 'success')\n return\n }\n const payload = {\n id: data.company.id,\n customFields: customPayload,\n }\n let customFieldsUpdatedAt: string | null = null\n try {\n const result = await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => apiCallOrThrow<{ ok?: boolean; updatedAt?: string | null }>(\n '/api/customers/companies',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: t('customers.companies.detail.inline.error', 'Unable to update company.') },\n ),\n ),\n payload,\n )\n customFieldsUpdatedAt = result?.result?.updatedAt ?? null\n } catch (err) {\n const { message: helperMessage, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const message = helperMessage ?? t('customers.companies.detail.inline.error', 'Unable to update company.')\n const mappedErrors: Record<string, string> | undefined = fieldErrors\n ? Object.entries(fieldErrors).reduce<Record<string, string>>((acc, [key, value]) => {\n const formKey = key.startsWith('cf_') ? key : `cf_${key}`\n acc[formKey] = value\n return acc\n }, {})\n : undefined\n const error = new Error(message) as Error & { fieldErrors?: Record<string, string> }\n if (mappedErrors && Object.keys(mappedErrors).length) error.fieldErrors = mappedErrors\n throw error\n }\n setData((prev) => {\n if (!prev) return prev\n return {\n ...prev,\n company: customFieldsUpdatedAt\n ? { ...prev.company, updatedAt: customFieldsUpdatedAt }\n : prev.company,\n customFields: {\n ...prev.customFields,\n ...normalized,\n },\n }\n })\n if (showFlash) flash(t('ui.forms.flash.saveSuccess', 'Saved successfully.'), 'success')\n },\n [data, runMutationWithContext, t],\n )\n\n const handleAnnualRevenueChange = React.useCallback(\n async ({ amount, currency }: { amount: number | null; currency: string | null }) => {\n await saveCompany(\n { annualRevenue: amount ?? null },\n (prev) => {\n if (!prev.profile) return prev\n return {\n ...prev,\n profile: {\n ...prev.profile,\n annualRevenue: amount === null ? null : String(amount),\n },\n }\n }\n )\n await submitCustomFields(\n { cf_annual_revenue_currency: currency ?? null },\n { showFlash: false },\n )\n flash(t('ui.forms.flash.saveSuccess', 'Saved successfully.'), 'success')\n },\n [saveCompany, submitCustomFields, t],\n )\n\n const handleDelete = React.useCallback(async () => {\n if (!currentCompanyId) return\n const confirmed = await confirm({\n title: t('customers.companies.list.deleteConfirm', undefined, { name: companyName }),\n variant: 'destructive',\n })\n if (!confirmed) return\n setIsDeleting(true)\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => apiCallOrThrow(\n `/api/customers/companies?id=${encodeURIComponent(currentCompanyId)}`,\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n },\n { errorMessage: t('customers.companies.list.deleteError', 'Failed to delete company.') },\n ),\n ),\n { id: currentCompanyId },\n )\n flash(t('customers.companies.list.deleteSuccess', 'Company deleted.'), 'success')\n router.push('/backend/customers/companies')\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.companies.list.deleteError', 'Failed to delete company.')\n flash(message, 'error')\n } finally {\n setIsDeleting(false)\n }\n }, [companyName, confirm, currentCompanyId, router, runMutationWithContext, t])\n\n const handleTagsChange = React.useCallback((nextTags: TagOption[]) => {\n setData((prev) => (prev ? { ...prev, tags: nextTags } : prev))\n }, [])\n\n const handleCustomFieldsSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n await submitCustomFields(values)\n },\n [submitCustomFields],\n )\n\n const handleNotesLoadingChange = React.useCallback(() => {}, [])\n\n const handleActivitiesLoadingChange = React.useCallback(() => {}, [])\n\n const handleDealsLoadingChange = React.useCallback(() => {}, [])\n\n const handlePeopleLoadingChange = React.useCallback(() => {}, [])\n\n const handleAddressesLoadingChange = React.useCallback(() => {}, [])\n\n const handleTasksLoadingChange = React.useCallback(() => {}, [])\n\n const dealsScope = React.useMemo(\n () => (currentCompanyId ? ({ kind: 'company', entityId: currentCompanyId } as const) : null),\n [currentCompanyId],\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('customers.companies.detail.loading', 'Loading company\u2026')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('customers.companies.detail.error.notFound', 'Company not found.')}\n backHref=\"/backend/customers/companies\"\n backLabel={t('customers.companies.detail.actions.backToList', 'Back to companies')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data?.company?.id) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error ?? t('customers.companies.detail.error.notFound', 'Company not found.')}\n action={\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/backend/customers/companies\">\n {t('customers.companies.detail.actions.backToList', 'Back to companies')}\n </Link>\n </Button>\n }\n />\n </PageBody>\n </Page>\n )\n }\n\n const { company, profile } = data\n const companyId = company.id\n\n const annualRevenueCurrency =\n typeof data.customFields?.annual_revenue_currency === 'string'\n ? (data.customFields.annual_revenue_currency as string)\n : null\n\n const detailFields: DetailFieldConfig[] = [\n {\n key: 'displayName',\n kind: 'text',\n label: t('customers.companies.detail.fields.displayName', 'Display name'),\n value: company.displayName,\n placeholder: t('customers.companies.form.displayName.placeholder', 'Enter company name'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n validator: validators.displayName,\n onSave: updateDisplayName,\n },\n {\n key: 'legalName',\n kind: 'text',\n label: t('customers.companies.detail.fields.legalName', 'Legal name'),\n value: profile?.legalName ?? null,\n placeholder: t('customers.companies.detail.fields.legalNamePlaceholder', 'Add legal name'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('legalName', value),\n },\n {\n key: 'brandName',\n kind: 'text',\n label: t('customers.companies.detail.fields.brandName', 'Brand name'),\n value: profile?.brandName ?? null,\n placeholder: t('customers.companies.detail.fields.brandNamePlaceholder', 'Add brand name'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('brandName', value),\n },\n {\n key: 'description',\n kind: 'multiline',\n label: t('customers.companies.detail.fields.description', 'Description'),\n value: company.description ?? null,\n placeholder: t('customers.companies.detail.fields.descriptionPlaceholder', 'Describe the company'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n gridClassName: 'sm:col-span-2 xl:col-span-3',\n renderDisplay: renderMultilineMarkdownDisplay,\n onSave: async (next) => {\n const send = typeof next === 'string' ? next : ''\n await saveCompany(\n { description: send },\n (prev) => ({\n ...prev,\n company: { ...prev.company, description: next && next.length ? next : null },\n })\n )\n },\n },\n {\n key: 'lifecycleStage',\n kind: 'custom',\n label: t('customers.companies.detail.fields.lifecycleStage', 'Lifecycle stage'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <InlineDictionaryEditor\n label={t('customers.companies.detail.fields.lifecycleStage', 'Lifecycle stage')}\n value={company.lifecycleStage ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n kind=\"lifecycle-stages\"\n onSave={(next) => updateCompanyField('lifecycleStage', next)}\n selectClassName=\"h-9 w-full rounded border px-3 text-sm\"\n variant=\"muted\"\n activateOnClick\n />\n ),\n },\n {\n key: 'source',\n kind: 'custom',\n label: t('customers.companies.detail.fields.source', 'Source'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <InlineDictionaryEditor\n label={t('customers.companies.detail.fields.source', 'Source')}\n value={company.source ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n kind=\"sources\"\n onSave={(next) => updateCompanyField('source', next)}\n selectClassName=\"h-9 w-full rounded border px-3 text-sm\"\n variant=\"muted\"\n activateOnClick\n />\n ),\n },\n {\n key: 'domain',\n kind: 'text',\n label: t('customers.companies.detail.fields.domain', 'Domain'),\n value: profile?.domain ?? null,\n placeholder: t('customers.companies.detail.fields.domainPlaceholder', 'example.com'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('domain', value),\n },\n {\n key: 'industry',\n kind: 'custom',\n label: t('customers.companies.detail.fields.industry', 'Industry'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <InlineDictionaryEditor\n label={t('customers.companies.detail.fields.industry', 'Industry')}\n value={profile?.industry ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n kind=\"industries\"\n onSave={(next) => updateProfileField('industry', next)}\n selectClassName=\"h-9 w-full rounded border px-3 text-sm\"\n variant=\"muted\"\n activateOnClick\n />\n ),\n },\n {\n key: 'sizeBucket',\n kind: 'text',\n label: t('customers.companies.detail.fields.sizeBucket', 'Company size'),\n value: profile?.sizeBucket ?? null,\n placeholder: t('customers.companies.detail.fields.sizeBucketPlaceholder', 'Add size bucket'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n onSave: (value) => updateProfileField('sizeBucket', value),\n },\n {\n key: 'annualRevenue',\n kind: 'custom',\n label: t('customers.companies.detail.fields.annualRevenue', 'Annual revenue'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n render: () => (\n <AnnualRevenueField\n label={t('customers.companies.detail.fields.annualRevenue', 'Annual revenue')}\n amount={profile?.annualRevenue ?? null}\n currency={annualRevenueCurrency}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n validator={validators.annualRevenue}\n onSave={handleAnnualRevenueChange}\n />\n ),\n },\n {\n key: 'websiteUrl',\n kind: 'text',\n label: t('customers.companies.detail.fields.website', 'Website'),\n value: profile?.websiteUrl ?? null,\n placeholder: t('customers.companies.detail.fields.websitePlaceholder', 'https://example.com'),\n emptyLabel: t('customers.companies.detail.noValue', 'Not provided'),\n inputType: 'url',\n validator: validators.website,\n onSave: (value) => updateProfileField('websiteUrl', value),\n },\n ]\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-8\">\n <CompanyHighlights\n company={company}\n profile={profile ?? null}\n validators={validators}\n onDisplayNameSave={updateDisplayName}\n utilityActions={(\n <SendObjectMessageDialog\n object={{\n entityModule: 'customers',\n entityType: 'company',\n entityId: companyId,\n previewData: {\n title: company.displayName,\n subtitle: company.primaryEmail ?? undefined,\n metadata: {\n [t('customers.companies.detail.highlights.primaryPhone')]: company.primaryPhone ?? '-',\n [t('customers.companies.detail.fields.industry')]: profile?.industry ?? '-',\n },\n },\n }}\n viewHref={`/backend/customers/companies/${companyId}`}\n />\n )}\n onPrimaryEmailSave={(value) => updateCompanyField('primaryEmail', value)}\n onPrimaryPhoneSave={(value) => updateCompanyField('primaryPhone', value)}\n onStatusSave={(value) => updateCompanyField('status', value)}\n onNextInteractionSave={async (payload) => {\n await saveCompany(\n {\n nextInteraction: payload\n ? {\n at: payload.at,\n name: payload.name ?? undefined,\n refId: payload.refId ?? undefined,\n icon: payload.icon ?? undefined,\n color: payload.color ?? undefined,\n }\n : null,\n },\n (prev) => ({\n ...prev,\n company: {\n ...prev.company,\n nextInteractionAt: payload?.at ?? null,\n nextInteractionName: payload?.name ?? null,\n nextInteractionRefId: payload?.refId ?? null,\n nextInteractionIcon: payload?.icon ?? null,\n nextInteractionColor: payload?.color ?? null,\n },\n })\n )\n }}\n onDelete={handleDelete}\n isDeleting={isDeleting}\n />\n\n <DetailTabsLayout\n className=\"space-y-6\"\n tabs={tabs}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n sectionAction={sectionAction}\n onSectionAction={handleSectionAction}\n navAriaLabel={t('customers.companies.detail.tabs.label', 'Company detail sections')}\n navClassName=\"gap-4\"\n >\n {(() => {\n const injected = injectedTabMap.get(activeTab)\n if (injected) return injected()\n if (activeTab === 'notes') {\n return (\n <NotesSection\n entityId={companyId}\n emptyLabel={t('customers.companies.detail.empty.comments', 'No notes yet.')}\n viewerUserId={data.viewer?.userId ?? null}\n viewerName={data.viewer?.name ?? null}\n viewerEmail={data.viewer?.email ?? null}\n addActionLabel={t('customers.companies.detail.notes.addLabel', 'Add note')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.notes.title', 'Keep everyone in the loop'),\n actionLabel: t('customers.companies.detail.emptyState.notes.action', 'Create a note'),\n }}\n onActionChange={handleSectionActionChange}\n translator={translateCompanyDetail}\n onLoadingChange={handleNotesLoadingChange}\n dataAdapter={notesAdapter}\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n iconSuggestions={ICON_SUGGESTIONS}\n readMarkdownPreference={readMarkdownPreferenceCookie}\n writeMarkdownPreference={writeMarkdownPreferenceCookie}\n />\n )\n }\n if (activeTab === 'activities') {\n return (\n <ActivitiesSection\n entityId={companyId}\n runGuardedMutation={runMutationWithContext}\n addActionLabel={t('customers.companies.detail.activities.add', 'Log activity')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.activities.title', 'No activities logged yet'),\n actionLabel: t('customers.companies.detail.emptyState.activities.action', 'Log activity'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleActivitiesLoadingChange}\n />\n )\n }\n if (activeTab === 'deals') {\n return (\n <DealsSection\n scope={dealsScope}\n emptyLabel={t('customers.companies.detail.empty.deals', 'No deals linked to this company.')}\n addActionLabel={t('customers.companies.detail.actions.addDeal', 'Add deal')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.deals.title', 'No deals yet'),\n actionLabel: t('customers.companies.detail.emptyState.deals.action', 'Create a deal'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleDealsLoadingChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n />\n )\n }\n if (activeTab === 'people') {\n return (\n <CompanyPeopleSection\n companyId={companyId}\n initialPeople={data.people ?? []}\n addActionLabel={t('customers.companies.detail.people.add', 'Add person')}\n emptyLabel={t('customers.companies.detail.people.empty', 'No people linked to this company yet.')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.people.title', 'Build the account team'),\n actionLabel: t('customers.companies.detail.emptyState.people.action', 'Create person'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handlePeopleLoadingChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onPeopleChange={(next) => {\n setData((prev) => (prev ? { ...prev, people: next } : prev))\n }}\n />\n )\n }\n if (activeTab === 'addresses') {\n return (\n <AddressesSection\n entityId={companyId}\n emptyLabel={t('customers.companies.detail.empty.addresses', 'No addresses recorded.')}\n addActionLabel={t('customers.companies.detail.addresses.add', 'Add address')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.addresses.title', 'No addresses yet'),\n actionLabel: t('customers.companies.detail.emptyState.addresses.action', 'Add address'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleAddressesLoadingChange}\n translator={detailTranslator}\n />\n )\n }\n if (activeTab === 'tasks') {\n return (\n <TasksSection\n entityId={companyId}\n initialTasks={data.todos}\n runGuardedMutation={runMutationWithContext}\n emptyLabel={t('customers.companies.detail.empty.todos', 'No tasks linked to this company.')}\n addActionLabel={t('customers.companies.detail.tasks.add', 'Add task')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.tasks.title', 'Plan what happens next'),\n actionLabel: t('customers.companies.detail.emptyState.tasks.action', 'Create task'),\n }}\n onActionChange={handleSectionActionChange}\n onLoadingChange={handleTasksLoadingChange}\n translator={translateCompanyDetail}\n entityName={companyName}\n dialogContextKey=\"customers.companies.detail.tasks.dialog.context\"\n dialogContextFallback=\"This task will be linked to {{name}}\"\n />\n )\n }\n return null\n })()}\n </DetailTabsLayout>\n\n <div className=\"space-y-6\">\n <div className=\"space-y-3\">\n <h2 className=\"text-sm font-semibold\">{t('customers.companies.detail.sections.details', 'Company details')}</h2>\n <DetailFieldsSection fields={detailFields} />\n <InjectionSpot\n spotId={extensionPoints.hosts.companyLegacyDetails.spotId}\n context={injectionContext}\n data={data}\n onDataChange={(next) => setData(next as CompanyOverview)}\n />\n </div>\n\n <CustomDataSection\n entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}\n values={data.customFields ?? {}}\n onSubmit={handleCustomFieldsSubmit}\n title={t('customers.companies.detail.sections.customFields', 'Custom fields')}\n />\n\n <TagsSection\n entityId={companyId}\n tags={data.tags}\n onChange={handleTagsChange}\n isSubmitting={false}\n />\n </div>\n\n <Separator className=\"my-4\" />\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
+ "mappings": ";AAkQY,cA2TF,YA3TE;AAhQZ,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAChC,OAAO,UAAU;AACjB,SAAS,WAAW,uBAAuB;AAC3C,SAAS,MAAM,gBAAgB;AAC/B,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,gBAAgB,sBAAsB,mCAAmC;AAClF,SAAS,iCAAiC;AAC1C,SAAS,gCAAgC;AACzC,SAAS,sCAAsC;AAC/C,SAAS,SAAS;AAClB,SAAS,YAAY;AACrB,SAAS,qBAAqB,oBAAoB;AAClD,SAAS,wBAAwB;AACjC,SAAS,2BAAmD;AAC5D;AAAA,EACE;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAGK;AACP;AAAA,EACE;AAAA,OAEK;AACP,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,oBAAoB;AAC7B,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAClC,SAAS,uCAAuC;AAChD,SAAS,wBAAwB,sCAAsC;AACvE,SAAS,sBAAsB;AAC/B,SAAS,yBAAyB;AAClC,SAAS,oCAAoC;AAC7C;AAAA,EACE;AAAA,OAEK;AACP,SAAS,0BAA0B;AAEnC,SAAS,uBAAuB,4BAA4B;AAC5D,SAAS,wBAAwB;AACjC,SAAS,kCAAkC;AAC3C,SAAS,8BAA8B,qCAAqC;AAC5E,SAAS,eAAe,2BAA2B;AACnD,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AA+CzB,SAAR,0BAA2C,EAAE,OAAO,GAAiC;AAC1F,QAAM,KAAK,QAAQ;AACnB,QAAM,IAAI,KAAK;AACf,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAC3D,QAAM,mBAAmB,MAAM,QAAQ,MAAM,6BAA6B,CAAC,GAAG,CAAC,CAAC,CAAC;AACjF,QAAM,eAAe,MAAM,QAAQ,MAAM,2BAA2B,gBAAgB,GAAG,CAAC,gBAAgB,CAAC;AACzG,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,gBAAgB;AACrC,QAAM,aAAa,MAAM,QAAQ,MAAM;AACrC,UAAM,MAAM,cAAc,IAAI,KAAK;AACnC,QAAI,QAAQ,WAAW,QAAQ,gBAAgB,QAAQ,WAAW,QAAQ,YAAY,QAAQ,eAAe,QAAQ,SAAS;AAC5H,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,CAAC;AACjB,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAiC,IAAI;AACnE,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,IAAI;AACrD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAqB,UAAU;AACvE,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAA+B,IAAI;AACnF,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,mBAAmB,MAAM,SAAS,MAAM;AAC9C,QAAM,qBAAqB,kBAAkB,MAAM,SAAS,WAAW;AACvE,QAAM,cAAc,mBAAmB,KAAK,EAAE,SAC1C,qBACA,EAAE,+CAA+C,cAAc;AACnE,QAAM,yBAAyB,MAAM;AAAA,IACnC,CAAC,KAAa,UAAmBA,YAA6C;AAC5E,YAAM,YAAY,IAAI,WAAW,0BAA0B,IACvD,IAAI,QAAQ,4BAA4B,6BAA6B,IACrE;AACJ,YAAM,mBACJ,IAAI,WAAW,0BAA0B,KAAK,WAC1C,SACG,QAAQ,eAAe,SAAS,EAChC,QAAQ,eAAe,SAAS,EAChC,QAAQ,eAAe,WAAW,EAClC,QAAQ,eAAe,WAAW,IACrC;AACN,YAAM,aAAa,EAAE,WAAWA,OAAM;AACtC,UAAI,eAAe,aAAa,cAAc,IAAK,QAAO;AAC1D,YAAM,gBAAgB,EAAE,KAAKA,OAAM;AACnC,UAAI,kBAAkB,IAAK,QAAO;AAClC,UAAI,CAAC,iBAAkB,QAAO;AAC9B,aAAO,eAAe,kBAAkBA,OAAM;AAAA,IAChD;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AACA,QAAM,qBACJ,cAAc,eACV,EAAE,iDAAiD,0BAAqB,IACxE,cAAc,UACZ,EAAE,4CAA4C,qBAAgB,IAC9D,cAAc,WACZ,EAAE,6CAA6C,sBAAiB,IAClE,EAAE,6CAA6C,eAAU;AACjE,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAO,mBAAmB,oBAAoB,gBAAgB,KAAK,oBAAoB,MAAM,SAAS;AAAA,IACtG,CAAC,kBAAkB,EAAE;AAAA,EACvB;AACA,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAOxC;AAAA,IACD,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AACD,QAAM,mBAAmB,MAAM;AAAA,IAC7B,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,cAAc;AAAA,MACd,YAAY,qBAAqB,MAAM;AAAA,MACvC;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,MAAM,IAAI,mBAAmB,iBAAiB;AAAA,EACnE;AACA,QAAM,yBAAyB,MAAM;AAAA,IACnC,OAAW,WAA6B,oBAA0D;AAChG,aAAO,YAAY;AAAA,QACjB;AAAA,QACA;AAAA,QACA,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,IACA,CAAC,kBAAkB,WAAW;AAAA,EAChC;AAEA,QAAM,4BAA4B,MAAM,YAAY,CAAC,WAAiC;AACpF,qBAAiB,MAAM;AAAA,EACzB,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAsB,MAAM,YAAY,MAAM;AAClD,QAAI,CAAC,iBAAiB,cAAc,SAAU;AAC9C,kBAAc,QAAQ;AAAA,EACxB,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,UAAU,MAAM;AACpB,qBAAiB,IAAI;AAAA,EACvB,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,aAAa,MAAM,QAAQ,OAAO;AAAA,IACtC,OAAO,CAAC,UAAkB;AACxB,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,aAAa;AACnB,aAAO,WAAW,KAAK,KAAK,IAAI,OAAO,EAAE,kDAAkD,8BAA8B;AAAA,IAC3H;AAAA,IACA,OAAO,CAAC,UAAkB;AACxB,UAAI,CAAC,MAAO,QAAO;AACnB,aAAO,MAAM,UAAU,IAAI,OAAO,EAAE,kDAAkD,4BAA4B;AAAA,IACpH;AAAA,IACA,aAAa,CAAC,UAAkB;AAC9B,YAAM,UAAU,MAAM,KAAK;AAC3B,aAAO,QAAQ,SAAS,OAAO,EAAE,8CAA8C,2BAA2B;AAAA,IAC5G;AAAA,IACA,SAAS,CAAC,UAAkB;AAC1B,UAAI,CAAC,MAAO,QAAO;AACnB,UAAI;AACF,cAAM,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC;AAChC,eAAO,IAAI,aAAa,WAAW,IAAI,aAAa,WAChD,OACA,EAAE,oDAAoD,8BAA8B;AAAA,MAC1F,QAAQ;AACN,eAAO,EAAE,oDAAoD,8BAA8B;AAAA,MAC7F;AAAA,IACF;AAAA,IACA,eAAe,CAAC,UAAkB;AAChC,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,aAAa,MAAM,QAAQ,UAAU,EAAE;AAC7C,YAAM,SAAS,OAAO,UAAU;AAChC,UAAI,OAAO,MAAM,MAAM,KAAK,SAAS,GAAG;AACtC,eAAO,EAAE,0DAA0D,8BAA8B;AAAA,MACnG;AACA,aAAO;AAAA,IACT;AAAA,EACF,IAAI,CAAC,CAAC,CAAC;AAEP,QAAM,EAAE,SAAS,mBAAmB,IAAI,oBAAoB,iCAAiC;AAAA,IAC3F,SAAS;AAAA,IACT,eAAe;AAAA,EACjB,CAAC;AACD,QAAM,eAAe,MAAM;AAAA,IACzB,OACG,sBAAsB,CAAC,GACrB,OAAO,CAAC,YAAY,OAAO,WAAW,QAAQ,WAAW,KAAK,EAC9D,IAAI,CAAC,WAAW;AACf,YAAMC,MAAK,OAAO,WAAW,WAAW,OAAO;AAC/C,YAAM,QAAQ,OAAO,WAAW,cAAc,OAAO,OAAO,SAAS;AACrE,YAAM,WAAW,OAAO,OAAO,WAAW,aAAa,WAAW,OAAO,UAAU,WAAW;AAC9F,YAAM,SAAS,MACb;AAAA,QAAC,OAAO,OAAO;AAAA,QAAd;AAAA,UACC,SAAS;AAAA,UACT;AAAA,UACA,cAAc,CAAC,SAAS,QAAQ,IAAuB;AAAA;AAAA,MACzD;AAEF,aAAO,EAAE,IAAAA,KAAI,OAAO,UAAU,OAAO;AAAA,IACvC,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,IAC3C,CAAC,MAAM,oBAAoB,gBAAgB;AAAA,EAC7C;AACA,QAAM,iBAAiB,MAAM,QAAQ,MAAM,IAAI,IAAI,aAAa,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AAEnH,QAAM,OAAO,MAAM;AAAA,IACjB,MAAM;AAAA,MACJ,EAAE,IAAI,SAAkB,OAAO,EAAE,yCAAyC,OAAO,EAAE;AAAA,MACnF,EAAE,IAAI,cAAuB,OAAO,EAAE,8CAA8C,YAAY,EAAE;AAAA,MAClG,EAAE,IAAI,SAAkB,OAAO,EAAE,yCAAyC,OAAO,EAAE;AAAA,MACnF,EAAE,IAAI,UAAmB,OAAO,EAAE,0CAA0C,QAAQ,EAAE;AAAA,MACtF,EAAE,IAAI,aAAsB,OAAO,EAAE,6CAA6C,WAAW,EAAE;AAAA,MAC/F,EAAE,IAAI,SAAkB,OAAO,EAAE,yCAAyC,OAAO,EAAE;AAAA,MACnF,GAAG,aAAa,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,IAAkB,OAAO,IAAI,MAAM,EAAE;AAAA,IAC/E;AAAA,IACA,CAAC,cAAc,CAAC;AAAA,EAClB;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,IAAI;AACP,oBAAc,IAAI;AAClB,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,UAAMC,aAAY;AAClB,QAAI,YAAY;AAChB,mBAAe,OAAO;AACpB,mBAAa,IAAI;AACjB,eAAS,IAAI;AACb,UAAI;AACF,cAAM,SAAS,IAAI,gBAAgB;AACnC,eAAO,OAAO,WAAW,OAAO;AAChC,eAAO,OAAO,WAAW,QAAQ;AACjC,cAAM,UAAU,MAAM;AAAA,UACpB,4BAA4B,mBAAmBA,UAAS,CAAC,IAAI,OAAO,SAAS,CAAC;AAAA,UAC9E;AAAA,UACA,EAAE,cAAc,EAAE,yCAAyC,yBAAyB,EAAE;AAAA,QACxF;AACA,YAAI,UAAW;AACf,gBAAQ,OAA0B;AAAA,MACpC,SAAS,KAAK;AACZ,YAAI,UAAW;AACf,YAAK,IAA4B,WAAW,KAAK;AAC/C,wBAAc,IAAI;AAAA,QACpB,OAAO;AACL,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,EAAE,yCAAyC,yBAAyB;AACzH,mBAAS,OAAO;AAAA,QAClB;AACA,gBAAQ,IAAI;AAAA,MACd,UAAE;AACA,YAAI,CAAC,UAAW,cAAa,KAAK;AAAA,MACpC;AAAA,IACF;AACA,SAAK,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACrB,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,IAAI,CAAC,CAAC;AAEV,QAAM,cAAc,MAAM;AAAA,IACxB,OAAO,OAAgC,UAAsD;AAC3F,UAAI,CAAC,KAAM;AACX,YAAM,UAAU,EAAE,IAAI,KAAK,QAAQ,IAAI,GAAG,MAAM;AAChD,YAAM,SAAS,MAAM;AAAA,QACnB,MAAM;AAAA,UACJ,0BAA2B,MAAM,SAAgD,SAAS;AAAA,UAC1F,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,cAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,YAC9B;AAAA,YACA,EAAE,cAAc,EAAE,2CAA2C,2BAA2B,EAAE;AAAA,UAC5F;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAGA,YAAM,gBAAgB,QAAQ,QAAQ,aAAa;AACnD,cAAQ,CAAC,SAAS;AAChB,YAAI,CAAC,KAAM,QAAO;AAClB,cAAM,UAAU,MAAM,IAAI;AAC1B,eAAO,gBACH,EAAE,GAAG,SAAS,SAAS,EAAE,GAAG,QAAQ,SAAS,WAAW,cAAc,EAAE,IACxE;AAAA,MACN,CAAC;AAAA,IACH;AAAA,IACA,CAAC,MAAM,wBAAwB,CAAC;AAAA,EAClC;AAEA,QAAM,oBAAoB,MAAM;AAAA,IAC9B,OAAO,SAAwB;AAC7B,YAAM,OAAO,OAAO,SAAS,WAAW,OAAO;AAC/C,YAAM;AAAA,QACJ,EAAE,aAAa,KAAK;AAAA,QACpB,CAAC,UAAU;AAAA,UACT,GAAG;AAAA,UACH,SAAS;AAAA,YACP,GAAG,KAAK;AAAA,YACR,aAAa,QAAQ,KAAK,SAAS,OAAO,KAAK,QAAQ;AAAA,UACzD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,OAAO,OAAiF,SAAwB;AAC9G,YAAM,OAAO,OAAO,SAAS,WAAW,OAAO;AAC/C,YAAM;AAAA,QACJ,EAAE,CAAC,KAAK,GAAG,KAAK;AAAA,QAChB,CAAC,UAAU;AAAA,UACT,GAAG;AAAA,UACH,SAAS;AAAA,YACP,GAAG,KAAK;AAAA,YACR,CAAC,KAAK,GAAG,QAAQ,KAAK,SAAS,OAAO;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,OACE,OACA,SACG;AACH,YAAM,OAAO,OAAO,SAAS,WAAW,OAAO;AAC/C,YAAM;AAAA,QACJ,EAAE,CAAC,KAAK,GAAG,KAAK;AAAA,QAChB,CAAC,SAAS;AACR,cAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,gBAAM,YAAY,QAAQ,KAAK,SAAS,OAAO;AAC/C,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,SAAS;AAAA,cACP,GAAG,KAAK;AAAA,cACR,CAAC,KAAK,GAAG;AAAA,YACX;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,OAAO,gBAAyC,EAAE,YAAY,KAAK,IAAI,CAAC,MAAM;AAC5E,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,EAAE,2CAA2C,2BAA2B,CAAC;AACpG,YAAM,gBAAgB,yBAAyB,gBAAgB;AAAA,QAC7D,WAAW,CAAC,UAAU,gCAAgC,KAAK;AAAA,MAC7D,CAAC;AACD,YAAM,aAAsC,CAAC;AAC7C,iBAAW,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,aAAa,GAAG;AAC5D,mBAAW,MAAM,OAAO,EAAE,IAAI;AAAA,MAChC;AACA,UAAI,CAAC,OAAO,KAAK,aAAa,EAAE,QAAQ;AACtC,YAAI,UAAW,OAAM,EAAE,8BAA8B,qBAAqB,GAAG,SAAS;AACtF;AAAA,MACF;AACA,YAAM,UAAU;AAAA,QACd,IAAI,KAAK,QAAQ;AAAA,QACjB,cAAc;AAAA,MAChB;AACA,UAAI,wBAAuC;AAC3C,UAAI;AACF,cAAM,SAAS,MAAM;AAAA,UACnB,MAAM;AAAA,YACJ,0BAA2B,MAAM,SAAgD,SAAS;AAAA,YAC1F,MAAM;AAAA,cACJ;AAAA,cACA;AAAA,gBACE,QAAQ;AAAA,gBACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,gBAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,cAC9B;AAAA,cACA,EAAE,cAAc,EAAE,2CAA2C,2BAA2B,EAAE;AAAA,YAC5F;AAAA,UACF;AAAA,UACA;AAAA,QACF;AACA,gCAAwB,QAAQ,QAAQ,aAAa;AAAA,MACvD,SAAS,KAAK;AACZ,cAAM,EAAE,SAAS,eAAe,YAAY,IAAI,+BAA+B,GAAG;AAClF,cAAM,UAAU,iBAAiB,EAAE,2CAA2C,2BAA2B;AACzG,cAAM,eAAmD,cACrD,OAAO,QAAQ,WAAW,EAAE,OAA+B,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM;AAChF,gBAAM,UAAU,IAAI,WAAW,KAAK,IAAI,MAAM,MAAM,GAAG;AACvD,cAAI,OAAO,IAAI;AACf,iBAAO;AAAA,QACT,GAAG,CAAC,CAAC,IACL;AACJ,cAAMC,SAAQ,IAAI,MAAM,OAAO;AAC/B,YAAI,gBAAgB,OAAO,KAAK,YAAY,EAAE,OAAQ,CAAAA,OAAM,cAAc;AAC1E,cAAMA;AAAA,MACR;AACA,cAAQ,CAAC,SAAS;AAChB,YAAI,CAAC,KAAM,QAAO;AAClB,eAAO;AAAA,UACL,GAAG;AAAA,UACH,SAAS,wBACL,EAAE,GAAG,KAAK,SAAS,WAAW,sBAAsB,IACpD,KAAK;AAAA,UACT,cAAc;AAAA,YACZ,GAAG,KAAK;AAAA,YACR,GAAG;AAAA,UACL;AAAA,QACF;AAAA,MACF,CAAC;AACD,UAAI,UAAW,OAAM,EAAE,8BAA8B,qBAAqB,GAAG,SAAS;AAAA,IACxF;AAAA,IACA,CAAC,MAAM,wBAAwB,CAAC;AAAA,EAClC;AAEA,QAAM,4BAA4B,MAAM;AAAA,IACtC,OAAO,EAAE,QAAQ,SAAS,MAA0D;AAClF,YAAM;AAAA,QACJ,EAAE,eAAe,UAAU,KAAK;AAAA,QAChC,CAAC,SAAS;AACR,cAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,SAAS;AAAA,cACP,GAAG,KAAK;AAAA,cACR,eAAe,WAAW,OAAO,OAAO,OAAO,MAAM;AAAA,YACvD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,YAAM;AAAA,QACJ,EAAE,4BAA4B,YAAY,KAAK;AAAA,QAC/C,EAAE,WAAW,MAAM;AAAA,MACrB;AACA,YAAM,EAAE,8BAA8B,qBAAqB,GAAG,SAAS;AAAA,IACzE;AAAA,IACA,CAAC,aAAa,oBAAoB,CAAC;AAAA,EACrC;AAEA,QAAM,eAAe,MAAM,YAAY,YAAY;AACjD,QAAI,CAAC,iBAAkB;AACvB,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,EAAE,0CAA0C,QAAW,EAAE,MAAM,YAAY,CAAC;AAAA,MACnF,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW;AAChB,kBAAc,IAAI;AAClB,QAAI;AACF,YAAM;AAAA,QACJ,MAAM;AAAA,UACJ,0BAA2B,MAAM,SAAgD,SAAS;AAAA,UAC1F,MAAM;AAAA,YACJ,+BAA+B,mBAAmB,gBAAgB,CAAC;AAAA,YACnE;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAChD;AAAA,YACA,EAAE,cAAc,EAAE,wCAAwC,2BAA2B,EAAE;AAAA,UACzF;AAAA,QACF;AAAA,QACA,EAAE,IAAI,iBAAiB;AAAA,MACzB;AACA,YAAM,EAAE,0CAA0C,kBAAkB,GAAG,SAAS;AAChF,aAAO,KAAK,8BAA8B;AAAA,IAC5C,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,EAAE,wCAAwC,2BAA2B;AAC1H,YAAM,SAAS,OAAO;AAAA,IACxB,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,aAAa,SAAS,kBAAkB,QAAQ,wBAAwB,CAAC,CAAC;AAE9E,QAAM,mBAAmB,MAAM,YAAY,CAAC,aAA0B;AACpE,YAAQ,CAAC,SAAU,OAAO,EAAE,GAAG,MAAM,MAAM,SAAS,IAAI,IAAK;AAAA,EAC/D,GAAG,CAAC,CAAC;AAEL,QAAM,2BAA2B,MAAM;AAAA,IACrC,OAAO,WAAoC;AACzC,YAAM,mBAAmB,MAAM;AAAA,IACjC;AAAA,IACA,CAAC,kBAAkB;AAAA,EACrB;AAEA,QAAM,2BAA2B,MAAM,YAAY,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAE/D,QAAM,gCAAgC,MAAM,YAAY,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAEpE,QAAM,2BAA2B,MAAM,YAAY,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAE/D,QAAM,4BAA4B,MAAM,YAAY,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAEhE,QAAM,+BAA+B,MAAM,YAAY,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAEnE,QAAM,2BAA2B,MAAM,YAAY,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAE/D,QAAM,aAAa,MAAM;AAAA,IACvB,MAAO,mBAAoB,EAAE,MAAM,WAAW,UAAU,iBAAiB,IAAc;AAAA,IACvF,CAAC,gBAAgB;AAAA,EACnB;AAEA,MAAI,WAAW;AACb,WACE,oBAAC,QACC,8BAAC,YACC,+BAAC,SAAI,WAAU,kFACb;AAAA,0BAAC,WAAQ,WAAU,WAAU;AAAA,MAC7B,oBAAC,UAAM,YAAE,sCAAsC,uBAAkB,GAAE;AAAA,OACrE,GACF,GACF;AAAA,EAEJ;AAEA,MAAI,YAAY;AACd,WACE,oBAAC,QACC,8BAAC,YACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,6CAA6C,oBAAoB;AAAA,QAC1E,UAAS;AAAA,QACT,WAAW,EAAE,iDAAiD,mBAAmB;AAAA;AAAA,IACnF,GACF,GACF;AAAA,EAEJ;AAEA,MAAI,SAAS,CAAC,MAAM,SAAS,IAAI;AAC/B,WACE,oBAAC,QACC,8BAAC,YACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,SAAS,EAAE,6CAA6C,oBAAoB;AAAA,QACnF,QACE,oBAAC,UAAO,SAAO,MAAC,SAAQ,WAAU,MAAK,MACrC,8BAAC,QAAK,MAAK,gCACR,YAAE,iDAAiD,mBAAmB,GACzE,GACF;AAAA;AAAA,IAEJ,GACF,GACF;AAAA,EAEJ;AAEA,QAAM,EAAE,SAAS,QAAQ,IAAI;AAC7B,QAAM,YAAY,QAAQ;AAE1B,QAAM,wBACJ,OAAO,KAAK,cAAc,4BAA4B,WACjD,KAAK,aAAa,0BACnB;AAEN,QAAM,eAAoC;AAAA,IACxC;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,iDAAiD,cAAc;AAAA,MACxE,OAAO,QAAQ;AAAA,MACf,aAAa,EAAE,oDAAoD,oBAAoB;AAAA,MACvF,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,WAAW,WAAW;AAAA,MACtB,QAAQ;AAAA,IACV;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,+CAA+C,YAAY;AAAA,MACpE,OAAO,SAAS,aAAa;AAAA,MAC7B,aAAa,EAAE,0DAA0D,gBAAgB;AAAA,MACzF,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,CAAC,UAAU,mBAAmB,aAAa,KAAK;AAAA,IAC1D;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,+CAA+C,YAAY;AAAA,MACpE,OAAO,SAAS,aAAa;AAAA,MAC7B,aAAa,EAAE,0DAA0D,gBAAgB;AAAA,MACzF,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,CAAC,UAAU,mBAAmB,aAAa,KAAK;AAAA,IAC1D;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,iDAAiD,aAAa;AAAA,MACvE,OAAO,QAAQ,eAAe;AAAA,MAC9B,aAAa,EAAE,4DAA4D,sBAAsB;AAAA,MACjG,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,eAAe;AAAA,MACf,eAAe;AAAA,MACf,QAAQ,OAAO,SAAS;AACtB,cAAM,OAAO,OAAO,SAAS,WAAW,OAAO;AAC/C,cAAM;AAAA,UACJ,EAAE,aAAa,KAAK;AAAA,UACpB,CAAC,UAAU;AAAA,YACT,GAAG;AAAA,YACH,SAAS,EAAE,GAAG,KAAK,SAAS,aAAa,QAAQ,KAAK,SAAS,OAAO,KAAK;AAAA,UAC7E;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,oDAAoD,iBAAiB;AAAA,MAC9E,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,MACN;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,oDAAoD,iBAAiB;AAAA,UAC9E,OAAO,QAAQ,kBAAkB;AAAA,UACjC,YAAY,EAAE,sCAAsC,cAAc;AAAA,UAClE,MAAK;AAAA,UACL,QAAQ,CAAC,SAAS,mBAAmB,kBAAkB,IAAI;AAAA,UAC3D,iBAAgB;AAAA,UAChB,SAAQ;AAAA,UACR,iBAAe;AAAA;AAAA,MACjB;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,4CAA4C,QAAQ;AAAA,MAC7D,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,MACN;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,4CAA4C,QAAQ;AAAA,UAC7D,OAAO,QAAQ,UAAU;AAAA,UACzB,YAAY,EAAE,sCAAsC,cAAc;AAAA,UAClE,MAAK;AAAA,UACL,QAAQ,CAAC,SAAS,mBAAmB,UAAU,IAAI;AAAA,UACnD,iBAAgB;AAAA,UAChB,SAAQ;AAAA,UACR,iBAAe;AAAA;AAAA,MACjB;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,4CAA4C,QAAQ;AAAA,MAC7D,OAAO,SAAS,UAAU;AAAA,MAC1B,aAAa,EAAE,uDAAuD,aAAa;AAAA,MACnF,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,CAAC,UAAU,mBAAmB,UAAU,KAAK;AAAA,IACvD;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,8CAA8C,UAAU;AAAA,MACjE,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,MACN;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,8CAA8C,UAAU;AAAA,UACjE,OAAO,SAAS,YAAY;AAAA,UAC5B,YAAY,EAAE,sCAAsC,cAAc;AAAA,UAClE,MAAK;AAAA,UACL,QAAQ,CAAC,SAAS,mBAAmB,YAAY,IAAI;AAAA,UACrD,iBAAgB;AAAA,UAChB,SAAQ;AAAA,UACR,iBAAe;AAAA;AAAA,MACjB;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,gDAAgD,cAAc;AAAA,MACvE,OAAO,SAAS,cAAc;AAAA,MAC9B,aAAa,EAAE,2DAA2D,iBAAiB;AAAA,MAC3F,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,CAAC,UAAU,mBAAmB,cAAc,KAAK;AAAA,IAC3D;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,mDAAmD,gBAAgB;AAAA,MAC5E,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,QAAQ,MACN;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,mDAAmD,gBAAgB;AAAA,UAC5E,QAAQ,SAAS,iBAAiB;AAAA,UAClC,UAAU;AAAA,UACV,YAAY,EAAE,sCAAsC,cAAc;AAAA,UAClE,WAAW,WAAW;AAAA,UACtB,QAAQ;AAAA;AAAA,MACV;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,6CAA6C,SAAS;AAAA,MAC/D,OAAO,SAAS,cAAc;AAAA,MAC9B,aAAa,EAAE,wDAAwD,qBAAqB;AAAA,MAC5F,YAAY,EAAE,sCAAsC,cAAc;AAAA,MAClE,WAAW;AAAA,MACX,WAAW,WAAW;AAAA,MACtB,QAAQ,CAAC,UAAU,mBAAmB,cAAc,KAAK;AAAA,IAC3D;AAAA,EACF;AAEA,SACE,qBAAC,QACC;AAAA,wBAAC,YACC,+BAAC,SAAI,WAAU,aACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,SAAS,WAAW;AAAA,UACpB;AAAA,UACA,mBAAmB;AAAA,UACnB,gBACE;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,gBACN,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,aAAa;AAAA,kBACX,OAAO,QAAQ;AAAA,kBACf,UAAU,QAAQ,gBAAgB;AAAA,kBAClC,UAAU;AAAA,oBACR,CAAC,EAAE,oDAAoD,CAAC,GAAG,QAAQ,gBAAgB;AAAA,oBACnF,CAAC,EAAE,4CAA4C,CAAC,GAAG,SAAS,YAAY;AAAA,kBAC1E;AAAA,gBACF;AAAA,cACF;AAAA,cACA,UAAU,gCAAgC,SAAS;AAAA;AAAA,UACrD;AAAA,UAEF,oBAAoB,CAAC,UAAU,mBAAmB,gBAAgB,KAAK;AAAA,UACvE,oBAAoB,CAAC,UAAU,mBAAmB,gBAAgB,KAAK;AAAA,UACvE,cAAc,CAAC,UAAU,mBAAmB,UAAU,KAAK;AAAA,UAC3D,uBAAuB,OAAO,YAAY;AACxC,kBAAM;AAAA,cACJ;AAAA,gBACE,iBAAiB,UACb;AAAA,kBACE,IAAI,QAAQ;AAAA,kBACZ,MAAM,QAAQ,QAAQ;AAAA,kBACtB,OAAO,QAAQ,SAAS;AAAA,kBACxB,MAAM,QAAQ,QAAQ;AAAA,kBACtB,OAAO,QAAQ,SAAS;AAAA,gBAC1B,IACA;AAAA,cACN;AAAA,cACA,CAAC,UAAU;AAAA,gBACT,GAAG;AAAA,gBACH,SAAS;AAAA,kBACP,GAAG,KAAK;AAAA,kBACR,mBAAmB,SAAS,MAAM;AAAA,kBAClC,qBAAqB,SAAS,QAAQ;AAAA,kBACtC,sBAAsB,SAAS,SAAS;AAAA,kBACxC,qBAAqB,SAAS,QAAQ;AAAA,kBACtC,sBAAsB,SAAS,SAAS;AAAA,gBAC1C;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA,UAAU;AAAA,UACV;AAAA;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb;AAAA,UACA,iBAAiB;AAAA,UACjB,cAAc,EAAE,yCAAyC,yBAAyB;AAAA,UAClF,cAAa;AAAA,UAEX,iBAAM;AACN,kBAAM,WAAW,eAAe,IAAI,SAAS;AAC7C,gBAAI,SAAU,QAAO,SAAS;AAC9B,gBAAI,cAAc,SAAS;AACzB,qBACE;AAAA,gBAAC;AAAA;AAAA,kBACC,UAAU;AAAA,kBACV,YAAY,EAAE,6CAA6C,eAAe;AAAA,kBAC1E,cAAc,KAAK,QAAQ,UAAU;AAAA,kBACrC,YAAY,KAAK,QAAQ,QAAQ;AAAA,kBACjC,aAAa,KAAK,QAAQ,SAAS;AAAA,kBACnC,gBAAgB,EAAE,6CAA6C,UAAU;AAAA,kBACzE,YAAY;AAAA,oBACV,OAAO,EAAE,qDAAqD,2BAA2B;AAAA,oBACzF,aAAa,EAAE,sDAAsD,eAAe;AAAA,kBACtF;AAAA,kBACA,gBAAgB;AAAA,kBAChB,YAAY;AAAA,kBACZ,iBAAiB;AAAA,kBACjB,aAAa;AAAA,kBACb,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb,iBAAiB;AAAA,kBACjB,wBAAwB;AAAA,kBACxB,yBAAyB;AAAA;AAAA,cAC3B;AAAA,YAEJ;AACA,gBAAI,cAAc,cAAc;AAC9B,qBACE;AAAA,gBAAC;AAAA;AAAA,kBACC,UAAU;AAAA,kBACV,oBAAoB;AAAA,kBACpB,gBAAgB,EAAE,6CAA6C,cAAc;AAAA,kBAC7E,YAAY;AAAA,oBACV,OAAO,EAAE,0DAA0D,0BAA0B;AAAA,oBAC7F,aAAa,EAAE,2DAA2D,cAAc;AAAA,kBAC1F;AAAA,kBACA,gBAAgB;AAAA,kBAChB,iBAAiB;AAAA;AAAA,cACnB;AAAA,YAEJ;AACA,gBAAI,cAAc,SAAS;AACzB,qBACE;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,kBACP,YAAY,EAAE,0CAA0C,kCAAkC;AAAA,kBAC1F,gBAAgB,EAAE,8CAA8C,UAAU;AAAA,kBAC1E,YAAY;AAAA,oBACV,OAAO,EAAE,qDAAqD,cAAc;AAAA,oBAC5E,aAAa,EAAE,sDAAsD,eAAe;AAAA,kBACtF;AAAA,kBACA,gBAAgB;AAAA,kBAChB,iBAAiB;AAAA,kBACjB,YAAY;AAAA,kBACZ,oBAAoB;AAAA;AAAA,cACtB;AAAA,YAEJ;AACA,gBAAI,cAAc,UAAU;AAC1B,qBACE;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,eAAe,KAAK,UAAU,CAAC;AAAA,kBAC/B,gBAAgB,EAAE,yCAAyC,YAAY;AAAA,kBACvE,YAAY,EAAE,2CAA2C,uCAAuC;AAAA,kBAChG,YAAY;AAAA,oBACV,OAAO,EAAE,sDAAsD,wBAAwB;AAAA,oBACvF,aAAa,EAAE,uDAAuD,eAAe;AAAA,kBACvF;AAAA,kBACA,gBAAgB;AAAA,kBAChB,iBAAiB;AAAA,kBACjB,YAAY;AAAA,kBACZ,oBAAoB;AAAA,kBACpB,gBAAgB,CAAC,SAAS;AACxB,4BAAQ,CAAC,SAAU,OAAO,EAAE,GAAG,MAAM,QAAQ,KAAK,IAAI,IAAK;AAAA,kBAC7D;AAAA;AAAA,cACF;AAAA,YAEJ;AACA,gBAAI,cAAc,aAAa;AAC7B,qBACE;AAAA,gBAAC;AAAA;AAAA,kBACC,UAAU;AAAA,kBACV,YAAY,EAAE,8CAA8C,wBAAwB;AAAA,kBACpF,gBAAgB,EAAE,4CAA4C,aAAa;AAAA,kBAC3E,YAAY;AAAA,oBACV,OAAO,EAAE,yDAAyD,kBAAkB;AAAA,oBACpF,aAAa,EAAE,0DAA0D,aAAa;AAAA,kBACxF;AAAA,kBACA,gBAAgB;AAAA,kBAChB,iBAAiB;AAAA,kBACjB,YAAY;AAAA;AAAA,cACd;AAAA,YAEJ;AACA,gBAAI,cAAc,SAAS;AACzB,qBACE;AAAA,gBAAC;AAAA;AAAA,kBACC,UAAU;AAAA,kBACV,cAAc,KAAK;AAAA,kBACnB,oBAAoB;AAAA,kBACpB,YAAY,EAAE,0CAA0C,kCAAkC;AAAA,kBAC1F,gBAAgB,EAAE,wCAAwC,UAAU;AAAA,kBACpE,YAAY;AAAA,oBACV,OAAO,EAAE,qDAAqD,wBAAwB;AAAA,oBACtF,aAAa,EAAE,sDAAsD,aAAa;AAAA,kBACpF;AAAA,kBACA,gBAAgB;AAAA,kBAChB,iBAAiB;AAAA,kBACjB,YAAY;AAAA,kBACZ,YAAY;AAAA,kBACZ,kBAAiB;AAAA,kBACjB,uBAAsB;AAAA;AAAA,cACxB;AAAA,YAEJ;AACA,mBAAO;AAAA,UACT,GAAG;AAAA;AAAA,MACL;AAAA,MAEA,qBAAC,SAAI,WAAU,aACb;AAAA,6BAAC,SAAI,WAAU,aACb;AAAA,8BAAC,QAAG,WAAU,yBAAyB,YAAE,+CAA+C,iBAAiB,GAAE;AAAA,UAC3G,oBAAC,uBAAoB,QAAQ,cAAc;AAAA,UAC3C;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ,gBAAgB,MAAM,qBAAqB;AAAA,cACnD,SAAS;AAAA,cACT;AAAA,cACA,cAAc,CAAC,SAAS,QAAQ,IAAuB;AAAA;AAAA,UACzD;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,CAAC,EAAE,UAAU,iBAAiB,EAAE,UAAU,wBAAwB;AAAA,YAC7E,QAAQ,KAAK,gBAAgB,CAAC;AAAA,YAC9B,UAAU;AAAA,YACV,OAAO,EAAE,oDAAoD,eAAe;AAAA;AAAA,QAC9E;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,MAAM,KAAK;AAAA,YACX,UAAU;AAAA,YACV,cAAc;AAAA;AAAA,QAChB;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU,WAAU,QAAO;AAAA,OAC9B,GACF;AAAA,IACC;AAAA,KACH;AAEJ;",
6
6
  "names": ["params", "id", "companyId", "error"]
7
7
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { extensionPoints } from "@open-mercato/core/modules/customers/extension-points";
4
5
  import Link from "next/link";
5
6
  import { usePathname, useRouter, useSearchParams } from "next/navigation";
6
7
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
@@ -750,7 +751,7 @@ function CustomersCompaniesPage() {
750
751
  searchPlaceholder: t("customers.companies.list.searchPlaceholder"),
751
752
  entityIds: [E.customers.customer_entity, E.customers.customer_company_profile],
752
753
  onRowClick: (row) => router.push(`/backend/customers/companies-v2/${row.id}`),
753
- perspective: { tableId: "customers.companies.list" },
754
+ perspective: { tableId: extensionPoints.hosts.companiesTable.tableId },
754
755
  sortable: true,
755
756
  manualSorting: true,
756
757
  sorting,