@open-mercato/core 0.6.6-develop.6313.1.618a49a6b4 → 0.6.6-develop.6314.1.c7b8291aa2

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.
@@ -14,6 +14,9 @@ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuarde
14
14
  import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
15
15
  import { useT } from "@open-mercato/shared/lib/i18n/context";
16
16
  import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
17
+ import {
18
+ getCustomerDictionarySettingsSectionId
19
+ } from "../lib/dictionaries.js";
17
20
  import { ICON_SUGGESTIONS } from "@open-mercato/core/modules/dictionaries/components/dictionaryAppearance";
18
21
  import {
19
22
  DictionaryForm
@@ -27,6 +30,17 @@ const DEFAULT_FORM_VALUES = {
27
30
  color: null,
28
31
  icon: null
29
32
  };
33
+ const DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS = [100, 350, 1e3];
34
+ function getCurrentDictionaryHashTarget() {
35
+ if (typeof window === "undefined") return null;
36
+ const hash = window.location.hash;
37
+ if (!hash.startsWith("#customer-dictionary-")) return null;
38
+ try {
39
+ return document.getElementById(decodeURIComponent(hash.slice(1)));
40
+ } catch {
41
+ return document.getElementById(hash.slice(1));
42
+ }
43
+ }
30
44
  function DictionarySettings() {
31
45
  const t = useT();
32
46
  const sections = React.useMemo(() => [
@@ -76,6 +90,40 @@ function DictionarySettings() {
76
90
  description: t("customers.config.dictionaries.sections.addressTypes.description", "Define the available address types.")
77
91
  }
78
92
  ], [t]);
93
+ React.useEffect(() => {
94
+ const timeoutIds = [];
95
+ let frameId = null;
96
+ const clearScheduledScrolls = () => {
97
+ if (frameId !== null) {
98
+ window.cancelAnimationFrame(frameId);
99
+ frameId = null;
100
+ }
101
+ while (timeoutIds.length > 0) {
102
+ const timeoutId = timeoutIds.pop();
103
+ if (timeoutId !== void 0) window.clearTimeout(timeoutId);
104
+ }
105
+ };
106
+ const scrollToHashTarget = () => {
107
+ getCurrentDictionaryHashTarget()?.scrollIntoView({ block: "start" });
108
+ };
109
+ const scheduleHashScroll = () => {
110
+ clearScheduledScrolls();
111
+ if (!window.location.hash.startsWith("#customer-dictionary-")) return;
112
+ scrollToHashTarget();
113
+ if (typeof window.requestAnimationFrame === "function") {
114
+ frameId = window.requestAnimationFrame(scrollToHashTarget);
115
+ }
116
+ DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS.forEach((delay) => {
117
+ timeoutIds.push(window.setTimeout(scrollToHashTarget, delay));
118
+ });
119
+ };
120
+ scheduleHashScroll();
121
+ window.addEventListener("hashchange", scheduleHashScroll);
122
+ return () => {
123
+ window.removeEventListener("hashchange", scheduleHashScroll);
124
+ clearScheduledScrolls();
125
+ };
126
+ }, []);
79
127
  return /* @__PURE__ */ jsxs("div", { className: "space-y-8", children: [
80
128
  /* @__PURE__ */ jsxs("header", { className: "space-y-2", children: [
81
129
  /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold", children: t("customers.config.dictionaries.title", "Customers dictionaries") }),
@@ -336,43 +384,50 @@ function CustomerDictionarySection({ kind, title, description }) {
336
384
  previewEmptyLabel: t("customers.config.dictionaries.appearance.empty", "None")
337
385
  }
338
386
  }), [dialog, t]);
339
- return /* @__PURE__ */ jsxs("section", { className: "rounded border bg-card text-card-foreground shadow-sm", children: [
340
- /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4 space-y-1", children: [
341
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium", children: title }),
342
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
343
- ] }),
344
- /* @__PURE__ */ jsx("div", { className: "px-2 py-4 sm:px-4", children: /* @__PURE__ */ jsx(
345
- DictionaryTable,
346
- {
347
- entries,
348
- loading,
349
- canManage: true,
350
- onCreate: handleCreate,
351
- onEdit: handleEdit,
352
- onDelete: handleDelete,
353
- onRefresh: loadEntries,
354
- translations: tableTranslations
355
- }
356
- ) }),
357
- /* @__PURE__ */ jsx(Dialog, { open: dialog !== null, onOpenChange: (open) => {
358
- if (!open) closeDialog();
359
- }, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-lg", children: [
360
- /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: formTranslations.title }) }),
361
- /* @__PURE__ */ jsx(
362
- DictionaryForm,
363
- {
364
- mode: dialog?.mode === "edit" ? "edit" : "create",
365
- initialValues: currentValues,
366
- onSubmit: submitForm,
367
- onCancel: closeDialog,
368
- submitting,
369
- translations: formTranslations,
370
- iconSuggestions: ICON_SUGGESTIONS
371
- }
372
- )
373
- ] }) }),
374
- ConfirmDialogElement
375
- ] });
387
+ return /* @__PURE__ */ jsxs(
388
+ "section",
389
+ {
390
+ id: getCustomerDictionarySettingsSectionId(kind),
391
+ className: "scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm",
392
+ children: [
393
+ /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4 space-y-1", children: [
394
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium", children: title }),
395
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
396
+ ] }),
397
+ /* @__PURE__ */ jsx("div", { className: "px-2 py-4 sm:px-4", children: /* @__PURE__ */ jsx(
398
+ DictionaryTable,
399
+ {
400
+ entries,
401
+ loading,
402
+ canManage: true,
403
+ onCreate: handleCreate,
404
+ onEdit: handleEdit,
405
+ onDelete: handleDelete,
406
+ onRefresh: loadEntries,
407
+ translations: tableTranslations
408
+ }
409
+ ) }),
410
+ /* @__PURE__ */ jsx(Dialog, { open: dialog !== null, onOpenChange: (open) => {
411
+ if (!open) closeDialog();
412
+ }, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-lg", children: [
413
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: formTranslations.title }) }),
414
+ /* @__PURE__ */ jsx(
415
+ DictionaryForm,
416
+ {
417
+ mode: dialog?.mode === "edit" ? "edit" : "create",
418
+ initialValues: currentValues,
419
+ onSubmit: submitForm,
420
+ onCancel: closeDialog,
421
+ submitting,
422
+ translations: formTranslations,
423
+ iconSuggestions: ICON_SUGGESTIONS
424
+ }
425
+ )
426
+ ] }) }),
427
+ ConfirmDialogElement
428
+ ]
429
+ }
430
+ );
376
431
  }
377
432
  export {
378
433
  DictionarySettings as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/components/DictionarySettings.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport type { CustomerDictionaryKind } from '../lib/dictionaries'\nimport { ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport {\n DictionaryForm,\n type DictionaryFormValues,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryForm'\nimport {\n DictionaryTable,\n type DictionaryTableEntry,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryTable'\n\ntype SectionDefinition = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\ntype DictionaryDeleteError = Error & {\n code?: string\n usageCount?: number\n}\n\ntype DialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: DictionaryTableEntry }\n\nconst DEFAULT_FORM_VALUES: DictionaryFormValues = {\n value: '',\n label: '',\n color: null,\n icon: null,\n}\n\nexport default function DictionarySettings() {\n const t = useT()\n\n const sections = React.useMemo<SectionDefinition[]>(() => [\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n return (\n <div className=\"space-y-8\">\n <header className=\"space-y-2\">\n <h1 className=\"text-2xl font-semibold\">\n {t('customers.config.dictionaries.title', 'Customers dictionaries')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionaries.description', 'Manage the dictionaries used by the customers module.')}\n </p>\n </header>\n\n <div className=\"space-y-6\">\n {sections.map((section) => (\n <CustomerDictionarySection key={section.kind} {...section} />\n ))}\n </div>\n </div>\n )\n}\n\ntype CustomerDictionarySectionProps = SectionDefinition\n\nfunction CustomerDictionarySection({ kind, title, description }: CustomerDictionarySectionProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const scopeVersion = useOrganizationScopeVersion()\n const [entries, setEntries] = React.useState<DictionaryTableEntry[]>([])\n const [loading, setLoading] = React.useState<boolean>(true)\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [submitting, setSubmitting] = React.useState(false)\n\n const saveContextId = `customers-dictionary-${kind}`\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: saveContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: saveContextId,\n resourceKind: 'customers.dictionary',\n retryLastMutation,\n }),\n [retryLastMutation, saveContextId],\n )\n\n const inheritedActionBlocked = t('customers.config.dictionaries.inherited.blocked', 'Inherited entries can only be edited from the parent organization.')\n const inheritedTooltip = t('customers.config.dictionaries.inherited.tooltip', 'Managed in parent organization')\n const inheritedLabel = t('customers.config.dictionaries.inherited.label', 'Inherited')\n const errorLoad = t('customers.config.dictionaries.error.load', 'Failed to load dictionary entries.')\n const errorSave = t('customers.config.dictionaries.error.save', 'Failed to save dictionary entry.')\n const errorDelete = t('customers.config.dictionaries.error.delete', 'Failed to delete dictionary entry.')\n const successSave = t('customers.config.dictionaries.success.save', 'Dictionary entry saved.')\n const successDelete = t('customers.config.dictionaries.success.delete', 'Dictionary entry deleted.')\n const deleteConfirmTemplate = t('customers.config.dictionaries.deleteConfirm', 'Delete \"{{value}}\"?')\n const roleTypeDeleteBlockedTitle = t('customers.config.dictionaries.roleTypes.deleteBlocked.title', 'Role type is in use')\n const roleTypeDeleteBlockedText = t(\n 'customers.config.dictionaries.roleTypes.deleteBlocked.text',\n 'This role type is assigned to {{count}} records. Remove or replace those assignments before deleting it.',\n )\n const usageCountLabel = t('customers.config.dictionaries.roleTypes.usageCount', 'In use on {{count}} records')\n const searchPlaceholder = t('customers.config.dictionaries.searchPlaceholder', 'Search entries\u2026')\n\n const formatCountMessage = React.useCallback((template: string, count: number) => {\n return template.replace('{{count}}', String(count))\n }, [])\n\n const loadEntries = React.useCallback(async () => {\n setLoading(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/dictionaries/${kind}`,\n undefined,\n { errorMessage: errorLoad },\n )\n if (!Array.isArray(data?.items)) throw new Error(errorLoad)\n const mapped: DictionaryTableEntry[] = data.items.map((item: any) => ({\n id: String(item.id),\n value: String(item.value ?? ''),\n label: typeof item.label === 'string' ? item.label : '',\n color: typeof item.color === 'string' ? item.color : null,\n icon: typeof item.icon === 'string' ? item.icon : null,\n usageCount: typeof item.usageCount === 'number' ? item.usageCount : undefined,\n organizationId: typeof item.organizationId === 'string' ? item.organizationId : null,\n tenantId: typeof item.tenantId === 'string' ? item.tenantId : null,\n isInherited: item.isInherited === true,\n createdAt: typeof item.createdAt === 'string' ? item.createdAt : null,\n updatedAt: typeof item.updatedAt === 'string' ? item.updatedAt : null,\n }))\n setEntries(mapped)\n } catch (err) {\n console.error('customers.dictionaries.list failed', err)\n flash(errorLoad, 'error')\n } finally {\n setLoading(false)\n }\n }, [errorLoad, kind, scopeVersion])\n\n React.useEffect(() => {\n loadEntries().catch(() => {})\n }, [loadEntries])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n }, [])\n\n const handleCreate = React.useCallback(() => {\n setDialog({ mode: 'create' })\n }, [])\n\n const handleEdit = React.useCallback((entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n setDialog({ mode: 'edit', entry })\n }, [inheritedActionBlocked])\n\n const handleDelete = React.useCallback(async (entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n if (kind === 'person-company-roles' && (entry.usageCount ?? 0) > 0) {\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, entry.usageCount ?? 0),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const message = deleteConfirmTemplate.replace('{{value}}', entry.label || entry.value)\n const confirmed = await confirm({\n title: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(entry.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(entry.id)}`,\n { method: 'DELETE' },\n { errorMessage: errorDelete },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'delete', id: entry.id, kind },\n })\n flash(successDelete, 'success')\n await loadEntries()\n } catch (err) {\n console.error('customers.dictionaries.delete failed', err)\n if (kind === 'person-company-roles' && (err as DictionaryDeleteError)?.code === 'role_type_in_use') {\n const usageCount = Number((err as DictionaryDeleteError).usageCount ?? 0)\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, usageCount),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const messageValue = err instanceof Error ? err.message : errorDelete\n flash(messageValue, 'error')\n }\n }, [confirm, deleteConfirmTemplate, errorDelete, formatCountMessage, inheritedActionBlocked, kind, loadEntries, mutationContext, roleTypeDeleteBlockedText, roleTypeDeleteBlockedTitle, runMutation, successDelete, t])\n\n const submitForm = React.useCallback(async (values: DictionaryFormValues) => {\n const payload = {\n value: values.value,\n label: values.label,\n color: values.color,\n icon: values.icon,\n }\n setSubmitting(true)\n try {\n if (!dialog || dialog.mode === 'create') {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: errorSave },\n ),\n context: mutationContext,\n mutationPayload: { action: 'create', kind, ...payload },\n })\n flash(successSave, 'success')\n } else if (dialog.mode === 'edit') {\n const target = dialog.entry\n if (target.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n const body: Record<string, unknown> = {}\n if (values.value !== target.value) body.value = values.value\n if (values.label !== target.label) body.label = values.label\n const nextColor = values.color ?? null\n if (nextColor !== (target.color ?? null)) body.color = nextColor\n const nextIcon = values.icon ?? null\n if (nextIcon !== (target.icon ?? null)) body.icon = nextIcon\n if (Object.keys(body).length === 0) {\n closeDialog()\n return\n }\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(target.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(target.id)}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n },\n { errorMessage: errorSave },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'update', id: target.id, kind, ...body },\n })\n flash(successSave, 'success')\n }\n closeDialog()\n await loadEntries()\n } catch (err) {\n console.error('customers.dictionaries.submit failed', err)\n throw err instanceof Error ? err : new Error(errorSave)\n } finally {\n setSubmitting(false)\n }\n }, [closeDialog, dialog, errorSave, inheritedActionBlocked, kind, loadEntries, mutationContext, runMutation, successSave])\n\n const currentValues = React.useMemo<DictionaryFormValues>(() => {\n if (dialog && dialog.mode === 'edit') {\n return {\n value: dialog.entry.value,\n label: dialog.entry.label,\n color: dialog.entry.color,\n icon: dialog.entry.icon,\n }\n }\n return DEFAULT_FORM_VALUES\n }, [dialog])\n\n const tableTranslations = React.useMemo(() => ({\n title,\n valueColumn: t('customers.config.dictionaries.columns.value', 'Value'),\n labelColumn: t('customers.config.dictionaries.columns.label', 'Label'),\n appearanceColumn: t('customers.config.dictionaries.columns.appearance', 'Appearance'),\n addLabel: t('customers.config.dictionaries.actions.add', 'Add entry'),\n editLabel: t('customers.config.dictionaries.actions.edit', 'Edit'),\n deleteLabel: t('customers.config.dictionaries.actions.delete', 'Delete'),\n refreshLabel: t('customers.config.dictionaries.actions.refresh', 'Refresh'),\n inheritedLabel,\n inheritedTooltip,\n emptyLabel: t('customers.config.dictionaries.empty', 'No entries yet.'),\n usageCountLabel: kind === 'person-company-roles' ? usageCountLabel : undefined,\n searchPlaceholder,\n }), [inheritedLabel, inheritedTooltip, kind, searchPlaceholder, t, title, usageCountLabel])\n\n const formTranslations = React.useMemo(() => ({\n title: dialog?.mode === 'edit'\n ? t('customers.config.dictionaries.dialog.editTitle', 'Edit entry')\n : t('customers.config.dictionaries.dialog.addTitle', 'Add entry'),\n valueLabel: t('customers.config.dictionaries.dialog.valueLabel', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n saveLabel: t('customers.config.dictionaries.dialog.save', 'Save'),\n cancelLabel: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n appearance: {\n colorLabel: t('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: t('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: t('customers.config.dictionaries.dialog.iconLabel', 'Icon'),\n iconPlaceholder: t('customers.config.dictionaries.dialog.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('customers.config.dictionaries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('customers.config.dictionaries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.config.dictionaries.appearance.empty', 'None'),\n },\n }), [dialog, t])\n\n return (\n <section className=\"rounded border bg-card text-card-foreground shadow-sm\">\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-medium\">{title}</h2>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n <DictionaryTable\n entries={entries}\n loading={loading}\n canManage\n onCreate={handleCreate}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onRefresh={loadEntries}\n translations={tableTranslations}\n />\n </div>\n <Dialog open={dialog !== null} onOpenChange={(open) => { if (!open) closeDialog() }}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>{formTranslations.title}</DialogTitle>\n </DialogHeader>\n <DictionaryForm\n mode={dialog?.mode === 'edit' ? 'edit' : 'create'}\n initialValues={currentValues}\n onSubmit={submitForm}\n onCancel={closeDialog}\n submitting={submitting}\n translations={formTranslations}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </section>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n getCustomerDictionarySettingsSectionId,\n type CustomerDictionaryKind,\n} from '../lib/dictionaries'\nimport { ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport {\n DictionaryForm,\n type DictionaryFormValues,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryForm'\nimport {\n DictionaryTable,\n type DictionaryTableEntry,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryTable'\n\ntype SectionDefinition = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\ntype DictionaryDeleteError = Error & {\n code?: string\n usageCount?: number\n}\n\ntype DialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: DictionaryTableEntry }\n\nconst DEFAULT_FORM_VALUES: DictionaryFormValues = {\n value: '',\n label: '',\n color: null,\n icon: null,\n}\n\nconst DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS = [100, 350, 1000] as const\n\nfunction getCurrentDictionaryHashTarget(): HTMLElement | null {\n if (typeof window === 'undefined') return null\n const hash = window.location.hash\n if (!hash.startsWith('#customer-dictionary-')) return null\n try {\n return document.getElementById(decodeURIComponent(hash.slice(1)))\n } catch {\n return document.getElementById(hash.slice(1))\n }\n}\n\nexport default function DictionarySettings() {\n const t = useT()\n\n const sections = React.useMemo<SectionDefinition[]>(() => [\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n React.useEffect(() => {\n const timeoutIds: number[] = []\n let frameId: number | null = null\n\n const clearScheduledScrolls = () => {\n if (frameId !== null) {\n window.cancelAnimationFrame(frameId)\n frameId = null\n }\n while (timeoutIds.length > 0) {\n const timeoutId = timeoutIds.pop()\n if (timeoutId !== undefined) window.clearTimeout(timeoutId)\n }\n }\n\n const scrollToHashTarget = () => {\n getCurrentDictionaryHashTarget()?.scrollIntoView({ block: 'start' })\n }\n\n const scheduleHashScroll = () => {\n clearScheduledScrolls()\n if (!window.location.hash.startsWith('#customer-dictionary-')) return\n scrollToHashTarget()\n if (typeof window.requestAnimationFrame === 'function') {\n frameId = window.requestAnimationFrame(scrollToHashTarget)\n }\n DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS.forEach((delay) => {\n timeoutIds.push(window.setTimeout(scrollToHashTarget, delay))\n })\n }\n\n scheduleHashScroll()\n window.addEventListener('hashchange', scheduleHashScroll)\n return () => {\n window.removeEventListener('hashchange', scheduleHashScroll)\n clearScheduledScrolls()\n }\n }, [])\n\n return (\n <div className=\"space-y-8\">\n <header className=\"space-y-2\">\n <h1 className=\"text-2xl font-semibold\">\n {t('customers.config.dictionaries.title', 'Customers dictionaries')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionaries.description', 'Manage the dictionaries used by the customers module.')}\n </p>\n </header>\n\n <div className=\"space-y-6\">\n {sections.map((section) => (\n <CustomerDictionarySection key={section.kind} {...section} />\n ))}\n </div>\n </div>\n )\n}\n\ntype CustomerDictionarySectionProps = SectionDefinition\n\nfunction CustomerDictionarySection({ kind, title, description }: CustomerDictionarySectionProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const scopeVersion = useOrganizationScopeVersion()\n const [entries, setEntries] = React.useState<DictionaryTableEntry[]>([])\n const [loading, setLoading] = React.useState<boolean>(true)\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [submitting, setSubmitting] = React.useState(false)\n\n const saveContextId = `customers-dictionary-${kind}`\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: saveContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: saveContextId,\n resourceKind: 'customers.dictionary',\n retryLastMutation,\n }),\n [retryLastMutation, saveContextId],\n )\n\n const inheritedActionBlocked = t('customers.config.dictionaries.inherited.blocked', 'Inherited entries can only be edited from the parent organization.')\n const inheritedTooltip = t('customers.config.dictionaries.inherited.tooltip', 'Managed in parent organization')\n const inheritedLabel = t('customers.config.dictionaries.inherited.label', 'Inherited')\n const errorLoad = t('customers.config.dictionaries.error.load', 'Failed to load dictionary entries.')\n const errorSave = t('customers.config.dictionaries.error.save', 'Failed to save dictionary entry.')\n const errorDelete = t('customers.config.dictionaries.error.delete', 'Failed to delete dictionary entry.')\n const successSave = t('customers.config.dictionaries.success.save', 'Dictionary entry saved.')\n const successDelete = t('customers.config.dictionaries.success.delete', 'Dictionary entry deleted.')\n const deleteConfirmTemplate = t('customers.config.dictionaries.deleteConfirm', 'Delete \"{{value}}\"?')\n const roleTypeDeleteBlockedTitle = t('customers.config.dictionaries.roleTypes.deleteBlocked.title', 'Role type is in use')\n const roleTypeDeleteBlockedText = t(\n 'customers.config.dictionaries.roleTypes.deleteBlocked.text',\n 'This role type is assigned to {{count}} records. Remove or replace those assignments before deleting it.',\n )\n const usageCountLabel = t('customers.config.dictionaries.roleTypes.usageCount', 'In use on {{count}} records')\n const searchPlaceholder = t('customers.config.dictionaries.searchPlaceholder', 'Search entries\u2026')\n\n const formatCountMessage = React.useCallback((template: string, count: number) => {\n return template.replace('{{count}}', String(count))\n }, [])\n\n const loadEntries = React.useCallback(async () => {\n setLoading(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/dictionaries/${kind}`,\n undefined,\n { errorMessage: errorLoad },\n )\n if (!Array.isArray(data?.items)) throw new Error(errorLoad)\n const mapped: DictionaryTableEntry[] = data.items.map((item: any) => ({\n id: String(item.id),\n value: String(item.value ?? ''),\n label: typeof item.label === 'string' ? item.label : '',\n color: typeof item.color === 'string' ? item.color : null,\n icon: typeof item.icon === 'string' ? item.icon : null,\n usageCount: typeof item.usageCount === 'number' ? item.usageCount : undefined,\n organizationId: typeof item.organizationId === 'string' ? item.organizationId : null,\n tenantId: typeof item.tenantId === 'string' ? item.tenantId : null,\n isInherited: item.isInherited === true,\n createdAt: typeof item.createdAt === 'string' ? item.createdAt : null,\n updatedAt: typeof item.updatedAt === 'string' ? item.updatedAt : null,\n }))\n setEntries(mapped)\n } catch (err) {\n console.error('customers.dictionaries.list failed', err)\n flash(errorLoad, 'error')\n } finally {\n setLoading(false)\n }\n }, [errorLoad, kind, scopeVersion])\n\n React.useEffect(() => {\n loadEntries().catch(() => {})\n }, [loadEntries])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n }, [])\n\n const handleCreate = React.useCallback(() => {\n setDialog({ mode: 'create' })\n }, [])\n\n const handleEdit = React.useCallback((entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n setDialog({ mode: 'edit', entry })\n }, [inheritedActionBlocked])\n\n const handleDelete = React.useCallback(async (entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n if (kind === 'person-company-roles' && (entry.usageCount ?? 0) > 0) {\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, entry.usageCount ?? 0),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const message = deleteConfirmTemplate.replace('{{value}}', entry.label || entry.value)\n const confirmed = await confirm({\n title: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(entry.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(entry.id)}`,\n { method: 'DELETE' },\n { errorMessage: errorDelete },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'delete', id: entry.id, kind },\n })\n flash(successDelete, 'success')\n await loadEntries()\n } catch (err) {\n console.error('customers.dictionaries.delete failed', err)\n if (kind === 'person-company-roles' && (err as DictionaryDeleteError)?.code === 'role_type_in_use') {\n const usageCount = Number((err as DictionaryDeleteError).usageCount ?? 0)\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, usageCount),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const messageValue = err instanceof Error ? err.message : errorDelete\n flash(messageValue, 'error')\n }\n }, [confirm, deleteConfirmTemplate, errorDelete, formatCountMessage, inheritedActionBlocked, kind, loadEntries, mutationContext, roleTypeDeleteBlockedText, roleTypeDeleteBlockedTitle, runMutation, successDelete, t])\n\n const submitForm = React.useCallback(async (values: DictionaryFormValues) => {\n const payload = {\n value: values.value,\n label: values.label,\n color: values.color,\n icon: values.icon,\n }\n setSubmitting(true)\n try {\n if (!dialog || dialog.mode === 'create') {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: errorSave },\n ),\n context: mutationContext,\n mutationPayload: { action: 'create', kind, ...payload },\n })\n flash(successSave, 'success')\n } else if (dialog.mode === 'edit') {\n const target = dialog.entry\n if (target.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n const body: Record<string, unknown> = {}\n if (values.value !== target.value) body.value = values.value\n if (values.label !== target.label) body.label = values.label\n const nextColor = values.color ?? null\n if (nextColor !== (target.color ?? null)) body.color = nextColor\n const nextIcon = values.icon ?? null\n if (nextIcon !== (target.icon ?? null)) body.icon = nextIcon\n if (Object.keys(body).length === 0) {\n closeDialog()\n return\n }\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(target.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(target.id)}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n },\n { errorMessage: errorSave },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'update', id: target.id, kind, ...body },\n })\n flash(successSave, 'success')\n }\n closeDialog()\n await loadEntries()\n } catch (err) {\n console.error('customers.dictionaries.submit failed', err)\n throw err instanceof Error ? err : new Error(errorSave)\n } finally {\n setSubmitting(false)\n }\n }, [closeDialog, dialog, errorSave, inheritedActionBlocked, kind, loadEntries, mutationContext, runMutation, successSave])\n\n const currentValues = React.useMemo<DictionaryFormValues>(() => {\n if (dialog && dialog.mode === 'edit') {\n return {\n value: dialog.entry.value,\n label: dialog.entry.label,\n color: dialog.entry.color,\n icon: dialog.entry.icon,\n }\n }\n return DEFAULT_FORM_VALUES\n }, [dialog])\n\n const tableTranslations = React.useMemo(() => ({\n title,\n valueColumn: t('customers.config.dictionaries.columns.value', 'Value'),\n labelColumn: t('customers.config.dictionaries.columns.label', 'Label'),\n appearanceColumn: t('customers.config.dictionaries.columns.appearance', 'Appearance'),\n addLabel: t('customers.config.dictionaries.actions.add', 'Add entry'),\n editLabel: t('customers.config.dictionaries.actions.edit', 'Edit'),\n deleteLabel: t('customers.config.dictionaries.actions.delete', 'Delete'),\n refreshLabel: t('customers.config.dictionaries.actions.refresh', 'Refresh'),\n inheritedLabel,\n inheritedTooltip,\n emptyLabel: t('customers.config.dictionaries.empty', 'No entries yet.'),\n usageCountLabel: kind === 'person-company-roles' ? usageCountLabel : undefined,\n searchPlaceholder,\n }), [inheritedLabel, inheritedTooltip, kind, searchPlaceholder, t, title, usageCountLabel])\n\n const formTranslations = React.useMemo(() => ({\n title: dialog?.mode === 'edit'\n ? t('customers.config.dictionaries.dialog.editTitle', 'Edit entry')\n : t('customers.config.dictionaries.dialog.addTitle', 'Add entry'),\n valueLabel: t('customers.config.dictionaries.dialog.valueLabel', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n saveLabel: t('customers.config.dictionaries.dialog.save', 'Save'),\n cancelLabel: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n appearance: {\n colorLabel: t('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: t('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: t('customers.config.dictionaries.dialog.iconLabel', 'Icon'),\n iconPlaceholder: t('customers.config.dictionaries.dialog.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('customers.config.dictionaries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('customers.config.dictionaries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.config.dictionaries.appearance.empty', 'None'),\n },\n }), [dialog, t])\n\n return (\n <section\n id={getCustomerDictionarySettingsSectionId(kind)}\n className=\"scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm\"\n >\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-medium\">{title}</h2>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n <DictionaryTable\n entries={entries}\n loading={loading}\n canManage\n onCreate={handleCreate}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onRefresh={loadEntries}\n translations={tableTranslations}\n />\n </div>\n <Dialog open={dialog !== null} onOpenChange={(open) => { if (!open) closeDialog() }}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>{formTranslations.title}</DialogTitle>\n </DialogHeader>\n <DictionaryForm\n mode={dialog?.mode === 'edit' ? 'edit' : 'create'}\n initialValues={currentValues}\n onSubmit={submitForm}\n onCancel={closeDialog}\n submitting={submitting}\n translations={formTranslations}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </section>\n )\n}\n"],
5
+ "mappings": ";AA6JM,SACE,KADF;AA3JN,YAAY,WAAW;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,gBAAgB,sBAAsB,mCAAmC;AAClF,SAAS,iCAAiC;AAC1C,SAAS,0BAA0B;AACnC,SAAS,mCAAmC;AAC5C,SAAS,YAAY;AACrB,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EACE;AAAA,OAEK;AAiBP,MAAM,sBAA4C;AAAA,EAChD,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AACR;AAEA,MAAM,yCAAyC,CAAC,KAAK,KAAK,GAAI;AAE9D,SAAS,iCAAqD;AAC5D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,OAAO,OAAO,SAAS;AAC7B,MAAI,CAAC,KAAK,WAAW,uBAAuB,EAAG,QAAO;AACtD,MAAI;AACF,WAAO,SAAS,eAAe,mBAAmB,KAAK,MAAM,CAAC,CAAC,CAAC;AAAA,EAClE,QAAQ;AACN,WAAO,SAAS,eAAe,KAAK,MAAM,CAAC,CAAC;AAAA,EAC9C;AACF;AAEe,SAAR,qBAAsC;AAC3C,QAAM,IAAI,KAAK;AAEf,QAAM,WAAW,MAAM,QAA6B,MAAM;AAAA,IACxD;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,mEAAmE,YAAY;AAAA,MACxF,aAAa,EAAE,yEAAyE,iEAAiE;AAAA,IAC3J;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,yDAAyD,UAAU;AAAA,MAC5E,aAAa,EAAE,+DAA+D,qDAAqD;AAAA,IACrI;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,6DAA6D,eAAe;AAAA,MACrF,aAAa,EAAE,mEAAmE,0CAA0C;AAAA,IAC9H;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,0DAA0D,YAAY;AAAA,MAC/E,aAAa,EAAE,gEAAgE,6CAA6C;AAAA,IAC9H;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,wDAAwD,SAAS;AAAA,MAC1E,aAAa,EAAE,8DAA8D,sCAAsC;AAAA,IACrH;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,2DAA2D,YAAY;AAAA,MAChF,aAAa,EAAE,iEAAiE,0CAA0C;AAAA,IAC5H;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,0DAA0D,kBAAkB;AAAA,MACrF,aAAa,EAAE,gEAAgE,wDAAwD;AAAA,IACzI;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,8DAA8D,gBAAgB;AAAA,MACvF,aAAa,EAAE,oEAAoE,2DAA2D;AAAA,IAChJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,6DAA6D,eAAe;AAAA,MACrF,aAAa,EAAE,mEAAmE,qCAAqC;AAAA,IACzH;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,UAAM,aAAuB,CAAC;AAC9B,QAAI,UAAyB;AAE7B,UAAM,wBAAwB,MAAM;AAClC,UAAI,YAAY,MAAM;AACpB,eAAO,qBAAqB,OAAO;AACnC,kBAAU;AAAA,MACZ;AACA,aAAO,WAAW,SAAS,GAAG;AAC5B,cAAM,YAAY,WAAW,IAAI;AACjC,YAAI,cAAc,OAAW,QAAO,aAAa,SAAS;AAAA,MAC5D;AAAA,IACF;AAEA,UAAM,qBAAqB,MAAM;AAC/B,qCAA+B,GAAG,eAAe,EAAE,OAAO,QAAQ,CAAC;AAAA,IACrE;AAEA,UAAM,qBAAqB,MAAM;AAC/B,4BAAsB;AACtB,UAAI,CAAC,OAAO,SAAS,KAAK,WAAW,uBAAuB,EAAG;AAC/D,yBAAmB;AACnB,UAAI,OAAO,OAAO,0BAA0B,YAAY;AACtD,kBAAU,OAAO,sBAAsB,kBAAkB;AAAA,MAC3D;AACA,6CAAuC,QAAQ,CAAC,UAAU;AACxD,mBAAW,KAAK,OAAO,WAAW,oBAAoB,KAAK,CAAC;AAAA,MAC9D,CAAC;AAAA,IACH;AAEA,uBAAmB;AACnB,WAAO,iBAAiB,cAAc,kBAAkB;AACxD,WAAO,MAAM;AACX,aAAO,oBAAoB,cAAc,kBAAkB;AAC3D,4BAAsB;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,yBAAC,YAAO,WAAU,aAChB;AAAA,0BAAC,QAAG,WAAU,0BACX,YAAE,uCAAuC,wBAAwB,GACpE;AAAA,MACA,oBAAC,OAAE,WAAU,iCACV,YAAE,6CAA6C,uDAAuD,GACzG;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,aACZ,mBAAS,IAAI,CAAC,YACb,oBAAC,6BAA8C,GAAG,WAAlB,QAAQ,IAAmB,CAC5D,GACH;AAAA,KACF;AAEJ;AAIA,SAAS,0BAA0B,EAAE,MAAM,OAAO,YAAY,GAAmC;AAC/F,QAAM,IAAI,KAAK;AACf,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAC3D,QAAM,eAAe,4BAA4B;AACjD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAiC,CAAC,CAAC;AACvE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAkB,IAAI;AAC1D,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAA6B,IAAI;AACnE,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AAExD,QAAM,gBAAgB,wBAAwB,IAAI;AAClD,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAIxC;AAAA,IACD,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AACD,QAAM,kBAAkB,MAAM;AAAA,IAC5B,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,cAAc;AAAA,MACd;AAAA,IACF;AAAA,IACA,CAAC,mBAAmB,aAAa;AAAA,EACnC;AAEA,QAAM,yBAAyB,EAAE,mDAAmD,oEAAoE;AACxJ,QAAM,mBAAmB,EAAE,mDAAmD,gCAAgC;AAC9G,QAAM,iBAAiB,EAAE,iDAAiD,WAAW;AACrF,QAAM,YAAY,EAAE,4CAA4C,oCAAoC;AACpG,QAAM,YAAY,EAAE,4CAA4C,kCAAkC;AAClG,QAAM,cAAc,EAAE,8CAA8C,oCAAoC;AACxG,QAAM,cAAc,EAAE,8CAA8C,yBAAyB;AAC7F,QAAM,gBAAgB,EAAE,gDAAgD,2BAA2B;AACnG,QAAM,wBAAwB,EAAE,+CAA+C,qBAAqB;AACpG,QAAM,6BAA6B,EAAE,+DAA+D,qBAAqB;AACzH,QAAM,4BAA4B;AAAA,IAChC;AAAA,IACA;AAAA,EACF;AACA,QAAM,kBAAkB,EAAE,sDAAsD,6BAA6B;AAC7G,QAAM,oBAAoB,EAAE,mDAAmD,sBAAiB;AAEhG,QAAM,qBAAqB,MAAM,YAAY,CAAC,UAAkB,UAAkB;AAChF,WAAO,SAAS,QAAQ,aAAa,OAAO,KAAK,CAAC;AAAA,EACpD,GAAG,CAAC,CAAC;AAEL,QAAM,cAAc,MAAM,YAAY,YAAY;AAChD,eAAW,IAAI;AACf,QAAI;AACF,YAAM,OAAO,MAAM;AAAA,QACjB,+BAA+B,IAAI;AAAA,QACnC;AAAA,QACA,EAAE,cAAc,UAAU;AAAA,MAC5B;AACA,UAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,EAAG,OAAM,IAAI,MAAM,SAAS;AAC1D,YAAM,SAAiC,KAAK,MAAM,IAAI,CAAC,UAAe;AAAA,QACpE,IAAI,OAAO,KAAK,EAAE;AAAA,QAClB,OAAO,OAAO,KAAK,SAAS,EAAE;AAAA,QAC9B,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAAA,QACrD,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAAA,QACrD,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,QAClD,YAAY,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAAA,QACpE,gBAAgB,OAAO,KAAK,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,QAChF,UAAU,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;AAAA,QAC9D,aAAa,KAAK,gBAAgB;AAAA,QAClC,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAAA,QACjE,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAAA,MACnE,EAAE;AACF,iBAAW,MAAM;AAAA,IACnB,SAAS,KAAK;AACZ,cAAQ,MAAM,sCAAsC,GAAG;AACvD,YAAM,WAAW,OAAO;AAAA,IAC1B,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,WAAW,MAAM,YAAY,CAAC;AAElC,QAAM,UAAU,MAAM;AACpB,gBAAY,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC9B,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,cAAU,IAAI;AAAA,EAChB,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,MAAM,YAAY,MAAM;AAC3C,cAAU,EAAE,MAAM,SAAS,CAAC;AAAA,EAC9B,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa,MAAM,YAAY,CAAC,UAAgC;AACpE,QAAI,MAAM,aAAa;AACrB,YAAM,wBAAwB,MAAM;AACpC;AAAA,IACF;AACA,cAAU,EAAE,MAAM,QAAQ,MAAM,CAAC;AAAA,EACnC,GAAG,CAAC,sBAAsB,CAAC;AAE3B,QAAM,eAAe,MAAM,YAAY,OAAO,UAAgC;AAC5E,QAAI,MAAM,aAAa;AACrB,YAAM,wBAAwB,MAAM;AACpC;AAAA,IACF;AACA,QAAI,SAAS,2BAA2B,MAAM,cAAc,KAAK,GAAG;AAClE,YAAM,QAAQ;AAAA,QACZ,OAAO;AAAA,QACP,aAAa,mBAAmB,2BAA2B,MAAM,cAAc,CAAC;AAAA,QAChF,aAAa;AAAA,QACb,YAAY,EAAE,+CAA+C,QAAQ;AAAA,MACvE,CAAC;AACD;AAAA,IACF;AACA,UAAM,UAAU,sBAAsB,QAAQ,aAAa,MAAM,SAAS,MAAM,KAAK;AACrF,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW;AAChB,QAAI;AACF,YAAM,YAAY;AAAA,QAChB,WAAW,MACT;AAAA,UAA4B,0BAA0B,MAAM,SAAS;AAAA,UAAG,MACtE;AAAA,YACE,+BAA+B,IAAI,IAAI,mBAAmB,MAAM,EAAE,CAAC;AAAA,YACnE,EAAE,QAAQ,SAAS;AAAA,YACnB,EAAE,cAAc,YAAY;AAAA,UAC9B;AAAA,QACF;AAAA,QACF,SAAS;AAAA,QACT,iBAAiB,EAAE,QAAQ,UAAU,IAAI,MAAM,IAAI,KAAK;AAAA,MAC1D,CAAC;AACD,YAAM,eAAe,SAAS;AAC9B,YAAM,YAAY;AAAA,IACpB,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG;AACzD,UAAI,SAAS,0BAA2B,KAA+B,SAAS,oBAAoB;AAClG,cAAM,aAAa,OAAQ,IAA8B,cAAc,CAAC;AACxE,cAAM,QAAQ;AAAA,UACZ,OAAO;AAAA,UACP,aAAa,mBAAmB,2BAA2B,UAAU;AAAA,UACrE,aAAa;AAAA,UACb,YAAY,EAAE,+CAA+C,QAAQ;AAAA,QACvE,CAAC;AACD;AAAA,MACF;AACA,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,YAAM,cAAc,OAAO;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,SAAS,uBAAuB,aAAa,oBAAoB,wBAAwB,MAAM,aAAa,iBAAiB,2BAA2B,4BAA4B,aAAa,eAAe,CAAC,CAAC;AAEtN,QAAM,aAAa,MAAM,YAAY,OAAO,WAAiC;AAC3E,UAAM,UAAU;AAAA,MACd,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,MAAM,OAAO;AAAA,IACf;AACA,kBAAc,IAAI;AAClB,QAAI;AACF,UAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,cAAM,YAAY;AAAA,UAChB,WAAW,MACT;AAAA,YACE,+BAA+B,IAAI;AAAA,YACnC;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,cAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,YAC9B;AAAA,YACA,EAAE,cAAc,UAAU;AAAA,UAC5B;AAAA,UACF,SAAS;AAAA,UACT,iBAAiB,EAAE,QAAQ,UAAU,MAAM,GAAG,QAAQ;AAAA,QACxD,CAAC;AACD,cAAM,aAAa,SAAS;AAAA,MAC9B,WAAW,OAAO,SAAS,QAAQ;AACjC,cAAM,SAAS,OAAO;AACtB,YAAI,OAAO,aAAa;AACtB,gBAAM,wBAAwB,MAAM;AACpC;AAAA,QACF;AACA,cAAM,OAAgC,CAAC;AACvC,YAAI,OAAO,UAAU,OAAO,MAAO,MAAK,QAAQ,OAAO;AACvD,YAAI,OAAO,UAAU,OAAO,MAAO,MAAK,QAAQ,OAAO;AACvD,cAAM,YAAY,OAAO,SAAS;AAClC,YAAI,eAAe,OAAO,SAAS,MAAO,MAAK,QAAQ;AACvD,cAAM,WAAW,OAAO,QAAQ;AAChC,YAAI,cAAc,OAAO,QAAQ,MAAO,MAAK,OAAO;AACpD,YAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAClC,sBAAY;AACZ;AAAA,QACF;AACA,cAAM,YAAY;AAAA,UAChB,WAAW,MACT;AAAA,YAA4B,0BAA0B,OAAO,SAAS;AAAA,YAAG,MACvE;AAAA,cACE,+BAA+B,IAAI,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,cACpE;AAAA,gBACE,QAAQ;AAAA,gBACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,gBAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,cAC3B;AAAA,cACA,EAAE,cAAc,UAAU;AAAA,YAC5B;AAAA,UACF;AAAA,UACF,SAAS;AAAA,UACT,iBAAiB,EAAE,QAAQ,UAAU,IAAI,OAAO,IAAI,MAAM,GAAG,KAAK;AAAA,QACpE,CAAC;AACD,cAAM,aAAa,SAAS;AAAA,MAC9B;AACA,kBAAY;AACZ,YAAM,YAAY;AAAA,IACpB,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG;AACzD,YAAM,eAAe,QAAQ,MAAM,IAAI,MAAM,SAAS;AAAA,IACxD,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,aAAa,QAAQ,WAAW,wBAAwB,MAAM,aAAa,iBAAiB,aAAa,WAAW,CAAC;AAEzH,QAAM,gBAAgB,MAAM,QAA8B,MAAM;AAC9D,QAAI,UAAU,OAAO,SAAS,QAAQ;AACpC,aAAO;AAAA,QACL,OAAO,OAAO,MAAM;AAAA,QACpB,OAAO,OAAO,MAAM;AAAA,QACpB,OAAO,OAAO,MAAM;AAAA,QACpB,MAAM,OAAO,MAAM;AAAA,MACrB;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,oBAAoB,MAAM,QAAQ,OAAO;AAAA,IAC7C;AAAA,IACA,aAAa,EAAE,+CAA+C,OAAO;AAAA,IACrE,aAAa,EAAE,+CAA+C,OAAO;AAAA,IACrE,kBAAkB,EAAE,oDAAoD,YAAY;AAAA,IACpF,UAAU,EAAE,6CAA6C,WAAW;AAAA,IACpE,WAAW,EAAE,8CAA8C,MAAM;AAAA,IACjE,aAAa,EAAE,gDAAgD,QAAQ;AAAA,IACvE,cAAc,EAAE,iDAAiD,SAAS;AAAA,IAC1E;AAAA,IACA;AAAA,IACA,YAAY,EAAE,uCAAuC,iBAAiB;AAAA,IACtE,iBAAiB,SAAS,yBAAyB,kBAAkB;AAAA,IACrE;AAAA,EACF,IAAI,CAAC,gBAAgB,kBAAkB,MAAM,mBAAmB,GAAG,OAAO,eAAe,CAAC;AAE1F,QAAM,mBAAmB,MAAM,QAAQ,OAAO;AAAA,IAC5C,OAAO,QAAQ,SAAS,SACpB,EAAE,kDAAkD,YAAY,IAChE,EAAE,iDAAiD,WAAW;AAAA,IAClE,YAAY,EAAE,mDAAmD,OAAO;AAAA,IACxE,YAAY,EAAE,mDAAmD,OAAO;AAAA,IACxE,WAAW,EAAE,6CAA6C,MAAM;AAAA,IAChE,aAAa,EAAE,+CAA+C,QAAQ;AAAA,IACtE,YAAY;AAAA,MACV,YAAY,EAAE,mDAAmD,OAAO;AAAA,MACxE,WAAW,EAAE,kDAAkD,wCAAwC;AAAA,MACvG,iBAAiB,EAAE,mDAAmD,cAAc;AAAA,MACpF,WAAW,EAAE,kDAAkD,MAAM;AAAA,MACrE,iBAAiB,EAAE,wDAAwD,+CAA+C;AAAA,MAC1H,wBAAwB,EAAE,mDAAmD,yBAAyB;AAAA,MACtG,uBAAuB,EAAE,8DAA8D,8BAAyB;AAAA,MAChH,sBAAsB,EAAE,wDAAwD,6BAA6B;AAAA,MAC7G,sBAAsB,EAAE,wDAAwD,aAAa;AAAA,MAC7F,gBAAgB,EAAE,kDAAkD,aAAa;AAAA,MACjF,mBAAmB,EAAE,kDAAkD,MAAM;AAAA,IAC/E;AAAA,EACF,IAAI,CAAC,QAAQ,CAAC,CAAC;AAEf,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,uCAAuC,IAAI;AAAA,MAC/C,WAAU;AAAA,MAEV;AAAA,6BAAC,SAAI,WAAU,gCACb;AAAA,8BAAC,QAAG,WAAU,uBAAuB,iBAAM;AAAA,UAC3C,oBAAC,OAAE,WAAU,iCAAiC,uBAAY;AAAA,WAC5D;AAAA,QACA,oBAAC,SAAI,WAAU,qBACb;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,WAAS;AAAA,YACT,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,WAAW;AAAA,YACX,cAAc;AAAA;AAAA,QAChB,GACF;AAAA,QACA,oBAAC,UAAO,MAAM,WAAW,MAAM,cAAc,CAAC,SAAS;AAAE,cAAI,CAAC,KAAM,aAAY;AAAA,QAAE,GAChF,+BAAC,iBAAc,WAAU,YACvB;AAAA,8BAAC,gBACC,8BAAC,eAAa,2BAAiB,OAAM,GACvC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,QAAQ,SAAS,SAAS,SAAS;AAAA,cACzC,eAAe;AAAA,cACf,UAAU;AAAA,cACV,UAAU;AAAA,cACV;AAAA,cACA,cAAc;AAAA,cACd,iBAAiB;AAAA;AAAA,UACnB;AAAA,WACF,GACF;AAAA,QACC;AAAA;AAAA;AAAA,EACH;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -44,6 +44,10 @@ import {
44
44
  ensureCustomerDictionary,
45
45
  invalidateCustomerDictionary
46
46
  } from "./detail/hooks/useCustomerDictionary.js";
47
+ import {
48
+ CUSTOMER_DICTIONARIES_MANAGE_HREF,
49
+ getCustomerDictionaryManageHref
50
+ } from "../lib/dictionaries.js";
47
51
  import { normalizeCustomFieldSubmitValue } from "./detail/customFieldUtils.js";
48
52
  import { CUSTOMER_PHONE_INVALID_MESSAGE_KEY } from "../data/validators.js";
49
53
  const metadata = {
@@ -155,7 +159,7 @@ function DictionarySelectField({
155
159
  fetchOptions,
156
160
  createOption,
157
161
  labels,
158
- manageHref,
162
+ manageHref: manageHref ?? getCustomerDictionaryManageHref(kind),
159
163
  selectClassName,
160
164
  allowInlineCreate,
161
165
  allowAppearance,
@@ -1450,6 +1454,7 @@ function mapPersonOverviewToFormValues(overview) {
1450
1454
  };
1451
1455
  }
1452
1456
  export {
1457
+ CUSTOMER_DICTIONARIES_MANAGE_HREF,
1453
1458
  CompanySelectField,
1454
1459
  DictionarySelectField,
1455
1460
  buildCompanyEditPayload,
@@ -1471,6 +1476,7 @@ export {
1471
1476
  createPersonFormGroups,
1472
1477
  createPersonFormSchema,
1473
1478
  createPersonPersonalDataGroups,
1479
+ getCustomerDictionaryManageHref,
1474
1480
  mapCompanyOverviewToFormValues,
1475
1481
  mapPersonOverviewToFormValues,
1476
1482
  metadata
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/components/formConfig.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport Link from 'next/link'\nimport { Check, Pencil, Plus, Settings } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { EmailInput } from '@open-mercato/ui/primitives/email-input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { coerceDisplayName, deriveDisplayName, isDerivedDisplayName } from '../lib/displayName'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { PhoneNumberField } from '@open-mercato/ui/backend/inputs/PhoneNumberField'\nimport { isValidPhoneNumber } from '@open-mercato/shared/lib/phone'\nimport type {\n CrudCustomFieldRenderProps,\n CrudField,\n CrudFormGroup,\n CrudFormGroupComponentProps,\n} from '@open-mercato/ui/backend/CrudForm'\nimport {\n DictionaryEntrySelect,\n type DictionarySelectLabels,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { RolesSection } from './detail/RolesSection'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useEmailDuplicateCheck } from '../backend/hooks/useEmailDuplicateCheck'\nimport { lookupPhoneDuplicate } from '../utils/phoneDuplicates'\nimport { CustomerAddressTiles, type CustomerAddressInput, type CustomerAddressValue } from './AddressTiles'\nimport {\n ensureCustomerDictionary,\n invalidateCustomerDictionary,\n} from './detail/hooks/useCustomerDictionary'\nimport type { CustomerDictionaryKind } from '../lib/dictionaries'\nimport { normalizeCustomFieldSubmitValue } from './detail/customFieldUtils'\nimport { CUSTOMER_PHONE_INVALID_MESSAGE_KEY } from '../data/validators'\n\nexport const metadata = {\n navHidden: true,\n} as const\n\nfunction cn(...values: Array<string | null | undefined | false>) {\n return values.filter(Boolean).join(' ')\n}\n\nexport type Translator = (\n key: string,\n fallback?: string,\n params?: Record<string, string | number>,\n) => string\n\nexport type PersonFormValues = {\n displayName: string\n firstName: string\n lastName: string\n jobTitle?: string\n companyEntityId?: string | null\n primaryEmail?: string\n primaryPhone?: string\n status?: string\n lifecycleStage?: string\n source?: string\n description?: string\n addresses?: CustomerAddressValue[]\n} & Record<string, unknown>\n\nexport type CompanyFormValues = {\n displayName: string\n primaryEmail?: string\n primaryPhone?: string\n status?: string\n lifecycleStage?: string\n source?: string\n legalName?: string\n brandName?: string\n domain?: string\n websiteUrl?: string\n industry?: string\n sizeBucket?: string\n annualRevenue?: string\n description?: string\n addresses?: CustomerAddressValue[]\n} & Record<string, unknown>\n\ntype DictionarySelectFieldProps = {\n kind: CustomerDictionaryKind\n value?: string\n onChange: (value: string | undefined) => void\n labels: DictionarySelectLabels\n selectClassName?: string\n manageHref?: string\n allowInlineCreate?: boolean\n allowAppearance?: boolean\n showManage?: boolean\n showLabelInput?: boolean\n showActiveAppearance?: boolean\n}\n\nconst emailValidationSchema = z.string().email()\nconst EMAIL_CHECK_DEBOUNCE_MS = 350\n\nconst createSectionHeadingField = (id: string, title: string): CrudField => ({\n id,\n label: '',\n type: 'custom',\n layout: 'full',\n component: () => (\n <div className=\"mt-4 border-t border-border pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n ),\n})\n\nexport function DictionarySelectField({\n kind,\n value,\n onChange,\n labels,\n selectClassName,\n manageHref,\n allowInlineCreate = false,\n allowAppearance = false,\n showManage = false,\n showLabelInput = true,\n showActiveAppearance = true,\n}: DictionarySelectFieldProps) {\n const t = useT()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const translate = React.useCallback(\n (key: string, fallback: string) => {\n const result = t(key)\n return result === key ? fallback : result\n },\n [t],\n )\n\n const appearanceLabels = React.useMemo(\n () => ({\n colorLabel: translate('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: translate('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: translate('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: translate('customers.config.dictionaries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: translate(\n 'customers.config.dictionaries.dialog.iconPlaceholder',\n 'Type an emoji or pick one of the suggestions.',\n ),\n iconPickerTriggerLabel: translate('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: translate(\n 'customers.config.dictionaries.dialog.iconSearchPlaceholder',\n 'Search icons or emojis\u2026',\n ),\n iconSearchEmptyLabel: translate(\n 'customers.config.dictionaries.dialog.iconSearchEmpty',\n 'No icons match your search.',\n ),\n iconSuggestionsLabel: translate('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: translate('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: translate('customers.config.dictionaries.dialog.previewEmpty', 'No appearance selected'),\n }),\n [translate],\n )\n\n const fetchOptions = React.useCallback(async () => {\n const data = await ensureCustomerDictionary(queryClient, kind, scopeVersion)\n return data.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }, [kind, queryClient, scopeVersion])\n\n const createOption = React.useCallback(\n async (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/customers/dictionaries/${kind}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n value: input.value,\n label: input.label ?? input.value,\n color: input.color ?? undefined,\n icon: input.icon ?? undefined,\n }),\n },\n )\n const payload = call.result ?? {}\n if (!call.ok) {\n const message = typeof payload.error === 'string' ? payload.error : labels.errorSave\n throw new Error(message)\n }\n await invalidateCustomerDictionary(queryClient, kind)\n const valueCreated = typeof payload.value === 'string' ? payload.value : input.value\n const label =\n typeof payload.label === 'string' && payload.label.trim().length ? payload.label.trim() : valueCreated\n const color =\n typeof payload.color === 'string' && payload.color.trim().startsWith('#')\n ? payload.color.trim()\n : null\n const icon =\n typeof payload.icon === 'string' && payload.icon.trim().length ? payload.icon.trim() : null\n return { value: valueCreated, label, color, icon }\n },\n [kind, labels.errorSave, queryClient],\n )\n\n return (\n <DictionaryEntrySelect\n value={value}\n onChange={onChange}\n fetchOptions={fetchOptions}\n createOption={createOption}\n labels={labels}\n manageHref={manageHref}\n selectClassName={selectClassName}\n allowInlineCreate={allowInlineCreate}\n allowAppearance={allowAppearance}\n showManage={showManage}\n showLabelInput={showLabelInput}\n sortOptions=\"none\"\n showActiveAppearance={showActiveAppearance}\n />\n )\n}\n\nconst createPrimaryEmailField = (t: Translator): CrudField => ({\n id: 'primaryEmail',\n label: t('customers.people.form.primaryEmail'),\n type: 'custom',\n component: function PrimaryEmailField({ value, setValue, error, autoFocus, disabled, recordId }: CrudCustomFieldRenderProps) {\n const [inputValue, setInputValue] = React.useState(() => (typeof value === 'string' ? value : ''))\n const trimmedInput = inputValue.trim()\n const isValidEmail = React.useMemo(\n () => !!trimmedInput.length && emailValidationSchema.safeParse(trimmedInput).success,\n [trimmedInput]\n )\n const { duplicate, checking } = useEmailDuplicateCheck(inputValue, {\n recordId: typeof recordId === 'string' ? recordId : null,\n disabled: disabled || !!error || !isValidEmail,\n debounceMs: EMAIL_CHECK_DEBOUNCE_MS,\n matchMode: 'prefix',\n })\n\n React.useEffect(() => {\n setInputValue(typeof value === 'string' ? value : '')\n }, [value])\n\n return (\n <div className=\"space-y-2\">\n <EmailInput\n value={inputValue}\n onChange={(event) => {\n const nextValue = event.target.value\n setInputValue(nextValue)\n setValue(nextValue)\n }}\n placeholder={t('customers.people.form.primaryEmailPlaceholder', 'name@example.com')}\n spellCheck={false}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n />\n {!error && duplicate ? (\n <p className=\"text-xs text-status-warning-text\">\n {t('customers.people.form.emailDuplicateNotice', undefined, { name: duplicate.displayName })}{' '}\n <Link className=\"font-medium text-primary underline underline-offset-2\" href={`/backend/customers/people-v2/${duplicate.id}`}>\n {t('customers.people.form.emailDuplicateLink')}\n </Link>\n </p>\n ) : null}\n {!error && !duplicate && checking ? (\n <p className=\"text-xs text-muted-foreground\">{t('customers.people.form.emailChecking')}</p>\n ) : null}\n </div>\n )\n },\n})\n\ntype DictionaryFieldDefinition = {\n id: 'status' | 'lifecycleStage' | 'source'\n kind: 'statuses' | 'lifecycle-stages' | 'sources'\n labelKey: string\n placeholderKey: string\n addLabelKey: string\n promptKey: string\n dialogTitleKey: string\n layout?: CrudField['layout']\n}\n\nconst dictionaryFieldDefinitions: DictionaryFieldDefinition[] = [\n {\n id: 'status',\n kind: 'statuses',\n labelKey: 'customers.people.form.status',\n placeholderKey: 'customers.people.form.status.placeholder',\n addLabelKey: 'customers.people.form.dictionary.addStatus',\n promptKey: 'customers.people.form.dictionary.promptStatus',\n dialogTitleKey: 'customers.people.form.dictionary.dialogTitleStatus',\n layout: 'half',\n },\n {\n id: 'lifecycleStage',\n kind: 'lifecycle-stages',\n labelKey: 'customers.people.form.lifecycleStage',\n placeholderKey: 'customers.people.form.lifecycleStage.placeholder',\n addLabelKey: 'customers.people.form.dictionary.addLifecycleStage',\n promptKey: 'customers.people.form.dictionary.promptLifecycleStage',\n dialogTitleKey: 'customers.people.form.dictionary.dialogTitleLifecycleStage',\n layout: 'half',\n },\n {\n id: 'source',\n kind: 'sources',\n labelKey: 'customers.people.form.source',\n placeholderKey: 'customers.people.form.source.placeholder',\n addLabelKey: 'customers.people.form.dictionary.addSource',\n promptKey: 'customers.people.form.dictionary.promptSource',\n dialogTitleKey: 'customers.people.form.dictionary.dialogTitleSource',\n layout: 'half',\n },\n]\n\nconst buildDictionaryLabels = (t: Translator, definition: DictionaryFieldDefinition): DictionarySelectLabels => ({\n placeholder: t(definition.placeholderKey),\n addLabel: t(definition.addLabelKey),\n addPrompt: t(definition.promptKey),\n dialogTitle: t(definition.dialogTitleKey),\n valueLabel: t('customers.people.form.dictionary.valueLabel', 'Value'),\n valuePlaceholder: t('customers.people.form.dictionary.valuePlaceholder', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('customers.people.form.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n successCreateLabel: undefined,\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.dictionary.loading'),\n manageTitle: t('customers.people.form.dictionary.manage'),\n})\n\nconst companyDictionaryFieldDefinitions: DictionaryFieldDefinition[] = [\n {\n id: 'status',\n kind: 'statuses',\n labelKey: 'customers.companies.form.status',\n placeholderKey: 'customers.companies.form.status.placeholder',\n addLabelKey: 'customers.companies.form.dictionary.addStatus',\n promptKey: 'customers.companies.form.dictionary.promptStatus',\n dialogTitleKey: 'customers.companies.form.dictionary.dialogTitleStatus',\n layout: 'third',\n },\n {\n id: 'lifecycleStage',\n kind: 'lifecycle-stages',\n labelKey: 'customers.companies.form.lifecycleStage',\n placeholderKey: 'customers.companies.form.lifecycleStage.placeholder',\n addLabelKey: 'customers.companies.form.dictionary.addLifecycleStage',\n promptKey: 'customers.companies.form.dictionary.promptLifecycleStage',\n dialogTitleKey: 'customers.companies.form.dictionary.dialogTitleLifecycleStage',\n layout: 'third',\n },\n {\n id: 'source',\n kind: 'sources',\n labelKey: 'customers.companies.form.source',\n placeholderKey: 'customers.companies.form.source.placeholder',\n addLabelKey: 'customers.companies.form.dictionary.addSource',\n promptKey: 'customers.companies.form.dictionary.promptSource',\n dialogTitleKey: 'customers.companies.form.dictionary.dialogTitleSource',\n layout: 'third',\n },\n]\n\nconst createPrimaryPhoneField = (t: Translator): CrudField => ({\n id: 'primaryPhone',\n label: t('customers.people.form.primaryPhone'),\n type: 'custom',\n component: function PrimaryPhoneField({ value, setValue, error, autoFocus, disabled, recordId }: CrudCustomFieldRenderProps) {\n const currentRecordId = React.useMemo(() => (typeof recordId === 'string' ? recordId : null), [recordId])\n\n const duplicateLookup = React.useCallback(\n async (digits: string) => {\n if (disabled || error) return null\n return lookupPhoneDuplicate(digits, { recordId: currentRecordId })\n },\n [currentRecordId, disabled, error]\n )\n\n return (\n <PhoneNumberField\n value={typeof value === 'string' ? value : null}\n onValueChange={(next) => setValue(typeof next === 'string' ? next : '')}\n externalError={error}\n autoFocus={autoFocus}\n disabled={disabled}\n placeholder={t('customers.people.form.primaryPhonePlaceholder', '+1 555 123 4567')}\n checkingLabel={t('customers.people.form.phoneChecking')}\n duplicateLabel={(match) => t('customers.people.form.phoneDuplicateNotice', undefined, { name: match.label })}\n duplicateLinkLabel={t('customers.people.form.phoneDuplicateLink')}\n invalidLabel={t('customers.people.form.primaryPhone.invalid', 'Enter a valid phone number with country code (e.g. +1 212 555 1234)')}\n minDigits={7}\n onDuplicateLookup={!disabled && !error ? duplicateLookup : undefined}\n />\n )\n },\n})\n\nconst blankToUndefined = (value?: string | null): string | undefined => {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length ? trimmed : undefined\n}\n\ntype CompanySelectLabels = {\n placeholder: string\n addLabel: string\n addPrompt?: string\n dialogTitle: string\n inputLabel: string\n inputPlaceholder: string\n emptyError: string\n cancelLabel: string\n saveLabel: string\n errorLoad: string\n errorSave: string\n loadingLabel: string\n}\n\ntype CompanySelectFieldProps = {\n value?: string\n onChange: (value: string | undefined) => void\n labels: CompanySelectLabels\n}\n\ntype CompanyOption = { value: string; label: string }\n\nfunction mergeCompanyOptions(options: CompanyOption[], selected: CompanyOption | null): CompanyOption[] {\n if (!selected) return options\n if (options.some((option) => option.value === selected.value)) return options\n return [selected, ...options]\n}\n\nfunction normalizeCompanyOption(raw: unknown): CompanyOption | null {\n if (!raw || typeof raw !== 'object') return null\n const candidate = raw as Record<string, unknown>\n const id = typeof candidate.id === 'string' ? candidate.id : null\n if (!id) return null\n const displayName =\n typeof candidate.display_name === 'string' && candidate.display_name.trim().length\n ? candidate.display_name.trim()\n : typeof candidate.displayName === 'string' && candidate.displayName.trim().length\n ? candidate.displayName.trim()\n : null\n if (!displayName) return null\n return { value: id, label: displayName }\n}\n\nexport function CompanySelectField({ value, onChange, labels }: CompanySelectFieldProps) {\n const [options, setOptions] = React.useState<CompanyOption[]>([])\n const [loading, setLoading] = React.useState(true)\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [newCompany, setNewCompany] = React.useState('')\n const [saving, setSaving] = React.useState(false)\n const [formError, setFormError] = React.useState<string | null>(null)\n\n const loadCompanyOption = React.useCallback(\n async (companyId: string): Promise<CompanyOption | null> => {\n const payload = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/companies?id=${encodeURIComponent(companyId)}&pageSize=1`,\n undefined,\n { errorMessage: labels.errorLoad },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item: unknown) => normalizeCompanyOption(item))\n .find((option): option is CompanyOption => option?.value === companyId) ?? null\n },\n [labels.errorLoad],\n )\n\n const loadOptions = React.useCallback(async () => {\n setLoading(true)\n try {\n const payload = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/customers/companies?pageSize=100&sortField=name&sortDir=asc',\n undefined,\n { errorMessage: labels.errorLoad },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n const normalized = items\n .map((item: unknown) => normalizeCompanyOption(item))\n .filter((item: CompanyOption | null): item is CompanyOption => item !== null)\n .sort((a: CompanyOption, b: CompanyOption) =>\n a.label.localeCompare(b.label, undefined, { sensitivity: 'base' })\n )\n const selected =\n value && !normalized.some((option) => option.value === value)\n ? await loadCompanyOption(value).catch(() => null)\n : null\n setOptions(mergeCompanyOptions(normalized, selected))\n } catch (err) {\n const message = err instanceof Error ? err.message : labels.errorLoad\n flash(message, 'error')\n setOptions([])\n } finally {\n setLoading(false)\n }\n }, [labels.errorLoad, loadCompanyOption, value])\n\n React.useEffect(() => {\n loadOptions().catch(() => {})\n }, [loadOptions])\n\n React.useEffect(() => {\n if (!value || options.some((option) => option.value === value)) return\n loadCompanyOption(value)\n .then((selected) => {\n setOptions((current) => mergeCompanyOptions(current, selected))\n })\n .catch(() => {})\n }, [loadCompanyOption, options, value])\n\n const handleDialogChange = React.useCallback((open: boolean) => {\n setDialogOpen(open)\n if (!open) {\n setNewCompany('')\n setFormError(null)\n setSaving(false)\n }\n }, [])\n\n const handleDialogSubmit = React.useCallback(async () => {\n if (saving) return\n const trimmed = newCompany.trim()\n if (!trimmed) {\n setFormError(labels.emptyError)\n return\n }\n setSaving(true)\n try {\n const call = await apiCallOrThrow<{ id?: string; entityId?: string }>(\n '/api/customers/companies',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ displayName: trimmed }),\n },\n { errorMessage: labels.errorSave },\n )\n const payload = call.result ?? {}\n const createdId =\n typeof payload?.id === 'string'\n ? payload.id\n : typeof payload?.entityId === 'string'\n ? payload.entityId\n : null\n await loadOptions()\n if (createdId) {\n onChange(createdId)\n }\n setDialogOpen(false)\n setNewCompany('')\n setFormError(null)\n } catch (err) {\n const message = err instanceof Error ? err.message : labels.errorSave\n flash(message, 'error')\n } finally {\n setSaving(false)\n }\n }, [labels.emptyError, labels.errorSave, loadOptions, newCompany, onChange, saving])\n\n const handleInputKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n handleDialogSubmit().catch(() => {})\n }\n },\n [handleDialogSubmit]\n )\n\n const disabled = loading || saving\n const selectedOption = value ? options.find((option) => option.value === value) : null\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Select\n value={value || undefined}\n onValueChange={(next) => onChange(next || undefined)}\n disabled={loading}\n >\n <SelectTrigger>\n <SelectValue placeholder={labels.placeholder}>{selectedOption?.label}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Dialog open={dialogOpen} onOpenChange={handleDialogChange}>\n <DialogTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n disabled={disabled}\n aria-label={labels.addLabel}\n title={labels.addLabel}\n >\n <Plus className=\"h-4 w-4\" aria-hidden />\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-sm\">\n <DialogHeader>\n <DialogTitle>{labels.dialogTitle}</DialogTitle>\n {labels.addPrompt ? <DialogDescription>{labels.addPrompt}</DialogDescription> : null}\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">{labels.inputLabel}</label>\n <Input\n placeholder={labels.inputPlaceholder}\n value={newCompany}\n onChange={(event) => {\n setNewCompany(event.target.value)\n if (formError) setFormError(null)\n }}\n onKeyDown={handleInputKeyDown}\n autoFocus\n disabled={saving}\n />\n </div>\n {formError ? <p className=\"text-sm text-status-error-text\">{formError}</p> : null}\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setDialogOpen(false)} disabled={saving}>\n {labels.cancelLabel}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n handleDialogSubmit().catch(() => {})\n }}\n disabled={saving || !newCompany.trim()}\n >\n {saving ? `${labels.saveLabel}\u2026` : labels.saveLabel}\n </Button>\n </DialogFooter>\n </div>\n </DialogContent>\n </Dialog>\n </div>\n {loading ? <div className=\"text-xs text-muted-foreground\">{labels.loadingLabel}</div> : null}\n </div>\n )\n}\n\nexport const createPersonFormSchema = () =>\n z\n .object({\n displayName: z.string().trim().min(1),\n firstName: z.string().trim().min(1),\n lastName: z.string().trim().min(1),\n jobTitle: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n primaryEmail: z\n .string()\n .trim()\n .email()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val)),\n primaryPhone: z\n .string()\n .trim()\n .max(50)\n .refine((value) => isValidPhoneNumber(value), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n status: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n lifecycleStage: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n source: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n description: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n companyEntityId: z\n .string()\n .trim()\n .uuid()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n })\n .passthrough()\n\nexport const createDisplayNameSection = (t: Translator) =>\n function DisplayNameSection({ values, setValue, errors }: CrudFormGroupComponentProps) {\n const [editing, setEditing] = React.useState(false)\n const [manualOverride, setManualOverride] = React.useState(() => {\n const current = typeof values.displayName === 'string' ? values.displayName : ''\n const firstInit = typeof values.firstName === 'string' ? values.firstName : ''\n const lastInit = typeof values.lastName === 'string' ? values.lastName : ''\n // Sticky-manual: treat as user-customized only when the persisted display name\n // doesn't match the first+last derivation (matches the server-side rule in\n // updatePersonCommand). Empty values are considered derived.\n return !isDerivedDisplayName(current, firstInit, lastInit)\n })\n\n const first = typeof values.firstName === 'string' ? values.firstName.trim() : ''\n const last = typeof values.lastName === 'string' ? values.lastName.trim() : ''\n const derived = React.useMemo(() => deriveDisplayName(first, last), [first, last])\n\n React.useEffect(() => {\n if (!manualOverride) {\n const target = derived || ''\n const current = typeof values.displayName === 'string' ? values.displayName : ''\n if (current !== target) {\n setValue('displayName', target)\n }\n }\n }, [manualOverride, derived, setValue, values.displayName])\n\n const currentValue = typeof values.displayName === 'string' ? values.displayName : ''\n const previewValue = currentValue || derived\n const placeholder = t('customers.people.form.displayNamePreview.empty')\n const error = errors.displayName\n\n const toggleEditing = () => {\n if (!editing && !manualOverride) {\n const target = derived || previewValue || ''\n setValue('displayName', target)\n setManualOverride(true)\n }\n setEditing((state) => !state)\n }\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (!manualOverride) setManualOverride(true)\n setValue('displayName', event.target.value)\n }\n\n const handleReset = () => {\n setManualOverride(false)\n setEditing(false)\n }\n\n return (\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1\">\n <div className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.people.form.displayNamePreview')}\n </div>\n {editing ? (\n <div className=\"mt-2 space-y-2\">\n <Input\n value={currentValue}\n onChange={handleChange}\n placeholder={t('customers.people.form.displayName.placeholder')}\n />\n {error ? <p className=\"text-xs text-status-error-text\">{error}</p> : null}\n </div>\n ) : (\n <div className=\"mt-1 text-base font-medium\">{previewValue || placeholder}</div>\n )}\n </div>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={toggleEditing}>\n {editing ? (\n <>\n <Check className=\"mr-2 h-4 w-4\" />\n {t('customers.people.form.displayName.done')}\n </>\n ) : (\n <>\n <Pencil className=\"mr-2 h-4 w-4\" />\n {t('customers.people.form.displayName.edit')}\n </>\n )}\n </Button>\n </div>\n {manualOverride ? (\n <div className=\"mt-3\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={handleReset} disabled={!derived}>\n {t('customers.people.form.displayName.reset')}\n </Button>\n </div>\n ) : null}\n </div>\n )\n }\n\nexport const createPersonFormFields = (t: Translator): CrudField[] => {\n const contactSection = createSectionHeadingField('__contactInformationSection', t('customers.people.form.sections.contactInformation'))\n const companySection = createSectionHeadingField('__companyInformationSection', t('customers.people.form.sections.companyInformation'))\n const dictionaryFields: CrudField[] = dictionaryFieldDefinitions.map((definition) => ({\n id: definition.id,\n label: t(definition.labelKey),\n type: 'custom',\n layout: definition.layout ?? 'third',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind={definition.kind}\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={buildDictionaryLabels(t, definition)}\n allowInlineCreate\n allowAppearance\n showManage\n />\n ),\n }))\n\n return [\n { id: 'displayName', label: t('customers.people.form.displayName.label'), type: 'text', required: true },\n { id: 'firstName', label: t('customers.people.form.firstName'), type: 'text', required: true, layout: 'half' },\n { id: 'lastName', label: t('customers.people.form.lastName'), type: 'text', required: true, layout: 'half' },\n {\n id: 'jobTitle',\n label: t('customers.people.form.jobTitle', 'Job title'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind=\"job-titles\"\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={{\n placeholder: t('customers.people.form.jobTitle.placeholder', 'Select a job title'),\n addLabel: t('customers.people.form.dictionary.addJobTitle', 'Add job title'),\n addPrompt: t('customers.people.form.dictionary.promptJobTitle', 'Enter a new job title'),\n dialogTitle: t('customers.people.form.dictionary.dialogTitleJobTitle', 'Add job title'),\n valueLabel: t('customers.people.form.dictionary.valueLabel', 'Value'),\n valuePlaceholder: t('customers.people.form.dictionary.valuePlaceholder', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('customers.people.form.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n successCreateLabel: undefined,\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.dictionary.loading'),\n manageTitle: t('customers.people.form.dictionary.manage'),\n }}\n allowInlineCreate\n allowAppearance\n showManage\n />\n ),\n },\n contactSection,\n createPrimaryEmailField(t),\n createPrimaryPhoneField(t),\n companySection,\n {\n id: 'companyEntityId',\n label: t('customers.people.form.company'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }) => (\n <CompanySelectField\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={{\n placeholder: t('customers.people.form.company.placeholder'),\n addLabel: t('customers.people.form.company.add'),\n addPrompt: t('customers.people.form.company.prompt'),\n dialogTitle: t('customers.people.form.company.dialogTitle'),\n inputLabel: t('customers.people.form.company.inputLabel'),\n inputPlaceholder: t('customers.people.form.company.inputPlaceholder'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.company.loading'),\n }}\n />\n ),\n },\n ...dictionaryFields,\n { id: 'description', label: t('customers.people.form.description'), type: 'textarea' },\n {\n id: 'addresses',\n label: '',\n type: 'custom',\n layout: 'full',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => {\n const addresses = Array.isArray(value) ? (value as CustomerAddressValue[]) : []\n return (\n <CustomerAddressTiles\n addresses={addresses}\n t={t}\n emptyLabel={t('customers.people.detail.empty.addresses')}\n gridClassName=\"grid gap-4 min-[480px]:grid-cols-1 xl:grid-cols-2\"\n onCreate={async (payload: CustomerAddressInput) => {\n const nextId =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `tmp-${Math.random().toString(36).slice(2)}`\n const next: CustomerAddressValue = {\n id: nextId,\n name: payload.name ?? undefined,\n purpose: payload.purpose ?? undefined,\n companyName: payload.companyName ?? undefined,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? undefined,\n buildingNumber: payload.buildingNumber ?? undefined,\n flatNumber: payload.flatNumber ?? undefined,\n city: payload.city ?? undefined,\n region: payload.region ?? undefined,\n postalCode: payload.postalCode ?? undefined,\n country: payload.country ?? undefined,\n isPrimary: payload.isPrimary ?? false,\n }\n const current = Array.isArray(addresses) ? addresses : []\n const nextAddresses =\n next.isPrimary === true\n ? [next, ...current.map((item) => ({ ...item, isPrimary: false }))]\n : [next, ...current]\n setValue(nextAddresses)\n }}\n onUpdate={async (id, payload) => {\n const current = Array.isArray(addresses) ? addresses : []\n const updated = current.map((item) => {\n if (item.id !== id) {\n return payload.isPrimary ? { ...item, isPrimary: false } : item\n }\n return {\n ...item,\n name: payload.name ?? null,\n purpose: payload.purpose ?? null,\n companyName: payload.companyName ?? null,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? null,\n buildingNumber: payload.buildingNumber ?? null,\n flatNumber: payload.flatNumber ?? null,\n city: payload.city ?? null,\n region: payload.region ?? null,\n postalCode: payload.postalCode ?? null,\n country: payload.country ?? null,\n isPrimary: payload.isPrimary ?? false,\n }\n })\n setValue(updated)\n }}\n onDelete={async (id) => {\n const current = Array.isArray(addresses) ? addresses : []\n setValue(current.filter((item) => item.id !== id))\n }}\n />\n )\n },\n },\n ]\n}\n\nexport const createPersonFormGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.people.form.groups.details'),\n column: 1,\n component: createDisplayNameSection(t),\n fields: [\n 'firstName',\n 'lastName',\n '__contactInformationSection',\n 'primaryEmail',\n 'primaryPhone',\n '__companyInformationSection',\n 'jobTitle',\n 'companyEntityId',\n 'status',\n 'lifecycleStage',\n 'source',\n ],\n },\n {\n id: 'addresses',\n title: t('customers.people.form.groups.addresses'),\n column: 1,\n fields: ['addresses'],\n },\n {\n id: 'notes',\n title: t('customers.people.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.people.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\nexport function buildPersonPayload(\n values: PersonFormValues | PersonEditFormValues,\n organizationId?: string | null,\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {}\n\n const displayNameValue = typeof values.displayName === 'string' ? values.displayName.trim() : ''\n if (!displayNameValue) {\n throw new Error('DISPLAY_NAME_REQUIRED')\n }\n payload.displayName = displayNameValue\n payload.firstName = typeof values.firstName === 'string' ? values.firstName.trim() : ''\n payload.lastName = typeof values.lastName === 'string' ? values.lastName.trim() : ''\n\n const assign = (key: string, val?: string | null) => {\n if (val === null) {\n payload[key] = null\n return\n }\n const normalized = blankToUndefined(val)\n if (normalized !== undefined) payload[key] = normalized\n }\n\n assign('jobTitle', typeof values.jobTitle === 'string' ? values.jobTitle : undefined)\n assign('primaryEmail', typeof values.primaryEmail === 'string' ? values.primaryEmail : undefined)\n assign('primaryPhone', typeof values.primaryPhone === 'string' ? values.primaryPhone : undefined)\n assign('status', typeof values.status === 'string' ? values.status : undefined)\n assign('lifecycleStage', typeof values.lifecycleStage === 'string' ? values.lifecycleStage : undefined)\n assign('source', typeof values.source === 'string' ? values.source : undefined)\n assign(\n 'companyEntityId',\n typeof values.companyEntityId === 'string'\n ? values.companyEntityId\n : values.companyEntityId === null\n ? null\n : undefined,\n )\n assign('description', typeof values.description === 'string' ? values.description : undefined)\n\n const customFields = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n if (Object.keys(customFields).length) {\n payload.customFields = customFields\n }\n\n if (organizationId) payload.organizationId = organizationId\n\n return payload\n}\n\nexport const createCompanyFormSchema = () =>\n z\n .object({\n displayName: z.string().trim().min(1),\n primaryEmail: z\n .string()\n .trim()\n .email()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val)),\n primaryPhone: z\n .string()\n .trim()\n .max(50)\n .refine((value) => isValidPhoneNumber(value), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n status: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n lifecycleStage: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n source: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n legalName: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n brandName: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n domain: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n websiteUrl: z\n .string()\n .trim()\n .url()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n industry: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n sizeBucket: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n annualRevenue: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n })\n .passthrough()\n\nexport const createCompanyFormFields = (t: Translator): CrudField[] => {\n const dictionaryFields: CrudField[] = companyDictionaryFieldDefinitions.map((definition) => ({\n id: definition.id,\n label: t(definition.labelKey),\n type: 'custom',\n layout: definition.layout ?? 'third',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind={definition.kind}\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={buildDictionaryLabels(t, definition)}\n />\n ),\n }))\n\n return [\n {\n id: 'displayName',\n label: t('customers.companies.form.displayName.label', 'Display name'),\n type: 'text',\n required: true,\n },\n {\n id: 'primaryEmail',\n label: t('customers.companies.detail.highlights.primaryEmail', 'Primary email'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.form.primaryEmailPlaceholder', 'name@example.com'),\n },\n {\n id: 'primaryPhone',\n label: t('customers.companies.detail.highlights.primaryPhone', 'Primary phone'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue, error, disabled, autoFocus }: CrudCustomFieldRenderProps) => (\n <PhoneNumberField\n value={typeof value === 'string' ? value : null}\n onValueChange={(next) => setValue(typeof next === 'string' ? next : '')}\n externalError={error}\n autoFocus={autoFocus}\n disabled={disabled}\n placeholder={t('customers.companies.form.primaryPhonePlaceholder', '+1 555 123 4567')}\n invalidLabel={t('customers.people.form.primaryPhone.invalid', 'Enter a valid phone number with country code (e.g. +1 212 555 1234)')}\n minDigits={7}\n />\n ),\n } as CrudField,\n ...dictionaryFields,\n {\n id: 'legalName',\n label: t('customers.companies.detail.fields.legalName', 'Legal name'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'brandName',\n label: t('customers.companies.detail.fields.brandName', 'Brand name'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'domain',\n label: t('customers.companies.detail.fields.domain', 'Domain'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.detail.fields.domainPlaceholder', 'example.com'),\n description: t('customers.companies.detail.fields.domainHelp', 'Use a plain domain like example.com.'),\n },\n {\n id: 'websiteUrl',\n label: t('customers.companies.detail.highlights.website', 'Website'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.detail.highlights.websitePlaceholder', 'https://example.com'),\n description: t('customers.companies.detail.fields.websiteHelp', 'Use a full URL like https://example.com.'),\n },\n {\n id: 'industry',\n label: t('customers.companies.detail.highlights.industry', 'Industry'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'sizeBucket',\n label: t('customers.companies.detail.fields.sizeBucket', 'Company size'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'annualRevenue',\n label: t('customers.companies.detail.highlights.annualRevenue', 'Annual revenue'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.detail.highlights.annualRevenuePlaceholder', 'Enter amount'),\n },\n {\n id: 'description',\n label: t('customers.companies.detail.fields.description', 'Description'),\n type: 'textarea',\n },\n {\n id: 'addresses',\n label: '',\n type: 'custom',\n layout: 'full',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => {\n const addresses = Array.isArray(value) ? (value as CustomerAddressValue[]) : []\n return (\n <CustomerAddressTiles\n addresses={addresses}\n t={t}\n emptyLabel={t('customers.companies.detail.empty.addresses')}\n gridClassName=\"grid gap-4 min-[480px]:grid-cols-1 xl:grid-cols-2\"\n onCreate={async (payload: CustomerAddressInput) => {\n const nextId =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `tmp-${Math.random().toString(36).slice(2)}`\n const next: CustomerAddressValue = {\n id: nextId,\n name: payload.name ?? undefined,\n purpose: payload.purpose ?? undefined,\n companyName: payload.companyName ?? undefined,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? undefined,\n buildingNumber: payload.buildingNumber ?? undefined,\n flatNumber: payload.flatNumber ?? undefined,\n city: payload.city ?? undefined,\n region: payload.region ?? undefined,\n postalCode: payload.postalCode ?? undefined,\n country: payload.country ?? undefined,\n isPrimary: payload.isPrimary ?? false,\n }\n const current = Array.isArray(addresses) ? addresses : []\n const nextAddresses =\n next.isPrimary === true\n ? [next, ...current.map((item) => ({ ...item, isPrimary: false }))]\n : [next, ...current]\n setValue(nextAddresses)\n }}\n onUpdate={async (id, payload) => {\n const current = Array.isArray(addresses) ? addresses : []\n const updated = current.map((item) => {\n if (item.id !== id) {\n return payload.isPrimary ? { ...item, isPrimary: false } : item\n }\n return {\n ...item,\n name: payload.name ?? null,\n purpose: payload.purpose ?? null,\n companyName: payload.companyName ?? null,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? null,\n buildingNumber: payload.buildingNumber ?? null,\n flatNumber: payload.flatNumber ?? null,\n city: payload.city ?? null,\n region: payload.region ?? null,\n postalCode: payload.postalCode ?? null,\n country: payload.country ?? null,\n isPrimary: payload.isPrimary ?? false,\n }\n })\n setValue(updated)\n }}\n onDelete={async (id) => {\n const current = Array.isArray(addresses) ? addresses : []\n setValue(current.filter((item) => item.id !== id))\n }}\n />\n )\n },\n },\n ]\n}\n\nexport const createCompanyFormGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.companies.form.groups.details'),\n column: 1,\n fields: ['displayName', 'primaryEmail', 'primaryPhone', 'status', 'lifecycleStage', 'source'],\n },\n {\n id: 'profile',\n title: t('customers.companies.form.groups.profile'),\n column: 1,\n fields: ['legalName', 'brandName', 'domain', 'websiteUrl', 'industry', 'sizeBucket', 'annualRevenue'],\n },\n {\n id: 'addresses',\n title: t('customers.companies.form.groups.addresses'),\n column: 1,\n fields: ['addresses'],\n },\n {\n id: 'notes',\n title: t('customers.companies.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.companies.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\nexport function buildCompanyPayload(\n values: CompanyFormValues | CompanyEditFormValues,\n organizationId?: string | null,\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {}\n\n const displayNameValue = blankToUndefined(\n typeof values.displayName === 'string' ? values.displayName : undefined,\n )\n if (!displayNameValue) {\n throw new Error('DISPLAY_NAME_REQUIRED')\n }\n payload.displayName = displayNameValue\n\n const assign = (key: string, val?: string) => {\n const normalized = blankToUndefined(val)\n if (normalized !== undefined) payload[key] = normalized\n }\n\n assign('primaryEmail', typeof values.primaryEmail === 'string' ? values.primaryEmail : undefined)\n assign('primaryPhone', typeof values.primaryPhone === 'string' ? values.primaryPhone : undefined)\n assign('status', typeof values.status === 'string' ? values.status : undefined)\n assign('lifecycleStage', typeof values.lifecycleStage === 'string' ? values.lifecycleStage : undefined)\n assign('source', typeof values.source === 'string' ? values.source : undefined)\n assign('legalName', typeof values.legalName === 'string' ? values.legalName : undefined)\n assign('brandName', typeof values.brandName === 'string' ? values.brandName : undefined)\n assign('domain', typeof values.domain === 'string' ? values.domain?.toLowerCase() : undefined)\n assign('websiteUrl', typeof values.websiteUrl === 'string' ? values.websiteUrl : undefined)\n assign('industry', typeof values.industry === 'string' ? values.industry : undefined)\n assign('sizeBucket', typeof values.sizeBucket === 'string' ? values.sizeBucket : undefined)\n assign('description', typeof values.description === 'string' ? values.description : undefined)\n\n const rawRevenue = typeof values.annualRevenue === 'string' ? values.annualRevenue.trim() : ''\n if (rawRevenue.length) {\n const normalized = rawRevenue.replace(/,/g, '').replace(/\\s+/g, '')\n if (!/^\\d+(\\.\\d{1,2})?$/.test(normalized)) {\n throw new Error('ANNUAL_REVENUE_INVALID')\n }\n payload.annualRevenue = normalized\n }\n\n const customFields = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n if (Object.keys(customFields).length) {\n payload.customFields = customFields\n }\n\n if (organizationId) payload.organizationId = organizationId\n\n return payload\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode types\n// ---------------------------------------------------------------------------\n\n// URL/email/phone fields are clearable on edit: blanking a previously-set value transmits null,\n// so the edit-form value types widen to `string | null` to match the edit-schema output. See #2526.\nexport type CompanyEditFormValues = Omit<\n CompanyFormValues,\n | 'addresses'\n | 'primaryEmail'\n | 'primaryPhone'\n | 'websiteUrl'\n | 'domain'\n | 'legalName'\n | 'brandName'\n | 'sizeBucket'\n | 'annualRevenue'\n | 'description'\n> & {\n id: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n websiteUrl?: string | null\n domain?: string | null\n legalName?: string | null\n brandName?: string | null\n sizeBucket?: string | null\n annualRevenue?: string | null\n description?: string | null\n}\n\nexport type PersonEditFormValues = Omit<PersonFormValues, 'addresses' | 'primaryEmail' | 'primaryPhone'> & {\n id: string\n department?: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n linkedInUrl?: string | null\n twitterUrl?: string | null\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode schemas\n// ---------------------------------------------------------------------------\n\nconst optionalString = () =>\n z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional()\n\n// Edit-mode URL/email/phone fields map to nullable columns and must be clearable: blanking a\n// previously-set value transforms '' \u2192 null so the payload builder can transmit an explicit\n// clear (omitting the key can never remove an existing value). Create-mode schemas keep the\n// '' \u2192 undefined transform. See #2526.\nconst clearableUrlField = () =>\n z\n .string()\n .trim()\n .url()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\nconst clearableEmailField = () =>\n z\n .string()\n .trim()\n .email()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\n// Domain maps to a nullable column; on edit a blanked value must transmit null\n// (not undefined) so it actually clears \u2014 mirroring the website field. See #2529.\nconst clearableDomainField = () =>\n z\n .string()\n .trim()\n .max(200)\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\n// Plain optional string fields that map to nullable columns (legal name, brand name,\n// company size, annual revenue, description). On edit a blanked value must transmit null\n// so it actually clears \u2014 create-mode keeps the '' \u2192 undefined transform. See #3050.\nconst clearableTextField = () =>\n z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\nconst clearablePhoneField = () =>\n z\n .string()\n .trim()\n .max(50)\n .refine((value) => value === '' || isValidPhoneNumber(value), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\nexport const createCompanyEditSchema = () =>\n createCompanyFormSchema().extend({\n id: z.string().uuid(),\n primaryEmail: clearableEmailField(),\n primaryPhone: clearablePhoneField(),\n websiteUrl: clearableUrlField(),\n domain: clearableDomainField(),\n legalName: clearableTextField(),\n brandName: clearableTextField(),\n sizeBucket: clearableTextField(),\n annualRevenue: clearableTextField(),\n description: clearableTextField(),\n })\n\nexport const createPersonEditSchema = () =>\n createPersonFormSchema().extend({\n id: z.string().uuid(),\n department: optionalString(),\n primaryEmail: clearableEmailField(),\n primaryPhone: clearablePhoneField(),\n linkedInUrl: clearableUrlField(),\n twitterUrl: clearableUrlField(),\n })\n\n// ---------------------------------------------------------------------------\n// Edit-mode fields\n// ---------------------------------------------------------------------------\n\nconst buildIndustryLabels = (t: Translator): DictionarySelectLabels => ({\n placeholder: t('customers.companies.form.industry.placeholder', 'Select industry\u2026'),\n addLabel: t('customers.companies.form.dictionary.addIndustry', 'Add industry'),\n addPrompt: t('customers.companies.form.dictionary.promptIndustry', 'Enter a new industry.'),\n dialogTitle: t('customers.companies.form.dictionary.dialogTitleIndustry', 'Add industry'),\n valueLabel: t('customers.people.form.dictionary.valueLabel', 'Value'),\n valuePlaceholder: t('customers.people.form.dictionary.valuePlaceholder', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('customers.people.form.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n successCreateLabel: undefined,\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.dictionary.loading'),\n manageTitle: t('customers.people.form.dictionary.manage'),\n})\n\nexport const createCompanyEditFields = (t: Translator): CrudField[] => {\n const baseFields = createCompanyFormFields(t)\n const industryLabels = buildIndustryLabels(t)\n\n return baseFields.map((field) => {\n if (field.id === 'industry') {\n return {\n id: 'industry',\n label: t('customers.companies.detail.fields.industry', 'Industry'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind={'industries' as CustomerDictionaryKind}\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={industryLabels}\n />\n ),\n } as CrudField\n }\n return field\n })\n}\n\nexport const createPersonEditFields = (t: Translator): CrudField[] => {\n const baseFields = createPersonFormFields(t)\n return [\n ...baseFields,\n {\n id: 'department',\n label: t('customers.people.form.department', 'Department'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'linkedInUrl',\n label: t('customers.people.form.linkedInUrl', 'LinkedIn URL'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.people.form.linkedInUrl.placeholder', 'https://linkedin.com/in/...'),\n },\n {\n id: 'twitterUrl',\n label: t('customers.people.form.twitterUrl', 'Twitter / X URL'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.people.form.twitterUrl.placeholder', 'https://x.com/...'),\n },\n ]\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode groups\n// ---------------------------------------------------------------------------\n\nexport const createCompanyEditGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.companies.form.groups.details'),\n column: 1,\n fields: ['displayName', 'primaryEmail', 'primaryPhone', 'status', 'lifecycleStage', 'source'],\n },\n {\n id: 'roles',\n title: t('customers.roles.groupTitle', 'Roles'),\n column: 1,\n component: ({ values }: CrudFormGroupComponentProps) => (\n values.id ? (\n <RolesSection\n entityType=\"company\"\n entityId={values.id as string}\n entityName={typeof values.displayName === 'string' ? values.displayName : null}\n />\n ) : null\n ),\n },\n {\n id: 'profile',\n title: t('customers.companies.form.groups.profile'),\n column: 1,\n fields: ['legalName', 'brandName', 'domain', 'websiteUrl', 'industry', 'sizeBucket', 'annualRevenue'],\n },\n {\n id: 'notes',\n title: t('customers.companies.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.companies.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\n/**\n * Groups for the \"Dane firmy\" tab layout (Figma SPEC-048 mockup).\n * All zone-1 groups stay in a single vertical stack so drag-and-drop ordering\n * applies consistently across every section and persists per page type.\n */\nexport const createCompanyDaneFiremyGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'identity',\n title: t('customers.companies.form.groups.identity', 'To\u017Csamo\u015B\u0107').toUpperCase(),\n column: 1,\n fields: ['displayName', 'legalName', 'brandName'],\n },\n {\n id: 'contact',\n title: t('customers.companies.form.groups.contact', 'Kontakt').toUpperCase(),\n column: 1,\n fields: ['primaryEmail', 'primaryPhone', 'domain', 'websiteUrl'],\n },\n {\n id: 'classification',\n title: t('customers.companies.form.groups.classification', 'Klasyfikacja').toUpperCase(),\n column: 1,\n fields: ['status', 'lifecycleStage', 'source'],\n },\n {\n id: 'businessProfile',\n title: t('customers.companies.form.groups.businessProfile', 'Profil biznesowy').toUpperCase(),\n column: 1,\n fields: ['industry', 'sizeBucket', 'annualRevenue'],\n },\n {\n id: 'notes',\n title: t('customers.companies.form.groups.notes', 'Notatki'),\n column: 1,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.companies.form.groups.customAttributes', 'Atrybuty niestandardowe'),\n column: 1,\n kind: 'customFields',\n },\n]\n\nexport const createPersonEditGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.people.form.groups.details'),\n column: 1,\n fields: [\n 'firstName',\n 'lastName',\n '__contactInformationSection',\n 'primaryEmail',\n 'primaryPhone',\n '__companyInformationSection',\n 'jobTitle',\n 'companyEntityId',\n 'status',\n 'lifecycleStage',\n 'source',\n ],\n component: createDisplayNameSection(t),\n },\n {\n id: 'roles',\n title: t('customers.roles.groupTitle', 'Roles'),\n column: 1,\n component: ({ values }: CrudFormGroupComponentProps) => (\n values.id ? (\n <RolesSection\n entityType=\"person\"\n entityId={values.id as string}\n entityName={typeof values.displayName === 'string' ? values.displayName : null}\n />\n ) : null\n ),\n },\n {\n id: 'social',\n title: t('customers.people.form.groups.social', 'Social & links'),\n column: 1,\n fields: ['department', 'linkedInUrl', 'twitterUrl'],\n },\n {\n id: 'notes',\n title: t('customers.people.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.people.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\n/**\n * Groups for the Person v2 \"Dane osobowe\" Figma layout (SPEC-048 mockup).\n * All groups in column 1 (Zone 1). Notes handled separately in Zone 2 tabs.\n */\nexport const createPersonPersonalDataGroups = (\n t: Translator,\n options?: { entityName?: string | null },\n): CrudFormGroup[] => {\n const entityName = options?.entityName?.trim() || null\n const rolesTitle = entityName\n ? t('customers.roles.groupTitle.person', 'My roles with {{name}}', { name: entityName })\n : t('customers.people.form.groups.roles', 'My roles')\n return [\n {\n id: 'personalDataDisplay',\n title: t('customers.people.form.groups.displayName', 'Display name'),\n column: 1,\n bare: true,\n component: createDisplayNameSection(t),\n },\n {\n id: 'personalData',\n title: t('customers.people.form.groups.personalData', 'Personal data'),\n column: 1,\n fields: ['firstName', 'lastName', 'jobTitle', 'primaryEmail', 'primaryPhone'],\n },\n {\n id: 'companyRole',\n title: t('customers.people.form.groups.companyRole', 'Company & role'),\n column: 1,\n fields: ['companyEntityId', 'status', 'lifecycleStage', 'source'],\n },\n {\n id: 'customFields',\n title: t('customers.people.form.groups.customAttributes', 'Custom attributes'),\n column: 1,\n kind: 'customFields',\n },\n {\n id: 'roles',\n title: rolesTitle,\n column: 1,\n component: ({ values }: CrudFormGroupComponentProps) => (\n values.id ? (\n <RolesSection\n entityType=\"person\"\n entityId={values.id as string}\n entityName={typeof values.displayName === 'string' ? values.displayName : null}\n />\n ) : null\n ),\n },\n ]\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode payload builders\n// ---------------------------------------------------------------------------\n\n// On edit, optional URL/email/phone fields that map to nullable columns must transmit an explicit\n// `null` when the user blanks a previously-set value \u2014 omitting the key can never clear it.\n// The base create-mode builders omit blanks (correct for create), so the edit builders\n// override these clearable fields here. See #2526.\nconst assignClearable = (payload: Record<string, unknown>, key: string, raw: unknown): void => {\n if (raw === null) {\n payload[key] = null\n return\n }\n if (typeof raw !== 'string') return\n const trimmed = raw.trim()\n payload[key] = trimmed.length ? trimmed : null\n}\n\nexport function buildCompanyEditPayload(values: CompanyEditFormValues, organizationId?: string | null): Record<string, unknown> {\n const payload = buildCompanyPayload(values, organizationId)\n payload.id = values.id\n\n assignClearable(payload, 'primaryEmail', values.primaryEmail)\n assignClearable(payload, 'primaryPhone', values.primaryPhone)\n assignClearable(payload, 'websiteUrl', values.websiteUrl)\n assignClearable(payload, 'domain', typeof values.domain === 'string' ? values.domain.toLowerCase() : values.domain)\n\n // Plain nullable string fields that must transmit null when blanked on edit (#3050).\n assignClearable(payload, 'legalName', values.legalName)\n assignClearable(payload, 'brandName', values.brandName)\n assignClearable(payload, 'sizeBucket', values.sizeBucket)\n assignClearable(payload, 'description', values.description)\n\n // Annual revenue maps to a nullable numeric column: a blanked value must clear it.\n // Non-empty values are already validated/normalized by buildCompanyPayload; an omitted\n // (undefined) value stays a no-op like the other clearable fields. (#3050)\n const annualRevenueRaw = values.annualRevenue\n const annualRevenueBlank =\n annualRevenueRaw === null ||\n (typeof annualRevenueRaw === 'string' && annualRevenueRaw.trim().length === 0)\n if (annualRevenueBlank) payload.annualRevenue = null\n\n return payload\n}\n\nexport function buildPersonEditPayload(values: PersonEditFormValues, organizationId?: string | null): Record<string, unknown> {\n const payload = buildPersonPayload(values, organizationId)\n payload.id = values.id\n\n const department = typeof values.department === 'string' ? values.department.trim() : ''\n if (department.length) payload.department = department\n\n assignClearable(payload, 'primaryEmail', values.primaryEmail)\n assignClearable(payload, 'primaryPhone', values.primaryPhone)\n assignClearable(payload, 'linkedInUrl', values.linkedInUrl)\n assignClearable(payload, 'twitterUrl', values.twitterUrl)\n\n return payload\n}\n\n// ---------------------------------------------------------------------------\n// Overview types (shared between v1 and v2 detail pages)\n// ---------------------------------------------------------------------------\n\nimport type {\n TagSummary,\n CommentSummary,\n ActivitySummary,\n DealSummary,\n TodoLinkSummary,\n InteractionSummary,\n} from './detail/types'\n\nexport type { TagSummary, CommentSummary, ActivitySummary, DealSummary, TodoLinkSummary, InteractionSummary }\n\nexport type CompanyPersonSummary = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n jobTitle?: string | null\n department?: string | null\n createdAt?: string | null\n organizationId?: string | null\n source?: string | null\n temperature?: string | null\n linkedAt?: string | null\n}\n\nexport type CompanyOverview = {\n company: {\n id: string\n displayName: string\n description?: string | null\n ownerUserId?: string | null\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n source?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n temperature?: string | null\n renewalQuarter?: string | null\n organizationId?: string | null\n }\n profile: {\n id: string\n legalName?: string | null\n brandName?: string | null\n domain?: string | null\n websiteUrl?: string | null\n industry?: string | null\n sizeBucket?: string | null\n annualRevenue?: string | null\n } | null\n customFields: Record<string, unknown>\n tags: TagSummary[]\n comments: CommentSummary[]\n activities: ActivitySummary[]\n interactions: InteractionSummary[]\n deals: DealSummary[]\n todos: TodoLinkSummary[]\n people: CompanyPersonSummary[]\n counts?: {\n comments: number\n activities: number\n interactions: number\n todos: number\n deals: number\n people: number\n addresses: number\n tags: number\n }\n plannedActivitiesPreview?: InteractionSummary[]\n kpis?: {\n activeDealsCount: number\n activeDealsValue: number | null\n dealCurrency: string | null\n activityCount: number\n activityTrend: {\n value: number\n direction: 'up' | 'down' | 'unchanged'\n } | null\n ltvValue: number | null\n completedDealsCount: number\n clientTenureYears: number | null\n }\n interactionMode?: 'canonical' | 'legacy'\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\nexport type PersonOverview = {\n person: {\n id: string\n displayName: string\n description?: string | null\n ownerUserId?: string | null\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n source?: string | null\n temperature?: string | null\n renewalQuarter?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n updatedAt?: string | null\n updated_at?: string | null\n }\n profile: {\n id: string\n firstName?: string | null\n lastName?: string | null\n preferredName?: string | null\n jobTitle?: string | null\n department?: string | null\n seniority?: string | null\n timezone?: string | null\n linkedInUrl?: string | null\n twitterUrl?: string | null\n companyEntityId?: string | null\n } | null\n customFields: Record<string, unknown>\n tags: TagSummary[]\n comments: CommentSummary[]\n activities: ActivitySummary[]\n interactions: InteractionSummary[]\n deals: DealSummary[]\n todos: TodoLinkSummary[]\n counts?: {\n comments: number\n activities: number\n interactions: number\n todos: number\n deals: number\n companies: number\n addresses: number\n tags: number\n }\n plannedActivitiesPreview?: InteractionSummary[]\n interactionMode?: 'canonical' | 'legacy'\n /** Whether this person is the primary contact for any linked company. */\n isPrimary?: boolean\n companies?: Array<{\n id: string\n displayName: string\n isPrimary: boolean\n }>\n company?: {\n id: string\n displayName: string\n } | null\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\n// ---------------------------------------------------------------------------\n// API response \u2192 form values mapping\n// ---------------------------------------------------------------------------\n\nexport function mapCompanyOverviewToFormValues(overview: CompanyOverview): Partial<CompanyEditFormValues> {\n const rawPhone = overview.company.primaryPhone\n const phoneValue = rawPhone == null ? '' : String(rawPhone)\n return {\n id: overview.company.id,\n displayName: coerceDisplayName(overview.company.displayName),\n primaryEmail: overview.company.primaryEmail ?? '',\n primaryPhone: phoneValue,\n status: overview.company.status ?? '',\n lifecycleStage: overview.company.lifecycleStage ?? '',\n source: overview.company.source ?? '',\n description: overview.company.description ?? '',\n legalName: overview.profile?.legalName ?? '',\n brandName: overview.profile?.brandName ?? '',\n domain: overview.profile?.domain ?? '',\n websiteUrl: overview.profile?.websiteUrl ?? '',\n industry: overview.profile?.industry ?? '',\n sizeBucket: overview.profile?.sizeBucket ?? '',\n annualRevenue: overview.profile?.annualRevenue ?? '',\n ...extractCustomFieldEntries({ customFields: overview.customFields }),\n }\n}\n\nexport function mapPersonOverviewToFormValues(overview: PersonOverview): Partial<PersonEditFormValues> {\n const rawPhone = overview.person.primaryPhone\n const phoneValue = rawPhone == null ? '' : String(rawPhone)\n return {\n id: overview.person.id,\n displayName: coerceDisplayName(overview.person.displayName),\n firstName: overview.profile?.firstName ?? '',\n lastName: overview.profile?.lastName ?? '',\n primaryEmail: overview.person.primaryEmail ?? '',\n primaryPhone: phoneValue,\n companyEntityId: overview.profile?.companyEntityId ?? '',\n jobTitle: overview.profile?.jobTitle ?? '',\n status: overview.person.status ?? '',\n lifecycleStage: overview.person.lifecycleStage ?? '',\n source: overview.person.source ?? '',\n description: overview.person.description ?? '',\n department: overview.profile?.department ?? '',\n linkedInUrl: overview.profile?.linkedInUrl ?? '',\n twitterUrl: overview.profile?.twitterUrl ?? '',\n ...extractCustomFieldEntries({ customFields: overview.customFields }),\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport Link from 'next/link'\nimport { Check, Pencil, Plus, Settings } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { EmailInput } from '@open-mercato/ui/primitives/email-input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { coerceDisplayName, deriveDisplayName, isDerivedDisplayName } from '../lib/displayName'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { PhoneNumberField } from '@open-mercato/ui/backend/inputs/PhoneNumberField'\nimport { isValidPhoneNumber } from '@open-mercato/shared/lib/phone'\nimport type {\n CrudCustomFieldRenderProps,\n CrudField,\n CrudFormGroup,\n CrudFormGroupComponentProps,\n} from '@open-mercato/ui/backend/CrudForm'\nimport {\n DictionaryEntrySelect,\n type DictionarySelectLabels,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { RolesSection } from './detail/RolesSection'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useEmailDuplicateCheck } from '../backend/hooks/useEmailDuplicateCheck'\nimport { lookupPhoneDuplicate } from '../utils/phoneDuplicates'\nimport { CustomerAddressTiles, type CustomerAddressInput, type CustomerAddressValue } from './AddressTiles'\nimport {\n ensureCustomerDictionary,\n invalidateCustomerDictionary,\n} from './detail/hooks/useCustomerDictionary'\nimport {\n CUSTOMER_DICTIONARIES_MANAGE_HREF,\n getCustomerDictionaryManageHref,\n type CustomerDictionaryKind,\n} from '../lib/dictionaries'\nimport { normalizeCustomFieldSubmitValue } from './detail/customFieldUtils'\nimport { CUSTOMER_PHONE_INVALID_MESSAGE_KEY } from '../data/validators'\n\nexport const metadata = {\n navHidden: true,\n} as const\n\nfunction cn(...values: Array<string | null | undefined | false>) {\n return values.filter(Boolean).join(' ')\n}\n\nexport type Translator = (\n key: string,\n fallback?: string,\n params?: Record<string, string | number>,\n) => string\n\nexport type PersonFormValues = {\n displayName: string\n firstName: string\n lastName: string\n jobTitle?: string\n companyEntityId?: string | null\n primaryEmail?: string\n primaryPhone?: string\n status?: string\n lifecycleStage?: string\n source?: string\n description?: string\n addresses?: CustomerAddressValue[]\n} & Record<string, unknown>\n\nexport type CompanyFormValues = {\n displayName: string\n primaryEmail?: string\n primaryPhone?: string\n status?: string\n lifecycleStage?: string\n source?: string\n legalName?: string\n brandName?: string\n domain?: string\n websiteUrl?: string\n industry?: string\n sizeBucket?: string\n annualRevenue?: string\n description?: string\n addresses?: CustomerAddressValue[]\n} & Record<string, unknown>\n\ntype DictionarySelectFieldProps = {\n kind: CustomerDictionaryKind\n value?: string\n onChange: (value: string | undefined) => void\n labels: DictionarySelectLabels\n selectClassName?: string\n manageHref?: string\n allowInlineCreate?: boolean\n allowAppearance?: boolean\n showManage?: boolean\n showLabelInput?: boolean\n showActiveAppearance?: boolean\n}\n\nexport { CUSTOMER_DICTIONARIES_MANAGE_HREF, getCustomerDictionaryManageHref }\n\nconst emailValidationSchema = z.string().email()\nconst EMAIL_CHECK_DEBOUNCE_MS = 350\n\nconst createSectionHeadingField = (id: string, title: string): CrudField => ({\n id,\n label: '',\n type: 'custom',\n layout: 'full',\n component: () => (\n <div className=\"mt-4 border-t border-border pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n ),\n})\n\nexport function DictionarySelectField({\n kind,\n value,\n onChange,\n labels,\n selectClassName,\n manageHref,\n allowInlineCreate = false,\n allowAppearance = false,\n showManage = false,\n showLabelInput = true,\n showActiveAppearance = true,\n}: DictionarySelectFieldProps) {\n const t = useT()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const translate = React.useCallback(\n (key: string, fallback: string) => {\n const result = t(key)\n return result === key ? fallback : result\n },\n [t],\n )\n\n const appearanceLabels = React.useMemo(\n () => ({\n colorLabel: translate('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: translate('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: translate('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: translate('customers.config.dictionaries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: translate(\n 'customers.config.dictionaries.dialog.iconPlaceholder',\n 'Type an emoji or pick one of the suggestions.',\n ),\n iconPickerTriggerLabel: translate('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: translate(\n 'customers.config.dictionaries.dialog.iconSearchPlaceholder',\n 'Search icons or emojis\u2026',\n ),\n iconSearchEmptyLabel: translate(\n 'customers.config.dictionaries.dialog.iconSearchEmpty',\n 'No icons match your search.',\n ),\n iconSuggestionsLabel: translate('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: translate('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: translate('customers.config.dictionaries.dialog.previewEmpty', 'No appearance selected'),\n }),\n [translate],\n )\n\n const fetchOptions = React.useCallback(async () => {\n const data = await ensureCustomerDictionary(queryClient, kind, scopeVersion)\n return data.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }, [kind, queryClient, scopeVersion])\n\n const createOption = React.useCallback(\n async (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/customers/dictionaries/${kind}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n value: input.value,\n label: input.label ?? input.value,\n color: input.color ?? undefined,\n icon: input.icon ?? undefined,\n }),\n },\n )\n const payload = call.result ?? {}\n if (!call.ok) {\n const message = typeof payload.error === 'string' ? payload.error : labels.errorSave\n throw new Error(message)\n }\n await invalidateCustomerDictionary(queryClient, kind)\n const valueCreated = typeof payload.value === 'string' ? payload.value : input.value\n const label =\n typeof payload.label === 'string' && payload.label.trim().length ? payload.label.trim() : valueCreated\n const color =\n typeof payload.color === 'string' && payload.color.trim().startsWith('#')\n ? payload.color.trim()\n : null\n const icon =\n typeof payload.icon === 'string' && payload.icon.trim().length ? payload.icon.trim() : null\n return { value: valueCreated, label, color, icon }\n },\n [kind, labels.errorSave, queryClient],\n )\n\n return (\n <DictionaryEntrySelect\n value={value}\n onChange={onChange}\n fetchOptions={fetchOptions}\n createOption={createOption}\n labels={labels}\n manageHref={manageHref ?? getCustomerDictionaryManageHref(kind)}\n selectClassName={selectClassName}\n allowInlineCreate={allowInlineCreate}\n allowAppearance={allowAppearance}\n showManage={showManage}\n showLabelInput={showLabelInput}\n sortOptions=\"none\"\n showActiveAppearance={showActiveAppearance}\n />\n )\n}\n\nconst createPrimaryEmailField = (t: Translator): CrudField => ({\n id: 'primaryEmail',\n label: t('customers.people.form.primaryEmail'),\n type: 'custom',\n component: function PrimaryEmailField({ value, setValue, error, autoFocus, disabled, recordId }: CrudCustomFieldRenderProps) {\n const [inputValue, setInputValue] = React.useState(() => (typeof value === 'string' ? value : ''))\n const trimmedInput = inputValue.trim()\n const isValidEmail = React.useMemo(\n () => !!trimmedInput.length && emailValidationSchema.safeParse(trimmedInput).success,\n [trimmedInput]\n )\n const { duplicate, checking } = useEmailDuplicateCheck(inputValue, {\n recordId: typeof recordId === 'string' ? recordId : null,\n disabled: disabled || !!error || !isValidEmail,\n debounceMs: EMAIL_CHECK_DEBOUNCE_MS,\n matchMode: 'prefix',\n })\n\n React.useEffect(() => {\n setInputValue(typeof value === 'string' ? value : '')\n }, [value])\n\n return (\n <div className=\"space-y-2\">\n <EmailInput\n value={inputValue}\n onChange={(event) => {\n const nextValue = event.target.value\n setInputValue(nextValue)\n setValue(nextValue)\n }}\n placeholder={t('customers.people.form.primaryEmailPlaceholder', 'name@example.com')}\n spellCheck={false}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n />\n {!error && duplicate ? (\n <p className=\"text-xs text-status-warning-text\">\n {t('customers.people.form.emailDuplicateNotice', undefined, { name: duplicate.displayName })}{' '}\n <Link className=\"font-medium text-primary underline underline-offset-2\" href={`/backend/customers/people-v2/${duplicate.id}`}>\n {t('customers.people.form.emailDuplicateLink')}\n </Link>\n </p>\n ) : null}\n {!error && !duplicate && checking ? (\n <p className=\"text-xs text-muted-foreground\">{t('customers.people.form.emailChecking')}</p>\n ) : null}\n </div>\n )\n },\n})\n\ntype DictionaryFieldDefinition = {\n id: 'status' | 'lifecycleStage' | 'source'\n kind: 'statuses' | 'lifecycle-stages' | 'sources'\n labelKey: string\n placeholderKey: string\n addLabelKey: string\n promptKey: string\n dialogTitleKey: string\n layout?: CrudField['layout']\n}\n\nconst dictionaryFieldDefinitions: DictionaryFieldDefinition[] = [\n {\n id: 'status',\n kind: 'statuses',\n labelKey: 'customers.people.form.status',\n placeholderKey: 'customers.people.form.status.placeholder',\n addLabelKey: 'customers.people.form.dictionary.addStatus',\n promptKey: 'customers.people.form.dictionary.promptStatus',\n dialogTitleKey: 'customers.people.form.dictionary.dialogTitleStatus',\n layout: 'half',\n },\n {\n id: 'lifecycleStage',\n kind: 'lifecycle-stages',\n labelKey: 'customers.people.form.lifecycleStage',\n placeholderKey: 'customers.people.form.lifecycleStage.placeholder',\n addLabelKey: 'customers.people.form.dictionary.addLifecycleStage',\n promptKey: 'customers.people.form.dictionary.promptLifecycleStage',\n dialogTitleKey: 'customers.people.form.dictionary.dialogTitleLifecycleStage',\n layout: 'half',\n },\n {\n id: 'source',\n kind: 'sources',\n labelKey: 'customers.people.form.source',\n placeholderKey: 'customers.people.form.source.placeholder',\n addLabelKey: 'customers.people.form.dictionary.addSource',\n promptKey: 'customers.people.form.dictionary.promptSource',\n dialogTitleKey: 'customers.people.form.dictionary.dialogTitleSource',\n layout: 'half',\n },\n]\n\nconst buildDictionaryLabels = (t: Translator, definition: DictionaryFieldDefinition): DictionarySelectLabels => ({\n placeholder: t(definition.placeholderKey),\n addLabel: t(definition.addLabelKey),\n addPrompt: t(definition.promptKey),\n dialogTitle: t(definition.dialogTitleKey),\n valueLabel: t('customers.people.form.dictionary.valueLabel', 'Value'),\n valuePlaceholder: t('customers.people.form.dictionary.valuePlaceholder', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('customers.people.form.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n successCreateLabel: undefined,\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.dictionary.loading'),\n manageTitle: t('customers.people.form.dictionary.manage'),\n})\n\nconst companyDictionaryFieldDefinitions: DictionaryFieldDefinition[] = [\n {\n id: 'status',\n kind: 'statuses',\n labelKey: 'customers.companies.form.status',\n placeholderKey: 'customers.companies.form.status.placeholder',\n addLabelKey: 'customers.companies.form.dictionary.addStatus',\n promptKey: 'customers.companies.form.dictionary.promptStatus',\n dialogTitleKey: 'customers.companies.form.dictionary.dialogTitleStatus',\n layout: 'third',\n },\n {\n id: 'lifecycleStage',\n kind: 'lifecycle-stages',\n labelKey: 'customers.companies.form.lifecycleStage',\n placeholderKey: 'customers.companies.form.lifecycleStage.placeholder',\n addLabelKey: 'customers.companies.form.dictionary.addLifecycleStage',\n promptKey: 'customers.companies.form.dictionary.promptLifecycleStage',\n dialogTitleKey: 'customers.companies.form.dictionary.dialogTitleLifecycleStage',\n layout: 'third',\n },\n {\n id: 'source',\n kind: 'sources',\n labelKey: 'customers.companies.form.source',\n placeholderKey: 'customers.companies.form.source.placeholder',\n addLabelKey: 'customers.companies.form.dictionary.addSource',\n promptKey: 'customers.companies.form.dictionary.promptSource',\n dialogTitleKey: 'customers.companies.form.dictionary.dialogTitleSource',\n layout: 'third',\n },\n]\n\nconst createPrimaryPhoneField = (t: Translator): CrudField => ({\n id: 'primaryPhone',\n label: t('customers.people.form.primaryPhone'),\n type: 'custom',\n component: function PrimaryPhoneField({ value, setValue, error, autoFocus, disabled, recordId }: CrudCustomFieldRenderProps) {\n const currentRecordId = React.useMemo(() => (typeof recordId === 'string' ? recordId : null), [recordId])\n\n const duplicateLookup = React.useCallback(\n async (digits: string) => {\n if (disabled || error) return null\n return lookupPhoneDuplicate(digits, { recordId: currentRecordId })\n },\n [currentRecordId, disabled, error]\n )\n\n return (\n <PhoneNumberField\n value={typeof value === 'string' ? value : null}\n onValueChange={(next) => setValue(typeof next === 'string' ? next : '')}\n externalError={error}\n autoFocus={autoFocus}\n disabled={disabled}\n placeholder={t('customers.people.form.primaryPhonePlaceholder', '+1 555 123 4567')}\n checkingLabel={t('customers.people.form.phoneChecking')}\n duplicateLabel={(match) => t('customers.people.form.phoneDuplicateNotice', undefined, { name: match.label })}\n duplicateLinkLabel={t('customers.people.form.phoneDuplicateLink')}\n invalidLabel={t('customers.people.form.primaryPhone.invalid', 'Enter a valid phone number with country code (e.g. +1 212 555 1234)')}\n minDigits={7}\n onDuplicateLookup={!disabled && !error ? duplicateLookup : undefined}\n />\n )\n },\n})\n\nconst blankToUndefined = (value?: string | null): string | undefined => {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length ? trimmed : undefined\n}\n\ntype CompanySelectLabels = {\n placeholder: string\n addLabel: string\n addPrompt?: string\n dialogTitle: string\n inputLabel: string\n inputPlaceholder: string\n emptyError: string\n cancelLabel: string\n saveLabel: string\n errorLoad: string\n errorSave: string\n loadingLabel: string\n}\n\ntype CompanySelectFieldProps = {\n value?: string\n onChange: (value: string | undefined) => void\n labels: CompanySelectLabels\n}\n\ntype CompanyOption = { value: string; label: string }\n\nfunction mergeCompanyOptions(options: CompanyOption[], selected: CompanyOption | null): CompanyOption[] {\n if (!selected) return options\n if (options.some((option) => option.value === selected.value)) return options\n return [selected, ...options]\n}\n\nfunction normalizeCompanyOption(raw: unknown): CompanyOption | null {\n if (!raw || typeof raw !== 'object') return null\n const candidate = raw as Record<string, unknown>\n const id = typeof candidate.id === 'string' ? candidate.id : null\n if (!id) return null\n const displayName =\n typeof candidate.display_name === 'string' && candidate.display_name.trim().length\n ? candidate.display_name.trim()\n : typeof candidate.displayName === 'string' && candidate.displayName.trim().length\n ? candidate.displayName.trim()\n : null\n if (!displayName) return null\n return { value: id, label: displayName }\n}\n\nexport function CompanySelectField({ value, onChange, labels }: CompanySelectFieldProps) {\n const [options, setOptions] = React.useState<CompanyOption[]>([])\n const [loading, setLoading] = React.useState(true)\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [newCompany, setNewCompany] = React.useState('')\n const [saving, setSaving] = React.useState(false)\n const [formError, setFormError] = React.useState<string | null>(null)\n\n const loadCompanyOption = React.useCallback(\n async (companyId: string): Promise<CompanyOption | null> => {\n const payload = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/companies?id=${encodeURIComponent(companyId)}&pageSize=1`,\n undefined,\n { errorMessage: labels.errorLoad },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item: unknown) => normalizeCompanyOption(item))\n .find((option): option is CompanyOption => option?.value === companyId) ?? null\n },\n [labels.errorLoad],\n )\n\n const loadOptions = React.useCallback(async () => {\n setLoading(true)\n try {\n const payload = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/customers/companies?pageSize=100&sortField=name&sortDir=asc',\n undefined,\n { errorMessage: labels.errorLoad },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n const normalized = items\n .map((item: unknown) => normalizeCompanyOption(item))\n .filter((item: CompanyOption | null): item is CompanyOption => item !== null)\n .sort((a: CompanyOption, b: CompanyOption) =>\n a.label.localeCompare(b.label, undefined, { sensitivity: 'base' })\n )\n const selected =\n value && !normalized.some((option) => option.value === value)\n ? await loadCompanyOption(value).catch(() => null)\n : null\n setOptions(mergeCompanyOptions(normalized, selected))\n } catch (err) {\n const message = err instanceof Error ? err.message : labels.errorLoad\n flash(message, 'error')\n setOptions([])\n } finally {\n setLoading(false)\n }\n }, [labels.errorLoad, loadCompanyOption, value])\n\n React.useEffect(() => {\n loadOptions().catch(() => {})\n }, [loadOptions])\n\n React.useEffect(() => {\n if (!value || options.some((option) => option.value === value)) return\n loadCompanyOption(value)\n .then((selected) => {\n setOptions((current) => mergeCompanyOptions(current, selected))\n })\n .catch(() => {})\n }, [loadCompanyOption, options, value])\n\n const handleDialogChange = React.useCallback((open: boolean) => {\n setDialogOpen(open)\n if (!open) {\n setNewCompany('')\n setFormError(null)\n setSaving(false)\n }\n }, [])\n\n const handleDialogSubmit = React.useCallback(async () => {\n if (saving) return\n const trimmed = newCompany.trim()\n if (!trimmed) {\n setFormError(labels.emptyError)\n return\n }\n setSaving(true)\n try {\n const call = await apiCallOrThrow<{ id?: string; entityId?: string }>(\n '/api/customers/companies',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ displayName: trimmed }),\n },\n { errorMessage: labels.errorSave },\n )\n const payload = call.result ?? {}\n const createdId =\n typeof payload?.id === 'string'\n ? payload.id\n : typeof payload?.entityId === 'string'\n ? payload.entityId\n : null\n await loadOptions()\n if (createdId) {\n onChange(createdId)\n }\n setDialogOpen(false)\n setNewCompany('')\n setFormError(null)\n } catch (err) {\n const message = err instanceof Error ? err.message : labels.errorSave\n flash(message, 'error')\n } finally {\n setSaving(false)\n }\n }, [labels.emptyError, labels.errorSave, loadOptions, newCompany, onChange, saving])\n\n const handleInputKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n handleDialogSubmit().catch(() => {})\n }\n },\n [handleDialogSubmit]\n )\n\n const disabled = loading || saving\n const selectedOption = value ? options.find((option) => option.value === value) : null\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Select\n value={value || undefined}\n onValueChange={(next) => onChange(next || undefined)}\n disabled={loading}\n >\n <SelectTrigger>\n <SelectValue placeholder={labels.placeholder}>{selectedOption?.label}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Dialog open={dialogOpen} onOpenChange={handleDialogChange}>\n <DialogTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n disabled={disabled}\n aria-label={labels.addLabel}\n title={labels.addLabel}\n >\n <Plus className=\"h-4 w-4\" aria-hidden />\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-sm\">\n <DialogHeader>\n <DialogTitle>{labels.dialogTitle}</DialogTitle>\n {labels.addPrompt ? <DialogDescription>{labels.addPrompt}</DialogDescription> : null}\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">{labels.inputLabel}</label>\n <Input\n placeholder={labels.inputPlaceholder}\n value={newCompany}\n onChange={(event) => {\n setNewCompany(event.target.value)\n if (formError) setFormError(null)\n }}\n onKeyDown={handleInputKeyDown}\n autoFocus\n disabled={saving}\n />\n </div>\n {formError ? <p className=\"text-sm text-status-error-text\">{formError}</p> : null}\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setDialogOpen(false)} disabled={saving}>\n {labels.cancelLabel}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n handleDialogSubmit().catch(() => {})\n }}\n disabled={saving || !newCompany.trim()}\n >\n {saving ? `${labels.saveLabel}\u2026` : labels.saveLabel}\n </Button>\n </DialogFooter>\n </div>\n </DialogContent>\n </Dialog>\n </div>\n {loading ? <div className=\"text-xs text-muted-foreground\">{labels.loadingLabel}</div> : null}\n </div>\n )\n}\n\nexport const createPersonFormSchema = () =>\n z\n .object({\n displayName: z.string().trim().min(1),\n firstName: z.string().trim().min(1),\n lastName: z.string().trim().min(1),\n jobTitle: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n primaryEmail: z\n .string()\n .trim()\n .email()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val)),\n primaryPhone: z\n .string()\n .trim()\n .max(50)\n .refine((value) => isValidPhoneNumber(value), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n status: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n lifecycleStage: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n source: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n description: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n companyEntityId: z\n .string()\n .trim()\n .uuid()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n })\n .passthrough()\n\nexport const createDisplayNameSection = (t: Translator) =>\n function DisplayNameSection({ values, setValue, errors }: CrudFormGroupComponentProps) {\n const [editing, setEditing] = React.useState(false)\n const [manualOverride, setManualOverride] = React.useState(() => {\n const current = typeof values.displayName === 'string' ? values.displayName : ''\n const firstInit = typeof values.firstName === 'string' ? values.firstName : ''\n const lastInit = typeof values.lastName === 'string' ? values.lastName : ''\n // Sticky-manual: treat as user-customized only when the persisted display name\n // doesn't match the first+last derivation (matches the server-side rule in\n // updatePersonCommand). Empty values are considered derived.\n return !isDerivedDisplayName(current, firstInit, lastInit)\n })\n\n const first = typeof values.firstName === 'string' ? values.firstName.trim() : ''\n const last = typeof values.lastName === 'string' ? values.lastName.trim() : ''\n const derived = React.useMemo(() => deriveDisplayName(first, last), [first, last])\n\n React.useEffect(() => {\n if (!manualOverride) {\n const target = derived || ''\n const current = typeof values.displayName === 'string' ? values.displayName : ''\n if (current !== target) {\n setValue('displayName', target)\n }\n }\n }, [manualOverride, derived, setValue, values.displayName])\n\n const currentValue = typeof values.displayName === 'string' ? values.displayName : ''\n const previewValue = currentValue || derived\n const placeholder = t('customers.people.form.displayNamePreview.empty')\n const error = errors.displayName\n\n const toggleEditing = () => {\n if (!editing && !manualOverride) {\n const target = derived || previewValue || ''\n setValue('displayName', target)\n setManualOverride(true)\n }\n setEditing((state) => !state)\n }\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (!manualOverride) setManualOverride(true)\n setValue('displayName', event.target.value)\n }\n\n const handleReset = () => {\n setManualOverride(false)\n setEditing(false)\n }\n\n return (\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1\">\n <div className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.people.form.displayNamePreview')}\n </div>\n {editing ? (\n <div className=\"mt-2 space-y-2\">\n <Input\n value={currentValue}\n onChange={handleChange}\n placeholder={t('customers.people.form.displayName.placeholder')}\n />\n {error ? <p className=\"text-xs text-status-error-text\">{error}</p> : null}\n </div>\n ) : (\n <div className=\"mt-1 text-base font-medium\">{previewValue || placeholder}</div>\n )}\n </div>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={toggleEditing}>\n {editing ? (\n <>\n <Check className=\"mr-2 h-4 w-4\" />\n {t('customers.people.form.displayName.done')}\n </>\n ) : (\n <>\n <Pencil className=\"mr-2 h-4 w-4\" />\n {t('customers.people.form.displayName.edit')}\n </>\n )}\n </Button>\n </div>\n {manualOverride ? (\n <div className=\"mt-3\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={handleReset} disabled={!derived}>\n {t('customers.people.form.displayName.reset')}\n </Button>\n </div>\n ) : null}\n </div>\n )\n }\n\nexport const createPersonFormFields = (t: Translator): CrudField[] => {\n const contactSection = createSectionHeadingField('__contactInformationSection', t('customers.people.form.sections.contactInformation'))\n const companySection = createSectionHeadingField('__companyInformationSection', t('customers.people.form.sections.companyInformation'))\n const dictionaryFields: CrudField[] = dictionaryFieldDefinitions.map((definition) => ({\n id: definition.id,\n label: t(definition.labelKey),\n type: 'custom',\n layout: definition.layout ?? 'third',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind={definition.kind}\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={buildDictionaryLabels(t, definition)}\n allowInlineCreate\n allowAppearance\n showManage\n />\n ),\n }))\n\n return [\n { id: 'displayName', label: t('customers.people.form.displayName.label'), type: 'text', required: true },\n { id: 'firstName', label: t('customers.people.form.firstName'), type: 'text', required: true, layout: 'half' },\n { id: 'lastName', label: t('customers.people.form.lastName'), type: 'text', required: true, layout: 'half' },\n {\n id: 'jobTitle',\n label: t('customers.people.form.jobTitle', 'Job title'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind=\"job-titles\"\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={{\n placeholder: t('customers.people.form.jobTitle.placeholder', 'Select a job title'),\n addLabel: t('customers.people.form.dictionary.addJobTitle', 'Add job title'),\n addPrompt: t('customers.people.form.dictionary.promptJobTitle', 'Enter a new job title'),\n dialogTitle: t('customers.people.form.dictionary.dialogTitleJobTitle', 'Add job title'),\n valueLabel: t('customers.people.form.dictionary.valueLabel', 'Value'),\n valuePlaceholder: t('customers.people.form.dictionary.valuePlaceholder', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('customers.people.form.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n successCreateLabel: undefined,\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.dictionary.loading'),\n manageTitle: t('customers.people.form.dictionary.manage'),\n }}\n allowInlineCreate\n allowAppearance\n showManage\n />\n ),\n },\n contactSection,\n createPrimaryEmailField(t),\n createPrimaryPhoneField(t),\n companySection,\n {\n id: 'companyEntityId',\n label: t('customers.people.form.company'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }) => (\n <CompanySelectField\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={{\n placeholder: t('customers.people.form.company.placeholder'),\n addLabel: t('customers.people.form.company.add'),\n addPrompt: t('customers.people.form.company.prompt'),\n dialogTitle: t('customers.people.form.company.dialogTitle'),\n inputLabel: t('customers.people.form.company.inputLabel'),\n inputPlaceholder: t('customers.people.form.company.inputPlaceholder'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.company.loading'),\n }}\n />\n ),\n },\n ...dictionaryFields,\n { id: 'description', label: t('customers.people.form.description'), type: 'textarea' },\n {\n id: 'addresses',\n label: '',\n type: 'custom',\n layout: 'full',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => {\n const addresses = Array.isArray(value) ? (value as CustomerAddressValue[]) : []\n return (\n <CustomerAddressTiles\n addresses={addresses}\n t={t}\n emptyLabel={t('customers.people.detail.empty.addresses')}\n gridClassName=\"grid gap-4 min-[480px]:grid-cols-1 xl:grid-cols-2\"\n onCreate={async (payload: CustomerAddressInput) => {\n const nextId =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `tmp-${Math.random().toString(36).slice(2)}`\n const next: CustomerAddressValue = {\n id: nextId,\n name: payload.name ?? undefined,\n purpose: payload.purpose ?? undefined,\n companyName: payload.companyName ?? undefined,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? undefined,\n buildingNumber: payload.buildingNumber ?? undefined,\n flatNumber: payload.flatNumber ?? undefined,\n city: payload.city ?? undefined,\n region: payload.region ?? undefined,\n postalCode: payload.postalCode ?? undefined,\n country: payload.country ?? undefined,\n isPrimary: payload.isPrimary ?? false,\n }\n const current = Array.isArray(addresses) ? addresses : []\n const nextAddresses =\n next.isPrimary === true\n ? [next, ...current.map((item) => ({ ...item, isPrimary: false }))]\n : [next, ...current]\n setValue(nextAddresses)\n }}\n onUpdate={async (id, payload) => {\n const current = Array.isArray(addresses) ? addresses : []\n const updated = current.map((item) => {\n if (item.id !== id) {\n return payload.isPrimary ? { ...item, isPrimary: false } : item\n }\n return {\n ...item,\n name: payload.name ?? null,\n purpose: payload.purpose ?? null,\n companyName: payload.companyName ?? null,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? null,\n buildingNumber: payload.buildingNumber ?? null,\n flatNumber: payload.flatNumber ?? null,\n city: payload.city ?? null,\n region: payload.region ?? null,\n postalCode: payload.postalCode ?? null,\n country: payload.country ?? null,\n isPrimary: payload.isPrimary ?? false,\n }\n })\n setValue(updated)\n }}\n onDelete={async (id) => {\n const current = Array.isArray(addresses) ? addresses : []\n setValue(current.filter((item) => item.id !== id))\n }}\n />\n )\n },\n },\n ]\n}\n\nexport const createPersonFormGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.people.form.groups.details'),\n column: 1,\n component: createDisplayNameSection(t),\n fields: [\n 'firstName',\n 'lastName',\n '__contactInformationSection',\n 'primaryEmail',\n 'primaryPhone',\n '__companyInformationSection',\n 'jobTitle',\n 'companyEntityId',\n 'status',\n 'lifecycleStage',\n 'source',\n ],\n },\n {\n id: 'addresses',\n title: t('customers.people.form.groups.addresses'),\n column: 1,\n fields: ['addresses'],\n },\n {\n id: 'notes',\n title: t('customers.people.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.people.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\nexport function buildPersonPayload(\n values: PersonFormValues | PersonEditFormValues,\n organizationId?: string | null,\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {}\n\n const displayNameValue = typeof values.displayName === 'string' ? values.displayName.trim() : ''\n if (!displayNameValue) {\n throw new Error('DISPLAY_NAME_REQUIRED')\n }\n payload.displayName = displayNameValue\n payload.firstName = typeof values.firstName === 'string' ? values.firstName.trim() : ''\n payload.lastName = typeof values.lastName === 'string' ? values.lastName.trim() : ''\n\n const assign = (key: string, val?: string | null) => {\n if (val === null) {\n payload[key] = null\n return\n }\n const normalized = blankToUndefined(val)\n if (normalized !== undefined) payload[key] = normalized\n }\n\n assign('jobTitle', typeof values.jobTitle === 'string' ? values.jobTitle : undefined)\n assign('primaryEmail', typeof values.primaryEmail === 'string' ? values.primaryEmail : undefined)\n assign('primaryPhone', typeof values.primaryPhone === 'string' ? values.primaryPhone : undefined)\n assign('status', typeof values.status === 'string' ? values.status : undefined)\n assign('lifecycleStage', typeof values.lifecycleStage === 'string' ? values.lifecycleStage : undefined)\n assign('source', typeof values.source === 'string' ? values.source : undefined)\n assign(\n 'companyEntityId',\n typeof values.companyEntityId === 'string'\n ? values.companyEntityId\n : values.companyEntityId === null\n ? null\n : undefined,\n )\n assign('description', typeof values.description === 'string' ? values.description : undefined)\n\n const customFields = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n if (Object.keys(customFields).length) {\n payload.customFields = customFields\n }\n\n if (organizationId) payload.organizationId = organizationId\n\n return payload\n}\n\nexport const createCompanyFormSchema = () =>\n z\n .object({\n displayName: z.string().trim().min(1),\n primaryEmail: z\n .string()\n .trim()\n .email()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val)),\n primaryPhone: z\n .string()\n .trim()\n .max(50)\n .refine((value) => isValidPhoneNumber(value), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n status: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n lifecycleStage: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n source: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n legalName: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n brandName: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n domain: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n websiteUrl: z\n .string()\n .trim()\n .url()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n industry: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n sizeBucket: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n annualRevenue: z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional(),\n })\n .passthrough()\n\nexport const createCompanyFormFields = (t: Translator): CrudField[] => {\n const dictionaryFields: CrudField[] = companyDictionaryFieldDefinitions.map((definition) => ({\n id: definition.id,\n label: t(definition.labelKey),\n type: 'custom',\n layout: definition.layout ?? 'third',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind={definition.kind}\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={buildDictionaryLabels(t, definition)}\n />\n ),\n }))\n\n return [\n {\n id: 'displayName',\n label: t('customers.companies.form.displayName.label', 'Display name'),\n type: 'text',\n required: true,\n },\n {\n id: 'primaryEmail',\n label: t('customers.companies.detail.highlights.primaryEmail', 'Primary email'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.form.primaryEmailPlaceholder', 'name@example.com'),\n },\n {\n id: 'primaryPhone',\n label: t('customers.companies.detail.highlights.primaryPhone', 'Primary phone'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue, error, disabled, autoFocus }: CrudCustomFieldRenderProps) => (\n <PhoneNumberField\n value={typeof value === 'string' ? value : null}\n onValueChange={(next) => setValue(typeof next === 'string' ? next : '')}\n externalError={error}\n autoFocus={autoFocus}\n disabled={disabled}\n placeholder={t('customers.companies.form.primaryPhonePlaceholder', '+1 555 123 4567')}\n invalidLabel={t('customers.people.form.primaryPhone.invalid', 'Enter a valid phone number with country code (e.g. +1 212 555 1234)')}\n minDigits={7}\n />\n ),\n } as CrudField,\n ...dictionaryFields,\n {\n id: 'legalName',\n label: t('customers.companies.detail.fields.legalName', 'Legal name'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'brandName',\n label: t('customers.companies.detail.fields.brandName', 'Brand name'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'domain',\n label: t('customers.companies.detail.fields.domain', 'Domain'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.detail.fields.domainPlaceholder', 'example.com'),\n description: t('customers.companies.detail.fields.domainHelp', 'Use a plain domain like example.com.'),\n },\n {\n id: 'websiteUrl',\n label: t('customers.companies.detail.highlights.website', 'Website'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.detail.highlights.websitePlaceholder', 'https://example.com'),\n description: t('customers.companies.detail.fields.websiteHelp', 'Use a full URL like https://example.com.'),\n },\n {\n id: 'industry',\n label: t('customers.companies.detail.highlights.industry', 'Industry'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'sizeBucket',\n label: t('customers.companies.detail.fields.sizeBucket', 'Company size'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'annualRevenue',\n label: t('customers.companies.detail.highlights.annualRevenue', 'Annual revenue'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.companies.detail.highlights.annualRevenuePlaceholder', 'Enter amount'),\n },\n {\n id: 'description',\n label: t('customers.companies.detail.fields.description', 'Description'),\n type: 'textarea',\n },\n {\n id: 'addresses',\n label: '',\n type: 'custom',\n layout: 'full',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => {\n const addresses = Array.isArray(value) ? (value as CustomerAddressValue[]) : []\n return (\n <CustomerAddressTiles\n addresses={addresses}\n t={t}\n emptyLabel={t('customers.companies.detail.empty.addresses')}\n gridClassName=\"grid gap-4 min-[480px]:grid-cols-1 xl:grid-cols-2\"\n onCreate={async (payload: CustomerAddressInput) => {\n const nextId =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `tmp-${Math.random().toString(36).slice(2)}`\n const next: CustomerAddressValue = {\n id: nextId,\n name: payload.name ?? undefined,\n purpose: payload.purpose ?? undefined,\n companyName: payload.companyName ?? undefined,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? undefined,\n buildingNumber: payload.buildingNumber ?? undefined,\n flatNumber: payload.flatNumber ?? undefined,\n city: payload.city ?? undefined,\n region: payload.region ?? undefined,\n postalCode: payload.postalCode ?? undefined,\n country: payload.country ?? undefined,\n isPrimary: payload.isPrimary ?? false,\n }\n const current = Array.isArray(addresses) ? addresses : []\n const nextAddresses =\n next.isPrimary === true\n ? [next, ...current.map((item) => ({ ...item, isPrimary: false }))]\n : [next, ...current]\n setValue(nextAddresses)\n }}\n onUpdate={async (id, payload) => {\n const current = Array.isArray(addresses) ? addresses : []\n const updated = current.map((item) => {\n if (item.id !== id) {\n return payload.isPrimary ? { ...item, isPrimary: false } : item\n }\n return {\n ...item,\n name: payload.name ?? null,\n purpose: payload.purpose ?? null,\n companyName: payload.companyName ?? null,\n addressLine1: payload.addressLine1,\n addressLine2: payload.addressLine2 ?? null,\n buildingNumber: payload.buildingNumber ?? null,\n flatNumber: payload.flatNumber ?? null,\n city: payload.city ?? null,\n region: payload.region ?? null,\n postalCode: payload.postalCode ?? null,\n country: payload.country ?? null,\n isPrimary: payload.isPrimary ?? false,\n }\n })\n setValue(updated)\n }}\n onDelete={async (id) => {\n const current = Array.isArray(addresses) ? addresses : []\n setValue(current.filter((item) => item.id !== id))\n }}\n />\n )\n },\n },\n ]\n}\n\nexport const createCompanyFormGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.companies.form.groups.details'),\n column: 1,\n fields: ['displayName', 'primaryEmail', 'primaryPhone', 'status', 'lifecycleStage', 'source'],\n },\n {\n id: 'profile',\n title: t('customers.companies.form.groups.profile'),\n column: 1,\n fields: ['legalName', 'brandName', 'domain', 'websiteUrl', 'industry', 'sizeBucket', 'annualRevenue'],\n },\n {\n id: 'addresses',\n title: t('customers.companies.form.groups.addresses'),\n column: 1,\n fields: ['addresses'],\n },\n {\n id: 'notes',\n title: t('customers.companies.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.companies.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\nexport function buildCompanyPayload(\n values: CompanyFormValues | CompanyEditFormValues,\n organizationId?: string | null,\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {}\n\n const displayNameValue = blankToUndefined(\n typeof values.displayName === 'string' ? values.displayName : undefined,\n )\n if (!displayNameValue) {\n throw new Error('DISPLAY_NAME_REQUIRED')\n }\n payload.displayName = displayNameValue\n\n const assign = (key: string, val?: string) => {\n const normalized = blankToUndefined(val)\n if (normalized !== undefined) payload[key] = normalized\n }\n\n assign('primaryEmail', typeof values.primaryEmail === 'string' ? values.primaryEmail : undefined)\n assign('primaryPhone', typeof values.primaryPhone === 'string' ? values.primaryPhone : undefined)\n assign('status', typeof values.status === 'string' ? values.status : undefined)\n assign('lifecycleStage', typeof values.lifecycleStage === 'string' ? values.lifecycleStage : undefined)\n assign('source', typeof values.source === 'string' ? values.source : undefined)\n assign('legalName', typeof values.legalName === 'string' ? values.legalName : undefined)\n assign('brandName', typeof values.brandName === 'string' ? values.brandName : undefined)\n assign('domain', typeof values.domain === 'string' ? values.domain?.toLowerCase() : undefined)\n assign('websiteUrl', typeof values.websiteUrl === 'string' ? values.websiteUrl : undefined)\n assign('industry', typeof values.industry === 'string' ? values.industry : undefined)\n assign('sizeBucket', typeof values.sizeBucket === 'string' ? values.sizeBucket : undefined)\n assign('description', typeof values.description === 'string' ? values.description : undefined)\n\n const rawRevenue = typeof values.annualRevenue === 'string' ? values.annualRevenue.trim() : ''\n if (rawRevenue.length) {\n const normalized = rawRevenue.replace(/,/g, '').replace(/\\s+/g, '')\n if (!/^\\d+(\\.\\d{1,2})?$/.test(normalized)) {\n throw new Error('ANNUAL_REVENUE_INVALID')\n }\n payload.annualRevenue = normalized\n }\n\n const customFields = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n if (Object.keys(customFields).length) {\n payload.customFields = customFields\n }\n\n if (organizationId) payload.organizationId = organizationId\n\n return payload\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode types\n// ---------------------------------------------------------------------------\n\n// URL/email/phone fields are clearable on edit: blanking a previously-set value transmits null,\n// so the edit-form value types widen to `string | null` to match the edit-schema output. See #2526.\nexport type CompanyEditFormValues = Omit<\n CompanyFormValues,\n | 'addresses'\n | 'primaryEmail'\n | 'primaryPhone'\n | 'websiteUrl'\n | 'domain'\n | 'legalName'\n | 'brandName'\n | 'sizeBucket'\n | 'annualRevenue'\n | 'description'\n> & {\n id: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n websiteUrl?: string | null\n domain?: string | null\n legalName?: string | null\n brandName?: string | null\n sizeBucket?: string | null\n annualRevenue?: string | null\n description?: string | null\n}\n\nexport type PersonEditFormValues = Omit<PersonFormValues, 'addresses' | 'primaryEmail' | 'primaryPhone'> & {\n id: string\n department?: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n linkedInUrl?: string | null\n twitterUrl?: string | null\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode schemas\n// ---------------------------------------------------------------------------\n\nconst optionalString = () =>\n z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? undefined : val))\n .optional()\n\n// Edit-mode URL/email/phone fields map to nullable columns and must be clearable: blanking a\n// previously-set value transforms '' \u2192 null so the payload builder can transmit an explicit\n// clear (omitting the key can never remove an existing value). Create-mode schemas keep the\n// '' \u2192 undefined transform. See #2526.\nconst clearableUrlField = () =>\n z\n .string()\n .trim()\n .url()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\nconst clearableEmailField = () =>\n z\n .string()\n .trim()\n .email()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\n// Domain maps to a nullable column; on edit a blanked value must transmit null\n// (not undefined) so it actually clears \u2014 mirroring the website field. See #2529.\nconst clearableDomainField = () =>\n z\n .string()\n .trim()\n .max(200)\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\n// Plain optional string fields that map to nullable columns (legal name, brand name,\n// company size, annual revenue, description). On edit a blanked value must transmit null\n// so it actually clears \u2014 create-mode keeps the '' \u2192 undefined transform. See #3050.\nconst clearableTextField = () =>\n z\n .string()\n .trim()\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\nconst clearablePhoneField = () =>\n z\n .string()\n .trim()\n .max(50)\n .refine((value) => value === '' || isValidPhoneNumber(value), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .optional()\n .or(z.literal(''))\n .transform((val) => (val === '' ? null : val))\n .optional()\n\nexport const createCompanyEditSchema = () =>\n createCompanyFormSchema().extend({\n id: z.string().uuid(),\n primaryEmail: clearableEmailField(),\n primaryPhone: clearablePhoneField(),\n websiteUrl: clearableUrlField(),\n domain: clearableDomainField(),\n legalName: clearableTextField(),\n brandName: clearableTextField(),\n sizeBucket: clearableTextField(),\n annualRevenue: clearableTextField(),\n description: clearableTextField(),\n })\n\nexport const createPersonEditSchema = () =>\n createPersonFormSchema().extend({\n id: z.string().uuid(),\n department: optionalString(),\n primaryEmail: clearableEmailField(),\n primaryPhone: clearablePhoneField(),\n linkedInUrl: clearableUrlField(),\n twitterUrl: clearableUrlField(),\n })\n\n// ---------------------------------------------------------------------------\n// Edit-mode fields\n// ---------------------------------------------------------------------------\n\nconst buildIndustryLabels = (t: Translator): DictionarySelectLabels => ({\n placeholder: t('customers.companies.form.industry.placeholder', 'Select industry\u2026'),\n addLabel: t('customers.companies.form.dictionary.addIndustry', 'Add industry'),\n addPrompt: t('customers.companies.form.dictionary.promptIndustry', 'Enter a new industry.'),\n dialogTitle: t('customers.companies.form.dictionary.dialogTitleIndustry', 'Add industry'),\n valueLabel: t('customers.people.form.dictionary.valueLabel', 'Value'),\n valuePlaceholder: t('customers.people.form.dictionary.valuePlaceholder', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n labelPlaceholder: t('customers.people.form.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n successCreateLabel: undefined,\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.dictionary.loading'),\n manageTitle: t('customers.people.form.dictionary.manage'),\n})\n\nexport const createCompanyEditFields = (t: Translator): CrudField[] => {\n const baseFields = createCompanyFormFields(t)\n const industryLabels = buildIndustryLabels(t)\n\n return baseFields.map((field) => {\n if (field.id === 'industry') {\n return {\n id: 'industry',\n label: t('customers.companies.detail.fields.industry', 'Industry'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }: CrudCustomFieldRenderProps) => (\n <DictionarySelectField\n kind={'industries' as CustomerDictionaryKind}\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next)}\n labels={industryLabels}\n />\n ),\n } as CrudField\n }\n return field\n })\n}\n\nexport const createPersonEditFields = (t: Translator): CrudField[] => {\n const baseFields = createPersonFormFields(t)\n return [\n ...baseFields,\n {\n id: 'department',\n label: t('customers.people.form.department', 'Department'),\n type: 'text',\n layout: 'half',\n },\n {\n id: 'linkedInUrl',\n label: t('customers.people.form.linkedInUrl', 'LinkedIn URL'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.people.form.linkedInUrl.placeholder', 'https://linkedin.com/in/...'),\n },\n {\n id: 'twitterUrl',\n label: t('customers.people.form.twitterUrl', 'Twitter / X URL'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.people.form.twitterUrl.placeholder', 'https://x.com/...'),\n },\n ]\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode groups\n// ---------------------------------------------------------------------------\n\nexport const createCompanyEditGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.companies.form.groups.details'),\n column: 1,\n fields: ['displayName', 'primaryEmail', 'primaryPhone', 'status', 'lifecycleStage', 'source'],\n },\n {\n id: 'roles',\n title: t('customers.roles.groupTitle', 'Roles'),\n column: 1,\n component: ({ values }: CrudFormGroupComponentProps) => (\n values.id ? (\n <RolesSection\n entityType=\"company\"\n entityId={values.id as string}\n entityName={typeof values.displayName === 'string' ? values.displayName : null}\n />\n ) : null\n ),\n },\n {\n id: 'profile',\n title: t('customers.companies.form.groups.profile'),\n column: 1,\n fields: ['legalName', 'brandName', 'domain', 'websiteUrl', 'industry', 'sizeBucket', 'annualRevenue'],\n },\n {\n id: 'notes',\n title: t('customers.companies.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.companies.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\n/**\n * Groups for the \"Dane firmy\" tab layout (Figma SPEC-048 mockup).\n * All zone-1 groups stay in a single vertical stack so drag-and-drop ordering\n * applies consistently across every section and persists per page type.\n */\nexport const createCompanyDaneFiremyGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'identity',\n title: t('customers.companies.form.groups.identity', 'To\u017Csamo\u015B\u0107').toUpperCase(),\n column: 1,\n fields: ['displayName', 'legalName', 'brandName'],\n },\n {\n id: 'contact',\n title: t('customers.companies.form.groups.contact', 'Kontakt').toUpperCase(),\n column: 1,\n fields: ['primaryEmail', 'primaryPhone', 'domain', 'websiteUrl'],\n },\n {\n id: 'classification',\n title: t('customers.companies.form.groups.classification', 'Klasyfikacja').toUpperCase(),\n column: 1,\n fields: ['status', 'lifecycleStage', 'source'],\n },\n {\n id: 'businessProfile',\n title: t('customers.companies.form.groups.businessProfile', 'Profil biznesowy').toUpperCase(),\n column: 1,\n fields: ['industry', 'sizeBucket', 'annualRevenue'],\n },\n {\n id: 'notes',\n title: t('customers.companies.form.groups.notes', 'Notatki'),\n column: 1,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.companies.form.groups.customAttributes', 'Atrybuty niestandardowe'),\n column: 1,\n kind: 'customFields',\n },\n]\n\nexport const createPersonEditGroups = (t: Translator): CrudFormGroup[] => [\n {\n id: 'details',\n title: t('customers.people.form.groups.details'),\n column: 1,\n fields: [\n 'firstName',\n 'lastName',\n '__contactInformationSection',\n 'primaryEmail',\n 'primaryPhone',\n '__companyInformationSection',\n 'jobTitle',\n 'companyEntityId',\n 'status',\n 'lifecycleStage',\n 'source',\n ],\n component: createDisplayNameSection(t),\n },\n {\n id: 'roles',\n title: t('customers.roles.groupTitle', 'Roles'),\n column: 1,\n component: ({ values }: CrudFormGroupComponentProps) => (\n values.id ? (\n <RolesSection\n entityType=\"person\"\n entityId={values.id as string}\n entityName={typeof values.displayName === 'string' ? values.displayName : null}\n />\n ) : null\n ),\n },\n {\n id: 'social',\n title: t('customers.people.form.groups.social', 'Social & links'),\n column: 1,\n fields: ['department', 'linkedInUrl', 'twitterUrl'],\n },\n {\n id: 'notes',\n title: t('customers.people.form.groups.notes'),\n column: 2,\n fields: ['description'],\n },\n {\n id: 'customFields',\n title: t('customers.people.form.groups.custom'),\n column: 2,\n kind: 'customFields',\n },\n]\n\n/**\n * Groups for the Person v2 \"Dane osobowe\" Figma layout (SPEC-048 mockup).\n * All groups in column 1 (Zone 1). Notes handled separately in Zone 2 tabs.\n */\nexport const createPersonPersonalDataGroups = (\n t: Translator,\n options?: { entityName?: string | null },\n): CrudFormGroup[] => {\n const entityName = options?.entityName?.trim() || null\n const rolesTitle = entityName\n ? t('customers.roles.groupTitle.person', 'My roles with {{name}}', { name: entityName })\n : t('customers.people.form.groups.roles', 'My roles')\n return [\n {\n id: 'personalDataDisplay',\n title: t('customers.people.form.groups.displayName', 'Display name'),\n column: 1,\n bare: true,\n component: createDisplayNameSection(t),\n },\n {\n id: 'personalData',\n title: t('customers.people.form.groups.personalData', 'Personal data'),\n column: 1,\n fields: ['firstName', 'lastName', 'jobTitle', 'primaryEmail', 'primaryPhone'],\n },\n {\n id: 'companyRole',\n title: t('customers.people.form.groups.companyRole', 'Company & role'),\n column: 1,\n fields: ['companyEntityId', 'status', 'lifecycleStage', 'source'],\n },\n {\n id: 'customFields',\n title: t('customers.people.form.groups.customAttributes', 'Custom attributes'),\n column: 1,\n kind: 'customFields',\n },\n {\n id: 'roles',\n title: rolesTitle,\n column: 1,\n component: ({ values }: CrudFormGroupComponentProps) => (\n values.id ? (\n <RolesSection\n entityType=\"person\"\n entityId={values.id as string}\n entityName={typeof values.displayName === 'string' ? values.displayName : null}\n />\n ) : null\n ),\n },\n ]\n}\n\n// ---------------------------------------------------------------------------\n// Edit-mode payload builders\n// ---------------------------------------------------------------------------\n\n// On edit, optional URL/email/phone fields that map to nullable columns must transmit an explicit\n// `null` when the user blanks a previously-set value \u2014 omitting the key can never clear it.\n// The base create-mode builders omit blanks (correct for create), so the edit builders\n// override these clearable fields here. See #2526.\nconst assignClearable = (payload: Record<string, unknown>, key: string, raw: unknown): void => {\n if (raw === null) {\n payload[key] = null\n return\n }\n if (typeof raw !== 'string') return\n const trimmed = raw.trim()\n payload[key] = trimmed.length ? trimmed : null\n}\n\nexport function buildCompanyEditPayload(values: CompanyEditFormValues, organizationId?: string | null): Record<string, unknown> {\n const payload = buildCompanyPayload(values, organizationId)\n payload.id = values.id\n\n assignClearable(payload, 'primaryEmail', values.primaryEmail)\n assignClearable(payload, 'primaryPhone', values.primaryPhone)\n assignClearable(payload, 'websiteUrl', values.websiteUrl)\n assignClearable(payload, 'domain', typeof values.domain === 'string' ? values.domain.toLowerCase() : values.domain)\n\n // Plain nullable string fields that must transmit null when blanked on edit (#3050).\n assignClearable(payload, 'legalName', values.legalName)\n assignClearable(payload, 'brandName', values.brandName)\n assignClearable(payload, 'sizeBucket', values.sizeBucket)\n assignClearable(payload, 'description', values.description)\n\n // Annual revenue maps to a nullable numeric column: a blanked value must clear it.\n // Non-empty values are already validated/normalized by buildCompanyPayload; an omitted\n // (undefined) value stays a no-op like the other clearable fields. (#3050)\n const annualRevenueRaw = values.annualRevenue\n const annualRevenueBlank =\n annualRevenueRaw === null ||\n (typeof annualRevenueRaw === 'string' && annualRevenueRaw.trim().length === 0)\n if (annualRevenueBlank) payload.annualRevenue = null\n\n return payload\n}\n\nexport function buildPersonEditPayload(values: PersonEditFormValues, organizationId?: string | null): Record<string, unknown> {\n const payload = buildPersonPayload(values, organizationId)\n payload.id = values.id\n\n const department = typeof values.department === 'string' ? values.department.trim() : ''\n if (department.length) payload.department = department\n\n assignClearable(payload, 'primaryEmail', values.primaryEmail)\n assignClearable(payload, 'primaryPhone', values.primaryPhone)\n assignClearable(payload, 'linkedInUrl', values.linkedInUrl)\n assignClearable(payload, 'twitterUrl', values.twitterUrl)\n\n return payload\n}\n\n// ---------------------------------------------------------------------------\n// Overview types (shared between v1 and v2 detail pages)\n// ---------------------------------------------------------------------------\n\nimport type {\n TagSummary,\n CommentSummary,\n ActivitySummary,\n DealSummary,\n TodoLinkSummary,\n InteractionSummary,\n} from './detail/types'\n\nexport type { TagSummary, CommentSummary, ActivitySummary, DealSummary, TodoLinkSummary, InteractionSummary }\n\nexport type CompanyPersonSummary = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n jobTitle?: string | null\n department?: string | null\n createdAt?: string | null\n organizationId?: string | null\n source?: string | null\n temperature?: string | null\n linkedAt?: string | null\n}\n\nexport type CompanyOverview = {\n company: {\n id: string\n displayName: string\n description?: string | null\n ownerUserId?: string | null\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n source?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n temperature?: string | null\n renewalQuarter?: string | null\n organizationId?: string | null\n }\n profile: {\n id: string\n legalName?: string | null\n brandName?: string | null\n domain?: string | null\n websiteUrl?: string | null\n industry?: string | null\n sizeBucket?: string | null\n annualRevenue?: string | null\n } | null\n customFields: Record<string, unknown>\n tags: TagSummary[]\n comments: CommentSummary[]\n activities: ActivitySummary[]\n interactions: InteractionSummary[]\n deals: DealSummary[]\n todos: TodoLinkSummary[]\n people: CompanyPersonSummary[]\n counts?: {\n comments: number\n activities: number\n interactions: number\n todos: number\n deals: number\n people: number\n addresses: number\n tags: number\n }\n plannedActivitiesPreview?: InteractionSummary[]\n kpis?: {\n activeDealsCount: number\n activeDealsValue: number | null\n dealCurrency: string | null\n activityCount: number\n activityTrend: {\n value: number\n direction: 'up' | 'down' | 'unchanged'\n } | null\n ltvValue: number | null\n completedDealsCount: number\n clientTenureYears: number | null\n }\n interactionMode?: 'canonical' | 'legacy'\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\nexport type PersonOverview = {\n person: {\n id: string\n displayName: string\n description?: string | null\n ownerUserId?: string | null\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycleStage?: string | null\n source?: string | null\n temperature?: string | null\n renewalQuarter?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n updatedAt?: string | null\n updated_at?: string | null\n }\n profile: {\n id: string\n firstName?: string | null\n lastName?: string | null\n preferredName?: string | null\n jobTitle?: string | null\n department?: string | null\n seniority?: string | null\n timezone?: string | null\n linkedInUrl?: string | null\n twitterUrl?: string | null\n companyEntityId?: string | null\n } | null\n customFields: Record<string, unknown>\n tags: TagSummary[]\n comments: CommentSummary[]\n activities: ActivitySummary[]\n interactions: InteractionSummary[]\n deals: DealSummary[]\n todos: TodoLinkSummary[]\n counts?: {\n comments: number\n activities: number\n interactions: number\n todos: number\n deals: number\n companies: number\n addresses: number\n tags: number\n }\n plannedActivitiesPreview?: InteractionSummary[]\n interactionMode?: 'canonical' | 'legacy'\n /** Whether this person is the primary contact for any linked company. */\n isPrimary?: boolean\n companies?: Array<{\n id: string\n displayName: string\n isPrimary: boolean\n }>\n company?: {\n id: string\n displayName: string\n } | null\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\n// ---------------------------------------------------------------------------\n// API response \u2192 form values mapping\n// ---------------------------------------------------------------------------\n\nexport function mapCompanyOverviewToFormValues(overview: CompanyOverview): Partial<CompanyEditFormValues> {\n const rawPhone = overview.company.primaryPhone\n const phoneValue = rawPhone == null ? '' : String(rawPhone)\n return {\n id: overview.company.id,\n displayName: coerceDisplayName(overview.company.displayName),\n primaryEmail: overview.company.primaryEmail ?? '',\n primaryPhone: phoneValue,\n status: overview.company.status ?? '',\n lifecycleStage: overview.company.lifecycleStage ?? '',\n source: overview.company.source ?? '',\n description: overview.company.description ?? '',\n legalName: overview.profile?.legalName ?? '',\n brandName: overview.profile?.brandName ?? '',\n domain: overview.profile?.domain ?? '',\n websiteUrl: overview.profile?.websiteUrl ?? '',\n industry: overview.profile?.industry ?? '',\n sizeBucket: overview.profile?.sizeBucket ?? '',\n annualRevenue: overview.profile?.annualRevenue ?? '',\n ...extractCustomFieldEntries({ customFields: overview.customFields }),\n }\n}\n\nexport function mapPersonOverviewToFormValues(overview: PersonOverview): Partial<PersonEditFormValues> {\n const rawPhone = overview.person.primaryPhone\n const phoneValue = rawPhone == null ? '' : String(rawPhone)\n return {\n id: overview.person.id,\n displayName: coerceDisplayName(overview.person.displayName),\n firstName: overview.profile?.firstName ?? '',\n lastName: overview.profile?.lastName ?? '',\n primaryEmail: overview.person.primaryEmail ?? '',\n primaryPhone: phoneValue,\n companyEntityId: overview.profile?.companyEntityId ?? '',\n jobTitle: overview.profile?.jobTitle ?? '',\n status: overview.person.status ?? '',\n lifecycleStage: overview.person.lifecycleStage ?? '',\n source: overview.person.source ?? '',\n description: overview.person.description ?? '',\n department: overview.profile?.department ?? '',\n linkedInUrl: overview.profile?.linkedInUrl ?? '',\n twitterUrl: overview.profile?.twitterUrl ?? '',\n ...extractCustomFieldEntries({ customFields: overview.customFields }),\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -21,6 +21,13 @@ const CUSTOMER_DICTIONARY_KINDS = [
21
21
  "renewal-quarters",
22
22
  "person-company-roles"
23
23
  ];
24
+ const CUSTOMER_DICTIONARIES_MANAGE_HREF = "/backend/config/customers";
25
+ function getCustomerDictionarySettingsSectionId(kind) {
26
+ return `customer-dictionary-${kind}`;
27
+ }
28
+ function getCustomerDictionaryManageHref(kind) {
29
+ return `${CUSTOMER_DICTIONARIES_MANAGE_HREF}#${getCustomerDictionarySettingsSectionId(kind)}`;
30
+ }
24
31
  function createEmptyCustomerDictionaryMaps() {
25
32
  return CUSTOMER_DICTIONARY_KINDS.reduce(
26
33
  (acc, kind) => {
@@ -31,12 +38,15 @@ function createEmptyCustomerDictionaryMaps() {
31
38
  );
32
39
  }
33
40
  export {
41
+ CUSTOMER_DICTIONARIES_MANAGE_HREF,
34
42
  CUSTOMER_DICTIONARY_KINDS,
35
43
  DictionaryValue,
36
44
  ICON_LIBRARY,
37
45
  ICON_SUGGESTIONS,
38
46
  createDictionaryMap,
39
47
  createEmptyCustomerDictionaryMaps,
48
+ getCustomerDictionaryManageHref,
49
+ getCustomerDictionarySettingsSectionId,
40
50
  normalizeDictionaryEntries,
41
51
  renderDictionaryColor,
42
52
  renderDictionaryIcon
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/lib/dictionaries.ts"],
4
- "sourcesContent": ["import {\n ICON_LIBRARY,\n ICON_SUGGESTIONS,\n type IconOption,\n type DictionaryDisplayEntry,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n DictionaryValue,\n renderDictionaryColor,\n renderDictionaryIcon,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\nexport const CUSTOMER_DICTIONARY_KINDS = [\n 'statuses',\n 'sources',\n 'lifecycle-stages',\n 'address-types',\n 'activity-types',\n 'deal-statuses',\n 'pipeline-stages',\n 'job-titles',\n 'industries',\n 'temperature',\n 'renewal-quarters',\n 'person-company-roles',\n] as const\n\nexport type CustomerDictionaryKind = typeof CUSTOMER_DICTIONARY_KINDS[number]\nexport type CustomerDictionaryDisplayEntry = DictionaryDisplayEntry\nexport type CustomerDictionaryMap = DictionaryMap\n\nexport function createEmptyCustomerDictionaryMaps(): Record<CustomerDictionaryKind, CustomerDictionaryMap> {\n return CUSTOMER_DICTIONARY_KINDS.reduce<Record<CustomerDictionaryKind, CustomerDictionaryMap>>(\n (acc, kind) => {\n acc[kind] = {}\n return acc\n },\n {} as Record<CustomerDictionaryKind, CustomerDictionaryMap>,\n )\n}\n\nexport {\n ICON_LIBRARY,\n ICON_SUGGESTIONS,\n type IconOption,\n DictionaryValue,\n createDictionaryMap,\n normalizeDictionaryEntries,\n renderDictionaryColor,\n renderDictionaryIcon,\n}\n"],
5
- "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,4BAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,SAAS,oCAA2F;AACzG,SAAO,0BAA0B;AAAA,IAC/B,CAAC,KAAK,SAAS;AACb,UAAI,IAAI,IAAI,CAAC;AACb,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AACF;",
4
+ "sourcesContent": ["import {\n ICON_LIBRARY,\n ICON_SUGGESTIONS,\n type IconOption,\n type DictionaryDisplayEntry,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n DictionaryValue,\n renderDictionaryColor,\n renderDictionaryIcon,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\nexport const CUSTOMER_DICTIONARY_KINDS = [\n 'statuses',\n 'sources',\n 'lifecycle-stages',\n 'address-types',\n 'activity-types',\n 'deal-statuses',\n 'pipeline-stages',\n 'job-titles',\n 'industries',\n 'temperature',\n 'renewal-quarters',\n 'person-company-roles',\n] as const\n\nexport type CustomerDictionaryKind = typeof CUSTOMER_DICTIONARY_KINDS[number]\nexport type CustomerDictionaryDisplayEntry = DictionaryDisplayEntry\nexport type CustomerDictionaryMap = DictionaryMap\n\nexport const CUSTOMER_DICTIONARIES_MANAGE_HREF = '/backend/config/customers'\n\nexport function getCustomerDictionarySettingsSectionId(kind: CustomerDictionaryKind) {\n return `customer-dictionary-${kind}`\n}\n\nexport function getCustomerDictionaryManageHref(kind: CustomerDictionaryKind) {\n return `${CUSTOMER_DICTIONARIES_MANAGE_HREF}#${getCustomerDictionarySettingsSectionId(kind)}`\n}\n\nexport function createEmptyCustomerDictionaryMaps(): Record<CustomerDictionaryKind, CustomerDictionaryMap> {\n return CUSTOMER_DICTIONARY_KINDS.reduce<Record<CustomerDictionaryKind, CustomerDictionaryMap>>(\n (acc, kind) => {\n acc[kind] = {}\n return acc\n },\n {} as Record<CustomerDictionaryKind, CustomerDictionaryMap>,\n )\n}\n\nexport {\n ICON_LIBRARY,\n ICON_SUGGESTIONS,\n type IconOption,\n DictionaryValue,\n createDictionaryMap,\n normalizeDictionaryEntries,\n renderDictionaryColor,\n renderDictionaryIcon,\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,4BAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,MAAM,oCAAoC;AAE1C,SAAS,uCAAuC,MAA8B;AACnF,SAAO,uBAAuB,IAAI;AACpC;AAEO,SAAS,gCAAgC,MAA8B;AAC5E,SAAO,GAAG,iCAAiC,IAAI,uCAAuC,IAAI,CAAC;AAC7F;AAEO,SAAS,oCAA2F;AACzG,SAAO,0BAA0B;AAAA,IAC/B,CAAC,KAAK,SAAS;AACb,UAAI,IAAI,IAAI,CAAC;AACb,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6313.1.618a49a6b4",
3
+ "version": "0.6.6-develop.6314.1.c7b8291aa2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -246,16 +246,16 @@
246
246
  "zod": "^4.4.3"
247
247
  },
248
248
  "peerDependencies": {
249
- "@open-mercato/ai-assistant": "0.6.6-develop.6313.1.618a49a6b4",
250
- "@open-mercato/shared": "0.6.6-develop.6313.1.618a49a6b4",
251
- "@open-mercato/ui": "0.6.6-develop.6313.1.618a49a6b4",
249
+ "@open-mercato/ai-assistant": "0.6.6-develop.6314.1.c7b8291aa2",
250
+ "@open-mercato/shared": "0.6.6-develop.6314.1.c7b8291aa2",
251
+ "@open-mercato/ui": "0.6.6-develop.6314.1.c7b8291aa2",
252
252
  "react": "^19.0.0",
253
253
  "react-dom": "^19.0.0"
254
254
  },
255
255
  "devDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.6-develop.6313.1.618a49a6b4",
257
- "@open-mercato/shared": "0.6.6-develop.6313.1.618a49a6b4",
258
- "@open-mercato/ui": "0.6.6-develop.6313.1.618a49a6b4",
256
+ "@open-mercato/ai-assistant": "0.6.6-develop.6314.1.c7b8291aa2",
257
+ "@open-mercato/shared": "0.6.6-develop.6314.1.c7b8291aa2",
258
+ "@open-mercato/ui": "0.6.6-develop.6314.1.c7b8291aa2",
259
259
  "@testing-library/dom": "^10.4.1",
260
260
  "@testing-library/jest-dom": "^6.9.1",
261
261
  "@testing-library/react": "^16.3.1",
@@ -14,7 +14,10 @@ import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuarde
14
14
  import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
15
15
  import { useT } from '@open-mercato/shared/lib/i18n/context'
16
16
  import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
17
- import type { CustomerDictionaryKind } from '../lib/dictionaries'
17
+ import {
18
+ getCustomerDictionarySettingsSectionId,
19
+ type CustomerDictionaryKind,
20
+ } from '../lib/dictionaries'
18
21
  import { ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'
19
22
  import {
20
23
  DictionaryForm,
@@ -47,6 +50,19 @@ const DEFAULT_FORM_VALUES: DictionaryFormValues = {
47
50
  icon: null,
48
51
  }
49
52
 
53
+ const DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS = [100, 350, 1000] as const
54
+
55
+ function getCurrentDictionaryHashTarget(): HTMLElement | null {
56
+ if (typeof window === 'undefined') return null
57
+ const hash = window.location.hash
58
+ if (!hash.startsWith('#customer-dictionary-')) return null
59
+ try {
60
+ return document.getElementById(decodeURIComponent(hash.slice(1)))
61
+ } catch {
62
+ return document.getElementById(hash.slice(1))
63
+ }
64
+ }
65
+
50
66
  export default function DictionarySettings() {
51
67
  const t = useT()
52
68
 
@@ -98,6 +114,45 @@ export default function DictionarySettings() {
98
114
  },
99
115
  ], [t])
100
116
 
117
+ React.useEffect(() => {
118
+ const timeoutIds: number[] = []
119
+ let frameId: number | null = null
120
+
121
+ const clearScheduledScrolls = () => {
122
+ if (frameId !== null) {
123
+ window.cancelAnimationFrame(frameId)
124
+ frameId = null
125
+ }
126
+ while (timeoutIds.length > 0) {
127
+ const timeoutId = timeoutIds.pop()
128
+ if (timeoutId !== undefined) window.clearTimeout(timeoutId)
129
+ }
130
+ }
131
+
132
+ const scrollToHashTarget = () => {
133
+ getCurrentDictionaryHashTarget()?.scrollIntoView({ block: 'start' })
134
+ }
135
+
136
+ const scheduleHashScroll = () => {
137
+ clearScheduledScrolls()
138
+ if (!window.location.hash.startsWith('#customer-dictionary-')) return
139
+ scrollToHashTarget()
140
+ if (typeof window.requestAnimationFrame === 'function') {
141
+ frameId = window.requestAnimationFrame(scrollToHashTarget)
142
+ }
143
+ DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS.forEach((delay) => {
144
+ timeoutIds.push(window.setTimeout(scrollToHashTarget, delay))
145
+ })
146
+ }
147
+
148
+ scheduleHashScroll()
149
+ window.addEventListener('hashchange', scheduleHashScroll)
150
+ return () => {
151
+ window.removeEventListener('hashchange', scheduleHashScroll)
152
+ clearScheduledScrolls()
153
+ }
154
+ }, [])
155
+
101
156
  return (
102
157
  <div className="space-y-8">
103
158
  <header className="space-y-2">
@@ -393,7 +448,10 @@ function CustomerDictionarySection({ kind, title, description }: CustomerDiction
393
448
  }), [dialog, t])
394
449
 
395
450
  return (
396
- <section className="rounded border bg-card text-card-foreground shadow-sm">
451
+ <section
452
+ id={getCustomerDictionarySettingsSectionId(kind)}
453
+ className="scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm"
454
+ >
397
455
  <div className="border-b px-6 py-4 space-y-1">
398
456
  <h2 className="text-lg font-medium">{title}</h2>
399
457
  <p className="text-sm text-muted-foreground">{description}</p>
@@ -51,7 +51,11 @@ import {
51
51
  ensureCustomerDictionary,
52
52
  invalidateCustomerDictionary,
53
53
  } from './detail/hooks/useCustomerDictionary'
54
- import type { CustomerDictionaryKind } from '../lib/dictionaries'
54
+ import {
55
+ CUSTOMER_DICTIONARIES_MANAGE_HREF,
56
+ getCustomerDictionaryManageHref,
57
+ type CustomerDictionaryKind,
58
+ } from '../lib/dictionaries'
55
59
  import { normalizeCustomFieldSubmitValue } from './detail/customFieldUtils'
56
60
  import { CUSTOMER_PHONE_INVALID_MESSAGE_KEY } from '../data/validators'
57
61
 
@@ -116,6 +120,8 @@ type DictionarySelectFieldProps = {
116
120
  showActiveAppearance?: boolean
117
121
  }
118
122
 
123
+ export { CUSTOMER_DICTIONARIES_MANAGE_HREF, getCustomerDictionaryManageHref }
124
+
119
125
  const emailValidationSchema = z.string().email()
120
126
  const EMAIL_CHECK_DEBOUNCE_MS = 350
121
127
 
@@ -233,7 +239,7 @@ export function DictionarySelectField({
233
239
  fetchOptions={fetchOptions}
234
240
  createOption={createOption}
235
241
  labels={labels}
236
- manageHref={manageHref}
242
+ manageHref={manageHref ?? getCustomerDictionaryManageHref(kind)}
237
243
  selectClassName={selectClassName}
238
244
  allowInlineCreate={allowInlineCreate}
239
245
  allowAppearance={allowAppearance}
@@ -30,6 +30,16 @@ export type CustomerDictionaryKind = typeof CUSTOMER_DICTIONARY_KINDS[number]
30
30
  export type CustomerDictionaryDisplayEntry = DictionaryDisplayEntry
31
31
  export type CustomerDictionaryMap = DictionaryMap
32
32
 
33
+ export const CUSTOMER_DICTIONARIES_MANAGE_HREF = '/backend/config/customers'
34
+
35
+ export function getCustomerDictionarySettingsSectionId(kind: CustomerDictionaryKind) {
36
+ return `customer-dictionary-${kind}`
37
+ }
38
+
39
+ export function getCustomerDictionaryManageHref(kind: CustomerDictionaryKind) {
40
+ return `${CUSTOMER_DICTIONARIES_MANAGE_HREF}#${getCustomerDictionarySettingsSectionId(kind)}`
41
+ }
42
+
33
43
  export function createEmptyCustomerDictionaryMaps(): Record<CustomerDictionaryKind, CustomerDictionaryMap> {
34
44
  return CUSTOMER_DICTIONARY_KINDS.reduce<Record<CustomerDictionaryKind, CustomerDictionaryMap>>(
35
45
  (acc, kind) => {