@open-mercato/core 0.6.1-develop.3246.1.dbef9d7392 → 0.6.1-develop.3260.1.dc719cac84

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 (130) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/authFixtures.js.map +1 -1
  3. package/dist/helpers/integration/authUi.js +10 -2
  4. package/dist/helpers/integration/authUi.js.map +2 -2
  5. package/dist/helpers/integration/salesUi.js +3 -1
  6. package/dist/helpers/integration/salesUi.js.map +2 -2
  7. package/dist/modules/api_docs/frontend/docs/api/Explorer.js +10 -1
  8. package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
  9. package/dist/modules/audit_logs/lib/display-helpers.js +28 -27
  10. package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
  11. package/dist/modules/auth/api/users/route.js +21 -3
  12. package/dist/modules/auth/api/users/route.js.map +2 -2
  13. package/dist/modules/auth/backend/users/[id]/edit/page.js +6 -1
  14. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  15. package/dist/modules/auth/backend/users/create/page.js +4 -1
  16. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  17. package/dist/modules/auth/backend/users/page.js +56 -2
  18. package/dist/modules/auth/backend/users/page.js.map +3 -3
  19. package/dist/modules/auth/commands/users.js +14 -0
  20. package/dist/modules/auth/commands/users.js.map +2 -2
  21. package/dist/modules/auth/data/validators.js +8 -0
  22. package/dist/modules/auth/data/validators.js.map +2 -2
  23. package/dist/modules/catalog/ai-agents.js +4 -0
  24. package/dist/modules/catalog/ai-agents.js.map +2 -2
  25. package/dist/modules/customers/ai-agents.js.map +2 -2
  26. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -1
  27. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  28. package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -9
  29. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  30. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -3
  31. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  32. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -1
  33. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  34. package/dist/modules/customers/components/PipelineSettings.js +108 -99
  35. package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
  36. package/dist/modules/customers/components/detail/AssignRoleDialog.js +13 -5
  37. package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
  38. package/dist/modules/customers/components/detail/EntityTagsDialog.js +10 -2
  39. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  40. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +15 -8
  41. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  42. package/dist/modules/customers/components/detail/RolesSection.js +35 -22
  43. package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
  44. package/dist/modules/customers/components/detail/TasksSection.js +2 -2
  45. package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
  46. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +73 -64
  47. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
  48. package/dist/modules/customers/components/linking/LinkEntityDialog.js +11 -2
  49. package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
  50. package/dist/modules/data_sync/backend/data-sync/page.js +2 -9
  51. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  52. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +14 -29
  53. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  54. package/dist/modules/dictionaries/components/DictionariesManager.js +10 -2
  55. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  56. package/dist/modules/entities/components/EncryptionManager.js +40 -17
  57. package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
  58. package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
  59. package/dist/modules/integrations/backend/integrations/[id]/page.js +79 -95
  60. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  61. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +49 -70
  62. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  63. package/dist/modules/planner/components/AvailabilityRuleSetForm.js +1 -1
  64. package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +1 -1
  65. package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -19
  66. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  67. package/dist/modules/resources/components/ResourceCrudForm.js +1 -1
  68. package/dist/modules/resources/components/ResourceCrudForm.js.map +1 -1
  69. package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -1
  70. package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
  71. package/dist/modules/sales/components/documents/ReturnDialog.js +11 -8
  72. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  73. package/dist/modules/staff/backend/staff/profile/create/page.js +1 -1
  74. package/dist/modules/staff/backend/staff/profile/create/page.js.map +2 -2
  75. package/dist/modules/staff/components/TeamForm.js +1 -1
  76. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  77. package/dist/modules/staff/components/TeamMemberForm.js +1 -1
  78. package/dist/modules/staff/components/TeamMemberForm.js.map +1 -1
  79. package/dist/modules/staff/components/TeamRoleForm.js +1 -1
  80. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  81. package/package.json +5 -5
  82. package/src/helpers/integration/authFixtures.ts +1 -1
  83. package/src/helpers/integration/authUi.ts +11 -2
  84. package/src/helpers/integration/salesUi.ts +10 -1
  85. package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +7 -3
  86. package/src/modules/audit_logs/lib/display-helpers.tsx +22 -14
  87. package/src/modules/auth/api/users/route.ts +22 -3
  88. package/src/modules/auth/backend/users/[id]/edit/page.tsx +9 -1
  89. package/src/modules/auth/backend/users/create/page.tsx +6 -2
  90. package/src/modules/auth/backend/users/page.tsx +60 -3
  91. package/src/modules/auth/commands/users.ts +15 -0
  92. package/src/modules/auth/data/validators.ts +8 -0
  93. package/src/modules/auth/i18n/de.json +4 -0
  94. package/src/modules/auth/i18n/en.json +4 -0
  95. package/src/modules/auth/i18n/es.json +4 -0
  96. package/src/modules/auth/i18n/pl.json +4 -0
  97. package/src/modules/catalog/ai-agents.ts +8 -49
  98. package/src/modules/customers/ai-agents.ts +4 -51
  99. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -1
  100. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +12 -13
  101. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +17 -13
  102. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -1
  103. package/src/modules/customers/components/PipelineSettings.tsx +95 -95
  104. package/src/modules/customers/components/detail/AssignRoleDialog.tsx +7 -4
  105. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +13 -8
  106. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +16 -12
  107. package/src/modules/customers/components/detail/RolesSection.tsx +34 -31
  108. package/src/modules/customers/components/detail/TasksSection.tsx +16 -8
  109. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +77 -51
  110. package/src/modules/customers/components/linking/LinkEntityDialog.tsx +7 -3
  111. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -7
  112. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -54
  113. package/src/modules/dictionaries/components/DictionariesManager.tsx +7 -4
  114. package/src/modules/entities/components/EncryptionManager.tsx +50 -21
  115. package/src/modules/inbox_ops/lib/llmProvider.ts +10 -0
  116. package/src/modules/integrations/backend/integrations/[id]/page.tsx +101 -146
  117. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +60 -103
  118. package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +1 -1
  119. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +17 -17
  120. package/src/modules/resources/components/ResourceCrudForm.tsx +1 -1
  121. package/src/modules/resources/components/ResourceTypeCrudForm.tsx +1 -1
  122. package/src/modules/sales/components/documents/ReturnDialog.tsx +10 -7
  123. package/src/modules/sales/i18n/de.json +2 -0
  124. package/src/modules/sales/i18n/en.json +2 -0
  125. package/src/modules/sales/i18n/es.json +2 -0
  126. package/src/modules/sales/i18n/pl.json +2 -0
  127. package/src/modules/staff/backend/staff/profile/create/page.tsx +1 -1
  128. package/src/modules/staff/components/TeamForm.tsx +1 -1
  129. package/src/modules/staff/components/TeamMemberForm.tsx +1 -1
  130. package/src/modules/staff/components/TeamRoleForm.tsx +1 -1
@@ -11,8 +11,10 @@ import {
11
11
  SelectTrigger,
12
12
  SelectValue
13
13
  } from "@open-mercato/ui/primitives/select";
14
+ import { Layers, MoveRight, Workflow } from "lucide-react";
14
15
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
15
16
  import { ErrorNotice } from "@open-mercato/ui/primitives/ErrorNotice";
17
+ import { EmptyState } from "@open-mercato/ui/primitives/empty-state";
16
18
  import { apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
17
19
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
18
20
  import { useT } from "@open-mercato/shared/lib/i18n/context";
@@ -399,7 +401,14 @@ function SalesPipelinePage() {
399
401
  ] })
400
402
  ] })
401
403
  ] }),
402
- !selectedPipelineId ? /* @__PURE__ */ jsx("div", { className: "flex h-[50vh] items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: translate("customers.deals.pipeline.noPipeline", "No pipeline selected. Create a pipeline in settings.") }) }) : dealsQuery.isLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-[50vh] items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) : dealsQuery.isError ? /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsx(
404
+ !selectedPipelineId ? /* @__PURE__ */ jsx(
405
+ EmptyState,
406
+ {
407
+ icon: /* @__PURE__ */ jsx(Workflow, { className: "h-8 w-8", "aria-hidden": "true" }),
408
+ title: translate("customers.deals.pipeline.noPipeline", "No pipeline selected. Create a pipeline in settings."),
409
+ className: "h-[50vh] w-full"
410
+ }
411
+ ) : dealsQuery.isLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-[50vh] items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) : dealsQuery.isError ? /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsx(
403
412
  ErrorNotice,
404
413
  {
405
414
  message: dealsQuery.error instanceof Error ? dealsQuery.error.message : translate("customers.deals.pipeline.loadError", "Failed to load deals.")
@@ -410,7 +419,14 @@ function SalesPipelinePage() {
410
419
  "Showing the first {count} deals. Refine your filters to see more.",
411
420
  { count: deals.length }
412
421
  ) }) : null,
413
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 pb-6 md:flex-row md:overflow-x-auto", children: stages.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-[50vh] w-full items-center justify-center rounded-lg border border-dashed border-border bg-muted/30", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: translate("customers.deals.pipeline.noStages", "Define pipeline stages to start tracking deals.") }) }) : stages.map((stage) => {
422
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 pb-6 md:flex-row md:overflow-x-auto", children: stages.length === 0 ? /* @__PURE__ */ jsx(
423
+ EmptyState,
424
+ {
425
+ icon: /* @__PURE__ */ jsx(Layers, { className: "h-8 w-8", "aria-hidden": "true" }),
426
+ title: translate("customers.deals.pipeline.noStages", "Define pipeline stages to start tracking deals."),
427
+ className: "h-[50vh] w-full"
428
+ }
429
+ ) : stages.map((stage) => {
414
430
  const stageKey = stage.value ?? null;
415
431
  const laneDeals = groupedDeals.get(stageKey) ?? [];
416
432
  const sortedLaneDeals = sortDeals(laneDeals, sortBy);
@@ -423,7 +439,14 @@ function SalesPipelinePage() {
423
439
  onDrop: handleDrop(stage),
424
440
  children: [
425
441
  renderLaneHeader(stage, laneDeals.length),
426
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto px-4 py-3", children: sortedLaneDeals.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-md border border-dashed border-border bg-muted/30 p-4 text-center text-xs text-muted-foreground", children: translate("customers.deals.pipeline.emptyLane", "No deals in this stage yet.") }) : sortedLaneDeals.map((deal) => {
442
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto px-4 py-3", children: sortedLaneDeals.length === 0 ? /* @__PURE__ */ jsx(
443
+ EmptyState,
444
+ {
445
+ size: "sm",
446
+ icon: /* @__PURE__ */ jsx(MoveRight, { className: "h-6 w-6", "aria-hidden": "true" }),
447
+ title: translate("customers.deals.pipeline.emptyLane", "No deals in this stage yet.")
448
+ }
449
+ ) : sortedLaneDeals.map((deal) => {
427
450
  const isDragging = draggingId === deal.id || pendingDealId === deal.id && updateStageMutation.isPending;
428
451
  const valueLabel = formatCurrency(
429
452
  deal.valueAmount,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/backend/customers/deals/pipeline/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { ErrorNotice } from '@open-mercato/ui/primitives/ErrorNotice'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\n\ntype DealAssociation = { id: string; label: string }\n\ntype DealRecord = {\n id: string\n title: string\n status: string | null\n pipelineStage: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: number | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: string | null\n expectedCloseAtTs: number | null\n createdAt: string | null\n createdAtTs: number | null\n updatedAt: string | null\n people: DealAssociation[]\n companies: DealAssociation[]\n}\n\ntype DealsQueryData = {\n deals: DealRecord[]\n total: number\n}\n\ntype StageDefinition = {\n id: string\n value: string | null\n label: string\n color: string | null\n icon: string | null\n}\n\ntype SortOption = 'probability' | 'createdAt' | 'expectedCloseAt'\n\ntype PipelineRecord = { id: string; name: string; isDefault: boolean }\ntype PipelineStageRecord = { id: string; label: string; order: number; pipelineId: string }\n\nconst DEALS_QUERY_LIMIT = 100\n\nconst dealsQueryKey = (scopeVersion: number, pipelineId: string | null) =>\n ['customers', 'deals', 'pipeline', `scope:${scopeVersion}`, `pipeline:${pipelineId ?? 'none'}`] as const\n\nconst sortOptions: SortOption[] = ['probability', 'createdAt', 'expectedCloseAt']\n\nfunction normalizeAmount(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = Number(trimmed)\n return Number.isFinite(parsed) ? parsed : null\n }\n return null\n}\n\nfunction normalizeProbability(value: unknown): number | null {\n const parsed = normalizeAmount(value)\n if (parsed === null) return null\n if (parsed < 0) return 0\n if (parsed > 100) return 100\n return Math.round(parsed)\n}\n\nfunction normalizeTimestamp(value: unknown): { iso: string | null; ts: number | null } {\n if (typeof value !== 'string' || !value.trim().length) return { iso: null, ts: null }\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return { iso: null, ts: null }\n return { iso: date.toISOString(), ts: date.getTime() }\n}\n\nfunction buildStageDefinitionsFromPipelineStages(\n pipelineStages: PipelineStageRecord[],\n deals: DealRecord[],\n t: ReturnType<typeof useT>,\n): StageDefinition[] {\n const result: StageDefinition[] = pipelineStages\n .slice()\n .sort((a, b) => a.order - b.order)\n .map((stage) => ({\n id: stage.id,\n value: stage.id,\n label: stage.label,\n color: null,\n icon: null,\n }))\n\n const knownIds = new Set(pipelineStages.map((s) => s.id))\n const hasUnassigned = deals.some((deal) => !deal.pipelineStageId || !knownIds.has(deal.pipelineStageId))\n if (hasUnassigned) {\n result.push({\n id: 'stage:__unassigned',\n value: null,\n label: translateWithFallback(t, 'customers.deals.pipeline.unassigned', 'No stage'),\n color: null,\n icon: null,\n })\n }\n\n return result\n}\n\nfunction createDealMap(deals: DealRecord[]): Map<string, DealRecord> {\n return deals.reduce<Map<string, DealRecord>>((acc, deal) => acc.set(deal.id, deal), new Map())\n}\n\nfunction groupDealsByStageId(deals: DealRecord[]): Map<string | null, DealRecord[]> {\n const byStage = new Map<string | null, DealRecord[]>()\n deals.forEach((deal) => {\n const stageKey = deal.pipelineStageId ?? null\n const bucket = byStage.get(stageKey) ?? []\n bucket.push(deal)\n byStage.set(stageKey, bucket)\n })\n return byStage\n}\n\nfunction sortDeals(deals: DealRecord[], option: SortOption): DealRecord[] {\n const sorted = [...deals]\n sorted.sort((a, b) => {\n if (option === 'probability') {\n const ap = typeof a.probability === 'number' ? a.probability : -1\n const bp = typeof b.probability === 'number' ? b.probability : -1\n if (ap !== bp) return bp - ap\n }\n if (option === 'expectedCloseAt') {\n const at = typeof a.expectedCloseAtTs === 'number' ? a.expectedCloseAtTs : Number.POSITIVE_INFINITY\n const bt = typeof b.expectedCloseAtTs === 'number' ? b.expectedCloseAtTs : Number.POSITIVE_INFINITY\n if (at !== bt) return at - bt\n }\n const at = typeof a.createdAtTs === 'number' ? a.createdAtTs : Number.NEGATIVE_INFINITY\n const bt = typeof b.createdAtTs === 'number' ? b.createdAtTs : Number.NEGATIVE_INFINITY\n if (option === 'createdAt') {\n if (at !== bt) return bt - at\n } else if (option === 'expectedCloseAt' || option === 'probability') {\n if (at !== bt) return bt - at\n }\n return a.title.localeCompare(b.title, undefined, { sensitivity: 'base' })\n })\n return sorted\n}\n\nfunction formatCurrency(amount: number | null, currency: string | null, fallback: string): string {\n if (amount === null || Number.isNaN(amount)) return fallback\n const code = currency && currency.length === 3 ? currency.toUpperCase() : 'USD'\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency: code,\n maximumFractionDigits: 2,\n }).format(amount)\n } catch {\n return `${code} ${amount.toFixed(2)}`\n }\n}\n\nfunction formatProbability(probability: number | null, fallback: string): string {\n if (typeof probability !== 'number' || Number.isNaN(probability)) return fallback\n return `${probability}%`\n}\n\nexport default function SalesPipelinePage(): React.ReactElement {\n const t = useT()\n const translate = React.useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>) => {\n const value = translateWithFallback(t, key, fallback, params)\n if (value === fallback && params) {\n return fallback.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (match, doubleToken, singleToken) => {\n const token = (doubleToken ?? singleToken) as string | undefined\n if (!token) return match\n const replacement = params[token]\n if (replacement === undefined) {\n return doubleToken ? `{{${token}}}` : `{${token}}`\n }\n return String(replacement)\n })\n }\n return value\n },\n [t],\n )\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n const [sortBy, setSortBy] = React.useState<SortOption>('probability')\n const [pendingDealId, setPendingDealId] = React.useState<string | null>(null)\n const [selectedPipelineId, setSelectedPipelineId] = React.useState<string | null>(null)\n\n const pipelinesQuery = useQuery<PipelineRecord[]>({\n queryKey: ['customers', 'pipelines', `scope:${scopeVersion}`],\n staleTime: 60_000,\n queryFn: async () => {\n const payload = await readApiResultOrThrow<{ items: PipelineRecord[] }>(\n '/api/customers/pipelines',\n undefined,\n { errorMessage: translate('customers.deals.pipeline.loadError', 'Failed to load pipelines.') },\n )\n return payload?.items ?? []\n },\n })\n\n React.useEffect(() => {\n if (selectedPipelineId) return\n const pipelines = pipelinesQuery.data\n if (!pipelines || !pipelines.length) return\n const defaultPipeline = pipelines.find((p) => p.isDefault) ?? pipelines[0]\n if (defaultPipeline) setSelectedPipelineId(defaultPipeline.id)\n }, [pipelinesQuery.data, selectedPipelineId])\n\n const stagesQuery = useQuery<PipelineStageRecord[]>({\n queryKey: ['customers', 'pipeline-stages', `scope:${scopeVersion}`, `pipeline:${selectedPipelineId}`],\n enabled: !!selectedPipelineId,\n staleTime: 30_000,\n queryFn: async () => {\n const payload = await readApiResultOrThrow<{ items: PipelineStageRecord[] }>(\n `/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(selectedPipelineId!)}`,\n undefined,\n { errorMessage: translate('customers.deals.pipeline.loadError', 'Failed to load stages.') },\n )\n return payload?.items ?? []\n },\n })\n\n const dealsKey = React.useMemo(() => dealsQueryKey(scopeVersion, selectedPipelineId), [scopeVersion, selectedPipelineId])\n\n const dealsQuery = useQuery<DealsQueryData>({\n queryKey: dealsKey,\n enabled: !!selectedPipelineId,\n staleTime: 30_000,\n queryFn: async () => {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', String(DEALS_QUERY_LIMIT))\n search.set('sortField', 'createdAt')\n search.set('sortDir', 'desc')\n if (selectedPipelineId) search.set('pipelineId', selectedPipelineId)\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/deals?${search.toString()}`,\n undefined,\n { errorMessage: translate('customers.deals.pipeline.loadError', 'Failed to load deals.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n const deals: DealRecord[] = []\n items.forEach((item) => {\n if (!item || typeof item !== 'object') return\n const data = item as Record<string, unknown>\n const id = typeof data.id === 'string' ? data.id : null\n if (!id) return\n const title =\n typeof data.title === 'string' && data.title.trim().length\n ? data.title.trim()\n : translate('customers.deals.pipeline.untitled', 'Untitled deal')\n const status =\n typeof data.status === 'string' && data.status.trim().length ? data.status.trim() : null\n const stage =\n typeof data.pipeline_stage === 'string' && data.pipeline_stage.trim().length\n ? data.pipeline_stage.trim()\n : null\n const amount = normalizeAmount(data.value_amount)\n const currency =\n typeof data.value_currency === 'string' && data.value_currency.trim().length\n ? data.value_currency.trim().toUpperCase()\n : null\n const probability = normalizeProbability(data.probability)\n const expected = normalizeTimestamp(data.expected_close_at)\n const created = normalizeTimestamp(data.created_at)\n const updated = normalizeTimestamp(data.updated_at)\n const rawPeople = Array.isArray(data.people) ? data.people : []\n const people: DealAssociation[] = rawPeople\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const ref = entry as Record<string, unknown>\n const personId = typeof ref.id === 'string' ? ref.id : null\n if (!personId) return null\n const label =\n typeof ref.label === 'string' && ref.label.trim().length\n ? ref.label.trim()\n : personId\n return { id: personId, label }\n })\n .filter((entry): entry is DealAssociation => !!entry)\n const rawCompanies = Array.isArray(data.companies) ? data.companies : []\n const companies: DealAssociation[] = rawCompanies\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const ref = entry as Record<string, unknown>\n const companyId = typeof ref.id === 'string' ? ref.id : null\n if (!companyId) return null\n const label =\n typeof ref.label === 'string' && ref.label.trim().length\n ? ref.label.trim()\n : companyId\n return { id: companyId, label }\n })\n .filter((entry): entry is DealAssociation => !!entry)\n deals.push({\n id,\n title,\n status,\n pipelineStage: stage,\n pipelineId: typeof data.pipeline_id === 'string' ? data.pipeline_id : null,\n pipelineStageId: typeof data.pipeline_stage_id === 'string' ? data.pipeline_stage_id : null,\n valueAmount: amount,\n valueCurrency: currency,\n probability,\n expectedCloseAt: expected.iso,\n expectedCloseAtTs: expected.ts,\n createdAt: created.iso,\n createdAtTs: created.ts,\n updatedAt: updated.iso,\n people,\n companies,\n })\n })\n\n const total = typeof payload?.total === 'number' ? payload.total : deals.length\n return { deals, total }\n },\n })\n\n const deals = dealsQuery.data?.deals ?? []\n const total = dealsQuery.data?.total ?? deals.length\n const dealMap = React.useMemo(() => createDealMap(deals), [deals])\n const groupedDeals = React.useMemo(() => groupDealsByStageId(deals), [deals])\n const stages = React.useMemo(\n () => buildStageDefinitionsFromPipelineStages(stagesQuery.data ?? [], deals, t),\n [stagesQuery.data, deals, t],\n )\n\n const dateFormatter = React.useMemo(\n () =>\n new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n }),\n [],\n )\n\n const updateStageMutation = useMutation({\n mutationFn: async ({ id, pipelineStageId }: { id: string; pipelineStageId: string }) => {\n await apiCallOrThrow(\n '/api/customers/deals',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id, pipelineStageId }),\n },\n { errorMessage: translate('customers.deals.pipeline.moveError', 'Failed to update deal stage.') },\n )\n return { id, pipelineStageId }\n },\n onMutate: async ({ id, pipelineStageId }) => {\n setPendingDealId(id)\n await queryClient.cancelQueries({ queryKey: dealsKey })\n const previous = queryClient.getQueryData<DealsQueryData>(dealsKey)\n if (previous) {\n const nextDeals = previous.deals.map((deal) =>\n deal.id === id ? { ...deal, pipelineStageId } : deal,\n )\n queryClient.setQueryData<DealsQueryData>(dealsKey, { ...previous, deals: nextDeals })\n }\n return { previous }\n },\n onError: (error, _variables, context) => {\n if (context?.previous) {\n queryClient.setQueryData<DealsQueryData>(dealsKey, context.previous)\n }\n const message =\n error instanceof Error && error.message\n ? error.message\n : translate('customers.deals.pipeline.moveError', 'Failed to update deal stage.')\n flash(message, 'error')\n },\n onSuccess: () => {\n flash(translate('customers.deals.pipeline.moveSuccess', 'Deal updated.'), 'success')\n },\n onSettled: () => {\n setPendingDealId(null)\n queryClient.invalidateQueries({ queryKey: dealsKey }).catch(() => {})\n },\n })\n\n const [draggingId, setDraggingId] = React.useState<string | null>(null)\n const [activeLane, setActiveLane] = React.useState<string | null>(null)\n const handleActionClick = React.useCallback((event: React.MouseEvent) => {\n event.stopPropagation()\n }, [])\n\n const handleSortChange = React.useCallback((value: string) => {\n if (sortOptions.includes(value as SortOption)) setSortBy(value as SortOption)\n }, [])\n\n const handleDragStart = React.useCallback((dealId: string) => {\n setDraggingId(dealId)\n }, [])\n\n const handleDragEnd = React.useCallback(() => {\n setDraggingId(null)\n setActiveLane(null)\n }, [])\n\n const handleDrop = React.useCallback(\n (stage: StageDefinition) => async (event: React.DragEvent<HTMLDivElement>) => {\n event.preventDefault()\n setActiveLane(null)\n const dealId = event.dataTransfer.getData('text/plain') || draggingId\n if (!dealId) return\n const deal = dealMap.get(dealId)\n if (!deal) return\n if (stage.value === null) {\n flash(\n translate('customers.deals.pipeline.unassignedDisabled', 'Moving to \"No stage\" is not supported.'),\n 'info',\n )\n return\n }\n if (deal.pipelineStageId === stage.value) return\n updateStageMutation.mutate({ id: dealId, pipelineStageId: stage.value })\n },\n [dealMap, draggingId, translate, updateStageMutation],\n )\n\n const handleDragOver = React.useCallback(\n (stageId: string) => (event: React.DragEvent<HTMLDivElement>) => {\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n if (activeLane !== stageId) setActiveLane(stageId)\n },\n [activeLane],\n )\n\n const renderLaneHeader = (stage: StageDefinition, count: number) => {\n return (\n <div className=\"flex items-center justify-between gap-3 border-b border-border px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">{stage.label}</span>\n <span className=\"text-xs text-muted-foreground\">\n {translate('customers.deals.pipeline.countLabel', 'Deals: {count}', { count })}\n </span>\n </div>\n </div>\n </div>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-col\">\n <h1 className=\"text-xl font-semibold text-foreground\">\n {translate('customers.deals.pipeline.title', 'Sales Pipeline')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {translate(\n 'customers.deals.pipeline.subtitle',\n 'Track deals by pipeline stage and drag them between lanes to update progress.',\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n {pipelinesQuery.data && pipelinesQuery.data.length > 0 ? (\n <label className=\"flex items-center gap-2 text-sm font-medium text-muted-foreground\">\n <span>{translate('customers.deals.pipeline.switch.label', 'Pipeline')}</span>\n <Select\n value={selectedPipelineId || undefined}\n onValueChange={(value) => setSelectedPipelineId(value || null)}\n >\n <SelectTrigger className=\"w-auto min-w-[12rem]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {pipelinesQuery.data.map((p) => (\n <SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n ) : null}\n <Link\n href=\"/backend/config/customers/pipeline-stages\"\n className=\"text-sm font-medium text-primary hover:underline\"\n >\n {translate('customers.deals.pipeline.manageStages', 'Manage stages')}\n </Link>\n <label className=\"flex items-center gap-2 text-sm font-medium text-muted-foreground\">\n <span>{translate('customers.deals.pipeline.sort.label', 'Sort by')}</span>\n <Select value={sortBy} onValueChange={handleSortChange}>\n <SelectTrigger className=\"w-auto min-w-[14rem]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"probability\">\n {translate('customers.deals.pipeline.sort.probability', 'Probability (high to low)')}\n </SelectItem>\n <SelectItem value=\"createdAt\">\n {translate('customers.deals.pipeline.sort.createdAt', 'Created (newest first)')}\n </SelectItem>\n <SelectItem value=\"expectedCloseAt\">\n {translate('customers.deals.pipeline.sort.expectedCloseAt', 'Expected close (soonest first)')}\n </SelectItem>\n </SelectContent>\n </Select>\n </label>\n </div>\n </div>\n\n {!selectedPipelineId ? (\n <div className=\"flex h-[50vh] items-center justify-center\">\n <span className=\"text-sm text-muted-foreground\">\n {translate('customers.deals.pipeline.noPipeline', 'No pipeline selected. Create a pipeline in settings.')}\n </span>\n </div>\n ) : dealsQuery.isLoading ? (\n <div className=\"flex h-[50vh] items-center justify-center\">\n <Spinner />\n </div>\n ) : dealsQuery.isError ? (\n <div className=\"max-w-xl\">\n <ErrorNotice\n message={\n dealsQuery.error instanceof Error\n ? dealsQuery.error.message\n : translate('customers.deals.pipeline.loadError', 'Failed to load deals.')\n }\n />\n </div>\n ) : (\n <div className=\"flex flex-col gap-3\">\n {total > deals.length ? (\n <div className=\"rounded-md border border-border bg-muted/30 px-4 py-2 text-sm text-muted-foreground\">\n {translate(\n 'customers.deals.pipeline.limitNotice',\n 'Showing the first {count} deals. Refine your filters to see more.',\n { count: deals.length },\n )}\n </div>\n ) : null}\n\n <div className=\"flex flex-col gap-4 pb-6 md:flex-row md:overflow-x-auto\">\n {stages.length === 0 ? (\n <div className=\"flex h-[50vh] w-full items-center justify-center rounded-lg border border-dashed border-border bg-muted/30\">\n <span className=\"text-sm text-muted-foreground\">\n {translate('customers.deals.pipeline.noStages', 'Define pipeline stages to start tracking deals.')}\n </span>\n </div>\n ) : (\n stages.map((stage) => {\n const stageKey = stage.value ?? null\n const laneDeals = groupedDeals.get(stageKey) ?? []\n const sortedLaneDeals = sortDeals(laneDeals, sortBy)\n const isActive = activeLane === stage.id\n return (\n <div\n key={stage.id}\n className={`flex min-h-[60vh] w-full flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card shadow-sm transition-all md:w-72 md:flex-none ${\n isActive ? 'ring-2 ring-ring/40' : ''\n }`}\n onDragOver={handleDragOver(stage.id)}\n onDrop={handleDrop(stage)}\n >\n {renderLaneHeader(stage, laneDeals.length)}\n <div className=\"flex flex-1 flex-col gap-3 overflow-y-auto px-4 py-3\">\n {sortedLaneDeals.length === 0 ? (\n <div className=\"rounded-md border border-dashed border-border bg-muted/30 p-4 text-center text-xs text-muted-foreground\">\n {translate('customers.deals.pipeline.emptyLane', 'No deals in this stage yet.')}\n </div>\n ) : (\n sortedLaneDeals.map((deal) => {\n const isDragging = draggingId === deal.id\n || (pendingDealId === deal.id && updateStageMutation.isPending)\n const valueLabel = formatCurrency(\n deal.valueAmount,\n deal.valueCurrency,\n translate('customers.deals.list.noValue', 'No value assigned'),\n )\n const probabilityLabel = formatProbability(\n deal.probability,\n translate('customers.deals.pipeline.noProbability', 'N/A'),\n )\n const expectedLabel = deal.expectedCloseAt\n ? dateFormatter.format(new Date(deal.expectedCloseAt))\n : translate('customers.deals.pipeline.noExpectedClose', 'No date')\n return (\n <div\n key={deal.id}\n className={`group flex cursor-grab flex-col gap-2 rounded-md border border-border bg-background p-4 shadow-xs transition ${\n isDragging ? 'opacity-50' : 'hover:shadow-sm'\n }`}\n draggable\n onDragStart={(event) => {\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', deal.id)\n handleDragStart(deal.id)\n }}\n onDragEnd={handleDragEnd}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex flex-col\">\n <span className=\"line-clamp-2 text-sm font-medium text-foreground\">\n {deal.title}\n </span>\n {deal.status ? (\n <span className=\"text-xs uppercase tracking-wide text-muted-foreground\">\n {deal.status}\n </span>\n ) : null}\n </div>\n {pendingDealId === deal.id && updateStageMutation.isPending ? (\n <Spinner className=\"size-4\" />\n ) : null}\n </div>\n <div className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n <div className=\"flex items-center justify-between gap-2\">\n <span>{translate('customers.deals.pipeline.card.value', 'Value')}</span>\n <span className=\"font-medium text-foreground\">{valueLabel}</span>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <span>{translate('customers.deals.pipeline.card.probability', 'Probability')}</span>\n <span className=\"font-medium text-foreground\">{probabilityLabel}</span>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <span>{translate('customers.deals.pipeline.card.expectedClose', 'Expected close')}</span>\n <span className=\"font-medium text-foreground\">{expectedLabel}</span>\n </div>\n </div>\n <div className=\"mt-1 flex flex-wrap gap-2 text-xs\">\n <Link\n href={`/backend/customers/deals/${deal.id}`}\n className=\"font-medium text-primary hover:underline\"\n draggable={false}\n onClick={handleActionClick}\n >\n {translate('customers.deals.pipeline.actions.openDeal', 'Open deal')}\n </Link>\n </div>\n {deal.people.length ? (\n <div className=\"flex flex-wrap gap-2\">\n {deal.people.map((person) => (\n <Link\n key={person.id}\n className=\"rounded-full bg-primary/5 px-3 py-1 text-xs text-primary transition-colors hover:bg-primary/10\"\n href={`/backend/customers/people-v2/${person.id}`}\n draggable={false}\n onClick={handleActionClick}\n >\n {person.label}\n </Link>\n ))}\n </div>\n ) : null}\n {deal.companies.length ? (\n <div className=\"flex flex-wrap gap-2\">\n {deal.companies.map((company) => (\n <Link\n key={company.id}\n className=\"rounded-full bg-secondary/10 px-3 py-1 text-xs text-secondary-foreground transition-colors hover:bg-secondary/20\"\n href={`/backend/customers/companies-v2/${company.id}`}\n draggable={false}\n onClick={handleActionClick}\n >\n {company.label}\n </Link>\n ))}\n </div>\n ) : null}\n </div>\n )\n })\n )}\n </div>\n </div>\n )\n })\n )}\n </div>\n </div>\n )}\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 Link from 'next/link'\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Layers, MoveRight, Workflow } from 'lucide-react'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { ErrorNotice } from '@open-mercato/ui/primitives/ErrorNotice'\nimport { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\n\ntype DealAssociation = { id: string; label: string }\n\ntype DealRecord = {\n id: string\n title: string\n status: string | null\n pipelineStage: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: number | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: string | null\n expectedCloseAtTs: number | null\n createdAt: string | null\n createdAtTs: number | null\n updatedAt: string | null\n people: DealAssociation[]\n companies: DealAssociation[]\n}\n\ntype DealsQueryData = {\n deals: DealRecord[]\n total: number\n}\n\ntype StageDefinition = {\n id: string\n value: string | null\n label: string\n color: string | null\n icon: string | null\n}\n\ntype SortOption = 'probability' | 'createdAt' | 'expectedCloseAt'\n\ntype PipelineRecord = { id: string; name: string; isDefault: boolean }\ntype PipelineStageRecord = { id: string; label: string; order: number; pipelineId: string }\n\nconst DEALS_QUERY_LIMIT = 100\n\nconst dealsQueryKey = (scopeVersion: number, pipelineId: string | null) =>\n ['customers', 'deals', 'pipeline', `scope:${scopeVersion}`, `pipeline:${pipelineId ?? 'none'}`] as const\n\nconst sortOptions: SortOption[] = ['probability', 'createdAt', 'expectedCloseAt']\n\nfunction normalizeAmount(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = Number(trimmed)\n return Number.isFinite(parsed) ? parsed : null\n }\n return null\n}\n\nfunction normalizeProbability(value: unknown): number | null {\n const parsed = normalizeAmount(value)\n if (parsed === null) return null\n if (parsed < 0) return 0\n if (parsed > 100) return 100\n return Math.round(parsed)\n}\n\nfunction normalizeTimestamp(value: unknown): { iso: string | null; ts: number | null } {\n if (typeof value !== 'string' || !value.trim().length) return { iso: null, ts: null }\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return { iso: null, ts: null }\n return { iso: date.toISOString(), ts: date.getTime() }\n}\n\nfunction buildStageDefinitionsFromPipelineStages(\n pipelineStages: PipelineStageRecord[],\n deals: DealRecord[],\n t: ReturnType<typeof useT>,\n): StageDefinition[] {\n const result: StageDefinition[] = pipelineStages\n .slice()\n .sort((a, b) => a.order - b.order)\n .map((stage) => ({\n id: stage.id,\n value: stage.id,\n label: stage.label,\n color: null,\n icon: null,\n }))\n\n const knownIds = new Set(pipelineStages.map((s) => s.id))\n const hasUnassigned = deals.some((deal) => !deal.pipelineStageId || !knownIds.has(deal.pipelineStageId))\n if (hasUnassigned) {\n result.push({\n id: 'stage:__unassigned',\n value: null,\n label: translateWithFallback(t, 'customers.deals.pipeline.unassigned', 'No stage'),\n color: null,\n icon: null,\n })\n }\n\n return result\n}\n\nfunction createDealMap(deals: DealRecord[]): Map<string, DealRecord> {\n return deals.reduce<Map<string, DealRecord>>((acc, deal) => acc.set(deal.id, deal), new Map())\n}\n\nfunction groupDealsByStageId(deals: DealRecord[]): Map<string | null, DealRecord[]> {\n const byStage = new Map<string | null, DealRecord[]>()\n deals.forEach((deal) => {\n const stageKey = deal.pipelineStageId ?? null\n const bucket = byStage.get(stageKey) ?? []\n bucket.push(deal)\n byStage.set(stageKey, bucket)\n })\n return byStage\n}\n\nfunction sortDeals(deals: DealRecord[], option: SortOption): DealRecord[] {\n const sorted = [...deals]\n sorted.sort((a, b) => {\n if (option === 'probability') {\n const ap = typeof a.probability === 'number' ? a.probability : -1\n const bp = typeof b.probability === 'number' ? b.probability : -1\n if (ap !== bp) return bp - ap\n }\n if (option === 'expectedCloseAt') {\n const at = typeof a.expectedCloseAtTs === 'number' ? a.expectedCloseAtTs : Number.POSITIVE_INFINITY\n const bt = typeof b.expectedCloseAtTs === 'number' ? b.expectedCloseAtTs : Number.POSITIVE_INFINITY\n if (at !== bt) return at - bt\n }\n const at = typeof a.createdAtTs === 'number' ? a.createdAtTs : Number.NEGATIVE_INFINITY\n const bt = typeof b.createdAtTs === 'number' ? b.createdAtTs : Number.NEGATIVE_INFINITY\n if (option === 'createdAt') {\n if (at !== bt) return bt - at\n } else if (option === 'expectedCloseAt' || option === 'probability') {\n if (at !== bt) return bt - at\n }\n return a.title.localeCompare(b.title, undefined, { sensitivity: 'base' })\n })\n return sorted\n}\n\nfunction formatCurrency(amount: number | null, currency: string | null, fallback: string): string {\n if (amount === null || Number.isNaN(amount)) return fallback\n const code = currency && currency.length === 3 ? currency.toUpperCase() : 'USD'\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency: code,\n maximumFractionDigits: 2,\n }).format(amount)\n } catch {\n return `${code} ${amount.toFixed(2)}`\n }\n}\n\nfunction formatProbability(probability: number | null, fallback: string): string {\n if (typeof probability !== 'number' || Number.isNaN(probability)) return fallback\n return `${probability}%`\n}\n\nexport default function SalesPipelinePage(): React.ReactElement {\n const t = useT()\n const translate = React.useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>) => {\n const value = translateWithFallback(t, key, fallback, params)\n if (value === fallback && params) {\n return fallback.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (match, doubleToken, singleToken) => {\n const token = (doubleToken ?? singleToken) as string | undefined\n if (!token) return match\n const replacement = params[token]\n if (replacement === undefined) {\n return doubleToken ? `{{${token}}}` : `{${token}}`\n }\n return String(replacement)\n })\n }\n return value\n },\n [t],\n )\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n const [sortBy, setSortBy] = React.useState<SortOption>('probability')\n const [pendingDealId, setPendingDealId] = React.useState<string | null>(null)\n const [selectedPipelineId, setSelectedPipelineId] = React.useState<string | null>(null)\n\n const pipelinesQuery = useQuery<PipelineRecord[]>({\n queryKey: ['customers', 'pipelines', `scope:${scopeVersion}`],\n staleTime: 60_000,\n queryFn: async () => {\n const payload = await readApiResultOrThrow<{ items: PipelineRecord[] }>(\n '/api/customers/pipelines',\n undefined,\n { errorMessage: translate('customers.deals.pipeline.loadError', 'Failed to load pipelines.') },\n )\n return payload?.items ?? []\n },\n })\n\n React.useEffect(() => {\n if (selectedPipelineId) return\n const pipelines = pipelinesQuery.data\n if (!pipelines || !pipelines.length) return\n const defaultPipeline = pipelines.find((p) => p.isDefault) ?? pipelines[0]\n if (defaultPipeline) setSelectedPipelineId(defaultPipeline.id)\n }, [pipelinesQuery.data, selectedPipelineId])\n\n const stagesQuery = useQuery<PipelineStageRecord[]>({\n queryKey: ['customers', 'pipeline-stages', `scope:${scopeVersion}`, `pipeline:${selectedPipelineId}`],\n enabled: !!selectedPipelineId,\n staleTime: 30_000,\n queryFn: async () => {\n const payload = await readApiResultOrThrow<{ items: PipelineStageRecord[] }>(\n `/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(selectedPipelineId!)}`,\n undefined,\n { errorMessage: translate('customers.deals.pipeline.loadError', 'Failed to load stages.') },\n )\n return payload?.items ?? []\n },\n })\n\n const dealsKey = React.useMemo(() => dealsQueryKey(scopeVersion, selectedPipelineId), [scopeVersion, selectedPipelineId])\n\n const dealsQuery = useQuery<DealsQueryData>({\n queryKey: dealsKey,\n enabled: !!selectedPipelineId,\n staleTime: 30_000,\n queryFn: async () => {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', String(DEALS_QUERY_LIMIT))\n search.set('sortField', 'createdAt')\n search.set('sortDir', 'desc')\n if (selectedPipelineId) search.set('pipelineId', selectedPipelineId)\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/deals?${search.toString()}`,\n undefined,\n { errorMessage: translate('customers.deals.pipeline.loadError', 'Failed to load deals.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n const deals: DealRecord[] = []\n items.forEach((item) => {\n if (!item || typeof item !== 'object') return\n const data = item as Record<string, unknown>\n const id = typeof data.id === 'string' ? data.id : null\n if (!id) return\n const title =\n typeof data.title === 'string' && data.title.trim().length\n ? data.title.trim()\n : translate('customers.deals.pipeline.untitled', 'Untitled deal')\n const status =\n typeof data.status === 'string' && data.status.trim().length ? data.status.trim() : null\n const stage =\n typeof data.pipeline_stage === 'string' && data.pipeline_stage.trim().length\n ? data.pipeline_stage.trim()\n : null\n const amount = normalizeAmount(data.value_amount)\n const currency =\n typeof data.value_currency === 'string' && data.value_currency.trim().length\n ? data.value_currency.trim().toUpperCase()\n : null\n const probability = normalizeProbability(data.probability)\n const expected = normalizeTimestamp(data.expected_close_at)\n const created = normalizeTimestamp(data.created_at)\n const updated = normalizeTimestamp(data.updated_at)\n const rawPeople = Array.isArray(data.people) ? data.people : []\n const people: DealAssociation[] = rawPeople\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const ref = entry as Record<string, unknown>\n const personId = typeof ref.id === 'string' ? ref.id : null\n if (!personId) return null\n const label =\n typeof ref.label === 'string' && ref.label.trim().length\n ? ref.label.trim()\n : personId\n return { id: personId, label }\n })\n .filter((entry): entry is DealAssociation => !!entry)\n const rawCompanies = Array.isArray(data.companies) ? data.companies : []\n const companies: DealAssociation[] = rawCompanies\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const ref = entry as Record<string, unknown>\n const companyId = typeof ref.id === 'string' ? ref.id : null\n if (!companyId) return null\n const label =\n typeof ref.label === 'string' && ref.label.trim().length\n ? ref.label.trim()\n : companyId\n return { id: companyId, label }\n })\n .filter((entry): entry is DealAssociation => !!entry)\n deals.push({\n id,\n title,\n status,\n pipelineStage: stage,\n pipelineId: typeof data.pipeline_id === 'string' ? data.pipeline_id : null,\n pipelineStageId: typeof data.pipeline_stage_id === 'string' ? data.pipeline_stage_id : null,\n valueAmount: amount,\n valueCurrency: currency,\n probability,\n expectedCloseAt: expected.iso,\n expectedCloseAtTs: expected.ts,\n createdAt: created.iso,\n createdAtTs: created.ts,\n updatedAt: updated.iso,\n people,\n companies,\n })\n })\n\n const total = typeof payload?.total === 'number' ? payload.total : deals.length\n return { deals, total }\n },\n })\n\n const deals = dealsQuery.data?.deals ?? []\n const total = dealsQuery.data?.total ?? deals.length\n const dealMap = React.useMemo(() => createDealMap(deals), [deals])\n const groupedDeals = React.useMemo(() => groupDealsByStageId(deals), [deals])\n const stages = React.useMemo(\n () => buildStageDefinitionsFromPipelineStages(stagesQuery.data ?? [], deals, t),\n [stagesQuery.data, deals, t],\n )\n\n const dateFormatter = React.useMemo(\n () =>\n new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n }),\n [],\n )\n\n const updateStageMutation = useMutation({\n mutationFn: async ({ id, pipelineStageId }: { id: string; pipelineStageId: string }) => {\n await apiCallOrThrow(\n '/api/customers/deals',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id, pipelineStageId }),\n },\n { errorMessage: translate('customers.deals.pipeline.moveError', 'Failed to update deal stage.') },\n )\n return { id, pipelineStageId }\n },\n onMutate: async ({ id, pipelineStageId }) => {\n setPendingDealId(id)\n await queryClient.cancelQueries({ queryKey: dealsKey })\n const previous = queryClient.getQueryData<DealsQueryData>(dealsKey)\n if (previous) {\n const nextDeals = previous.deals.map((deal) =>\n deal.id === id ? { ...deal, pipelineStageId } : deal,\n )\n queryClient.setQueryData<DealsQueryData>(dealsKey, { ...previous, deals: nextDeals })\n }\n return { previous }\n },\n onError: (error, _variables, context) => {\n if (context?.previous) {\n queryClient.setQueryData<DealsQueryData>(dealsKey, context.previous)\n }\n const message =\n error instanceof Error && error.message\n ? error.message\n : translate('customers.deals.pipeline.moveError', 'Failed to update deal stage.')\n flash(message, 'error')\n },\n onSuccess: () => {\n flash(translate('customers.deals.pipeline.moveSuccess', 'Deal updated.'), 'success')\n },\n onSettled: () => {\n setPendingDealId(null)\n queryClient.invalidateQueries({ queryKey: dealsKey }).catch(() => {})\n },\n })\n\n const [draggingId, setDraggingId] = React.useState<string | null>(null)\n const [activeLane, setActiveLane] = React.useState<string | null>(null)\n const handleActionClick = React.useCallback((event: React.MouseEvent) => {\n event.stopPropagation()\n }, [])\n\n const handleSortChange = React.useCallback((value: string) => {\n if (sortOptions.includes(value as SortOption)) setSortBy(value as SortOption)\n }, [])\n\n const handleDragStart = React.useCallback((dealId: string) => {\n setDraggingId(dealId)\n }, [])\n\n const handleDragEnd = React.useCallback(() => {\n setDraggingId(null)\n setActiveLane(null)\n }, [])\n\n const handleDrop = React.useCallback(\n (stage: StageDefinition) => async (event: React.DragEvent<HTMLDivElement>) => {\n event.preventDefault()\n setActiveLane(null)\n const dealId = event.dataTransfer.getData('text/plain') || draggingId\n if (!dealId) return\n const deal = dealMap.get(dealId)\n if (!deal) return\n if (stage.value === null) {\n flash(\n translate('customers.deals.pipeline.unassignedDisabled', 'Moving to \"No stage\" is not supported.'),\n 'info',\n )\n return\n }\n if (deal.pipelineStageId === stage.value) return\n updateStageMutation.mutate({ id: dealId, pipelineStageId: stage.value })\n },\n [dealMap, draggingId, translate, updateStageMutation],\n )\n\n const handleDragOver = React.useCallback(\n (stageId: string) => (event: React.DragEvent<HTMLDivElement>) => {\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n if (activeLane !== stageId) setActiveLane(stageId)\n },\n [activeLane],\n )\n\n const renderLaneHeader = (stage: StageDefinition, count: number) => {\n return (\n <div className=\"flex items-center justify-between gap-3 border-b border-border px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">{stage.label}</span>\n <span className=\"text-xs text-muted-foreground\">\n {translate('customers.deals.pipeline.countLabel', 'Deals: {count}', { count })}\n </span>\n </div>\n </div>\n </div>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-col\">\n <h1 className=\"text-xl font-semibold text-foreground\">\n {translate('customers.deals.pipeline.title', 'Sales Pipeline')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {translate(\n 'customers.deals.pipeline.subtitle',\n 'Track deals by pipeline stage and drag them between lanes to update progress.',\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n {pipelinesQuery.data && pipelinesQuery.data.length > 0 ? (\n <label className=\"flex items-center gap-2 text-sm font-medium text-muted-foreground\">\n <span>{translate('customers.deals.pipeline.switch.label', 'Pipeline')}</span>\n <Select\n value={selectedPipelineId || undefined}\n onValueChange={(value) => setSelectedPipelineId(value || null)}\n >\n <SelectTrigger className=\"w-auto min-w-[12rem]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {pipelinesQuery.data.map((p) => (\n <SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n ) : null}\n <Link\n href=\"/backend/config/customers/pipeline-stages\"\n className=\"text-sm font-medium text-primary hover:underline\"\n >\n {translate('customers.deals.pipeline.manageStages', 'Manage stages')}\n </Link>\n <label className=\"flex items-center gap-2 text-sm font-medium text-muted-foreground\">\n <span>{translate('customers.deals.pipeline.sort.label', 'Sort by')}</span>\n <Select value={sortBy} onValueChange={handleSortChange}>\n <SelectTrigger className=\"w-auto min-w-[14rem]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"probability\">\n {translate('customers.deals.pipeline.sort.probability', 'Probability (high to low)')}\n </SelectItem>\n <SelectItem value=\"createdAt\">\n {translate('customers.deals.pipeline.sort.createdAt', 'Created (newest first)')}\n </SelectItem>\n <SelectItem value=\"expectedCloseAt\">\n {translate('customers.deals.pipeline.sort.expectedCloseAt', 'Expected close (soonest first)')}\n </SelectItem>\n </SelectContent>\n </Select>\n </label>\n </div>\n </div>\n\n {!selectedPipelineId ? (\n <EmptyState\n icon={<Workflow className=\"h-8 w-8\" aria-hidden=\"true\" />}\n title={translate('customers.deals.pipeline.noPipeline', 'No pipeline selected. Create a pipeline in settings.')}\n className=\"h-[50vh] w-full\"\n />\n ) : dealsQuery.isLoading ? (\n <div className=\"flex h-[50vh] items-center justify-center\">\n <Spinner />\n </div>\n ) : dealsQuery.isError ? (\n <div className=\"max-w-xl\">\n <ErrorNotice\n message={\n dealsQuery.error instanceof Error\n ? dealsQuery.error.message\n : translate('customers.deals.pipeline.loadError', 'Failed to load deals.')\n }\n />\n </div>\n ) : (\n <div className=\"flex flex-col gap-3\">\n {total > deals.length ? (\n <div className=\"rounded-md border border-border bg-muted/30 px-4 py-2 text-sm text-muted-foreground\">\n {translate(\n 'customers.deals.pipeline.limitNotice',\n 'Showing the first {count} deals. Refine your filters to see more.',\n { count: deals.length },\n )}\n </div>\n ) : null}\n\n <div className=\"flex flex-col gap-4 pb-6 md:flex-row md:overflow-x-auto\">\n {stages.length === 0 ? (\n <EmptyState\n icon={<Layers className=\"h-8 w-8\" aria-hidden=\"true\" />}\n title={translate('customers.deals.pipeline.noStages', 'Define pipeline stages to start tracking deals.')}\n className=\"h-[50vh] w-full\"\n />\n ) : (\n stages.map((stage) => {\n const stageKey = stage.value ?? null\n const laneDeals = groupedDeals.get(stageKey) ?? []\n const sortedLaneDeals = sortDeals(laneDeals, sortBy)\n const isActive = activeLane === stage.id\n return (\n <div\n key={stage.id}\n className={`flex min-h-[60vh] w-full flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card shadow-sm transition-all md:w-72 md:flex-none ${\n isActive ? 'ring-2 ring-ring/40' : ''\n }`}\n onDragOver={handleDragOver(stage.id)}\n onDrop={handleDrop(stage)}\n >\n {renderLaneHeader(stage, laneDeals.length)}\n <div className=\"flex flex-1 flex-col gap-3 overflow-y-auto px-4 py-3\">\n {sortedLaneDeals.length === 0 ? (\n <EmptyState\n size=\"sm\"\n icon={<MoveRight className=\"h-6 w-6\" aria-hidden=\"true\" />}\n title={translate('customers.deals.pipeline.emptyLane', 'No deals in this stage yet.')}\n />\n ) : (\n sortedLaneDeals.map((deal) => {\n const isDragging = draggingId === deal.id\n || (pendingDealId === deal.id && updateStageMutation.isPending)\n const valueLabel = formatCurrency(\n deal.valueAmount,\n deal.valueCurrency,\n translate('customers.deals.list.noValue', 'No value assigned'),\n )\n const probabilityLabel = formatProbability(\n deal.probability,\n translate('customers.deals.pipeline.noProbability', 'N/A'),\n )\n const expectedLabel = deal.expectedCloseAt\n ? dateFormatter.format(new Date(deal.expectedCloseAt))\n : translate('customers.deals.pipeline.noExpectedClose', 'No date')\n return (\n <div\n key={deal.id}\n className={`group flex cursor-grab flex-col gap-2 rounded-md border border-border bg-background p-4 shadow-xs transition ${\n isDragging ? 'opacity-50' : 'hover:shadow-sm'\n }`}\n draggable\n onDragStart={(event) => {\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', deal.id)\n handleDragStart(deal.id)\n }}\n onDragEnd={handleDragEnd}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex flex-col\">\n <span className=\"line-clamp-2 text-sm font-medium text-foreground\">\n {deal.title}\n </span>\n {deal.status ? (\n <span className=\"text-xs uppercase tracking-wide text-muted-foreground\">\n {deal.status}\n </span>\n ) : null}\n </div>\n {pendingDealId === deal.id && updateStageMutation.isPending ? (\n <Spinner className=\"size-4\" />\n ) : null}\n </div>\n <div className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n <div className=\"flex items-center justify-between gap-2\">\n <span>{translate('customers.deals.pipeline.card.value', 'Value')}</span>\n <span className=\"font-medium text-foreground\">{valueLabel}</span>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <span>{translate('customers.deals.pipeline.card.probability', 'Probability')}</span>\n <span className=\"font-medium text-foreground\">{probabilityLabel}</span>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <span>{translate('customers.deals.pipeline.card.expectedClose', 'Expected close')}</span>\n <span className=\"font-medium text-foreground\">{expectedLabel}</span>\n </div>\n </div>\n <div className=\"mt-1 flex flex-wrap gap-2 text-xs\">\n <Link\n href={`/backend/customers/deals/${deal.id}`}\n className=\"font-medium text-primary hover:underline\"\n draggable={false}\n onClick={handleActionClick}\n >\n {translate('customers.deals.pipeline.actions.openDeal', 'Open deal')}\n </Link>\n </div>\n {deal.people.length ? (\n <div className=\"flex flex-wrap gap-2\">\n {deal.people.map((person) => (\n <Link\n key={person.id}\n className=\"rounded-full bg-primary/5 px-3 py-1 text-xs text-primary transition-colors hover:bg-primary/10\"\n href={`/backend/customers/people-v2/${person.id}`}\n draggable={false}\n onClick={handleActionClick}\n >\n {person.label}\n </Link>\n ))}\n </div>\n ) : null}\n {deal.companies.length ? (\n <div className=\"flex flex-wrap gap-2\">\n {deal.companies.map((company) => (\n <Link\n key={company.id}\n className=\"rounded-full bg-secondary/10 px-3 py-1 text-xs text-secondary-foreground transition-colors hover:bg-secondary/20\"\n href={`/backend/customers/companies-v2/${company.id}`}\n draggable={false}\n onClick={handleActionClick}\n >\n {company.label}\n </Link>\n ))}\n </div>\n ) : null}\n </div>\n )\n })\n )}\n </div>\n </div>\n )\n })\n )}\n </div>\n </div>\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["at", "bt", "deals", "total"]
7
7
  }
@@ -347,7 +347,7 @@ function PersonDetailV2Page({ params }) {
347
347
  onSubmit: handleFormSubmit,
348
348
  onDelete: handleFormDelete,
349
349
  hideFooterActions: true,
350
- collapsibleGroups: { pageType: "person-v2", chevronPosition: "left" },
350
+ collapsibleGroups: { pageType: "person-v2", chevronPosition: "right" },
351
351
  sortableGroups: { pageType: "person-v2" },
352
352
  onDirtyChange: setIsDirty
353
353
  }
@@ -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 Link from 'next/link'\nimport { useRouter, useSearchParams } 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 { 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 { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\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, 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 { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\n\nimport { ActivitiesSection } from '../../../../components/detail/ActivitiesSection'\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 { 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'\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 { organizationId } = useOrganizationScopeDetail()\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 const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\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 () => {\n if (!id) {\n setError(t('customers.people.detail.error.notFound', 'Person not found.'))\n setIsLoading(false)\n return\n }\n if (!initialLoadDoneRef.current) {\n setIsLoading(true)\n }\n setError(null)\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 setData(payload as PersonOverview)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.error.load', 'Failed to load person.')\n setError(message)\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) => console.warn('[people-v2] loadData failed', 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) => console.warn('[people-v2] reload after activity failed', 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 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 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 await updateCrud('customers/people', payload)\n flash(t('customers.people.form.updateSuccess', 'Person updated.'), 'success')\n await loadData()\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 await runMutationWithContext(\n () => deleteCrud('customers/people', { id: personId }),\n { id: personId, operation: 'deletePerson' },\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 (error || !data?.person?.id || !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error || t('customers.people.detail.error.notFound', 'Person not found.')}\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 */}\n <InjectionSpot spotId=\"detail:customers.person:header\" context={injectionContext} data={data} />\n <InjectionSpot spotId=\"detail:customers.person:status-badges\" 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) => console.warn('[people-v2] onDataReload failed', 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=\"customers.person\"\n entityIds={[E.customers.customer_entity, E.customers.customer_person_profile]}\n schema={formSchema}\n fields={fields}\n groups={groups}\n initialValues={initialValues}\n onSubmit={handleFormSubmit}\n onDelete={handleFormDelete}\n hideFooterActions\n collapsibleGroups={{ pageType: 'person-v2', chevronPosition: 'left' }}\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 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 === '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 === '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 return (\n <>\n <div className=\"md:hidden\">\n <MobilePersonDetail zone1={zone1Content} zone2={zone2Content} />\n </div>\n <div className=\"hidden md:block\">\n <CollapsibleZoneLayout\n pageType=\"person-v2\"\n entityName={personName}\n isDirty={isDirty}\n sections={zoneSections}\n zone1={zone1Content}\n zone2={zone2Content}\n />\n </div>\n </>\n )\n })()}\n\n {/* UMES footer injection */}\n <InjectionSpot spotId=\"detail:customers.person:footer\" 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 Link from 'next/link'\nimport { useRouter, useSearchParams } 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 { 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 { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\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, 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 { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\n\nimport { ActivitiesSection } from '../../../../components/detail/ActivitiesSection'\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 { 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'\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 { organizationId } = useOrganizationScopeDetail()\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 const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\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 () => {\n if (!id) {\n setError(t('customers.people.detail.error.notFound', 'Person not found.'))\n setIsLoading(false)\n return\n }\n if (!initialLoadDoneRef.current) {\n setIsLoading(true)\n }\n setError(null)\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 setData(payload as PersonOverview)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.error.load', 'Failed to load person.')\n setError(message)\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) => console.warn('[people-v2] loadData failed', 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) => console.warn('[people-v2] reload after activity failed', 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 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 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 await updateCrud('customers/people', payload)\n flash(t('customers.people.form.updateSuccess', 'Person updated.'), 'success')\n await loadData()\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 await runMutationWithContext(\n () => deleteCrud('customers/people', { id: personId }),\n { id: personId, operation: 'deletePerson' },\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 (error || !data?.person?.id || !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error || t('customers.people.detail.error.notFound', 'Person not found.')}\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 */}\n <InjectionSpot spotId=\"detail:customers.person:header\" context={injectionContext} data={data} />\n <InjectionSpot spotId=\"detail:customers.person:status-badges\" 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) => console.warn('[people-v2] onDataReload failed', 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=\"customers.person\"\n entityIds={[E.customers.customer_entity, E.customers.customer_person_profile]}\n schema={formSchema}\n fields={fields}\n groups={groups}\n initialValues={initialValues}\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 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 === '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 === '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 return (\n <>\n <div className=\"md:hidden\">\n <MobilePersonDetail zone1={zone1Content} zone2={zone2Content} />\n </div>\n <div className=\"hidden md:block\">\n <CollapsibleZoneLayout\n pageType=\"person-v2\"\n entityName={personName}\n isDirty={isDirty}\n sections={zoneSections}\n zone1={zone1Content}\n zone2={zone2Content}\n />\n </div>\n </>\n )\n })()}\n\n {/* UMES footer injection */}\n <InjectionSpot spotId=\"detail:customers.person:footer\" 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
  }