@open-mercato/core 0.7.0 → 0.7.1-develop.7102.1.b41f7e3e51

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 (847) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/api.js +13 -1
  3. package/dist/helpers/integration/api.js.map +2 -2
  4. package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
  5. package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
  6. package/dist/modules/api_keys/api/keys/route.js +1 -1
  7. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  8. package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
  9. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  10. package/dist/modules/api_keys/di.js +9 -0
  11. package/dist/modules/api_keys/di.js.map +7 -0
  12. package/dist/modules/api_keys/services/principalService.js +31 -0
  13. package/dist/modules/api_keys/services/principalService.js.map +7 -0
  14. package/dist/modules/attachments/api/route.js +2 -2
  15. package/dist/modules/attachments/api/route.js.map +2 -2
  16. package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
  17. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  18. package/dist/modules/attachments/di.js +11 -1
  19. package/dist/modules/attachments/di.js.map +2 -2
  20. package/dist/modules/attachments/index.js.map +1 -1
  21. package/dist/modules/attachments/lib/attachment-service.js +313 -0
  22. package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
  23. package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
  24. package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
  25. package/dist/modules/attachments/lib/upload-limits.js +6 -2
  26. package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
  27. package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
  28. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  29. package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
  30. package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
  31. package/dist/modules/audit_logs/services/actionLogService.js +57 -12
  32. package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
  33. package/dist/modules/auth/acl.js +30 -5
  34. package/dist/modules/auth/acl.js.map +2 -2
  35. package/dist/modules/auth/api/feature-check.js +8 -2
  36. package/dist/modules/auth/api/feature-check.js.map +2 -2
  37. package/dist/modules/auth/api/login.js +4 -1
  38. package/dist/modules/auth/api/login.js.map +2 -2
  39. package/dist/modules/auth/api/reset/validate.js +55 -0
  40. package/dist/modules/auth/api/reset/validate.js.map +7 -0
  41. package/dist/modules/auth/api/roles/acl/route.js +28 -33
  42. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  43. package/dist/modules/auth/api/session/refresh.js +25 -1
  44. package/dist/modules/auth/api/session/refresh.js.map +2 -2
  45. package/dist/modules/auth/api/users/acl/route.js +96 -51
  46. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  47. package/dist/modules/auth/api/users/route.js +13 -5
  48. package/dist/modules/auth/api/users/route.js.map +2 -2
  49. package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
  50. package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
  51. package/dist/modules/auth/backend/roles/page.js +3 -1
  52. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  53. package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
  54. package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
  55. package/dist/modules/auth/backend/users/page.js +2 -1
  56. package/dist/modules/auth/backend/users/page.js.map +2 -2
  57. package/dist/modules/auth/commands/acl.js +254 -0
  58. package/dist/modules/auth/commands/acl.js.map +7 -0
  59. package/dist/modules/auth/components/AclEditor.js +39 -30
  60. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  61. package/dist/modules/auth/data/entities.js.map +2 -2
  62. package/dist/modules/auth/data/validators.js +5 -1
  63. package/dist/modules/auth/data/validators.js.map +2 -2
  64. package/dist/modules/auth/di.js +35 -9
  65. package/dist/modules/auth/di.js.map +2 -2
  66. package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
  67. package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
  68. package/dist/modules/auth/lib/grantChecks.js.map +2 -2
  69. package/dist/modules/auth/lib/userIdFilter.js +16 -0
  70. package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
  71. package/dist/modules/auth/services/authService.js +16 -2
  72. package/dist/modules/auth/services/authService.js.map +2 -2
  73. package/dist/modules/auth/services/principalService.js +200 -0
  74. package/dist/modules/auth/services/principalService.js.map +7 -0
  75. package/dist/modules/auth/services/rbacService.js +67 -24
  76. package/dist/modules/auth/services/rbacService.js.map +3 -3
  77. package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
  78. package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
  79. package/dist/modules/business_rules/backend/logs/page.js +3 -1
  80. package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
  81. package/dist/modules/business_rules/backend/rules/page.js +3 -1
  82. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  83. package/dist/modules/business_rules/backend/sets/page.js +3 -1
  84. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  85. package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
  86. package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
  87. package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
  88. package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
  89. package/dist/modules/catalog/ai-agents.js +1 -1
  90. package/dist/modules/catalog/ai-agents.js.map +1 -1
  91. package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
  92. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
  93. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
  94. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  95. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
  96. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  97. package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
  98. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  99. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
  100. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
  101. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
  102. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
  103. package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
  104. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  105. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
  106. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  107. package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
  108. package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
  109. package/dist/modules/communication_channels/di.js +7 -1
  110. package/dist/modules/communication_channels/di.js.map +2 -2
  111. package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
  112. package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
  113. package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
  114. package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
  115. package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
  116. package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
  117. package/dist/modules/communication_channels/lib/test-seed.js +41 -2
  118. package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
  119. package/dist/modules/configs/lib/system-status.js +9 -0
  120. package/dist/modules/configs/lib/system-status.js.map +2 -2
  121. package/dist/modules/currencies/backend/currencies/page.js +3 -1
  122. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  123. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
  124. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  125. package/dist/modules/currencies/services/rateFetchingService.js +6 -1
  126. package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
  127. package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
  128. package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
  129. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
  130. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  131. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
  132. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
  133. package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
  134. package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
  135. package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
  136. package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
  137. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
  138. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
  139. package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
  140. package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
  141. package/dist/modules/customers/ai-tools/people-pack.js +4 -1
  142. package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
  143. package/dist/modules/customers/api/activities/route.js +48 -6
  144. package/dist/modules/customers/api/activities/route.js.map +2 -2
  145. package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
  146. package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
  147. package/dist/modules/customers/api/companies/[id]/route.js +17 -94
  148. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  149. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
  150. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
  151. package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
  152. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
  153. package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
  154. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  155. package/dist/modules/customers/api/deals/[id]/route.js +8 -25
  156. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  157. package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
  158. package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
  159. package/dist/modules/customers/api/deals/aggregate/route.js +11 -4
  160. package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
  161. package/dist/modules/customers/api/deals/map/route.js +2 -1
  162. package/dist/modules/customers/api/deals/map/route.js.map +2 -2
  163. package/dist/modules/customers/api/deals/route.js +38 -1
  164. package/dist/modules/customers/api/deals/route.js.map +2 -2
  165. package/dist/modules/customers/api/entity-roles-factory.js +4 -4
  166. package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
  167. package/dist/modules/customers/api/interactions/route.js +3 -1
  168. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  169. package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
  170. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  171. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
  172. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  173. package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
  174. package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
  175. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
  176. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  177. package/dist/modules/customers/api/people/[id]/route.js +11 -10
  178. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  179. package/dist/modules/customers/api/people/check-phone/route.js +51 -9
  180. package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
  181. package/dist/modules/customers/api/todos/route.js +30 -5
  182. package/dist/modules/customers/api/todos/route.js.map +2 -2
  183. package/dist/modules/customers/backend/customers/companies/page.js +4 -2
  184. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  185. package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
  186. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  187. package/dist/modules/customers/backend/customers/deals/page.js +5 -2
  188. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  189. package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
  190. package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
  191. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
  192. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
  193. package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
  194. package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
  195. package/dist/modules/customers/backend/customers/people/page.js +4 -2
  196. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  197. package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
  198. package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
  199. package/dist/modules/customers/commands/deals.js +21 -34
  200. package/dist/modules/customers/commands/deals.js.map +2 -2
  201. package/dist/modules/customers/commands/interactions.js.map +1 -1
  202. package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
  203. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  204. package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
  205. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  206. package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
  207. package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
  208. package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
  209. package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
  210. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
  211. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
  212. package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
  213. package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
  214. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
  215. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  216. package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
  217. package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
  218. package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
  219. package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
  220. package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
  221. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  222. package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
  223. package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
  224. package/dist/modules/customers/components/calendar/types.js +1 -1
  225. package/dist/modules/customers/components/calendar/types.js.map +2 -2
  226. package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
  227. package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
  228. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
  229. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  230. package/dist/modules/customers/components/detail/DealForm.js +19 -7
  231. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  232. package/dist/modules/customers/components/detail/DealsSection.js +6 -5
  233. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  234. package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
  235. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  236. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
  237. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  238. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
  239. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  240. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
  241. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
  242. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
  243. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  244. package/dist/modules/customers/components/detail/utils.js +5 -5
  245. package/dist/modules/customers/components/detail/utils.js.map +2 -2
  246. package/dist/modules/customers/data/entities.js.map +1 -1
  247. package/dist/modules/customers/data/validators.js +32 -3
  248. package/dist/modules/customers/data/validators.js.map +2 -2
  249. package/dist/modules/customers/events.js +5 -0
  250. package/dist/modules/customers/events.js.map +2 -2
  251. package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
  252. package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
  253. package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
  254. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  255. package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
  256. package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
  257. package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
  258. package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
  259. package/dist/modules/customers/lib/closureStage.js +45 -0
  260. package/dist/modules/customers/lib/closureStage.js.map +7 -0
  261. package/dist/modules/customers/lib/dealStatus.js +30 -0
  262. package/dist/modules/customers/lib/dealStatus.js.map +2 -2
  263. package/dist/modules/customers/lib/detailReadAccess.js +12 -0
  264. package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
  265. package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
  266. package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
  267. package/dist/modules/customers/lib/personCompanies.js +100 -2
  268. package/dist/modules/customers/lib/personCompanies.js.map +2 -2
  269. package/dist/modules/customers/lib/todoCompatibility.js +12 -0
  270. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  271. package/dist/modules/dashboards/lib/widgetScope.js +6 -1
  272. package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
  273. package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
  274. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  275. package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
  276. package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
  277. package/dist/modules/data_sync/lib/sync-engine.js +72 -6
  278. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  279. package/dist/modules/data_sync/workers/sync-export.js +5 -1
  280. package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
  281. package/dist/modules/data_sync/workers/sync-import.js +5 -1
  282. package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
  283. package/dist/modules/devices/acl.js +9 -1
  284. package/dist/modules/devices/acl.js.map +2 -2
  285. package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
  286. package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
  287. package/dist/modules/devices/api/admin/devices/route.js +14 -1
  288. package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
  289. package/dist/modules/devices/api/deviceList.js +99 -12
  290. package/dist/modules/devices/api/deviceList.js.map +2 -2
  291. package/dist/modules/devices/api/deviceSerialization.js +46 -0
  292. package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
  293. package/dist/modules/devices/api/openapi.js +3 -1
  294. package/dist/modules/devices/api/openapi.js.map +2 -2
  295. package/dist/modules/devices/api/route.js +9 -1
  296. package/dist/modules/devices/api/route.js.map +2 -2
  297. package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
  298. package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
  299. package/dist/modules/devices/backend/devices/create/page.js +17 -1
  300. package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
  301. package/dist/modules/devices/backend/devices/page.js +28 -34
  302. package/dist/modules/devices/backend/devices/page.js.map +2 -2
  303. package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
  304. package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
  305. package/dist/modules/devices/backend/devices/userOptions.js +52 -0
  306. package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
  307. package/dist/modules/devices/setup.js +6 -2
  308. package/dist/modules/devices/setup.js.map +2 -2
  309. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  310. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  311. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  312. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  313. package/dist/modules/directory/di.js +9 -0
  314. package/dist/modules/directory/di.js.map +2 -2
  315. package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
  316. package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
  317. package/dist/modules/directory/services/organizationScopeService.js +56 -0
  318. package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
  319. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  320. package/dist/modules/entities/api/records.js +4 -2
  321. package/dist/modules/entities/api/records.js.map +2 -2
  322. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
  323. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  324. package/dist/modules/eudr/api/plots/route.js +5 -1
  325. package/dist/modules/eudr/api/plots/route.js.map +2 -2
  326. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
  327. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
  328. package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
  329. package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
  330. package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
  331. package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
  332. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
  333. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
  334. package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
  335. package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
  336. package/dist/modules/eudr/commands/statements.js +0 -3
  337. package/dist/modules/eudr/commands/statements.js.map +2 -2
  338. package/dist/modules/eudr/data/validators.js +4 -1
  339. package/dist/modules/eudr/data/validators.js.map +2 -2
  340. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
  341. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  342. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
  343. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  344. package/dist/modules/feature_toggles/defaults.json +0 -8
  345. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
  346. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  347. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
  348. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  349. package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
  350. package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
  351. package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
  352. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  353. package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
  354. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  355. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
  356. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  357. package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
  358. package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
  359. package/dist/modules/integrations/data/validators.js +11 -3
  360. package/dist/modules/integrations/data/validators.js.map +2 -2
  361. package/dist/modules/integrations/lib/credentials-masking.js +6 -2
  362. package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
  363. package/dist/modules/messages/api/[id]/route.js +29 -1
  364. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  365. package/dist/modules/messages/api/openapi.js +17 -2
  366. package/dist/modules/messages/api/openapi.js.map +2 -2
  367. package/dist/modules/messages/api/route.js +17 -2
  368. package/dist/modules/messages/api/route.js.map +2 -2
  369. package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
  370. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  371. package/dist/modules/messages/components/inboxFilters.js +15 -0
  372. package/dist/modules/messages/components/inboxFilters.js.map +2 -2
  373. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
  374. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
  375. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
  376. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
  377. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
  378. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
  379. package/dist/modules/messages/components/messageListLabels.js +14 -2
  380. package/dist/modules/messages/components/messageListLabels.js.map +2 -2
  381. package/dist/modules/messages/data/validators.js +18 -4
  382. package/dist/modules/messages/data/validators.js.map +2 -2
  383. package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
  384. package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
  385. package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
  386. package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
  387. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
  388. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  389. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
  390. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  391. package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
  392. package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
  393. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
  394. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  395. package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
  396. package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
  397. package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
  398. package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
  399. package/dist/modules/query_index/lib/engine.js +150 -51
  400. package/dist/modules/query_index/lib/engine.js.map +2 -2
  401. package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
  402. package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
  403. package/dist/modules/query_index/lib/search-tokens.js +79 -3
  404. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  405. package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
  406. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  407. package/dist/modules/resources/backend/resources/resources/page.js +3 -1
  408. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  409. package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
  410. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  411. package/dist/modules/sales/backend/sales/channels/page.js +3 -0
  412. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  413. package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
  414. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  415. package/dist/modules/sales/commands/documents.js +79 -1
  416. package/dist/modules/sales/commands/documents.js.map +2 -2
  417. package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
  418. package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
  419. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
  420. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  421. package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
  422. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  423. package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
  424. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  425. package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
  426. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  427. package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
  428. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  429. package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
  430. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  431. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
  432. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  433. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
  434. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
  435. package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
  436. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  437. package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
  438. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  439. package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
  440. package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
  441. package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
  442. package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
  443. package/dist/modules/sales/data/entities.js +8 -2
  444. package/dist/modules/sales/data/entities.js.map +2 -2
  445. package/dist/modules/sales/extension-points.js +1 -0
  446. package/dist/modules/sales/extension-points.js.map +2 -2
  447. package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
  448. package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
  449. package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
  450. package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
  451. package/dist/modules/sales/setup.js +2 -0
  452. package/dist/modules/sales/setup.js.map +2 -2
  453. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
  454. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
  455. package/dist/modules/sales/widgets/injection-table.js +4 -7
  456. package/dist/modules/sales/widgets/injection-table.js.map +2 -2
  457. package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
  458. package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
  459. package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
  460. package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
  461. package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
  462. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  463. package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
  464. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  465. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
  466. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  467. package/dist/modules/staff/backend/staff/teams/page.js +3 -0
  468. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  469. package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
  470. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  471. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
  472. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  473. package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
  474. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  475. package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
  476. package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
  477. package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
  478. package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
  479. package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
  480. package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
  481. package/dist/modules/warranty_claims/backend/page.js +3 -0
  482. package/dist/modules/warranty_claims/backend/page.js.map +2 -2
  483. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
  484. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
  485. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
  486. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
  487. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
  488. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
  489. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
  490. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
  491. package/dist/modules/wms/api/warehouseSearch.js +21 -0
  492. package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
  493. package/dist/modules/wms/api/warehouses/route.js +13 -9
  494. package/dist/modules/wms/api/warehouses/route.js.map +2 -2
  495. package/dist/modules/wms/api/zones/route.js +15 -2
  496. package/dist/modules/wms/api/zones/route.js.map +2 -2
  497. package/dist/modules/wms/commands/configuration.js +121 -9
  498. package/dist/modules/wms/commands/configuration.js.map +2 -2
  499. package/dist/modules/wms/commands/inventory-actions.js +3 -0
  500. package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
  501. package/dist/modules/wms/commands/shared.js +9 -1
  502. package/dist/modules/wms/commands/shared.js.map +2 -2
  503. package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
  504. package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
  505. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
  506. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
  507. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
  508. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  509. package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
  510. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  511. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
  512. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
  513. package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
  514. package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
  515. package/dist/modules/workflows/backend/definitions/page.js +3 -1
  516. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  517. package/dist/modules/workflows/backend/events/page.js +3 -1
  518. package/dist/modules/workflows/backend/events/page.js.map +2 -2
  519. package/dist/modules/workflows/backend/instances/page.js +3 -1
  520. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  521. package/dist/modules/workflows/backend/tasks/page.js +3 -1
  522. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  523. package/dist/modules/workflows/lib/activity-executor.js +4 -0
  524. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  525. package/package.json +9 -10
  526. package/src/helpers/integration/api.ts +33 -1
  527. package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
  528. package/src/modules/api_keys/api/keys/route.ts +3 -1
  529. package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
  530. package/src/modules/api_keys/di.ts +7 -0
  531. package/src/modules/api_keys/services/principalService.ts +33 -0
  532. package/src/modules/attachments/AGENTS.md +15 -0
  533. package/src/modules/attachments/api/route.ts +2 -2
  534. package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
  535. package/src/modules/attachments/di.ts +16 -0
  536. package/src/modules/attachments/i18n/de.json +5 -0
  537. package/src/modules/attachments/i18n/en.json +5 -0
  538. package/src/modules/attachments/i18n/es.json +5 -0
  539. package/src/modules/attachments/i18n/ko.json +5 -0
  540. package/src/modules/attachments/i18n/pl.json +5 -0
  541. package/src/modules/attachments/index.ts +10 -0
  542. package/src/modules/attachments/lib/attachment-service.ts +468 -0
  543. package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
  544. package/src/modules/attachments/lib/upload-limits.ts +6 -2
  545. package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
  546. package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
  547. package/src/modules/audit_logs/services/actionLogService.ts +74 -11
  548. package/src/modules/auth/acl.ts +30 -6
  549. package/src/modules/auth/api/feature-check.ts +10 -3
  550. package/src/modules/auth/api/login.ts +9 -1
  551. package/src/modules/auth/api/reset/validate.ts +57 -0
  552. package/src/modules/auth/api/roles/acl/route.ts +42 -39
  553. package/src/modules/auth/api/session/refresh.ts +32 -1
  554. package/src/modules/auth/api/users/acl/route.ts +177 -53
  555. package/src/modules/auth/api/users/route.ts +18 -5
  556. package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
  557. package/src/modules/auth/backend/roles/page.tsx +4 -2
  558. package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
  559. package/src/modules/auth/backend/users/page.tsx +3 -2
  560. package/src/modules/auth/commands/acl.ts +495 -0
  561. package/src/modules/auth/components/AclEditor.tsx +63 -33
  562. package/src/modules/auth/data/entities.ts +4 -1
  563. package/src/modules/auth/data/validators.ts +5 -0
  564. package/src/modules/auth/di.ts +46 -16
  565. package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
  566. package/src/modules/auth/i18n/de.json +389 -0
  567. package/src/modules/auth/i18n/en.json +389 -0
  568. package/src/modules/auth/i18n/es.json +389 -0
  569. package/src/modules/auth/i18n/ko.json +389 -0
  570. package/src/modules/auth/i18n/pl.json +391 -2
  571. package/src/modules/auth/lib/grantChecks.ts +6 -0
  572. package/src/modules/auth/lib/userIdFilter.ts +31 -0
  573. package/src/modules/auth/services/authService.ts +18 -2
  574. package/src/modules/auth/services/principalService.ts +266 -0
  575. package/src/modules/auth/services/rbacService.ts +110 -24
  576. package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
  577. package/src/modules/business_rules/backend/logs/page.tsx +4 -1
  578. package/src/modules/business_rules/backend/rules/page.tsx +4 -1
  579. package/src/modules/business_rules/backend/sets/page.tsx +4 -1
  580. package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
  581. package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
  582. package/src/modules/catalog/ai-agents.ts +1 -1
  583. package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
  584. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
  585. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
  586. package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
  587. package/src/modules/catalog/i18n/de.json +1 -0
  588. package/src/modules/catalog/i18n/en.json +1 -0
  589. package/src/modules/catalog/i18n/es.json +1 -0
  590. package/src/modules/catalog/i18n/ko.json +1 -0
  591. package/src/modules/catalog/i18n/pl.json +1 -0
  592. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
  593. package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
  594. package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
  595. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
  596. package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
  597. package/src/modules/communication_channels/di.ts +7 -0
  598. package/src/modules/communication_channels/lib/adapter.ts +14 -0
  599. package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
  600. package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
  601. package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
  602. package/src/modules/communication_channels/lib/test-seed.ts +64 -4
  603. package/src/modules/configs/i18n/de.json +2 -0
  604. package/src/modules/configs/i18n/en.json +2 -0
  605. package/src/modules/configs/i18n/es.json +2 -0
  606. package/src/modules/configs/i18n/ko.json +2 -0
  607. package/src/modules/configs/i18n/pl.json +2 -0
  608. package/src/modules/configs/lib/system-status.ts +9 -0
  609. package/src/modules/currencies/AGENTS.md +3 -0
  610. package/src/modules/currencies/backend/currencies/page.tsx +4 -1
  611. package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
  612. package/src/modules/currencies/services/README.md +45 -0
  613. package/src/modules/currencies/services/rateFetchingService.ts +6 -1
  614. package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
  615. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
  616. package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
  617. package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
  618. package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
  619. package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
  620. package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
  621. package/src/modules/customers/ai-tools/people-pack.ts +4 -1
  622. package/src/modules/customers/api/activities/route.ts +45 -0
  623. package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
  624. package/src/modules/customers/api/companies/[id]/route.ts +24 -107
  625. package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
  626. package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
  627. package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
  628. package/src/modules/customers/api/deals/[id]/route.ts +17 -28
  629. package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
  630. package/src/modules/customers/api/deals/aggregate/route.ts +14 -4
  631. package/src/modules/customers/api/deals/map/route.ts +1 -0
  632. package/src/modules/customers/api/deals/route.ts +50 -1
  633. package/src/modules/customers/api/entity-roles-factory.ts +8 -4
  634. package/src/modules/customers/api/interactions/route.ts +8 -2
  635. package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
  636. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
  637. package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
  638. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
  639. package/src/modules/customers/api/people/[id]/route.ts +16 -11
  640. package/src/modules/customers/api/people/check-phone/route.ts +75 -10
  641. package/src/modules/customers/api/todos/route.ts +27 -2
  642. package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
  643. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
  644. package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
  645. package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
  646. package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
  647. package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
  648. package/src/modules/customers/backend/customers/people/page.tsx +5 -2
  649. package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
  650. package/src/modules/customers/commands/deals.ts +34 -59
  651. package/src/modules/customers/commands/interactions.ts +1 -1
  652. package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
  653. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
  654. package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
  655. package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
  656. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
  657. package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
  658. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
  659. package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
  660. package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
  661. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
  662. package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
  663. package/src/modules/customers/components/calendar/types.ts +2 -2
  664. package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
  665. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
  666. package/src/modules/customers/components/detail/DealForm.tsx +22 -2
  667. package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
  668. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
  669. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
  670. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
  671. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
  672. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
  673. package/src/modules/customers/components/detail/types.ts +1 -1
  674. package/src/modules/customers/components/detail/utils.ts +15 -5
  675. package/src/modules/customers/data/entities.ts +1 -1
  676. package/src/modules/customers/data/validators.ts +50 -9
  677. package/src/modules/customers/events.ts +5 -0
  678. package/src/modules/customers/i18n/de.json +9 -1
  679. package/src/modules/customers/i18n/en.json +9 -1
  680. package/src/modules/customers/i18n/es.json +9 -1
  681. package/src/modules/customers/i18n/ko.json +9 -1
  682. package/src/modules/customers/i18n/pl.json +9 -1
  683. package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
  684. package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
  685. package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
  686. package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
  687. package/src/modules/customers/lib/closureStage.ts +76 -0
  688. package/src/modules/customers/lib/dealStatus.ts +42 -0
  689. package/src/modules/customers/lib/detailReadAccess.ts +35 -0
  690. package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
  691. package/src/modules/customers/lib/personCompanies.ts +136 -1
  692. package/src/modules/customers/lib/todoCompatibility.ts +19 -1
  693. package/src/modules/dashboards/i18n/es.json +4 -4
  694. package/src/modules/dashboards/i18n/pl.json +7 -7
  695. package/src/modules/dashboards/lib/widgetScope.ts +6 -0
  696. package/src/modules/data_sync/AGENTS.md +1 -1
  697. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
  698. package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
  699. package/src/modules/data_sync/lib/adapter.ts +36 -0
  700. package/src/modules/data_sync/lib/sync-engine.ts +113 -5
  701. package/src/modules/data_sync/workers/sync-export.ts +4 -0
  702. package/src/modules/data_sync/workers/sync-import.ts +4 -0
  703. package/src/modules/devices/AGENTS.md +20 -1
  704. package/src/modules/devices/acl.ts +9 -1
  705. package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
  706. package/src/modules/devices/api/admin/devices/route.ts +14 -1
  707. package/src/modules/devices/api/deviceList.ts +135 -11
  708. package/src/modules/devices/api/deviceSerialization.ts +50 -0
  709. package/src/modules/devices/api/openapi.ts +9 -1
  710. package/src/modules/devices/api/route.ts +9 -1
  711. package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
  712. package/src/modules/devices/backend/devices/create/page.tsx +17 -1
  713. package/src/modules/devices/backend/devices/page.tsx +44 -45
  714. package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
  715. package/src/modules/devices/backend/devices/userOptions.ts +99 -0
  716. package/src/modules/devices/i18n/de.json +3 -2
  717. package/src/modules/devices/i18n/en.json +3 -2
  718. package/src/modules/devices/i18n/es.json +3 -2
  719. package/src/modules/devices/i18n/ko.json +3 -2
  720. package/src/modules/devices/i18n/pl.json +3 -2
  721. package/src/modules/devices/setup.ts +6 -2
  722. package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
  723. package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
  724. package/src/modules/directory/di.ts +14 -2
  725. package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
  726. package/src/modules/directory/services/organizationScopeService.ts +85 -0
  727. package/src/modules/directory/utils/organizationScope.ts +4 -15
  728. package/src/modules/entities/api/records.ts +2 -0
  729. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
  730. package/src/modules/eudr/api/plots/route.ts +4 -0
  731. package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
  732. package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
  733. package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
  734. package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
  735. package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
  736. package/src/modules/eudr/commands/statements.ts +0 -3
  737. package/src/modules/eudr/data/validators.ts +16 -1
  738. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
  739. package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
  740. package/src/modules/feature_toggles/defaults.json +0 -8
  741. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
  742. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
  743. package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
  744. package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
  745. package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
  746. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
  747. package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
  748. package/src/modules/integrations/data/validators.ts +12 -2
  749. package/src/modules/integrations/i18n/de.json +1 -0
  750. package/src/modules/integrations/i18n/en.json +1 -0
  751. package/src/modules/integrations/i18n/es.json +1 -0
  752. package/src/modules/integrations/i18n/ko.json +1 -0
  753. package/src/modules/integrations/i18n/pl.json +1 -0
  754. package/src/modules/integrations/lib/credentials-masking.ts +10 -6
  755. package/src/modules/messages/api/[id]/route.ts +55 -1
  756. package/src/modules/messages/api/openapi.ts +20 -0
  757. package/src/modules/messages/api/route.ts +31 -2
  758. package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
  759. package/src/modules/messages/components/inboxFilters.ts +36 -0
  760. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
  761. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
  762. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
  763. package/src/modules/messages/components/message-detail/types.ts +3 -0
  764. package/src/modules/messages/components/messageListLabels.ts +52 -3
  765. package/src/modules/messages/data/validators.ts +43 -4
  766. package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
  767. package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
  768. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
  769. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
  770. package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
  771. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
  772. package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
  773. package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
  774. package/src/modules/query_index/lib/engine.ts +249 -61
  775. package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
  776. package/src/modules/query_index/lib/search-tokens.ts +135 -3
  777. package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
  778. package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
  779. package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
  780. package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
  781. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
  782. package/src/modules/sales/commands/documents.ts +93 -0
  783. package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
  784. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
  785. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
  786. package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
  787. package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
  788. package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
  789. package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
  790. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
  791. package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
  792. package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
  793. package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
  794. package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
  795. package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
  796. package/src/modules/sales/data/entities.ts +6 -0
  797. package/src/modules/sales/extension-points.ts +1 -0
  798. package/src/modules/sales/i18n/de.json +8 -0
  799. package/src/modules/sales/i18n/en.json +8 -0
  800. package/src/modules/sales/i18n/es.json +8 -0
  801. package/src/modules/sales/i18n/ko.json +8 -0
  802. package/src/modules/sales/i18n/pl.json +8 -0
  803. package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
  804. package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
  805. package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
  806. package/src/modules/sales/setup.ts +2 -0
  807. package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
  808. package/src/modules/sales/widgets/injection-table.ts +4 -7
  809. package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
  810. package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
  811. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
  812. package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
  813. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
  814. package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
  815. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
  816. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
  817. package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
  818. package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
  819. package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
  820. package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
  821. package/src/modules/warranty_claims/backend/page.tsx +4 -0
  822. package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
  823. package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
  824. package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
  825. package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
  826. package/src/modules/wms/api/warehouseSearch.ts +23 -0
  827. package/src/modules/wms/api/warehouses/route.ts +13 -9
  828. package/src/modules/wms/api/zones/route.ts +16 -0
  829. package/src/modules/wms/commands/configuration.ts +159 -10
  830. package/src/modules/wms/commands/inventory-actions.ts +3 -0
  831. package/src/modules/wms/commands/shared.ts +17 -0
  832. package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
  833. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
  834. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
  835. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
  836. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
  837. package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
  838. package/src/modules/wms/i18n/de.json +2 -0
  839. package/src/modules/wms/i18n/en.json +2 -0
  840. package/src/modules/wms/i18n/es.json +2 -0
  841. package/src/modules/wms/i18n/ko.json +2 -0
  842. package/src/modules/wms/i18n/pl.json +2 -0
  843. package/src/modules/workflows/backend/definitions/page.tsx +4 -1
  844. package/src/modules/workflows/backend/events/page.tsx +4 -1
  845. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  846. package/src/modules/workflows/backend/tasks/page.tsx +4 -1
  847. package/src/modules/workflows/lib/activity-executor.ts +9 -0
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { z } from 'zod'
4
5
  import { cn } from '@open-mercato/shared/lib/utils'
5
6
  import { useT } from '@open-mercato/shared/lib/i18n/context'
6
7
  import { Avatar } from '@open-mercato/ui/primitives/avatar'
@@ -11,6 +12,15 @@ import { composeAccessibleName } from '../../../lib/calendar/labels'
11
12
  import { searchPeopleOptions, type PersonOption } from './lookups'
12
13
  import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from './inputs'
13
14
 
15
+ // Mirrors the server-side guest rule in `interactionParticipantSchema`: a
16
+ // participant with no user record is addressable only by a routable email.
17
+ const guestEmailSchema = z.string().email().max(320)
18
+
19
+ function normalizeEmail(email: string | null | undefined): string | null {
20
+ const normalized = email?.trim().toLowerCase()
21
+ return normalized ? normalized : null
22
+ }
23
+
14
24
  export function PeopleField({
15
25
  mode,
16
26
  placeholder,
@@ -63,12 +73,38 @@ export function PeopleField({
63
73
  const selectedIds = new Set(value.map((participant) => participant.userId))
64
74
  const visibleOptions = options.filter((option) => !selectedIds.has(option.userId))
65
75
 
76
+ // An external guest has no record to search for, so a typed address that
77
+ // matches nothing is the only way to invite one (#5115). Multi mode only —
78
+ // the single-mode field is the task assignee, which becomes `ownerUserId` and
79
+ // must resolve to a real staff user.
80
+ const typedEmail = normalizeEmail(query)
81
+ const selectedEmails = new Set(
82
+ value.map((participant) => normalizeEmail(participant.email)).filter((email): email is string => email !== null),
83
+ )
84
+ const guestEmail =
85
+ mode === 'multi' &&
86
+ typedEmail !== null &&
87
+ guestEmailSchema.safeParse(typedEmail).success &&
88
+ !selectedEmails.has(typedEmail) &&
89
+ !options.some((option) => normalizeEmail(option.email) === typedEmail)
90
+ ? typedEmail
91
+ : null
92
+ const guestLabel = guestEmail
93
+ ? t('customers.calendar.editor.addGuest', 'Invite {email} as a guest', { email: guestEmail })
94
+ : ''
95
+
66
96
  const customerBadge = (
67
97
  <UppercaseBadge className="bg-status-info-bg text-status-info-text">
68
98
  {t('customers.calendar.editor.customerBadge', 'Customer')}
69
99
  </UppercaseBadge>
70
100
  )
71
101
 
102
+ const guestBadge = (
103
+ <UppercaseBadge className="bg-muted text-muted-foreground">
104
+ {t('customers.calendar.editor.guestBadge', 'Guest')}
105
+ </UppercaseBadge>
106
+ )
107
+
72
108
  return (
73
109
  <div
74
110
  ref={rootRef}
@@ -84,12 +120,12 @@ export function PeopleField({
84
120
  CONTROL_BORDER,
85
121
  )}
86
122
  >
87
- {value.map((participant) => (
123
+ {value.map((participant, index) => (
88
124
  <PersonChip
89
- key={participant.userId}
125
+ key={participant.userId ?? participant.email ?? index}
90
126
  name={participant.name}
91
- badge={participant.isCustomer ? customerBadge : undefined}
92
- onRemove={() => onChange(value.filter((entry) => entry.userId !== participant.userId))}
127
+ badge={participant.isCustomer ? customerBadge : participant.userId ? undefined : guestBadge}
128
+ onRemove={() => onChange(value.filter((_, entryIndex) => entryIndex !== index))}
93
129
  removeLabel={t('customers.calendar.editor.removePerson', 'Remove {name}', { name: participant.name })}
94
130
  />
95
131
  ))}
@@ -113,11 +149,31 @@ export function PeopleField({
113
149
  {t('customers.calendar.editor.searching', 'Searching…')}
114
150
  </p>
115
151
  ) : null}
116
- {!loading && visibleOptions.length === 0 ? (
152
+ {!loading && visibleOptions.length === 0 && !guestEmail ? (
117
153
  <p className="px-2 py-3 text-center text-xs text-muted-foreground">
118
154
  {t('customers.calendar.editor.noResults', 'No results')}
119
155
  </p>
120
156
  ) : null}
157
+ {!loading && guestEmail ? (
158
+ <Button
159
+ type="button"
160
+ variant="ghost"
161
+ role="option"
162
+ aria-selected={false}
163
+ aria-label={guestLabel}
164
+ title={guestLabel}
165
+ onClick={() => {
166
+ const participant: EditorParticipant = { name: guestEmail, email: guestEmail, isCustomer: false }
167
+ onChange([...value, participant])
168
+ setQuery('')
169
+ }}
170
+ className="h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground"
171
+ >
172
+ <Avatar size="xs" label={guestEmail} />
173
+ <span className="min-w-0 flex-1 truncate">{guestLabel}</span>
174
+ {guestBadge}
175
+ </Button>
176
+ ) : null}
121
177
  {!loading
122
178
  ? visibleOptions.map((option) => (
123
179
  <Button
@@ -8,6 +8,7 @@ import { computeDurationMinutes, type EditorFormState, type EditorKindConfig } f
8
8
  import { findEditorConflictItems } from '../../../lib/calendar/conflicts'
9
9
  import type { ConflictScope } from '../../../lib/calendar/preferences'
10
10
  import { mapInteractionToCalendarItem } from '../../../lib/calendar/mapItem'
11
+ import { participantActorKey } from '../../../lib/calendar/participantIdentity'
11
12
  import { expandOccurrences } from '../../../lib/calendar/recurrence'
12
13
  import { getFetchWindow } from '../../../lib/calendar/range'
13
14
  import type { CalendarItem } from '../types'
@@ -72,7 +73,12 @@ export function useConflictProbe(
72
73
  ): string | null {
73
74
  const t = useT()
74
75
  const [conflict, setConflict] = React.useState<string | null>(null)
75
- const participantsKey = form.participants.map((participant) => participant.userId).join(',')
76
+ // Keys on the canonical actor key, not the raw userId — an external guest has
77
+ // no userId, so a userId-only key never changes when guests are added or
78
+ // removed and the probe would keep reporting the previous attendee set.
79
+ const participantsKey = form.participants
80
+ .map((participant) => participantActorKey(participant) ?? '')
81
+ .join(',')
76
82
  React.useEffect(() => {
77
83
  if (!open || !form.date) {
78
84
  setConflict(null)
@@ -18,7 +18,7 @@ export type CalendarRange = { from: Date; to: Date }
18
18
 
19
19
  const calendarParticipantSchema = z
20
20
  .object({
21
- userId: z.string(),
21
+ userId: z.string().optional(),
22
22
  name: z.string().optional(),
23
23
  email: z.string().optional(),
24
24
  })
@@ -49,7 +49,7 @@ export const calendarInteractionPayloadSchema = z
49
49
 
50
50
  export type CalendarInteractionPayload = z.infer<typeof calendarInteractionPayloadSchema>
51
51
 
52
- export type CalendarParticipant = { userId: string; name?: string; email?: string }
52
+ export type CalendarParticipant = { userId?: string; name?: string; email?: string }
53
53
 
54
54
  export interface CalendarItem {
55
55
  id: string
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { EyeOff } from 'lucide-react'
5
- import { useT } from '@open-mercato/shared/lib/i18n/context'
5
+ import { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'
6
6
  import { KpiCard, type KpiTrend } from '@open-mercato/ui/backend/charts/KpiCard'
7
7
  import { Button } from '@open-mercato/ui/primitives/button'
8
8
  import { IconButton } from '@open-mercato/ui/primitives/icon-button'
@@ -67,6 +67,7 @@ type CompanyKpiBarProps = {
67
67
 
68
68
  export function CompanyKpiBar({ data }: CompanyKpiBarProps) {
69
69
  const t = useT()
70
+ const locale = useLocale()
70
71
 
71
72
  const activeDeals = React.useMemo(() => getActiveDeals(data.deals), [data.deals])
72
73
  const activeDealsValue = React.useMemo(
@@ -126,7 +127,7 @@ export function CompanyKpiBar({ data }: CompanyKpiBarProps) {
126
127
  title: t('customers.companies.dashboard.kpi.activeDeals', 'ACTIVE DEALS'),
127
128
  value: activeDealsValue,
128
129
  trend: dealTrend,
129
- formatValue: (v: number) => formatCurrency(v, dealCurrency),
130
+ formatValue: (v: number) => formatCurrency(v, dealCurrency, locale),
130
131
  comparisonLabel: `${data.kpis?.activeDealsCount ?? activeDeals.length} ${(data.kpis?.activeDealsCount ?? activeDeals.length) === 1 ? 'pipeline' : 'pipelines'}`,
131
132
  },
132
133
  {
@@ -140,7 +141,7 @@ export function CompanyKpiBar({ data }: CompanyKpiBarProps) {
140
141
  id: 'ltv',
141
142
  title: t('customers.companies.dashboard.kpi.ltv', 'CUSTOMER VALUE (LTV)'),
142
143
  value: ltvValue,
143
- formatValue: ltvValue !== null ? (v: number) => formatCurrency(v, dealCurrency) : undefined,
144
+ formatValue: ltvValue !== null ? (v: number) => formatCurrency(v, dealCurrency, locale) : undefined,
144
145
  comparisonLabel: ltvValue !== null
145
146
  ? t('customers.companies.dashboard.kpi.wonDeals', 'won deals total')
146
147
  : t('customers.companies.dashboard.kpi.noWonDeals', 'No won deals'),
@@ -158,7 +159,7 @@ export function CompanyKpiBar({ data }: CompanyKpiBarProps) {
158
159
  ? `${data.kpis?.completedDealsCount ?? data.deals.filter((d) => isWonDealStatus(d.status)).length} ${t('customers.companies.dashboard.kpi.completedDeals', 'completed deals')}`
159
160
  : t('customers.companies.dashboard.kpi.noInteractions', 'No interactions yet'),
160
161
  },
161
- ], [t, activeDealsValue, dealTrend, dealCurrency, activeDeals.length, activityTrend, ltvValue, clientTenureYears, data.deals, data.interactions.length, data.kpis])
162
+ ], [t, locale, activeDealsValue, dealTrend, dealCurrency, activeDeals.length, activityTrend, ltvValue, clientTenureYears, data.deals, data.interactions.length, data.kpis])
162
163
 
163
164
  const visibleTiles = kpiTiles.filter((tile) => !hiddenTiles.has(tile.id))
164
165
 
@@ -14,6 +14,7 @@ import {
14
14
  import { useT } from '@open-mercato/shared/lib/i18n/context'
15
15
  import { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'
16
16
  import { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'
17
+ import type { AppEventPayload } from '@open-mercato/shared/modules/widgets/injection'
17
18
  import type { SectionAction, TabEmptyStateConfig, Translator } from './types'
18
19
  import { CreatePersonDialog } from './CreatePersonDialog'
19
20
  import { PersonCard } from './PersonCard'
@@ -322,13 +323,19 @@ export function CompanyPeopleSection({
322
323
  void loadVisiblePeople()
323
324
  }, [loadVisiblePeople])
324
325
 
325
- useAppEvent('customers.person_company_link.deleted', (event) => {
326
+ const reloadOnCompanyDetach = React.useCallback((event: AppEventPayload) => {
326
327
  const payload = event.payload as { companyEntityId?: string | null } | null | undefined
327
328
  if (payload && payload.companyEntityId === companyId) {
328
329
  void loadVisiblePeople()
329
330
  }
330
331
  }, [companyId, loadVisiblePeople])
331
332
 
333
+ useAppEvent('customers.person_company_link.deleted', reloadOnCompanyDetach, [reloadOnCompanyDetach])
334
+ // Legacy profile-only assignments have no link row, so their detach broadcasts this sibling
335
+ // event instead of `customers.person_company_link.deleted` (#5114). Without it, other viewers
336
+ // of the same company keep listing a person who is already gone.
337
+ useAppEvent('customers.person.company_assignment.detached', reloadOnCompanyDetach, [reloadOnCompanyDetach])
338
+
332
339
  React.useEffect(() => {
333
340
  setListPage(1)
334
341
  }, [searchQuery, sortMode])
@@ -102,6 +102,12 @@ type EntityMultiSelectProps = {
102
102
  fetchByIds: (ids: string[]) => Promise<EntityOption[]>
103
103
  disabled?: boolean
104
104
  autoFocus?: boolean
105
+ /**
106
+ * Minimum trimmed query length before a lookup request is issued. Defaults to
107
+ * `1`, so a blank input never queries the address book (issue #5118). Set `0`
108
+ * to opt back into prefetching an unfiltered first page on mount.
109
+ */
110
+ minQueryLength?: number
105
111
  }
106
112
 
107
113
  const DEAL_ENTITY_IDS = [E.customers.customer_deal]
@@ -353,6 +359,7 @@ function EntityMultiSelect({
353
359
  fetchByIds,
354
360
  disabled = false,
355
361
  autoFocus = false,
362
+ minQueryLength = 1,
356
363
  }: EntityMultiSelectProps) {
357
364
  const [input, setInput] = React.useState('')
358
365
  const [suggestions, setSuggestions] = React.useState<EntityOption[]>([])
@@ -401,11 +408,18 @@ function EntityMultiSelect({
401
408
  setLoading(false)
402
409
  return
403
410
  }
411
+ const term = input.trim()
412
+ if (term.length < minQueryLength) {
413
+ setSuggestions([])
414
+ setLoading(false)
415
+ setError(null)
416
+ return
417
+ }
404
418
  let cancelled = false
405
419
  const handler = window.setTimeout(async () => {
406
420
  setLoading(true)
407
421
  try {
408
- const results = await search(input.trim())
422
+ const results = await search(term)
409
423
  if (cancelled) return
410
424
  setSuggestions(results)
411
425
  setCache((prev) => {
@@ -429,7 +443,7 @@ function EntityMultiSelect({
429
443
  cancelled = true
430
444
  window.clearTimeout(handler)
431
445
  }
432
- }, [disabled, errorLabel, input, search])
446
+ }, [disabled, errorLabel, input, minQueryLength, search])
433
447
 
434
448
  const filteredSuggestions = React.useMemo(
435
449
  () => suggestions.filter((option) => !normalizedValue.includes(option.id)),
@@ -660,12 +674,14 @@ export function DealPeopleSelector({
660
674
  options = [],
661
675
  disabled = false,
662
676
  autoFocus = false,
677
+ minQueryLength,
663
678
  }: {
664
679
  value: string[]
665
680
  onChange: (next: string[]) => void
666
681
  options?: EntityOption[]
667
682
  disabled?: boolean
668
683
  autoFocus?: boolean
684
+ minQueryLength?: number
669
685
  }) {
670
686
  const t = useT()
671
687
  const { searchPeople, fetchPeopleByIds } = useDealAssociationLookups()
@@ -685,6 +701,7 @@ export function DealPeopleSelector({
685
701
  fetchByIds={fetchPeopleByIds}
686
702
  disabled={disabled}
687
703
  autoFocus={autoFocus}
704
+ minQueryLength={minQueryLength}
688
705
  />
689
706
  )
690
707
  }
@@ -694,11 +711,13 @@ export function DealCompaniesSelector({
694
711
  onChange,
695
712
  options = [],
696
713
  disabled = false,
714
+ minQueryLength,
697
715
  }: {
698
716
  value: string[]
699
717
  onChange: (next: string[]) => void
700
718
  options?: EntityOption[]
701
719
  disabled?: boolean
720
+ minQueryLength?: number
702
721
  }) {
703
722
  const t = useT()
704
723
  const { searchCompanies, fetchCompaniesByIds } = useDealAssociationLookups()
@@ -717,6 +736,7 @@ export function DealCompaniesSelector({
717
736
  search={searchCompanies}
718
737
  fetchByIds={fetchCompaniesByIds}
719
738
  disabled={disabled}
739
+ minQueryLength={minQueryLength}
720
740
  />
721
741
  )
722
742
  }
@@ -12,7 +12,7 @@ import { LinkEntityDialog } from '../linking/LinkEntityDialog'
12
12
  import { createDealLinkAdapter } from '../linking/adapters/dealAdapter'
13
13
  import { LoadingMessage, TabEmptyState } from '@open-mercato/ui/backend/detail'
14
14
  import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
15
- import { useT } from '@open-mercato/shared/lib/i18n/context'
15
+ import { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'
16
16
  import { hasMoreFromPage } from '@open-mercato/shared/lib/pagination/load-more'
17
17
  import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
18
18
  import { E } from '#generated/entities.ids.generated'
@@ -275,9 +275,14 @@ function normalizeDeal(deal: Partial<DealSummary> & { id: string; title?: string
275
275
  }
276
276
  }
277
277
 
278
- function formatValueLabel(amount: number | null, currency: string | null, emptyLabel: string): string {
278
+ function formatValueLabel(
279
+ amount: number | null,
280
+ currency: string | null,
281
+ emptyLabel: string,
282
+ locale?: string,
283
+ ): string {
279
284
  if (typeof amount === 'number') {
280
- const formatter = new Intl.NumberFormat(undefined, {
285
+ const formatter = new Intl.NumberFormat(locale, {
281
286
  style: currency ? 'currency' : 'decimal',
282
287
  currency: currency ?? undefined,
283
288
  maximumFractionDigits: 2,
@@ -317,6 +322,7 @@ export function DealsSection({
317
322
  runGuardedMutation,
318
323
  }: DealsSectionProps) {
319
324
  const tHook = useT()
325
+ const locale = useLocale()
320
326
  const { confirm, ConfirmDialogElement } = useConfirmDialog()
321
327
  const fallbackTranslator = React.useMemo<Translator>(() => createTranslatorWithFallback(tHook), [tHook])
322
328
  const t: Translator = React.useMemo(() => translator ?? fallbackTranslator, [translator, fallbackTranslator])
@@ -963,8 +969,8 @@ export function DealsSection({
963
969
  ) : null}
964
970
  <div className="space-y-4">
965
971
  {sortedDeals.map((deal) => {
966
- const valueLabel = formatValueLabel(deal.valueAmount, deal.valueCurrency ?? null, emptyLabel)
967
- const expectedLabel = deal.expectedCloseAt ? formatDate(deal.expectedCloseAt) ?? emptyLabel : emptyLabel
972
+ const valueLabel = formatValueLabel(deal.valueAmount, deal.valueCurrency ?? null, emptyLabel, locale)
973
+ const expectedLabel = deal.expectedCloseAt ? formatDate(deal.expectedCloseAt, locale) ?? emptyLabel : emptyLabel
968
974
  const probabilityLabel =
969
975
  typeof deal.probability === 'number' ? `${deal.probability}%` : emptyLabel
970
976
  const isUnlinkPending = pendingAction?.kind === 'remove' && pendingAction.id === deal.id
@@ -6,6 +6,7 @@ import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
6
6
  import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
7
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
8
8
  import { cn, slugifyTagLabel } from '@open-mercato/shared/lib/utils'
9
+ import { hasMoreFromPage } from '@open-mercato/shared/lib/pagination/load-more'
9
10
  import { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
10
11
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
11
12
  import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
@@ -388,8 +389,19 @@ export function EntityTagsDialog({
388
389
  const [creatingKind, setCreatingKind] = React.useState<string | null>(null)
389
390
  const [manageTagsOpen, setManageTagsOpen] = React.useState(false)
390
391
  const [activeCategoryPage, setActiveCategoryPage] = React.useState(1)
391
- const [activeCategoryTotalPages, setActiveCategoryTotalPages] = React.useState(1)
392
+ // Short-page termination instead of `page < totalPages` — see
393
+ // `hasMoreFromPage`. Like the page number it belongs to whichever category is
394
+ // active: the fetch effect below rewrites it on every category, search and
395
+ // page change, and the reset effect clears it alongside the page so a
396
+ // category with more entries never leaves the affordance behind on one
397
+ // without.
398
+ const [activeCategoryHasMore, setActiveCategoryHasMore] = React.useState(false)
392
399
  const [activeCategoryLoading, setActiveCategoryLoading] = React.useState(false)
400
+ // A transport failure is not an end-of-list signal: it leaves the affordance
401
+ // in place and turns the next click into a retry of the page that failed,
402
+ // rather than advancing past it.
403
+ const [activeCategoryLoadFailed, setActiveCategoryLoadFailed] = React.useState(false)
404
+ const [activeCategoryReloadToken, setActiveCategoryReloadToken] = React.useState(0)
393
405
  const creationInFlightRef = React.useRef<string | null>(null)
394
406
  const mutationContextId = React.useMemo(
395
407
  () => `customer-tags:${entityType}:${entityId}`,
@@ -713,12 +725,15 @@ export function EntityTagsDialog({
713
725
  React.useEffect(() => {
714
726
  if (!open) return
715
727
  setActiveCategoryPage(1)
728
+ setActiveCategoryHasMore(false)
729
+ setActiveCategoryLoadFailed(false)
716
730
  }, [activeCategoryKind, open, searchValue])
717
731
 
718
732
  React.useEffect(() => {
719
733
  if (!open || !activeCategoryKindValue || (activeCategorySource !== 'tags' && activeCategorySource !== 'labels')) {
720
734
  setActiveCategoryLoading(false)
721
- setActiveCategoryTotalPages(1)
735
+ setActiveCategoryHasMore(false)
736
+ setActiveCategoryLoadFailed(false)
722
737
  return
723
738
  }
724
739
 
@@ -752,16 +767,36 @@ export function EntityTagsDialog({
752
767
  }))
753
768
 
754
769
  setActiveCategoryLoading(true)
755
- void apiCall<{ items?: Array<DictEntry | LabelItem>; totalPages?: number }>(endpoint, {
770
+ void apiCall<{ items?: Array<DictEntry | LabelItem>; page?: number }>(endpoint, {
756
771
  cache: 'no-store',
757
772
  headers: { 'x-om-unauthorized-redirect': '0' },
758
773
  })
759
774
  .then((response) => {
760
- if (!response.ok || cancelled) return
761
- const fetchedEntries = mapEntries(Array.isArray(response.result?.items) ? response.result.items : [])
762
- setActiveCategoryTotalPages(
763
- typeof response.result?.totalPages === 'number' ? response.result.totalPages : 1,
775
+ if (cancelled) return
776
+ if (!response.ok) {
777
+ setActiveCategoryLoadFailed(true)
778
+ return
779
+ }
780
+ setActiveCategoryLoadFailed(false)
781
+ const servedEntries = Array.isArray(response.result?.items) ? response.result.items : []
782
+ const fetchedEntries = mapEntries(servedEntries)
783
+ // The two sources paginate differently. `/api/customers/tags` is a
784
+ // query-engine list, so a page past the end comes back empty and the
785
+ // served count alone terminates the sequence. `/api/customers/labels`
786
+ // clamps the requested page to the last one and re-serves it in full
787
+ // forever, so short-page termination needs the second half of the
788
+ // helper's obligation 2: take an echoed page below the one asked for as
789
+ // the end of the list. Same guard as `AttachmentsSection`, whose
790
+ // endpoint clamps the same way.
791
+ const returnedPage =
792
+ typeof response.result?.page === 'number' ? response.result.page : activeCategoryPage
793
+ const servedRequestedPage = returnedPage >= activeCategoryPage
794
+ // Measured on what the endpoint served, before `mergeOptions` folds the
795
+ // page into the entries already on screen.
796
+ setActiveCategoryHasMore(
797
+ servedRequestedPage && hasMoreFromPage(servedEntries.length, REMOTE_CATEGORY_PAGE_SIZE),
764
798
  )
799
+ if (!servedRequestedPage) return
765
800
  updateCategoryEntries(activeCategoryKindValue, (currentEntries) =>
766
801
  activeCategoryPage <= 1
767
802
  ? mergeOptions(seedEntries, fetchedEntries)
@@ -770,8 +805,10 @@ export function EntityTagsDialog({
770
805
  })
771
806
  .catch(() => {
772
807
  if (cancelled) return
773
- setActiveCategoryTotalPages(1)
774
- updateCategoryEntries(activeCategoryKindValue, () => seedEntries)
808
+ setActiveCategoryLoadFailed(true)
809
+ if (activeCategoryPage <= 1) {
810
+ updateCategoryEntries(activeCategoryKindValue, () => seedEntries)
811
+ }
775
812
  })
776
813
  .finally(() => {
777
814
  if (!cancelled) {
@@ -785,6 +822,7 @@ export function EntityTagsDialog({
785
822
  }, [
786
823
  activeCategoryKindValue,
787
824
  activeCategoryPage,
825
+ activeCategoryReloadToken,
788
826
  activeCategorySource,
789
827
  entityId,
790
828
  entityOrganizationId,
@@ -1250,15 +1288,23 @@ export function EntityTagsDialog({
1250
1288
  {t('customers.personTags.loading', 'Loading...')}
1251
1289
  </div>
1252
1290
  ) : null}
1253
- {(activeCategory.source === 'tags' || activeCategory.source === 'labels') && activeCategoryPage < activeCategoryTotalPages ? (
1291
+ {(activeCategory.source === 'tags' || activeCategory.source === 'labels') && activeCategoryHasMore ? (
1254
1292
  <Button
1255
1293
  type="button"
1256
1294
  variant="outline"
1257
1295
  size="sm"
1258
1296
  className="rounded-lg px-3 text-xs"
1259
- onClick={() => setActiveCategoryPage((current) => current + 1)}
1297
+ onClick={() => {
1298
+ if (activeCategoryLoadFailed) {
1299
+ setActiveCategoryReloadToken((current) => current + 1)
1300
+ return
1301
+ }
1302
+ setActiveCategoryPage((current) => current + 1)
1303
+ }}
1260
1304
  >
1261
- {t('customers.activities.loadMore', 'Load more')}
1305
+ {activeCategoryLoadFailed
1306
+ ? t('customers.personTags.retry', 'Retry')
1307
+ : t('customers.activities.loadMore', 'Load more')}
1262
1308
  </Button>
1263
1309
  ) : null}
1264
1310
  </div>
@@ -10,6 +10,7 @@ import { Button } from '@open-mercato/ui/primitives/button'
10
10
  import { Input } from '@open-mercato/ui/primitives/input'
11
11
  import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
12
12
  import { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'
13
+ import type { AppEventPayload } from '@open-mercato/shared/modules/widgets/injection'
13
14
  import { CompanyCard, type EnrichedCompanyData } from './CompanyCard'
14
15
  import { useCustomerDictionary } from './hooks/useCustomerDictionary'
15
16
  import { LinkEntityDialog, type LinkEntityOption } from '../linking/LinkEntityDialog'
@@ -369,13 +370,19 @@ export function PersonCompaniesSection({
369
370
  [_personName, confirm, loadData, onChanged, personId, runWriteMutation, t, unlinkingId],
370
371
  )
371
372
 
372
- useAppEvent('customers.person_company_link.deleted', (event) => {
373
+ const reloadOnPersonDetach = React.useCallback((event: AppEventPayload) => {
373
374
  const payload = event.payload as { personEntityId?: string | null } | null | undefined
374
375
  if (payload && payload.personEntityId === personId) {
375
376
  void loadData({ showLoading: false })
376
377
  }
377
378
  }, [personId, loadData])
378
379
 
380
+ useAppEvent('customers.person_company_link.deleted', reloadOnPersonDetach, [reloadOnPersonDetach])
381
+ // Legacy profile-only assignments have no link row, so their detach broadcasts this sibling
382
+ // event instead of `customers.person_company_link.deleted` (#5114). Without it, other viewers
383
+ // of the same person keep listing a company that is already detached.
384
+ useAppEvent('customers.person.company_assignment.detached', reloadOnPersonDetach, [reloadOnPersonDetach])
385
+
379
386
  return (
380
387
  <>
381
388
  <div className="space-y-4">
@@ -7,6 +7,7 @@ import { resolveTodoApiPath } from '../utils'
7
7
  import type { TodoLinkSummary } from '../types'
8
8
  import { generateTempId } from '@open-mercato/core/modules/customers/lib/detailHelpers'
9
9
  import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
10
+ import { hasMoreFromPage } from '@open-mercato/shared/lib/pagination/load-more'
10
11
  import { CUSTOMER_INTERACTION_TASK_SOURCE } from '../../../lib/interactionCompatibility'
11
12
 
12
13
  const DEFAULT_TODO_SOURCE = CUSTOMER_INTERACTION_TASK_SOURCE
@@ -29,12 +30,15 @@ type CustomerTodoRow = {
29
30
  createdAt: string
30
31
  }
31
32
 
33
+ // `/api/customers/todos` also reports `totalPages`, deliberately left out of
34
+ // this type: the load-more affordance terminates on a short page instead — see
35
+ // `hasMoreFromPage`. `total` stays because it feeds the section's count badge,
36
+ // where an under-report is cosmetic rather than a way to strand rows.
32
37
  type CustomerTodosResponse = {
33
38
  items: CustomerTodoRow[]
34
39
  total: number
35
40
  page: number
36
41
  pageSize: number
37
- totalPages: number
38
42
  }
39
43
 
40
44
  export type TaskFormPayload = {
@@ -172,9 +176,9 @@ export function usePersonTasks({
172
176
  pageSize = 20,
173
177
  }: UsePersonTasksOptions): UsePersonTasksResult {
174
178
  const [tasks, setTasks] = React.useState<TodoLinkSummary[]>(initialTasks)
175
- const [pageInfo, setPageInfo] = React.useState<{ page: number; totalPages: number; total: number }>({
179
+ const [pageInfo, setPageInfo] = React.useState<{ page: number; hasMore: boolean; total: number }>({
176
180
  page: 1,
177
- totalPages: 1,
181
+ hasMore: false,
178
182
  total: initialTasks.length,
179
183
  })
180
184
  const [isInitialLoading, setIsInitialLoading] = React.useState<boolean>(() => Boolean(entityId))
@@ -187,12 +191,18 @@ export function usePersonTasks({
187
191
  const mapped = Array.isArray(payload.items) ? payload.items.map(mapRowToSummary) : []
188
192
  setPageInfo({
189
193
  page: payload.page ?? 1,
190
- totalPages: payload.totalPages ?? 0,
194
+ // Short-page termination instead of `page < totalPages` see
195
+ // `hasMoreFromPage`. `mapRowToSummary` is a 1:1 map and the `mergeUnique`
196
+ // dedupe happens after this, so `mapped.length` is what the server served.
197
+ // Measured against the page size the server echoed rather than the one
198
+ // requested, so a page size the endpoint narrows server-side cannot make a
199
+ // full page read as short and silently end the sequence.
200
+ hasMore: hasMoreFromPage(mapped.length, payload.pageSize ?? pageSize),
191
201
  total: payload.total ?? mapped.length,
192
202
  })
193
203
  setError(null)
194
204
  return mapped
195
- }, [])
205
+ }, [pageSize])
196
206
 
197
207
  const fetchPage = React.useCallback(
198
208
  async (page: number): Promise<CustomerTodosResponse> => {
@@ -202,7 +212,6 @@ export function usePersonTasks({
202
212
  total: 0,
203
213
  page: 1,
204
214
  pageSize,
205
- totalPages: 1,
206
215
  }
207
216
  }
208
217
  const params = new URLSearchParams({
@@ -222,7 +231,7 @@ export function usePersonTasks({
222
231
  const refresh = React.useCallback(async () => {
223
232
  if (!entityId) {
224
233
  setTasks([])
225
- setPageInfo({ page: 1, totalPages: 1, total: 0 })
234
+ setPageInfo({ page: 1, hasMore: false, total: 0 })
226
235
  return
227
236
  }
228
237
  setIsInitialLoading(true)
@@ -242,7 +251,7 @@ export function usePersonTasks({
242
251
  const loadMore = React.useCallback(async () => {
243
252
  if (!entityId) return
244
253
  if (isLoadingMore) return
245
- if (pageInfo.page >= pageInfo.totalPages) return
254
+ if (!pageInfo.hasMore) return
246
255
  setIsLoadingMore(true)
247
256
  try {
248
257
  const payload = await fetchPage(pageInfo.page + 1)
@@ -255,12 +264,12 @@ export function usePersonTasks({
255
264
  } finally {
256
265
  setIsLoadingMore(false)
257
266
  }
258
- }, [entityId, fetchPage, isLoadingMore, mapResponse, pageInfo.page, pageInfo.totalPages])
267
+ }, [entityId, fetchPage, isLoadingMore, mapResponse, pageInfo.hasMore, pageInfo.page])
259
268
 
260
269
  React.useEffect(() => {
261
270
  if (!entityId) {
262
271
  setTasks([])
263
- setPageInfo({ page: 1, totalPages: 1, total: 0 })
272
+ setPageInfo({ page: 1, hasMore: false, total: 0 })
264
273
  setError(null)
265
274
  setIsInitialLoading(false)
266
275
  return
@@ -268,7 +277,7 @@ export function usePersonTasks({
268
277
  setTasks(initialTasks)
269
278
  setPageInfo({
270
279
  page: 1,
271
- totalPages: 1,
280
+ hasMore: false,
272
281
  total: initialTasks.length,
273
282
  })
274
283
  setError(null)
@@ -342,7 +351,7 @@ export function usePersonTasks({
342
351
  setTasks((prev) => [newTask, ...prev])
343
352
  setPageInfo((prev) => ({
344
353
  page: 1,
345
- totalPages: prev.totalPages,
354
+ hasMore: prev.hasMore,
346
355
  total: prev.total + 1,
347
356
  }))
348
357
  await refresh()
@@ -466,7 +475,7 @@ export function usePersonTasks({
466
475
  setTasks((prev) => prev.filter((item) => item.id !== task.id))
467
476
  setPageInfo((prev) => ({
468
477
  page: prev.page,
469
- totalPages: prev.totalPages,
478
+ hasMore: prev.hasMore,
470
479
  total: Math.max(0, prev.total - 1),
471
480
  }))
472
481
  } finally {
@@ -476,7 +485,7 @@ export function usePersonTasks({
476
485
  [],
477
486
  )
478
487
 
479
- const hasMore = entityId != null && pageInfo.page < pageInfo.totalPages
488
+ const hasMore = entityId != null && pageInfo.hasMore
480
489
 
481
490
  return {
482
491
  tasks,