@open-mercato/core 0.6.7-develop.6795.1.8a3f27921c → 0.6.7-develop.6824.1.21fff90682

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 (228) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/customer_deal_person_link/index.js +2 -0
  3. package/dist/generated/entities/customer_deal_person_link/index.js.map +2 -2
  4. package/dist/generated/entities/customer_user_invitation/index.js +2 -0
  5. package/dist/generated/entities/customer_user_invitation/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +2 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/auth/lib/backendChrome.js +10 -9
  9. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  10. package/dist/modules/auth/lib/tenantAccess.js +7 -0
  11. package/dist/modules/auth/lib/tenantAccess.js.map +2 -2
  12. package/dist/modules/business_rules/api/openmercato-call-options/route.js +85 -0
  13. package/dist/modules/business_rules/api/openmercato-call-options/route.js.map +7 -0
  14. package/dist/modules/business_rules/api/rules/route.js +71 -4
  15. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  16. package/dist/modules/business_rules/components/ActionBuilder.js +47 -4
  17. package/dist/modules/business_rules/components/ActionBuilder.js.map +3 -3
  18. package/dist/modules/business_rules/components/ActionRow.js +106 -16
  19. package/dist/modules/business_rules/components/ActionRow.js.map +2 -2
  20. package/dist/modules/business_rules/components/utils/actionValidation.js +6 -0
  21. package/dist/modules/business_rules/components/utils/actionValidation.js.map +2 -2
  22. package/dist/modules/business_rules/lib/action-executor.js +148 -0
  23. package/dist/modules/business_rules/lib/action-executor.js.map +2 -2
  24. package/dist/modules/business_rules/lib/openmercato-call-options-types.js +5 -0
  25. package/dist/modules/business_rules/lib/openmercato-call-options-types.js.map +7 -0
  26. package/dist/modules/business_rules/lib/openmercato-call-options.js +231 -0
  27. package/dist/modules/business_rules/lib/openmercato-call-options.js.map +7 -0
  28. package/dist/modules/business_rules/lib/rule-engine.js +5 -1
  29. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  30. package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js +11 -1
  31. package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js.map +2 -2
  32. package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js +11 -6
  33. package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js.map +2 -2
  34. package/dist/modules/configs/lib/upgrade-actions.js +12 -0
  35. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  36. package/dist/modules/customer_accounts/api/admin/users/[id].js +10 -1
  37. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  38. package/dist/modules/customer_accounts/api/admin/users-invite.js +61 -4
  39. package/dist/modules/customer_accounts/api/admin/users-invite.js.map +2 -2
  40. package/dist/modules/customer_accounts/api/portal/users-invite.js +20 -2
  41. package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
  42. package/dist/modules/customer_accounts/data/entities.js +3 -0
  43. package/dist/modules/customer_accounts/data/entities.js.map +2 -2
  44. package/dist/modules/customer_accounts/data/validators.js +1 -0
  45. package/dist/modules/customer_accounts/data/validators.js.map +2 -2
  46. package/dist/modules/customer_accounts/emails/CustomerInvitationEmail.js +26 -0
  47. package/dist/modules/customer_accounts/emails/CustomerInvitationEmail.js.map +7 -0
  48. package/dist/modules/customer_accounts/lib/customerEntityOwnership.js +29 -3
  49. package/dist/modules/customer_accounts/lib/customerEntityOwnership.js.map +2 -2
  50. package/dist/modules/customer_accounts/lib/customerUrl.js +19 -10
  51. package/dist/modules/customer_accounts/lib/customerUrl.js.map +2 -2
  52. package/dist/modules/customer_accounts/lib/invitationEmail.js +35 -0
  53. package/dist/modules/customer_accounts/lib/invitationEmail.js.map +7 -0
  54. package/dist/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.js +13 -0
  55. package/dist/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.js.map +7 -0
  56. package/dist/modules/customer_accounts/services/customerInvitationService.js +32 -2
  57. package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
  58. package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js +47 -7
  59. package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js.map +2 -2
  60. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -2
  61. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  62. package/dist/modules/customer_accounts/widgets/injection-table.js +1 -1
  63. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  64. package/dist/modules/customers/api/deals/[id]/people/route.js +4 -2
  65. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  66. package/dist/modules/customers/api/deals/[id]/route.js +7 -3
  67. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  68. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +11 -1
  69. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  70. package/dist/modules/customers/backend/customers/deals/[id]/page.js +14 -8
  71. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  72. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +21 -6
  73. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  74. package/dist/modules/customers/commands/deals.js +48 -10
  75. package/dist/modules/customers/commands/deals.js.map +2 -2
  76. package/dist/modules/customers/commands/people.js +2 -0
  77. package/dist/modules/customers/commands/people.js.map +2 -2
  78. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +26 -6
  79. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
  80. package/dist/modules/customers/components/detail/DealDetailTabs.js +30 -8
  81. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
  82. package/dist/modules/customers/components/detail/PersonDetailTabs.js +30 -8
  83. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  84. package/dist/modules/customers/data/entities.js +8 -0
  85. package/dist/modules/customers/data/entities.js.map +2 -2
  86. package/dist/modules/customers/data/validators.js +2 -1
  87. package/dist/modules/customers/data/validators.js.map +2 -2
  88. package/dist/modules/customers/migrations/Migration20260723210000_customers.js +15 -0
  89. package/dist/modules/customers/migrations/Migration20260723210000_customers.js.map +7 -0
  90. package/dist/modules/directory/api/tenants/route.js +8 -2
  91. package/dist/modules/directory/api/tenants/route.js.map +2 -2
  92. package/dist/modules/directory/commands/tenants.js +6 -0
  93. package/dist/modules/directory/commands/tenants.js.map +2 -2
  94. package/dist/modules/entities/api/entity-settings.js +59 -9
  95. package/dist/modules/entities/api/entity-settings.js.map +2 -2
  96. package/dist/modules/entities/backend/config/settings/page.js +10 -0
  97. package/dist/modules/entities/backend/config/settings/page.js.map +7 -0
  98. package/dist/modules/entities/backend/config/settings/page.meta.js +36 -0
  99. package/dist/modules/entities/backend/config/settings/page.meta.js.map +7 -0
  100. package/dist/modules/entities/backend/entities/user/create/page.js +16 -7
  101. package/dist/modules/entities/backend/entities/user/create/page.js.map +2 -2
  102. package/dist/modules/entities/components/EntitySettingsManager.js +136 -0
  103. package/dist/modules/entities/components/EntitySettingsManager.js.map +7 -0
  104. package/dist/modules/inbox_ops/api/webhook/inbound.js +14 -10
  105. package/dist/modules/inbox_ops/api/webhook/inbound.js.map +2 -2
  106. package/dist/modules/payment_gateways/api/sessions/route.js +1 -3
  107. package/dist/modules/payment_gateways/api/sessions/route.js.map +2 -2
  108. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +11 -1
  109. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  110. package/dist/modules/payment_gateways/data/entities.js +4 -0
  111. package/dist/modules/payment_gateways/data/entities.js.map +2 -2
  112. package/dist/modules/payment_gateways/lib/gateway-service.js +15 -6
  113. package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
  114. package/dist/modules/payment_gateways/lib/session-idempotency.js +33 -0
  115. package/dist/modules/payment_gateways/lib/session-idempotency.js.map +2 -2
  116. package/dist/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.js +18 -0
  117. package/dist/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.js.map +7 -0
  118. package/dist/modules/payment_gateways/setup.js +47 -0
  119. package/dist/modules/payment_gateways/setup.js.map +2 -2
  120. package/dist/modules/payment_gateways/workers/session-initialization-prune.js +50 -0
  121. package/dist/modules/payment_gateways/workers/session-initialization-prune.js.map +7 -0
  122. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js +134 -0
  123. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js.map +7 -0
  124. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.js +11 -0
  125. package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.js.map +7 -0
  126. package/dist/modules/portal/lib/navigation.js +7 -0
  127. package/dist/modules/portal/lib/navigation.js.map +7 -0
  128. package/dist/modules/query_index/lib/engine.js +43 -0
  129. package/dist/modules/query_index/lib/engine.js.map +2 -2
  130. package/dist/modules/query_index/lib/search-tokens.js +15 -5
  131. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  132. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +11 -1
  133. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +2 -2
  134. package/generated/entities/customer_deal_person_link/index.ts +1 -0
  135. package/generated/entities/customer_user_invitation/index.ts +1 -0
  136. package/generated/entity-fields-registry.ts +2 -0
  137. package/package.json +7 -7
  138. package/src/modules/auth/lib/backendChrome.tsx +15 -9
  139. package/src/modules/auth/lib/tenantAccess.ts +8 -0
  140. package/src/modules/business_rules/api/openmercato-call-options/route.ts +94 -0
  141. package/src/modules/business_rules/api/rules/route.ts +92 -4
  142. package/src/modules/business_rules/components/ActionBuilder.tsx +54 -5
  143. package/src/modules/business_rules/components/ActionRow.tsx +156 -18
  144. package/src/modules/business_rules/components/utils/actionValidation.ts +6 -0
  145. package/src/modules/business_rules/i18n/de.json +12 -0
  146. package/src/modules/business_rules/i18n/en.json +12 -0
  147. package/src/modules/business_rules/i18n/es.json +12 -0
  148. package/src/modules/business_rules/i18n/pl.json +12 -0
  149. package/src/modules/business_rules/lib/action-executor.ts +198 -0
  150. package/src/modules/business_rules/lib/openmercato-call-options-types.ts +31 -0
  151. package/src/modules/business_rules/lib/openmercato-call-options.ts +297 -0
  152. package/src/modules/business_rules/lib/rule-engine.ts +4 -0
  153. package/src/modules/communication_channels/api/post/webhook/[provider]/route.ts +11 -1
  154. package/src/modules/communication_channels/api/post/webhooks/gmail/route.ts +17 -11
  155. package/src/modules/configs/lib/upgrade-actions.ts +14 -0
  156. package/src/modules/customer_accounts/api/admin/users/[id].ts +16 -1
  157. package/src/modules/customer_accounts/api/admin/users-invite.ts +78 -3
  158. package/src/modules/customer_accounts/api/portal/users-invite.ts +22 -1
  159. package/src/modules/customer_accounts/data/entities.ts +3 -0
  160. package/src/modules/customer_accounts/data/validators.ts +1 -0
  161. package/src/modules/customer_accounts/emails/CustomerInvitationEmail.tsx +45 -0
  162. package/src/modules/customer_accounts/i18n/de.json +6 -0
  163. package/src/modules/customer_accounts/i18n/en.json +6 -0
  164. package/src/modules/customer_accounts/i18n/es.json +6 -0
  165. package/src/modules/customer_accounts/i18n/pl.json +6 -0
  166. package/src/modules/customer_accounts/lib/customerEntityOwnership.ts +68 -2
  167. package/src/modules/customer_accounts/lib/customerUrl.ts +27 -11
  168. package/src/modules/customer_accounts/lib/invitationEmail.ts +42 -0
  169. package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +16 -0
  170. package/src/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.ts +13 -0
  171. package/src/modules/customer_accounts/services/customerInvitationService.ts +56 -3
  172. package/src/modules/customer_accounts/subscribers/autoLinkCrm.ts +75 -8
  173. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -2
  174. package/src/modules/customer_accounts/widgets/injection-table.ts +4 -1
  175. package/src/modules/customers/api/deals/[id]/people/route.ts +3 -0
  176. package/src/modules/customers/api/deals/[id]/route.ts +10 -2
  177. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +12 -1
  178. package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +1 -0
  179. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +15 -9
  180. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +24 -6
  181. package/src/modules/customers/commands/deals.ts +50 -9
  182. package/src/modules/customers/commands/people.ts +3 -0
  183. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +30 -7
  184. package/src/modules/customers/components/detail/DealDetailTabs.tsx +34 -9
  185. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +34 -9
  186. package/src/modules/customers/data/entities.ts +9 -1
  187. package/src/modules/customers/data/validators.ts +1 -0
  188. package/src/modules/customers/i18n/de.json +1 -0
  189. package/src/modules/customers/i18n/en.json +1 -0
  190. package/src/modules/customers/i18n/es.json +1 -0
  191. package/src/modules/customers/i18n/pl.json +1 -0
  192. package/src/modules/customers/migrations/.snapshot-open-mercato.json +27 -1
  193. package/src/modules/customers/migrations/Migration20260723210000_customers.ts +15 -0
  194. package/src/modules/directory/api/tenants/route.ts +9 -1
  195. package/src/modules/directory/commands/tenants.ts +6 -0
  196. package/src/modules/entities/api/entity-settings.ts +66 -22
  197. package/src/modules/entities/backend/config/settings/page.meta.ts +34 -0
  198. package/src/modules/entities/backend/config/settings/page.tsx +12 -0
  199. package/src/modules/entities/backend/entities/user/create/page.tsx +16 -7
  200. package/src/modules/entities/components/EntitySettingsManager.tsx +160 -0
  201. package/src/modules/entities/i18n/de.json +9 -0
  202. package/src/modules/entities/i18n/en.json +9 -0
  203. package/src/modules/entities/i18n/es.json +9 -0
  204. package/src/modules/entities/i18n/pl.json +9 -0
  205. package/src/modules/inbox_ops/api/webhook/inbound.ts +14 -12
  206. package/src/modules/payment_gateways/api/sessions/route.ts +1 -3
  207. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +13 -1
  208. package/src/modules/payment_gateways/data/entities.ts +5 -0
  209. package/src/modules/payment_gateways/i18n/de.json +5 -1
  210. package/src/modules/payment_gateways/i18n/en.json +5 -1
  211. package/src/modules/payment_gateways/i18n/es.json +5 -1
  212. package/src/modules/payment_gateways/i18n/pl.json +5 -1
  213. package/src/modules/payment_gateways/lib/gateway-service.ts +17 -8
  214. package/src/modules/payment_gateways/lib/session-idempotency.ts +36 -0
  215. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +10 -1
  216. package/src/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.ts +17 -0
  217. package/src/modules/payment_gateways/setup.ts +62 -0
  218. package/src/modules/payment_gateways/workers/session-initialization-prune.ts +63 -0
  219. package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.ts +9 -0
  220. package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.tsx +164 -0
  221. package/src/modules/portal/i18n/de.json +18 -0
  222. package/src/modules/portal/i18n/en.json +18 -0
  223. package/src/modules/portal/i18n/es.json +18 -0
  224. package/src/modules/portal/i18n/pl.json +18 -0
  225. package/src/modules/portal/lib/navigation.ts +3 -0
  226. package/src/modules/query_index/lib/engine.ts +52 -0
  227. package/src/modules/query_index/lib/search-tokens.ts +16 -4
  228. package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +11 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/backend/customers/people-v2/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams, usePathname } from 'next/navigation'\nimport { User, Hash, Users, Building2 } from 'lucide-react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AttachmentsSection, ErrorMessage, LoadingMessage, RecordNotFoundState, type SectionAction } from '@open-mercato/ui/backend/detail'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\n\nimport { ActivitiesSection } from '../../../../components/detail/ActivitiesSection'\nimport { PersonEmailThreadsTab } from '../../../../components/detail/PersonEmailThreadsTab'\nimport { ActivitiesCard } from '../../../../components/detail/ActivitiesCard'\nimport type { ActivityKind } from '../../../../components/detail/ActivitiesAddNewMenu'\nimport { DealsSection } from '../../../../components/detail/DealsSection'\nimport { TasksSection } from '../../../../components/detail/TasksSection'\nimport type { TagSummary } from '../../../../components/detail/types'\nimport { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'\nimport { PersonDetailHeader } from '../../../../components/detail/PersonDetailHeader'\nimport { ChangelogTab } from '../../../../components/detail/ChangelogTab'\nimport { PersonDetailTabs, resolveLegacyTab, type PersonTabId } from '../../../../components/detail/PersonDetailTabs'\nimport { AddressesSection } from '../../../../components/detail/AddressesSection'\nimport { PersonCompaniesSection } from '../../../../components/detail/PersonCompaniesSection'\nimport { MobilePersonDetail } from '../../../../components/detail/MobilePersonDetail'\nimport type { TagsSectionController } from '@open-mercato/ui/backend/detail'\nimport {\n buildPersonEditPayload,\n createPersonEditFields,\n createPersonPersonalDataGroups,\n createPersonEditSchema,\n mapPersonOverviewToFormValues,\n type PersonEditFormValues,\n type PersonOverview,\n} from '../../../../components/formConfig'\nimport { coerceDisplayName, coerceDisplayNameOrNull } from '../../../../lib/displayName'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport default function PersonDetailV2Page({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const pathname = usePathname()\n const { organizationId } = useOrganizationScopeDetail()\n const isMobile = useIsMobile()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n\n\n const formSchema = React.useMemo(() => createPersonEditSchema(), [])\n const fields = React.useMemo(() => createPersonEditFields(t), [t])\n\n const [data, setData] = React.useState<PersonOverview | null>(null)\n // Mirror the latest `data` into a ref so save handlers always read the current\n // optimistic-lock token (`person.updatedAt`) instead of the value captured in\n // their `useCallback` closure. Without this, a header-field save issued after a\n // prior in-page reload would send a stale token (or none), letting a concurrent\n // two-tab overwrite slip through without the 409 + conflict bar (#2055, Alina A7).\n const dataRef = React.useRef<PersonOverview | null>(null)\n React.useEffect(() => {\n dataRef.current = data\n }, [data])\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n // Form state lifted for header Save button\n const [isDirty, setIsDirty] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const formWrapperRef = React.useRef<HTMLDivElement>(null)\n\n const initialTab = React.useMemo(() => {\n return resolveLegacyTab(searchParams?.get('tab'))\n }, [searchParams])\n const [activeTab, setActiveTab] = React.useState<PersonTabId>(initialTab)\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const [scheduleDialogOpen, setScheduleDialogOpen] = React.useState(false)\n const [scheduleEditData, setScheduleEditData] = React.useState<ScheduleActivityEditData | null>(null)\n const [activityRefreshKey, setActivityRefreshKey] = React.useState(0)\n const [dealCount, setDealCount] = React.useState(0)\n\n const currentPersonId = data?.person?.id ?? null\n const mutationContextId = React.useMemo(\n () => (currentPersonId ? `customer-person:${currentPersonId}` : `customer-person:${id ?? 'pending'}`),\n [currentPersonId, id],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n personId?: string | null\n resourceKind: string\n resourceId?: string\n data: PersonOverview | null\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const personDisplayName = coerceDisplayName(data?.person?.displayName)\n const personName = personDisplayName.trim().length\n ? personDisplayName\n : t('customers.people.list.deleteFallbackName', 'this person')\n\n const personDisplayNameForGroups = personDisplayName.trim().length\n ? personDisplayName.trim()\n : null\n\n const scheduleDialogCompanyName = coerceDisplayNameOrNull(\n data?.company?.displayName ?? data?.companies?.[0]?.displayName ?? null,\n )\n\n const groups = React.useMemo(\n () => createPersonPersonalDataGroups(t, { entityName: personDisplayNameForGroups }),\n [t, personDisplayNameForGroups],\n )\n\n const zoneSections = React.useMemo<ZoneSectionDescriptor[]>(() => [\n { id: 'personalData', icon: User, label: t('customers.people.form.groups.personalData', 'Personal data') },\n { id: 'companyRole', icon: Building2, label: t('customers.people.form.groups.companyRole', 'Company & role') },\n { id: 'customFields', icon: Hash, label: t('customers.people.form.groups.customAttributes', 'Custom attributes') },\n { id: 'roles', icon: Users, label: t('customers.people.form.groups.roles', 'My roles') },\n ], [t])\n\n // Data loading\n const initialLoadDoneRef = React.useRef(false)\n const loadData = React.useCallback(async (lockTokenOverride?: string | null) => {\n if (!id) {\n setIsNotFound(true)\n setIsLoading(false)\n return\n }\n if (!initialLoadDoneRef.current) {\n setIsLoading(true)\n }\n setError(null)\n setIsNotFound(false)\n try {\n const payload = await readApiResultOrThrow<PersonOverview>(\n `/api/customers/people/${encodeURIComponent(id)}`,\n undefined,\n { errorMessage: t('customers.people.detail.error.load', 'Failed to load person.') },\n )\n // When the caller is the save handler, pin the optimistic-lock token to the\n // value the write itself returned rather than the one this GET observed \u2014 a\n // concurrent third-party bump between save and reload must stay stale so the\n // next in-page save 409s (#2055, Alina A7). Applied in the same state update\n // as the refresh to avoid a redundant second re-render.\n const next = lockTokenOverride && payload?.person\n ? { ...payload, person: { ...payload.person, updatedAt: lockTokenOverride, updated_at: lockTokenOverride } }\n : payload\n setData(next as PersonOverview)\n } catch (err) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('customers.people.detail.error.load', 'Failed to load person.')\n setError(message)\n }\n if (!initialLoadDoneRef.current) setData(null)\n } finally {\n setIsLoading(false)\n initialLoadDoneRef.current = true\n }\n }, [id, t])\n\n React.useEffect(() => {\n loadData().catch((err) => logger.warn('loadData failed', { component: 'people-v2', err }))\n }, [loadData])\n\n React.useEffect(() => {\n setDealCount(data?.counts?.deals ?? 0)\n }, [data?.counts?.deals])\n\n const handleActivityCreated = React.useCallback(() => {\n setActivityRefreshKey((k) => k + 1)\n loadData().catch((err) => logger.warn('reload after activity failed', { component: 'people-v2', err }))\n }, [loadData])\n\n const plannedActivities = React.useMemo(() => {\n return data?.plannedActivitiesPreview ?? []\n }, [data?.plannedActivitiesPreview])\n\n // Injection context for UMES\n const injectionContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n personId: currentPersonId,\n resourceKind: 'customers.person',\n resourceId: currentPersonId ?? (id ?? undefined),\n data,\n retryLastMutation,\n }),\n [currentPersonId, data, id, mutationContextId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {\n return runMutation({\n operation,\n mutationPayload,\n context: injectionContext,\n })\n },\n [injectionContext, runMutation],\n )\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `customers.person` + id\n // explicitly (the hardcoded path allowlist misses the `people-v2` route).\n // Presence/acquire/heartbeat run on load; the hook clears on unmount/record switch.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'customers.person',\n resourceId: currentPersonId,\n updatedAt: data?.person?.updatedAt ?? data?.person?.updated_at ?? null,\n data: data as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n const handleAddActivity = React.useCallback((kind: ActivityKind) => {\n setScheduleEditData({\n id: '',\n interactionType: kind,\n title: null,\n body: null,\n scheduledAt: null,\n durationMinutes: null,\n location: null,\n allDay: null,\n recurrenceRule: null,\n recurrenceEnd: null,\n participants: null,\n reminderMinutes: null,\n visibility: null,\n linkedEntities: null,\n guestPermissions: null,\n })\n setScheduleDialogOpen(true)\n }, [])\n\n const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; occurredAt?: string | null; [key: string]: unknown }) => {\n const raw = activity as Record<string, unknown>\n const durationValue = typeof raw.duration === 'number'\n ? raw.duration\n : typeof raw.durationMinutes === 'number'\n ? raw.durationMinutes as number\n : null\n // Forward `customValues` so per-type chip state (callPhoneNumber, callDirection,\n // taskPriority, \u2026) round-trips on edit (#1808 phone persistence).\n // Forward `occurredAt` so historical activity edits prefill from the original\n // moment instead of \"today\" (#1807 prefill).\n const editPayload = {\n id: activity.id,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt as string : typeof raw.updated_at === 'string' ? raw.updated_at as string : null,\n interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,\n title: typeof activity.title === 'string' ? activity.title : null,\n body: typeof activity.body === 'string' ? activity.body : null,\n scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,\n occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,\n durationMinutes: durationValue,\n location: typeof raw.location === 'string' ? raw.location as string : null,\n allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,\n recurrenceRule: typeof raw.recurrenceRule === 'string' ? raw.recurrenceRule as string : null,\n recurrenceEnd: typeof raw.recurrenceEnd === 'string' ? raw.recurrenceEnd as string : null,\n participants: Array.isArray(raw.participants) ? raw.participants as ScheduleActivityEditData['participants'] : null,\n reminderMinutes: typeof raw.reminderMinutes === 'number' ? raw.reminderMinutes as number : null,\n visibility: typeof raw.visibility === 'string' ? raw.visibility as string : null,\n linkedEntities: Array.isArray(raw.linkedEntities) ? raw.linkedEntities as ScheduleActivityEditData['linkedEntities'] : null,\n guestPermissions: raw.guestPermissions && typeof raw.guestPermissions === 'object'\n ? raw.guestPermissions as ScheduleActivityEditData['guestPermissions']\n : null,\n customValues: raw.customValues && typeof raw.customValues === 'object'\n ? raw.customValues as Record<string, unknown>\n : null,\n phoneNumber: typeof raw.phoneNumber === 'string' ? raw.phoneNumber as string : null,\n } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null }\n setScheduleEditData(editPayload)\n setScheduleDialogOpen(true)\n }, [])\n\n // Injected tabs from UMES\n const { widgets: injectedTabWidgets } = useInjectionWidgets('detail:customers.person:tabs', {\n context: injectionContext,\n triggerOnLoad: true,\n })\n\n const injectedTabs = React.useMemo(\n () =>\n (injectedTabWidgets ?? [])\n .filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')\n .map((widget) => {\n const tabId = widget.placement?.groupId ?? widget.widgetId\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? tabId\n const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0\n const render = () => (\n <widget.module.Widget\n context={injectionContext}\n data={data}\n onDataChange={(next: unknown) => setData(next as PersonOverview)}\n />\n )\n return { id: tabId, label, priority, render }\n })\n .sort((a, b) => b.priority - a.priority),\n [data, injectedTabWidgets, injectionContext],\n )\n\n const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])\n\n // Tags\n const handleTagsChange = React.useCallback((nextTags: TagSummary[]) => {\n setData((prev) => (prev ? { ...prev, tags: nextTags } : prev))\n }, [])\n const tagsSectionControllerRef = React.useRef<TagsSectionController | null>(null)\n\n // Section action (for tabs that expose add/create buttons)\n const handleSectionActionChange = React.useCallback((action: SectionAction | null) => {\n setSectionAction((prev) => (action !== null ? action : prev))\n }, [])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n // Deals scope\n const dealsScope = React.useMemo(\n () => (currentPersonId ? ({ kind: 'person', entityId: currentPersonId } as const) : null),\n [currentPersonId],\n )\n\n const initialValues = React.useMemo(\n () => (data ? mapPersonOverviewToFormValues(data) : undefined),\n [data],\n )\n\n // Form submit/delete\n const handleFormSubmit = React.useCallback(\n async (values: PersonEditFormValues) => {\n setIsSaving(true)\n try {\n await tagsSectionControllerRef.current?.flush()\n\n let payload: Record<string, unknown>\n try {\n payload = buildPersonEditPayload(values, organizationId)\n } catch (err) {\n if (err instanceof Error && err.message === 'DISPLAY_NAME_REQUIRED') {\n const message = t('customers.people.form.displayName.error')\n throw createCrudFormError(message, { displayName: message })\n }\n throw err\n }\n\n // Attach the current optimistic-lock token directly on this write path so\n // every header-field edit (displayName/status/\u2026) carries `updatedAt`, not\n // just the fields the embedded CrudForm intercepts. Read from `dataRef` so\n // the token reflects the latest in-page reload rather than a stale closure\n // capture, and let the 409 propagate to CrudForm's surfaceRecordConflict so\n // the unified conflict bar renders (#2055, Alina A7).\n const lockedUpdatedAt = dataRef.current?.person?.updatedAt\n ?? dataRef.current?.person?.updated_at\n ?? null\n const updateResponse = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(lockedUpdatedAt),\n () => updateCrud<{ updatedAt?: string | null }>('customers/people', payload),\n )\n flash(t('customers.people.form.updateSuccess', 'Person updated.'), 'success')\n // Refresh the view and pin the optimistic-lock token to the write's OWN\n // authoritative `updatedAt` in a single reload (see loadData) so a\n // concurrent third-party bump stays stale on the next save (#2055, Alina A7).\n const savedUpdatedAt = typeof updateResponse.result?.updatedAt === 'string'\n ? updateResponse.result.updatedAt\n : null\n await loadData(savedUpdatedAt)\n } finally {\n setIsSaving(false)\n }\n },\n [loadData, organizationId, t],\n )\n\n const handleFormDelete = React.useCallback(\n async () => {\n const personId = data?.person?.id ?? ''\n if (!personId) return\n const approved = await confirm({\n title: t('customers.people.detail.deleteConfirmTitle', 'Delete person?'),\n description: t('customers.people.detail.deleteConfirmDescription', 'This action cannot be undone.'),\n confirmText: t('customers.people.detail.actions.delete', 'Delete'),\n cancelText: t('customers.people.detail.actions.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!approved) return\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(data?.person?.updatedAt ?? data?.person?.updated_at ?? null),\n () => deleteCrud('customers/people', { id: personId }),\n ),\n { id: personId, operation: 'deletePerson' },\n )\n } catch (err) {\n // The guarded mutation routes a 409 to the unified conflict bar; surface\n // any other server error (e.g. a linked-records delete guard) as a flash\n // instead of letting it crash the page.\n if (!surfaceRecordConflict(err, t)) {\n flash(\n err instanceof Error && err.message.trim().length > 0\n ? err.message\n : t('customers.people.detail.deleteError', 'Failed to delete person.'),\n 'error',\n )\n }\n return\n }\n flash(t('customers.people.list.deleteSuccess', 'Person deleted.'), 'success')\n router.push('/backend/customers/people')\n },\n [confirm, data?.person?.id, router, runMutationWithContext, t],\n )\n\n const handleHeaderSave = React.useCallback(() => {\n const form = formWrapperRef.current?.querySelector('form')\n if (form) form.requestSubmit()\n }, [])\n\n // Counts for tab badges\n const interactionCount = data?.counts?.activities ?? 0\n const todoCount = data?.counts?.todos ?? 0\n const companyCount = data?.counts?.companies ?? (data?.companies?.length ?? (data?.company ? 1 : 0))\n\n // Loading / error states\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('customers.people.detail.loading', 'Loading person\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('customers.people.detail.error.notFound', 'Person not found.')}\n backHref=\"/backend/customers/people\"\n backLabel={t('customers.people.detail.actions.backToList', 'Back to people')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data?.person?.id || !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error ?? t('customers.people.detail.error.load', 'Failed to load person.')}\n action={(\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/customers/people\">\n {t('customers.people.detail.actions.backToList', 'Back to people')}\n </Link>\n </Button>\n )}\n />\n </PageBody>\n </Page>\n )\n }\n\n const personId = data.person.id\n const useCanonicalInteractions = data.interactionMode === 'canonical'\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-4\">\n {/* UMES header injection (third-party extensions) */}\n <InjectionSpot spotId={extensionPoints.hosts.personHeader.spotId} context={injectionContext} data={data} />\n <InjectionSpot spotId={extensionPoints.hosts.personStatusBadges.spotId} context={injectionContext} data={data} />\n\n {/* Persistent person header */}\n <PersonDetailHeader\n data={data}\n onTagsChange={handleTagsChange}\n tagsSectionControllerRef={tagsSectionControllerRef}\n onSave={handleHeaderSave}\n onDelete={handleFormDelete}\n isDirty={isDirty}\n isSaving={isSaving}\n onOpenCompaniesTab={() => setActiveTab('companies')}\n onDataReload={() => { loadData().catch((err) => logger.warn('onDataReload failed', { component: 'people-v2', err })) }}\n onFocusField={(fieldName) => {\n const selectorMap: Record<string, string> = {\n primaryEmail: 'input[type=\"email\"]',\n primaryPhone: 'input[type=\"tel\"]',\n }\n const selector = selectorMap[fieldName]\n const input = selector ? formWrapperRef.current?.querySelector<HTMLInputElement>(selector) : null\n if (input) {\n input.scrollIntoView({ behavior: 'smooth', block: 'center' })\n requestAnimationFrame(() => input.focus())\n }\n }}\n />\n\n {/* Zone content shared between desktop (CollapsibleZoneLayout) and mobile (MobilePersonDetail). */}\n {(() => {\n const zone1Content = (\n <div ref={formWrapperRef}>\n <CrudForm<PersonEditFormValues>\n embedded\n trackDirtyWhenEmbedded\n injectionSpotId={extensionPoints.hosts.personForm.spotId}\n entityIds={[E.customers.customer_entity, E.customers.customer_person_profile]}\n schema={formSchema}\n fields={fields}\n groups={groups}\n initialValues={initialValues}\n optimisticLockUpdatedAt={data.person.updatedAt ?? data.person.updated_at ?? null}\n onSubmit={handleFormSubmit}\n onDelete={handleFormDelete}\n hideFooterActions\n collapsibleGroups={{ pageType: 'person-v2', chevronPosition: 'right' }}\n sortableGroups={{ pageType: 'person-v2' }}\n onDirtyChange={setIsDirty}\n />\n </div>\n )\n const zone2Content = (\n <PersonDetailTabs\n activeTab={activeTab}\n onTabChange={setActiveTab}\n injectedTabs={injectedTabs.map((tab) => ({ id: tab.id, label: tab.label }))}\n activitiesCount={interactionCount}\n dealsCount={dealCount}\n companiesCount={companyCount}\n addressesCount={data?.counts?.addresses ?? 0}\n tasksCount={todoCount}\n sectionAction={sectionAction}\n >\n <div className=\"min-w-0\">\n {(() => {\n // Injected tab content\n const injected = injectedTabMap.get(activeTab)\n if (injected) return injected()\n\n if (activeTab === 'activities') {\n return (\n <div className=\"space-y-4\">\n <ActivitiesCard\n entityId={personId}\n plannedActivities={plannedActivities}\n refreshKey={activityRefreshKey}\n onAddNew={handleAddActivity}\n onEditActivity={handleEditActivity}\n entityCompanyName={data.company?.displayName ?? data.companies?.[0]?.displayName ?? null}\n />\n <ActivitiesSection\n entityId={personId}\n entityName={personName}\n useCanonicalInteractions={useCanonicalInteractions}\n runGuardedMutation={runMutationWithContext}\n onDataRefresh={handleActivityCreated}\n refreshKey={activityRefreshKey}\n addActionLabel={t('customers.people.detail.activities.add', 'Log activity')}\n emptyState={{\n title: t('customers.people.detail.emptyState.activities.title', 'No activities logged yet'),\n actionLabel: t('customers.people.detail.emptyState.activities.action', 'Log activity'),\n }}\n onActionChange={handleSectionActionChange}\n onEditActivity={handleEditActivity}\n />\n </div>\n )\n }\n\n if (activeTab === 'emails') {\n return (\n <PersonEmailThreadsTab\n personId={personId}\n defaultRecipient={data.person?.primaryEmail ?? null}\n />\n )\n }\n\n if (activeTab === 'deals') {\n return (\n <DealsSection\n scope={dealsScope}\n emptyLabel={t('customers.people.detail.empty.deals', 'No deals linked to this person.')}\n addActionLabel={t('customers.people.detail.actions.addDeal', 'Add deal')}\n emptyState={{\n title: t('customers.people.detail.emptyState.deals.title', 'No deals yet'),\n actionLabel: t('customers.people.detail.emptyState.deals.action', 'Create a deal'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onCountDelta={(delta) => setDealCount((current) => Math.max(0, current + delta))}\n />\n )\n }\n\n if (activeTab === 'companies') {\n return (\n <PersonCompaniesSection\n personId={personId}\n personName={personName}\n initialLinkedCompanies={data?.companies ?? []}\n onChanged={loadData}\n runGuardedMutation={runMutationWithContext}\n />\n )\n }\n\n if (activeTab === 'addresses') {\n return (\n <AddressesSection\n entityId={personId}\n emptyLabel={t('customers.people.detail.empty.addresses', 'No addresses linked to this person.')}\n addActionLabel={t('customers.people.detail.addresses.add', 'Add address')}\n emptyState={{\n title: t('customers.people.detail.emptyState.addresses.title', 'No addresses yet'),\n actionLabel: t('customers.people.detail.emptyState.addresses.action', 'Add address'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n />\n )\n }\n\n if (activeTab === 'tasks') {\n return (\n <TasksSection\n entityId={personId}\n initialTasks={[]}\n useCanonicalInteractions={useCanonicalInteractions}\n runGuardedMutation={runMutationWithContext}\n onDataRefresh={loadData}\n emptyLabel={t('customers.people.detail.empty.todos', 'No tasks linked to this person.')}\n addActionLabel={t('customers.people.detail.tasks.add', 'Add task')}\n emptyState={{\n title: t('customers.people.detail.emptyState.tasks.title', 'Plan what happens next'),\n actionLabel: t('customers.people.detail.emptyState.tasks.action', 'Create task'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n entityName={personName}\n dialogContextKey=\"customers.people.detail.tasks.dialog.context\"\n dialogContextFallback=\"This task will be linked to {{name}}\"\n />\n )\n }\n\n if (activeTab === 'files') {\n return (\n <AttachmentsSection\n entityId={E.customers.customer_entity}\n recordId={personId}\n title={t('customers.people.detail.tabs.files', 'Files')}\n description={t('customers.people.detail.files.subtitle', 'Upload and manage files linked to this person.')}\n />\n )\n }\n\n if (activeTab === 'changelog') {\n return <ChangelogTab entityId={personId} entityType=\"person\" />\n }\n\n return null\n })()}\n </div>\n </PersonDetailTabs>\n )\n // Render only the layout variant that matches the viewport. Mounting\n // both the mobile and desktop layouts at once would create two\n // CrudForm instances bound to one `formWrapperRef`, so header Save\n // could submit the hidden instance's stale values and silently\n // discard the edit (#2453). `useIsMobile` is SSR-safe.\n return isMobile ? (\n <MobilePersonDetail zone1={zone1Content} zone2={zone2Content} />\n ) : (\n <CollapsibleZoneLayout\n pageType=\"person-v2\"\n entityName={personName}\n isDirty={isDirty}\n sections={zoneSections}\n zone1={zone1Content}\n zone2={zone2Content}\n />\n )\n })()}\n\n {/* UMES footer injection */}\n <InjectionSpot spotId={extensionPoints.hosts.personFooter.spotId} context={injectionContext} data={data} />\n\n {/* Schedule Activity Dialog \u2014 opened from PlannedActivities \"+ Schedule\" or other triggers */}\n <ScheduleActivityDialog\n open={scheduleDialogOpen}\n onClose={() => { setScheduleDialogOpen(false); setScheduleEditData(null) }}\n entityId={personId}\n entityName={personName}\n companyName={scheduleDialogCompanyName}\n entityType=\"person\"\n onActivityCreated={handleActivityCreated}\n editData={scheduleEditData}\n />\n {ConfirmDialogElement}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams, usePathname } from 'next/navigation'\nimport { User, Hash, Users, Building2 } from 'lucide-react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AttachmentsSection, ErrorMessage, LoadingMessage, RecordNotFoundState, type SectionAction } from '@open-mercato/ui/backend/detail'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\n\nimport { ActivitiesSection } from '../../../../components/detail/ActivitiesSection'\nimport { PersonEmailThreadsTab } from '../../../../components/detail/PersonEmailThreadsTab'\nimport { ActivitiesCard } from '../../../../components/detail/ActivitiesCard'\nimport type { ActivityKind } from '../../../../components/detail/ActivitiesAddNewMenu'\nimport { DealsSection } from '../../../../components/detail/DealsSection'\nimport { TasksSection } from '../../../../components/detail/TasksSection'\nimport type { TagSummary } from '../../../../components/detail/types'\nimport { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'\nimport { PersonDetailHeader } from '../../../../components/detail/PersonDetailHeader'\nimport { ChangelogTab } from '../../../../components/detail/ChangelogTab'\nimport { PersonDetailTabs, resolveLegacyTab, type PersonTabId } from '../../../../components/detail/PersonDetailTabs'\nimport { AddressesSection } from '../../../../components/detail/AddressesSection'\nimport { PersonCompaniesSection } from '../../../../components/detail/PersonCompaniesSection'\nimport { MobilePersonDetail } from '../../../../components/detail/MobilePersonDetail'\nimport type { TagsSectionController } from '@open-mercato/ui/backend/detail'\nimport {\n buildPersonEditPayload,\n createPersonEditFields,\n createPersonPersonalDataGroups,\n createPersonEditSchema,\n mapPersonOverviewToFormValues,\n type PersonEditFormValues,\n type PersonOverview,\n} from '../../../../components/formConfig'\nimport { coerceDisplayName, coerceDisplayNameOrNull } from '../../../../lib/displayName'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport default function PersonDetailV2Page({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const pathname = usePathname()\n const { organizationId } = useOrganizationScopeDetail()\n const isMobile = useIsMobile()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n\n\n const formSchema = React.useMemo(() => createPersonEditSchema(), [])\n const fields = React.useMemo(() => createPersonEditFields(t), [t])\n\n const [data, setData] = React.useState<PersonOverview | null>(null)\n // Mirror the latest `data` into a ref so save handlers always read the current\n // optimistic-lock token (`person.updatedAt`) instead of the value captured in\n // their `useCallback` closure. Without this, a header-field save issued after a\n // prior in-page reload would send a stale token (or none), letting a concurrent\n // two-tab overwrite slip through without the 409 + conflict bar (#2055, Alina A7).\n const dataRef = React.useRef<PersonOverview | null>(null)\n React.useEffect(() => {\n dataRef.current = data\n }, [data])\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n // Form state lifted for header Save button\n const [isDirty, setIsDirty] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const formWrapperRef = React.useRef<HTMLDivElement>(null)\n\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const [scheduleDialogOpen, setScheduleDialogOpen] = React.useState(false)\n const [scheduleEditData, setScheduleEditData] = React.useState<ScheduleActivityEditData | null>(null)\n const [activityRefreshKey, setActivityRefreshKey] = React.useState(0)\n const [dealCount, setDealCount] = React.useState(0)\n\n const currentPersonId = data?.person?.id ?? null\n const mutationContextId = React.useMemo(\n () => (currentPersonId ? `customer-person:${currentPersonId}` : `customer-person:${id ?? 'pending'}`),\n [currentPersonId, id],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n personId?: string | null\n resourceKind: string\n resourceId?: string\n data: PersonOverview | null\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const personDisplayName = coerceDisplayName(data?.person?.displayName)\n const personName = personDisplayName.trim().length\n ? personDisplayName\n : t('customers.people.list.deleteFallbackName', 'this person')\n\n const personDisplayNameForGroups = personDisplayName.trim().length\n ? personDisplayName.trim()\n : null\n\n const scheduleDialogCompanyName = coerceDisplayNameOrNull(\n data?.company?.displayName ?? data?.companies?.[0]?.displayName ?? null,\n )\n\n const groups = React.useMemo(\n () => createPersonPersonalDataGroups(t, { entityName: personDisplayNameForGroups }),\n [t, personDisplayNameForGroups],\n )\n\n const zoneSections = React.useMemo<ZoneSectionDescriptor[]>(() => [\n { id: 'personalData', icon: User, label: t('customers.people.form.groups.personalData', 'Personal data') },\n { id: 'companyRole', icon: Building2, label: t('customers.people.form.groups.companyRole', 'Company & role') },\n { id: 'customFields', icon: Hash, label: t('customers.people.form.groups.customAttributes', 'Custom attributes') },\n { id: 'roles', icon: Users, label: t('customers.people.form.groups.roles', 'My roles') },\n ], [t])\n\n // Data loading\n const initialLoadDoneRef = React.useRef(false)\n const loadData = React.useCallback(async (lockTokenOverride?: string | null) => {\n if (!id) {\n setIsNotFound(true)\n setIsLoading(false)\n return\n }\n if (!initialLoadDoneRef.current) {\n setIsLoading(true)\n }\n setError(null)\n setIsNotFound(false)\n try {\n const payload = await readApiResultOrThrow<PersonOverview>(\n `/api/customers/people/${encodeURIComponent(id)}`,\n undefined,\n { errorMessage: t('customers.people.detail.error.load', 'Failed to load person.') },\n )\n // When the caller is the save handler, pin the optimistic-lock token to the\n // value the write itself returned rather than the one this GET observed \u2014 a\n // concurrent third-party bump between save and reload must stay stale so the\n // next in-page save 409s (#2055, Alina A7). Applied in the same state update\n // as the refresh to avoid a redundant second re-render.\n const next = lockTokenOverride && payload?.person\n ? { ...payload, person: { ...payload.person, updatedAt: lockTokenOverride, updated_at: lockTokenOverride } }\n : payload\n setData(next as PersonOverview)\n } catch (err) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('customers.people.detail.error.load', 'Failed to load person.')\n setError(message)\n }\n if (!initialLoadDoneRef.current) setData(null)\n } finally {\n setIsLoading(false)\n initialLoadDoneRef.current = true\n }\n }, [id, t])\n\n React.useEffect(() => {\n loadData().catch((err) => logger.warn('loadData failed', { component: 'people-v2', err }))\n }, [loadData])\n\n React.useEffect(() => {\n setDealCount(data?.counts?.deals ?? 0)\n }, [data?.counts?.deals])\n\n const handleActivityCreated = React.useCallback(() => {\n setActivityRefreshKey((k) => k + 1)\n loadData().catch((err) => logger.warn('reload after activity failed', { component: 'people-v2', err }))\n }, [loadData])\n\n const plannedActivities = React.useMemo(() => {\n return data?.plannedActivitiesPreview ?? []\n }, [data?.plannedActivitiesPreview])\n\n // Injection context for UMES\n const injectionContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n personId: currentPersonId,\n resourceKind: 'customers.person',\n resourceId: currentPersonId ?? (id ?? undefined),\n data,\n retryLastMutation,\n }),\n [currentPersonId, data, id, mutationContextId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {\n return runMutation({\n operation,\n mutationPayload,\n context: injectionContext,\n })\n },\n [injectionContext, runMutation],\n )\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `customers.person` + id\n // explicitly (the hardcoded path allowlist misses the `people-v2` route).\n // Presence/acquire/heartbeat run on load; the hook clears on unmount/record switch.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'customers.person',\n resourceId: currentPersonId,\n updatedAt: data?.person?.updatedAt ?? data?.person?.updated_at ?? null,\n data: data as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n const handleAddActivity = React.useCallback((kind: ActivityKind) => {\n setScheduleEditData({\n id: '',\n interactionType: kind,\n title: null,\n body: null,\n scheduledAt: null,\n durationMinutes: null,\n location: null,\n allDay: null,\n recurrenceRule: null,\n recurrenceEnd: null,\n participants: null,\n reminderMinutes: null,\n visibility: null,\n linkedEntities: null,\n guestPermissions: null,\n })\n setScheduleDialogOpen(true)\n }, [])\n\n const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; occurredAt?: string | null; [key: string]: unknown }) => {\n const raw = activity as Record<string, unknown>\n const durationValue = typeof raw.duration === 'number'\n ? raw.duration\n : typeof raw.durationMinutes === 'number'\n ? raw.durationMinutes as number\n : null\n // Forward `customValues` so per-type chip state (callPhoneNumber, callDirection,\n // taskPriority, \u2026) round-trips on edit (#1808 phone persistence).\n // Forward `occurredAt` so historical activity edits prefill from the original\n // moment instead of \"today\" (#1807 prefill).\n const editPayload = {\n id: activity.id,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt as string : typeof raw.updated_at === 'string' ? raw.updated_at as string : null,\n interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,\n title: typeof activity.title === 'string' ? activity.title : null,\n body: typeof activity.body === 'string' ? activity.body : null,\n scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,\n occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,\n durationMinutes: durationValue,\n location: typeof raw.location === 'string' ? raw.location as string : null,\n allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,\n recurrenceRule: typeof raw.recurrenceRule === 'string' ? raw.recurrenceRule as string : null,\n recurrenceEnd: typeof raw.recurrenceEnd === 'string' ? raw.recurrenceEnd as string : null,\n participants: Array.isArray(raw.participants) ? raw.participants as ScheduleActivityEditData['participants'] : null,\n reminderMinutes: typeof raw.reminderMinutes === 'number' ? raw.reminderMinutes as number : null,\n visibility: typeof raw.visibility === 'string' ? raw.visibility as string : null,\n linkedEntities: Array.isArray(raw.linkedEntities) ? raw.linkedEntities as ScheduleActivityEditData['linkedEntities'] : null,\n guestPermissions: raw.guestPermissions && typeof raw.guestPermissions === 'object'\n ? raw.guestPermissions as ScheduleActivityEditData['guestPermissions']\n : null,\n customValues: raw.customValues && typeof raw.customValues === 'object'\n ? raw.customValues as Record<string, unknown>\n : null,\n phoneNumber: typeof raw.phoneNumber === 'string' ? raw.phoneNumber as string : null,\n } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null }\n setScheduleEditData(editPayload)\n setScheduleDialogOpen(true)\n }, [])\n\n // Injected tabs from UMES\n const { widgets: injectedTabWidgets } = useInjectionWidgets('detail:customers.person:tabs', {\n context: injectionContext,\n triggerOnLoad: true,\n })\n\n const injectedTabs = React.useMemo(\n () =>\n (injectedTabWidgets ?? [])\n .filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')\n .map((widget) => {\n const tabId = widget.placement?.groupId ?? widget.widgetId\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? tabId\n const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0\n const render = () => (\n <widget.module.Widget\n context={injectionContext}\n data={data}\n onDataChange={(next: unknown) => setData(next as PersonOverview)}\n />\n )\n return { id: tabId, label, priority, render }\n })\n .sort((a, b) => b.priority - a.priority),\n [data, injectedTabWidgets, injectionContext],\n )\n\n const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])\n\n const injectedTabIds = React.useMemo(() => injectedTabs.map((tab) => tab.id), [injectedTabs])\n const initialTab = React.useMemo(\n () => resolveLegacyTab(searchParams?.get('tab'), injectedTabIds),\n [injectedTabIds, searchParams],\n )\n const [activeTab, setActiveTab] = React.useState<PersonTabId>(initialTab)\n\n React.useEffect(() => {\n setActiveTab(initialTab)\n }, [initialTab])\n\n const handleTabChange = React.useCallback(\n (tab: PersonTabId) => {\n setActiveTab(tab)\n if (!pathname) return\n const nextParams = new URLSearchParams(searchParams?.toString() ?? '')\n nextParams.set('tab', tab)\n router.replace(`${pathname}?${nextParams.toString()}`, { scroll: false })\n },\n [pathname, router, searchParams],\n )\n\n // Tags\n const handleTagsChange = React.useCallback((nextTags: TagSummary[]) => {\n setData((prev) => (prev ? { ...prev, tags: nextTags } : prev))\n }, [])\n const tagsSectionControllerRef = React.useRef<TagsSectionController | null>(null)\n\n // Section action (for tabs that expose add/create buttons)\n const handleSectionActionChange = React.useCallback((action: SectionAction | null) => {\n setSectionAction((prev) => (action !== null ? action : prev))\n }, [])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n // Deals scope\n const dealsScope = React.useMemo(\n () => (currentPersonId ? ({ kind: 'person', entityId: currentPersonId } as const) : null),\n [currentPersonId],\n )\n\n const initialValues = React.useMemo(\n () => (data ? mapPersonOverviewToFormValues(data) : undefined),\n [data],\n )\n\n // Form submit/delete\n const handleFormSubmit = React.useCallback(\n async (values: PersonEditFormValues) => {\n setIsSaving(true)\n try {\n await tagsSectionControllerRef.current?.flush()\n\n let payload: Record<string, unknown>\n try {\n payload = buildPersonEditPayload(values, organizationId)\n } catch (err) {\n if (err instanceof Error && err.message === 'DISPLAY_NAME_REQUIRED') {\n const message = t('customers.people.form.displayName.error')\n throw createCrudFormError(message, { displayName: message })\n }\n throw err\n }\n\n // Attach the current optimistic-lock token directly on this write path so\n // every header-field edit (displayName/status/\u2026) carries `updatedAt`, not\n // just the fields the embedded CrudForm intercepts. Read from `dataRef` so\n // the token reflects the latest in-page reload rather than a stale closure\n // capture, and let the 409 propagate to CrudForm's surfaceRecordConflict so\n // the unified conflict bar renders (#2055, Alina A7).\n const lockedUpdatedAt = dataRef.current?.person?.updatedAt\n ?? dataRef.current?.person?.updated_at\n ?? null\n const updateResponse = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(lockedUpdatedAt),\n () => updateCrud<{ updatedAt?: string | null }>('customers/people', payload),\n )\n flash(t('customers.people.form.updateSuccess', 'Person updated.'), 'success')\n // Refresh the view and pin the optimistic-lock token to the write's OWN\n // authoritative `updatedAt` in a single reload (see loadData) so a\n // concurrent third-party bump stays stale on the next save (#2055, Alina A7).\n const savedUpdatedAt = typeof updateResponse.result?.updatedAt === 'string'\n ? updateResponse.result.updatedAt\n : null\n await loadData(savedUpdatedAt)\n } finally {\n setIsSaving(false)\n }\n },\n [loadData, organizationId, t],\n )\n\n const handleFormDelete = React.useCallback(\n async () => {\n const personId = data?.person?.id ?? ''\n if (!personId) return\n const approved = await confirm({\n title: t('customers.people.detail.deleteConfirmTitle', 'Delete person?'),\n description: t('customers.people.detail.deleteConfirmDescription', 'This action cannot be undone.'),\n confirmText: t('customers.people.detail.actions.delete', 'Delete'),\n cancelText: t('customers.people.detail.actions.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!approved) return\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(data?.person?.updatedAt ?? data?.person?.updated_at ?? null),\n () => deleteCrud('customers/people', { id: personId }),\n ),\n { id: personId, operation: 'deletePerson' },\n )\n } catch (err) {\n // The guarded mutation routes a 409 to the unified conflict bar; surface\n // any other server error (e.g. a linked-records delete guard) as a flash\n // instead of letting it crash the page.\n if (!surfaceRecordConflict(err, t)) {\n flash(\n err instanceof Error && err.message.trim().length > 0\n ? err.message\n : t('customers.people.detail.deleteError', 'Failed to delete person.'),\n 'error',\n )\n }\n return\n }\n flash(t('customers.people.list.deleteSuccess', 'Person deleted.'), 'success')\n router.push('/backend/customers/people')\n },\n [confirm, data?.person?.id, router, runMutationWithContext, t],\n )\n\n const handleHeaderSave = React.useCallback(() => {\n const form = formWrapperRef.current?.querySelector('form')\n if (form) form.requestSubmit()\n }, [])\n\n // Counts for tab badges\n const interactionCount = data?.counts?.activities ?? 0\n const todoCount = data?.counts?.todos ?? 0\n const companyCount = data?.counts?.companies ?? (data?.companies?.length ?? (data?.company ? 1 : 0))\n\n // Loading / error states\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('customers.people.detail.loading', 'Loading person\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('customers.people.detail.error.notFound', 'Person not found.')}\n backHref=\"/backend/customers/people\"\n backLabel={t('customers.people.detail.actions.backToList', 'Back to people')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data?.person?.id || !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error ?? t('customers.people.detail.error.load', 'Failed to load person.')}\n action={(\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/customers/people\">\n {t('customers.people.detail.actions.backToList', 'Back to people')}\n </Link>\n </Button>\n )}\n />\n </PageBody>\n </Page>\n )\n }\n\n const personId = data.person.id\n const useCanonicalInteractions = data.interactionMode === 'canonical'\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-4\">\n {/* UMES header injection (third-party extensions) */}\n <InjectionSpot spotId={extensionPoints.hosts.personHeader.spotId} context={injectionContext} data={data} />\n <InjectionSpot spotId={extensionPoints.hosts.personStatusBadges.spotId} context={injectionContext} data={data} />\n\n {/* Persistent person header */}\n <PersonDetailHeader\n data={data}\n onTagsChange={handleTagsChange}\n tagsSectionControllerRef={tagsSectionControllerRef}\n onSave={handleHeaderSave}\n onDelete={handleFormDelete}\n isDirty={isDirty}\n isSaving={isSaving}\n onOpenCompaniesTab={() => handleTabChange('companies')}\n onDataReload={() => { loadData().catch((err) => logger.warn('onDataReload failed', { component: 'people-v2', err })) }}\n onFocusField={(fieldName) => {\n const selectorMap: Record<string, string> = {\n primaryEmail: 'input[type=\"email\"]',\n primaryPhone: 'input[type=\"tel\"]',\n }\n const selector = selectorMap[fieldName]\n const input = selector ? formWrapperRef.current?.querySelector<HTMLInputElement>(selector) : null\n if (input) {\n input.scrollIntoView({ behavior: 'smooth', block: 'center' })\n requestAnimationFrame(() => input.focus())\n }\n }}\n />\n\n {/* Zone content shared between desktop (CollapsibleZoneLayout) and mobile (MobilePersonDetail). */}\n {(() => {\n const zone1Content = (\n <div ref={formWrapperRef}>\n <CrudForm<PersonEditFormValues>\n embedded\n trackDirtyWhenEmbedded\n injectionSpotId={extensionPoints.hosts.personForm.spotId}\n entityIds={[E.customers.customer_entity, E.customers.customer_person_profile]}\n schema={formSchema}\n fields={fields}\n groups={groups}\n initialValues={initialValues}\n optimisticLockUpdatedAt={data.person.updatedAt ?? data.person.updated_at ?? null}\n onSubmit={handleFormSubmit}\n onDelete={handleFormDelete}\n hideFooterActions\n collapsibleGroups={{ pageType: 'person-v2', chevronPosition: 'right' }}\n sortableGroups={{ pageType: 'person-v2' }}\n onDirtyChange={setIsDirty}\n />\n </div>\n )\n const zone2Content = (\n <PersonDetailTabs\n activeTab={activeTab}\n onTabChange={handleTabChange}\n injectedTabs={injectedTabs.map((tab) => ({ id: tab.id, label: tab.label }))}\n activitiesCount={interactionCount}\n dealsCount={dealCount}\n companiesCount={companyCount}\n addressesCount={data?.counts?.addresses ?? 0}\n tasksCount={todoCount}\n sectionAction={sectionAction}\n >\n <div className=\"min-w-0\">\n {(() => {\n // Injected tab content\n const injected = injectedTabMap.get(activeTab)\n if (injected) return injected()\n\n if (activeTab === 'activities') {\n return (\n <div className=\"space-y-4\">\n <ActivitiesCard\n entityId={personId}\n plannedActivities={plannedActivities}\n refreshKey={activityRefreshKey}\n onAddNew={handleAddActivity}\n onEditActivity={handleEditActivity}\n entityCompanyName={data.company?.displayName ?? data.companies?.[0]?.displayName ?? null}\n />\n <ActivitiesSection\n entityId={personId}\n entityName={personName}\n useCanonicalInteractions={useCanonicalInteractions}\n runGuardedMutation={runMutationWithContext}\n onDataRefresh={handleActivityCreated}\n refreshKey={activityRefreshKey}\n addActionLabel={t('customers.people.detail.activities.add', 'Log activity')}\n emptyState={{\n title: t('customers.people.detail.emptyState.activities.title', 'No activities logged yet'),\n actionLabel: t('customers.people.detail.emptyState.activities.action', 'Log activity'),\n }}\n onActionChange={handleSectionActionChange}\n onEditActivity={handleEditActivity}\n />\n </div>\n )\n }\n\n if (activeTab === 'emails') {\n return (\n <PersonEmailThreadsTab\n personId={personId}\n defaultRecipient={data.person?.primaryEmail ?? null}\n />\n )\n }\n\n if (activeTab === 'deals') {\n return (\n <DealsSection\n scope={dealsScope}\n emptyLabel={t('customers.people.detail.empty.deals', 'No deals linked to this person.')}\n addActionLabel={t('customers.people.detail.actions.addDeal', 'Add deal')}\n emptyState={{\n title: t('customers.people.detail.emptyState.deals.title', 'No deals yet'),\n actionLabel: t('customers.people.detail.emptyState.deals.action', 'Create a deal'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onCountDelta={(delta) => setDealCount((current) => Math.max(0, current + delta))}\n />\n )\n }\n\n if (activeTab === 'companies') {\n return (\n <PersonCompaniesSection\n personId={personId}\n personName={personName}\n initialLinkedCompanies={data?.companies ?? []}\n onChanged={loadData}\n runGuardedMutation={runMutationWithContext}\n />\n )\n }\n\n if (activeTab === 'addresses') {\n return (\n <AddressesSection\n entityId={personId}\n emptyLabel={t('customers.people.detail.empty.addresses', 'No addresses linked to this person.')}\n addActionLabel={t('customers.people.detail.addresses.add', 'Add address')}\n emptyState={{\n title: t('customers.people.detail.emptyState.addresses.title', 'No addresses yet'),\n actionLabel: t('customers.people.detail.emptyState.addresses.action', 'Add address'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n />\n )\n }\n\n if (activeTab === 'tasks') {\n return (\n <TasksSection\n entityId={personId}\n initialTasks={[]}\n useCanonicalInteractions={useCanonicalInteractions}\n runGuardedMutation={runMutationWithContext}\n onDataRefresh={loadData}\n emptyLabel={t('customers.people.detail.empty.todos', 'No tasks linked to this person.')}\n addActionLabel={t('customers.people.detail.tasks.add', 'Add task')}\n emptyState={{\n title: t('customers.people.detail.emptyState.tasks.title', 'Plan what happens next'),\n actionLabel: t('customers.people.detail.emptyState.tasks.action', 'Create task'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n entityName={personName}\n dialogContextKey=\"customers.people.detail.tasks.dialog.context\"\n dialogContextFallback=\"This task will be linked to {{name}}\"\n />\n )\n }\n\n if (activeTab === 'files') {\n return (\n <AttachmentsSection\n entityId={E.customers.customer_entity}\n recordId={personId}\n title={t('customers.people.detail.tabs.files', 'Files')}\n description={t('customers.people.detail.files.subtitle', 'Upload and manage files linked to this person.')}\n />\n )\n }\n\n if (activeTab === 'changelog') {\n return <ChangelogTab entityId={personId} entityType=\"person\" />\n }\n\n return null\n })()}\n </div>\n </PersonDetailTabs>\n )\n // Render only the layout variant that matches the viewport. Mounting\n // both the mobile and desktop layouts at once would create two\n // CrudForm instances bound to one `formWrapperRef`, so header Save\n // could submit the hidden instance's stale values and silently\n // discard the edit (#2453). `useIsMobile` is SSR-safe.\n return isMobile ? (\n <MobilePersonDetail zone1={zone1Content} zone2={zone2Content} />\n ) : (\n <CollapsibleZoneLayout\n pageType=\"person-v2\"\n entityName={personName}\n isDirty={isDirty}\n sections={zoneSections}\n zone1={zone1Content}\n zone2={zone2Content}\n />\n )\n })()}\n\n {/* UMES footer injection */}\n <InjectionSpot spotId={extensionPoints.hosts.personFooter.spotId} context={injectionContext} data={data} />\n\n {/* Schedule Activity Dialog \u2014 opened from PlannedActivities \"+ Schedule\" or other triggers */}\n <ScheduleActivityDialog\n open={scheduleDialogOpen}\n onClose={() => { setScheduleDialogOpen(false); setScheduleEditData(null) }}\n entityId={personId}\n entityName={personName}\n companyName={scheduleDialogCompanyName}\n entityType=\"person\"\n onActivityCreated={handleActivityCreated}\n editData={scheduleEditData}\n />\n {ConfirmDialogElement}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["personId"]
7
7
  }
@@ -215,6 +215,7 @@ async function loadDealSnapshot(em, id) {
215
215
  tenantId: deal.tenantId,
216
216
  organizationId: deal.organizationId
217
217
  });
218
+ const primaryPerson = peopleLinks.find((link) => link.isPrimary)?.person;
218
219
  return {
219
220
  deal: {
220
221
  id: deal.id,
@@ -239,6 +240,7 @@ async function loadDealSnapshot(em, id) {
239
240
  people: peopleLinks.map(
240
241
  (link) => typeof link.person === "string" ? link.person : link.person.id
241
242
  ),
243
+ primaryPersonEntityId: typeof primaryPerson === "string" ? primaryPerson : primaryPerson?.id ?? null,
242
244
  companies: companyLinks.map(
243
245
  (link) => typeof link.company === "string" ? link.company : link.company.id
244
246
  ),
@@ -258,17 +260,53 @@ function toNumericString(value) {
258
260
  if (value === void 0 || value === null) return null;
259
261
  return value.toString();
260
262
  }
261
- async function syncDealPeople(em, deal, personIds) {
262
- if (personIds === void 0) return;
263
+ async function syncDealPeople(em, deal, personIds, primaryPersonEntityId) {
264
+ if (personIds === void 0) {
265
+ if (primaryPersonEntityId === void 0) return;
266
+ const links = await em.find(CustomerDealPersonLink, { deal });
267
+ if (primaryPersonEntityId !== null && !links.some((link) => link.person.id === primaryPersonEntityId)) {
268
+ const { translate } = await resolveTranslations();
269
+ throw new CrudHttpError(400, {
270
+ error: translate(
271
+ "customers.errors.primaryPersonMustBeLinked",
272
+ "Primary person must be linked to the deal"
273
+ )
274
+ });
275
+ }
276
+ for (const link of links) {
277
+ link.isPrimary = false;
278
+ }
279
+ await em.flush();
280
+ if (primaryPersonEntityId !== null) {
281
+ const primaryLink = links.find((link) => link.person.id === primaryPersonEntityId);
282
+ if (primaryLink) primaryLink.isPrimary = true;
283
+ }
284
+ return;
285
+ }
286
+ const unique = Array.from(new Set(personIds ?? []));
287
+ if (primaryPersonEntityId !== void 0 && primaryPersonEntityId !== null && !unique.includes(primaryPersonEntityId)) {
288
+ const { translate } = await resolveTranslations();
289
+ throw new CrudHttpError(400, {
290
+ error: translate(
291
+ "customers.errors.primaryPersonMustBeLinked",
292
+ "Primary person must be linked to the deal"
293
+ )
294
+ });
295
+ }
296
+ let effectivePrimaryId = primaryPersonEntityId;
297
+ if (effectivePrimaryId === void 0) {
298
+ const existingPrimary = await em.findOne(CustomerDealPersonLink, { deal, isPrimary: true });
299
+ effectivePrimaryId = existingPrimary?.person?.id ?? null;
300
+ }
263
301
  await em.nativeDelete(CustomerDealPersonLink, { deal });
264
- if (!personIds || !personIds.length) return;
265
- const unique = Array.from(new Set(personIds));
302
+ if (!unique.length) return;
266
303
  for (const personId of unique) {
267
304
  const person = await requireCustomerEntity(em, personId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, "person", "Person not found");
268
305
  ensureSameScope(person, deal.organizationId, deal.tenantId);
269
306
  const link = em.create(CustomerDealPersonLink, {
270
307
  deal,
271
- person
308
+ person,
309
+ isPrimary: personId === effectivePrimaryId
272
310
  });
273
311
  em.persist(link);
274
312
  }
@@ -353,7 +391,7 @@ const createDealCommand = {
353
391
  transitionedByUserId: normalizedTransitionAuthorUserId
354
392
  });
355
393
  },
356
- () => syncDealPeople(em, deal, parsed.personIds ?? []),
394
+ () => syncDealPeople(em, deal, parsed.personIds ?? [], parsed.primaryPersonEntityId),
357
395
  () => syncDealCompanies(em, deal, parsed.companyIds ?? [])
358
396
  ], { transaction: true });
359
397
  const de = ctx.container.resolve("dataEngine");
@@ -446,7 +484,7 @@ const createDealCommand = {
446
484
  }
447
485
  const restoredDeal = deal;
448
486
  await withAtomicFlush(em, [
449
- () => syncDealPeople(em, restoredDeal, after.people),
487
+ () => syncDealPeople(em, restoredDeal, after.people, after.primaryPersonEntityId),
450
488
  () => syncDealCompanies(em, restoredDeal, after.companies),
451
489
  () => deleteDealStageTransitions(em, restoredDeal),
452
490
  () => restoreDealStageTransitions(em, restoredDeal, after.transitions)
@@ -584,7 +622,7 @@ const updateDealCommand = {
584
622
  transitionedByUserId: normalizedTransitionAuthorUserId
585
623
  });
586
624
  },
587
- () => syncDealPeople(em, record, parsed.personIds),
625
+ () => syncDealPeople(em, record, parsed.personIds, parsed.primaryPersonEntityId),
588
626
  () => syncDealCompanies(em, record, parsed.companyIds)
589
627
  ]
590
628
  });
@@ -709,7 +747,7 @@ const updateDealCommand = {
709
747
  transitionedByUserId: normalizedTransitionAuthorUserId
710
748
  });
711
749
  },
712
- () => syncDealPeople(em, deal, before.people),
750
+ () => syncDealPeople(em, deal, before.people, before.primaryPersonEntityId),
713
751
  () => syncDealCompanies(em, deal, before.companies)
714
752
  ], { transaction: true });
715
753
  const de = ctx.container.resolve("dataEngine");
@@ -823,7 +861,7 @@ const deleteDealCommand = {
823
861
  em.persist(deal);
824
862
  }
825
863
  await withAtomicFlush(em, [
826
- () => syncDealPeople(em, deal, before.people),
864
+ () => syncDealPeople(em, deal, before.people, before.primaryPersonEntityId),
827
865
  () => syncDealCompanies(em, deal, before.companies),
828
866
  () => deleteDealStageTransitions(em, deal),
829
867
  () => restoreDealStageTransitions(em, deal, before.transitions)