@open-mercato/core 0.9.1-develop.7477.1.64ba865101 → 0.9.1-develop.7496.1.3346415f94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/business_rules/data/validators.js +8 -3
  3. package/dist/modules/business_rules/data/validators.js.map +2 -2
  4. package/dist/modules/catalog/api/dictionaries/[key]/route.js +35 -7
  5. package/dist/modules/catalog/api/dictionaries/[key]/route.js.map +2 -2
  6. package/dist/modules/communication_channels/lib/email-mime.js +1 -2
  7. package/dist/modules/communication_channels/lib/email-mime.js.map +2 -2
  8. package/dist/modules/configs/cli.js +8 -2
  9. package/dist/modules/configs/cli.js.map +2 -2
  10. package/dist/modules/customers/api/companies/[id]/people/route.js +3 -0
  11. package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
  12. package/dist/modules/customers/api/companies/route.js +3 -3
  13. package/dist/modules/customers/api/companies/route.js.map +2 -2
  14. package/dist/modules/customers/api/deals/[id]/companies/route.js +3 -0
  15. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
  16. package/dist/modules/customers/api/deals/[id]/people/route.js +3 -0
  17. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  18. package/dist/modules/customers/api/dictionaries/kind-settings/route.js +6 -0
  19. package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
  20. package/dist/modules/customers/api/labels/route.js +10 -1
  21. package/dist/modules/customers/api/labels/route.js.map +2 -2
  22. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +6 -0
  23. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  24. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +3 -0
  25. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  26. package/dist/modules/customers/api/people/[id]/companies/route.js +6 -0
  27. package/dist/modules/customers/api/people/[id]/companies/route.js.map +2 -2
  28. package/dist/modules/customers/api/people/route.js +3 -3
  29. package/dist/modules/customers/api/people/route.js.map +2 -2
  30. package/dist/modules/customers/commands/deals.js +2 -0
  31. package/dist/modules/customers/commands/deals.js.map +2 -2
  32. package/dist/modules/customers/components/detail/InlineEditors.js +7 -3
  33. package/dist/modules/customers/components/detail/InlineEditors.js.map +2 -2
  34. package/dist/modules/customers/components/detail/PersonHighlights.js +1 -1
  35. package/dist/modules/customers/components/detail/PersonHighlights.js.map +2 -2
  36. package/dist/modules/customers/components/detail/PlannedActivitiesSection.js +4 -5
  37. package/dist/modules/customers/components/detail/PlannedActivitiesSection.js.map +2 -2
  38. package/dist/modules/data_sync/di.js.map +2 -2
  39. package/dist/modules/data_sync/lib/sync-schedule-service.js +60 -27
  40. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  41. package/dist/modules/messages/commands/messages.js +10 -7
  42. package/dist/modules/messages/commands/messages.js.map +2 -2
  43. package/dist/modules/messages/lib/constants.js +3 -1
  44. package/dist/modules/messages/lib/constants.js.map +2 -2
  45. package/dist/modules/messages/subscribers/message-notification.js +2 -1
  46. package/dist/modules/messages/subscribers/message-notification.js.map +2 -2
  47. package/dist/modules/sales/api/documents/factory.js +3 -4
  48. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  49. package/dist/modules/sales/commands/payments.js +9 -1
  50. package/dist/modules/sales/commands/payments.js.map +2 -2
  51. package/package.json +7 -7
  52. package/src/modules/business_rules/data/validators.ts +12 -3
  53. package/src/modules/catalog/api/dictionaries/[key]/route.ts +49 -7
  54. package/src/modules/communication_channels/lib/email-mime.ts +1 -2
  55. package/src/modules/configs/cli.ts +10 -1
  56. package/src/modules/customers/api/companies/[id]/people/route.ts +3 -0
  57. package/src/modules/customers/api/companies/route.ts +6 -6
  58. package/src/modules/customers/api/deals/[id]/companies/route.ts +3 -0
  59. package/src/modules/customers/api/deals/[id]/people/route.ts +3 -0
  60. package/src/modules/customers/api/dictionaries/kind-settings/route.ts +6 -0
  61. package/src/modules/customers/api/labels/route.ts +10 -1
  62. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +6 -0
  63. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +3 -0
  64. package/src/modules/customers/api/people/[id]/companies/route.ts +6 -0
  65. package/src/modules/customers/api/people/route.ts +6 -6
  66. package/src/modules/customers/commands/deals.ts +2 -0
  67. package/src/modules/customers/components/detail/InlineEditors.tsx +8 -4
  68. package/src/modules/customers/components/detail/PersonHighlights.tsx +4 -1
  69. package/src/modules/customers/components/detail/PlannedActivitiesSection.tsx +4 -5
  70. package/src/modules/customers/i18n/de.json +2 -0
  71. package/src/modules/customers/i18n/en.json +2 -0
  72. package/src/modules/customers/i18n/es.json +2 -0
  73. package/src/modules/customers/i18n/ko.json +2 -0
  74. package/src/modules/customers/i18n/pl.json +2 -0
  75. package/src/modules/data_sync/di.ts +1 -0
  76. package/src/modules/data_sync/lib/sync-schedule-service.ts +80 -28
  77. package/src/modules/messages/commands/messages.ts +10 -7
  78. package/src/modules/messages/lib/constants.ts +6 -0
  79. package/src/modules/messages/subscribers/message-notification.ts +2 -0
  80. package/src/modules/sales/api/documents/factory.ts +6 -7
  81. package/src/modules/sales/commands/payments.ts +10 -2
@@ -15,7 +15,8 @@ import { lookupPhoneDuplicate } from "../../utils/phoneDuplicates.js";
15
15
  import {
16
16
  InlineMultilineEditor as UiInlineMultilineEditor,
17
17
  InlineTextEditor as UiInlineTextEditor,
18
- InlineSelectEditor as UiInlineSelectEditor
18
+ InlineSelectEditor as UiInlineSelectEditor,
19
+ INLINE_TRIGGER_HIDDEN_CLASSES
19
20
  } from "@open-mercato/ui/backend/detail/InlineEditors";
20
21
  import {
21
22
  DictionaryValue,
@@ -312,6 +313,7 @@ function InlineNextInteractionEditor({
312
313
  const dateErrorId = React.useId();
313
314
  const nameErrorId = React.useId();
314
315
  const containerClasses = cn("group relative rounded-lg border p-4", activateOnClick && !editing ? "cursor-pointer" : null);
316
+ const triggerLabel = editing ? t("ui.detail.inline.cancel", "Cancel") : t("ui.detail.inline.edit", "Edit");
315
317
  const requiredMessage = React.useMemo(
316
318
  () => t("customers.people.detail.inline.required", "This field is required"),
317
319
  [t]
@@ -463,13 +465,15 @@ function InlineNextInteractionEditor({
463
465
  size: "sm",
464
466
  className: cn(
465
467
  "absolute right-3 top-3 transition-opacity duration-150",
466
- editing ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100"
468
+ editing ? "opacity-100" : INLINE_TRIGGER_HIDDEN_CLASSES
467
469
  ),
468
470
  onClick: (event) => {
469
471
  event.stopPropagation();
470
472
  setEditing((state) => !state);
471
473
  },
472
- children: editing ? /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
474
+ "aria-label": triggerLabel,
475
+ title: triggerLabel,
476
+ children: editing ? /* @__PURE__ */ jsx(X, { className: "h-4 w-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4", "aria-hidden": true })
473
477
  }
474
478
  ),
475
479
  /* @__PURE__ */ jsx("div", { className: "flex items-start gap-2", ...interactiveProps, children: /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/InlineEditors.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { AtSign, Briefcase, Loader2, Pencil, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { MarkdownContent } from '@open-mercato/ui/backend/markdown'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useEmailDuplicateCheck } from '../../backend/hooks/useEmailDuplicateCheck'\nimport { lookupPhoneDuplicate } from '../../utils/phoneDuplicates'\nimport {\n InlineMultilineEditor as UiInlineMultilineEditor,\n InlineTextEditor as UiInlineTextEditor,\n type InlineFieldType as UiInlineFieldType,\n type InlineMultilineEditorProps,\n type InlineTextEditorProps,\n InlineSelectEditor as UiInlineSelectEditor,\n type InlineSelectOption,\n} from '@open-mercato/ui/backend/detail/InlineEditors'\nimport {\n DictionaryValue,\n ICON_SUGGESTIONS,\n renderDictionaryColor,\n renderDictionaryIcon,\n type CustomerDictionaryKind,\n} from '../../lib/dictionaries'\nimport { DictionarySelectField } from '../formConfig'\nimport { AppearanceSelector } from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport { createDictionarySelectLabels } from './utils'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport {\n invalidateCustomerDictionary,\n useCustomerDictionary,\n} from './hooks/useCustomerDictionary'\n\nexport type InlineFieldType = UiInlineFieldType\nexport type InlineFieldProps = InlineTextEditorProps\nexport type InlineMultilineDisplayRenderer = NonNullable<InlineMultilineEditorProps['renderDisplay']>\n\nexport function InlineTextEditor(props: InlineFieldProps) {\n const { type = 'text', validator, recordId } = props\n const t = useT()\n const normalizeText = React.useCallback((value: unknown) => {\n if (typeof value === 'string') return value\n if (value === null || value === undefined) return ''\n return String(value)\n }, [])\n const [draft, setDraft] = React.useState<string>(() => normalizeText(props.value))\n const setDraftValue = React.useCallback((value: unknown) => {\n setDraft(normalizeText(value))\n }, [normalizeText])\n const [editing, setEditing] = React.useState(false)\n const currentRecordId = React.useMemo(() => (typeof recordId === 'string' ? recordId : null), [recordId])\n const isEmailField = type === 'email'\n const isPhoneField = type === 'tel'\n const trimmedDraft = React.useMemo(() => draft.trim(), [draft])\n const validationError = React.useMemo(() => {\n if (!validator) return null\n return validator(trimmedDraft)\n }, [trimmedDraft, validator])\n const isValidEmailForLookup = React.useMemo(() => {\n if (!isEmailField) return false\n if (!trimmedDraft.length) return false\n return !validationError\n }, [isEmailField, trimmedDraft, validationError])\n const { duplicate: emailDuplicate, checking: emailChecking } = useEmailDuplicateCheck(draft, {\n recordId: currentRecordId,\n disabled: !editing || !isValidEmailForLookup,\n matchMode: 'prefix',\n })\n const [phoneDuplicate, setPhoneDuplicate] = React.useState<{ id: string; label: string; href?: string } | null>(null)\n const [phoneChecking, setPhoneChecking] = React.useState(false)\n\n React.useEffect(() => {\n if (!editing) {\n setDraftValue(props.value)\n }\n }, [editing, props.value, setDraftValue])\n\n React.useEffect(() => {\n if (!editing || !isPhoneField) {\n setPhoneDuplicate(null)\n setPhoneChecking(false)\n return\n }\n const digits = draft.replace(/\\\\D/g, '')\n if (digits.length < 7) {\n setPhoneDuplicate(null)\n setPhoneChecking(false)\n return\n }\n let cancelled = false\n setPhoneChecking(true)\n void lookupPhoneDuplicate(digits, { recordId: currentRecordId })\n .then((result) => {\n if (cancelled) return\n setPhoneDuplicate(result)\n })\n .catch(() => {\n if (cancelled) return\n setPhoneDuplicate(null)\n })\n .finally(() => {\n if (cancelled) return\n setPhoneChecking(false)\n })\n return () => {\n cancelled = true\n }\n }, [currentRecordId, draft, editing, isPhoneField])\n\n return (\n <UiInlineTextEditor\n {...props}\n type={type}\n validator={validator}\n value={normalizeText(props.value)}\n onDraftChange={setDraftValue}\n onEditingChange={setEditing}\n renderBelowInput={({ resolvedType, error }) => {\n if (resolvedType === 'email') {\n if (error || !editing || !isValidEmailForLookup) return null\n if (emailDuplicate) {\n return (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.people.detail.inline.emailDuplicate', undefined, { name: emailDuplicate.displayName })}{' '}\n <Link\n className=\"font-medium text-primary underline underline-offset-2\"\n href={`/backend/customers/people-v2/${emailDuplicate.id}`}\n >\n {t('customers.people.detail.inline.emailDuplicateLink')}\n </Link>\n </p>\n )\n }\n if (emailChecking) {\n return <p className=\"text-xs text-muted-foreground\">{t('customers.people.detail.inline.emailChecking')}</p>\n }\n }\n if (resolvedType === 'tel') {\n if (error || !editing) return null\n if (phoneDuplicate) {\n return (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.people.form.phoneDuplicateNotice', undefined, { name: phoneDuplicate.label })}{' '}\n {phoneDuplicate.href ? (\n <Link\n className=\"font-medium text-primary underline underline-offset-2\"\n href={phoneDuplicate.href}\n >\n {t('customers.people.form.phoneDuplicateLink')}\n </Link>\n ) : null}\n </p>\n )\n }\n if (phoneChecking) {\n return <p className=\"text-xs text-muted-foreground\">{t('customers.people.form.phoneChecking')}</p>\n }\n }\n return null\n }}\n />\n )\n}\nexport const InlineMultilineEditor = UiInlineMultilineEditor\nexport const InlineSelectEditor = UiInlineSelectEditor\n\nfunction createSocialRenderDisplay(IconComponent: typeof Briefcase): NonNullable<InlineFieldProps['renderDisplay']> {\n // eslint-disable-next-line react/display-name\n return ({ value, emptyLabel }) => {\n const raw = typeof value === 'string' ? value.trim() : ''\n if (!raw.length) {\n return <span className=\"text-sm text-muted-foreground\">{emptyLabel}</span>\n }\n const display = raw.replace(/^https?:\\/\\/(www\\.)?/i, '').replace(/\\/$/, '')\n return (\n <a\n className=\"inline-flex items-center gap-2 text-sm text-primary hover:text-primary/90 hover:underline\"\n href={raw}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconComponent aria-hidden className=\"h-4 w-4\" />\n <span className=\"truncate\">{display}</span>\n </a>\n )\n }\n}\n\nexport const renderLinkedInDisplay = createSocialRenderDisplay(Briefcase)\nexport const renderTwitterDisplay = createSocialRenderDisplay(AtSign)\n\nexport const renderMultilineMarkdownDisplay: InlineMultilineDisplayRenderer = ({ value, emptyLabel }) => {\n const raw = typeof value === 'string' ? value : ''\n const trimmed = raw.trim()\n if (!trimmed.length) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n return (\n <MarkdownContent\n format=\"markdown\"\n body={raw}\n className=\"text-sm text-foreground [&>*]:mb-2 [&>*:last-child]:mb-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs\"\n />\n )\n}\n\ntype DictionaryEditorProps = {\n label: string\n value: string | null | undefined\n emptyLabel: string\n onSave: (value: string | null) => Promise<void>\n kind: CustomerDictionaryKind\n variant?: 'default' | 'muted'\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n selectClassName?: string\n}\n\nexport function InlineDictionaryEditor({\n label,\n value,\n emptyLabel,\n onSave,\n kind,\n variant = 'default',\n activateOnClick = false,\n containerClassName,\n triggerClassName,\n selectClassName,\n}: DictionaryEditorProps) {\n const t = useT()\n const queryClient = useQueryClient()\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 const dictionaryLabels = React.useMemo(() => createDictionarySelectLabels(kind, translate), [kind, translate])\n const scopeVersion = useOrganizationScopeVersion()\n const dictionaryQuery = useCustomerDictionary(kind, scopeVersion)\n const dictionaryMap = dictionaryQuery.data?.map ?? null\n const selectOptions = React.useMemo<InlineSelectOption[]>(() => {\n if (!dictionaryMap) return []\n return Object.values(dictionaryMap).map((entry) => ({ value: entry.value, label: entry.label }))\n }, [dictionaryMap])\n\n const handleSave = React.useCallback(\n async (nextValue: string | null) => {\n try {\n await onSave(nextValue)\n await invalidateCustomerDictionary(queryClient, kind)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.inline.error')\n flash(message, 'error')\n }\n },\n [kind, onSave, queryClient, t],\n )\n\n return (\n <UiInlineSelectEditor\n label={label}\n value={value}\n emptyLabel={emptyLabel}\n options={selectOptions}\n onSave={handleSave}\n variant={variant}\n activateOnClick={activateOnClick}\n containerClassName={containerClassName}\n triggerClassName={triggerClassName}\n hideLabel={false}\n renderEditor={({ value: selectValue, onChange }) => (\n <>\n <DictionarySelectField\n kind={kind}\n value={selectValue.length ? selectValue : undefined}\n onChange={(next) => onChange(next ?? '')}\n labels={dictionaryLabels}\n selectClassName={selectClassName}\n />\n {dictionaryQuery.isError ? (\n <p className=\"text-xs text-status-error-text\">\n {dictionaryQuery.error instanceof Error\n ? dictionaryQuery.error.message\n : translate('customers.people.form.dictionary.errorLoad', 'Failed to load options')}\n </p>\n ) : null}\n </>\n )}\n renderDisplay={({ value: currentValue }) => {\n if (dictionaryMap) {\n return (\n <DictionaryValue\n value={currentValue}\n map={dictionaryMap}\n fallback={<span className=\"text-sm text-muted-foreground\">{emptyLabel}</span>}\n className=\"text-sm\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-card\"\n iconClassName=\"h-4 w-4\"\n colorClassName=\"h-3 w-3 rounded-full\"\n />\n )\n }\n if (currentValue && currentValue.length) {\n return <span className=\"break-words text-sm\">{currentValue}</span>\n }\n if (dictionaryQuery.isLoading) {\n return (\n <span className=\"text-sm text-muted-foreground\">\n {translate('customers.people.form.dictionary.loading', 'Loading\u2026')}\n </span>\n )\n }\n return <span className=\"text-sm text-muted-foreground\">{emptyLabel}</span>\n }}\n />\n )\n}\n\nexport type NextInteractionPayload = {\n at: string\n name: string\n refId?: string | null\n icon?: string | null\n color?: string | null\n}\n\ntype NextInteractionEditorProps = {\n label: string\n valueAt: string | null | undefined\n valueName: string | null | undefined\n valueRefId: string | null | undefined\n valueIcon: string | null | undefined\n valueColor: string | null | undefined\n emptyLabel: string\n onSave: (next: NextInteractionPayload | null) => Promise<void>\n activateOnClick?: boolean\n}\n\nexport function InlineNextInteractionEditor({\n label,\n valueAt,\n valueName,\n valueRefId,\n valueIcon,\n valueColor,\n emptyLabel,\n onSave,\n activateOnClick = false,\n}: NextInteractionEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draftDate, setDraftDate] = React.useState<string>(() => (valueAt ? valueAt.slice(0, 16) : ''))\n const [draftName, setDraftName] = React.useState(valueName ?? '')\n const [draftRefId, setDraftRefId] = React.useState(valueRefId ?? '')\n const [draftIcon, setDraftIcon] = React.useState(valueIcon ?? '')\n const [draftColor, setDraftColor] = React.useState<string | null>(valueColor ?? null)\n const [dateError, setDateError] = React.useState<string | null>(null)\n const [nameError, setNameError] = React.useState<string | null>(null)\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const formRef = React.useRef<HTMLFormElement | null>(null)\n const dateErrorId = React.useId()\n const nameErrorId = React.useId()\n const containerClasses = cn('group relative rounded-lg border p-4', activateOnClick && !editing ? 'cursor-pointer' : null)\n const requiredMessage = React.useMemo(\n () => t('customers.people.detail.inline.required', 'This field is required'),\n [t],\n )\n\n React.useEffect(() => {\n if (!editing) {\n setDraftDate(valueAt ? valueAt.slice(0, 16) : '')\n setDraftName(valueName ?? '')\n setDraftRefId(valueRefId ?? '')\n setDraftIcon(valueIcon ?? '')\n setDraftColor(valueColor ?? null)\n setDateError(null)\n setNameError(null)\n setSubmitError(null)\n }\n }, [editing, valueAt, valueName, valueRefId, valueIcon, valueColor])\n\n const appearanceLabels = React.useMemo(\n () => ({\n colorLabel: t('customers.people.detail.inline.nextInteractionColorLabel'),\n colorHelp: t('customers.people.detail.inline.nextInteractionColorHelp'),\n colorClearLabel: t('customers.people.detail.inline.nextInteractionColorClear'),\n iconLabel: t('customers.people.detail.inline.nextInteractionIconLabel'),\n iconPlaceholder: t('customers.people.detail.inline.nextInteractionIconPlaceholder'),\n iconPickerTriggerLabel: t('customers.people.detail.inline.nextInteractionIconBrowse'),\n iconSearchPlaceholder: t('customers.people.detail.inline.nextInteractionIconSearchPlaceholder'),\n iconSearchEmptyLabel: t('customers.people.detail.inline.nextInteractionIconSearchEmpty'),\n iconSuggestionsLabel: t('customers.people.detail.inline.nextInteractionIconSuggestions'),\n iconClearLabel: t('customers.people.detail.inline.nextInteractionIconClear'),\n previewEmptyLabel: t('customers.people.detail.inline.nextInteractionAppearanceEmpty'),\n }),\n [t],\n )\n\n const handleSave = React.useCallback(async () => {\n setSubmitError(null)\n setDateError(null)\n setNameError(null)\n const trimmedName = draftName.trim()\n let hasError = false\n if (!draftDate) {\n setDateError(requiredMessage)\n hasError = true\n }\n if (!trimmedName.length) {\n setNameError(requiredMessage)\n hasError = true\n }\n if (hasError) return\n const parsedDate = new Date(draftDate)\n if (Number.isNaN(parsedDate.getTime())) {\n setDateError(t('customers.people.detail.inline.nextInteractionInvalid'))\n return\n }\n const iso = parsedDate.toISOString()\n const trimmedRef = draftRefId.trim()\n const trimmedIcon = draftIcon.trim()\n const normalizedColor = (() => {\n if (!draftColor) return null\n const trimmed = draftColor.trim().toLowerCase()\n return /^#([0-9a-f]{6})$/.test(trimmed) ? trimmed : null\n })()\n setSaving(true)\n try {\n await onSave({\n at: iso,\n name: trimmedName,\n refId: trimmedRef.length ? trimmedRef : null,\n icon: trimmedIcon.length ? trimmedIcon : null,\n color: normalizedColor,\n })\n setEditing(false)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.inline.error')\n setSubmitError(message)\n } finally {\n setSaving(false)\n }\n }, [draftColor, draftDate, draftIcon, draftName, draftRefId, onSave, requiredMessage, t])\n\n const handleFormSubmit = React.useCallback(\n (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n if (saving) return\n void handleSave()\n },\n [handleSave, saving],\n )\n\n const handleFormKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditing(false)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (saving) return\n try {\n formRef.current?.requestSubmit()\n } catch {\n void handleSave()\n }\n }\n },\n [handleSave, saving],\n )\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditing(true)\n }, [editing])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleInteractiveClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n const target = event.target as HTMLElement\n const interactiveElement = target.closest('button, input, select, textarea, a, [role=\\\"link\\\"]')\n if (interactiveElement) {\n if (interactiveElement.tagName.toLowerCase() === 'a') {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n event.preventDefault()\n } else {\n return\n }\n }\n handleActivate()\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const interactiveProps: React.HTMLAttributes<HTMLDivElement> =\n activateOnClick && !editing\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick: handleInteractiveClick,\n onKeyDown: handleKeyDown,\n }\n : {}\n\n return (\n <div className={containerClasses} onClick={handleInteractiveClick}>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={cn(\n 'absolute right-3 top-3 transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n )}\n onClick={(event) => {\n event.stopPropagation()\n setEditing((state) => !state)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n <div className=\"flex items-start gap-2\" {...interactiveProps}>\n <div className=\"flex-1\">\n <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>\n {editing ? (\n <form\n ref={formRef}\n className=\"mt-2 space-y-4\"\n onSubmit={handleFormSubmit}\n onKeyDown={handleFormKeyDown}\n >\n <input\n type=\"datetime-local\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n dateError ? 'border-destructive aria-invalid:border-destructive aria-invalid:ring-destructive' : null,\n )}\n value={draftDate}\n aria-invalid={dateError ? 'true' : undefined}\n aria-required=\"true\"\n aria-describedby={dateError ? dateErrorId : undefined}\n onChange={(event) => {\n if (dateError) setDateError(null)\n if (submitError) setSubmitError(null)\n setDraftDate(event.target.value)\n }}\n />\n {dateError ? (\n <p id={dateErrorId} className=\"text-xs text-destructive\">\n {dateError}\n </p>\n ) : null}\n <input\n placeholder={t('customers.people.detail.inline.nextInteractionName')}\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n nameError ? 'border-destructive aria-invalid:border-destructive aria-invalid:ring-destructive' : null,\n )}\n value={draftName}\n aria-invalid={nameError ? 'true' : undefined}\n aria-required=\"true\"\n aria-describedby={nameError ? nameErrorId : undefined}\n onChange={(event) => {\n if (submitError) setSubmitError(null)\n if (nameError) setNameError(null)\n setDraftName(event.target.value)\n }}\n />\n {nameError ? (\n <p id={nameErrorId} className=\"text-xs text-destructive\">\n {nameError}\n </p>\n ) : null}\n <input\n placeholder={t('customers.people.detail.inline.nextInteractionRef')}\n className=\"w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={draftRefId}\n onChange={(event) => {\n if (submitError) setSubmitError(null)\n setDraftRefId(event.target.value)\n }}\n />\n <AppearanceSelector\n icon={draftIcon || null}\n color={draftColor}\n onIconChange={(next) => {\n if (submitError) setSubmitError(null)\n setDraftIcon(next ?? '')\n }}\n onColorChange={(next) => {\n if (submitError) setSubmitError(null)\n setDraftColor(next)\n }}\n iconSuggestions={ICON_SUGGESTIONS}\n disabled={saving}\n labels={appearanceLabels}\n />\n {submitError && !dateError && !nameError ? (\n <p className=\"text-xs text-destructive\">{submitError}</p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"submit\" size=\"sm\" disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('customers.people.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditing(false)} disabled={saving}>\n {t('customers.people.detail.inline.cancel')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n onClick={async () => {\n setDraftDate('')\n setDraftName('')\n setDraftRefId('')\n setDraftIcon('')\n setDraftColor(null)\n setDateError(null)\n setNameError(null)\n setSubmitError(null)\n setSaving(true)\n try {\n await onSave(null)\n setEditing(false)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.inline.error')\n setSubmitError(message)\n } finally {\n setSaving(false)\n }\n }}\n disabled={saving}\n >\n {t('customers.people.detail.inline.clear')}\n </Button>\n </div>\n </form>\n ) : (\n <div className=\"mt-1 text-sm\">\n {valueAt ? (\n <div className=\"flex items-start gap-3\">\n {valueIcon ? (\n <span className=\"inline-flex h-8 w-8 items-center justify-center rounded border border-border bg-card\">\n {renderDictionaryIcon(valueIcon, 'h-4 w-4')}\n </span>\n ) : null}\n <div className=\"flex-1\">\n <span className=\"block\">{formatDateTime(valueAt)}</span>\n {valueName ? <span className=\"text-xs text-muted-foreground\">{valueName}</span> : null}\n {valueRefId ? <span className=\"text-xs text-muted-foreground\">#{valueRefId}</span> : null}\n </div>\n {valueColor ? renderDictionaryColor(valueColor, 'h-3 w-3 rounded-full border border-border') : null}\n </div>\n ) : (\n <span className=\"text-muted-foreground\">{emptyLabel}</span>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { AtSign, Briefcase, Loader2, Pencil, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { MarkdownContent } from '@open-mercato/ui/backend/markdown'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useEmailDuplicateCheck } from '../../backend/hooks/useEmailDuplicateCheck'\nimport { lookupPhoneDuplicate } from '../../utils/phoneDuplicates'\nimport {\n InlineMultilineEditor as UiInlineMultilineEditor,\n InlineTextEditor as UiInlineTextEditor,\n type InlineFieldType as UiInlineFieldType,\n type InlineMultilineEditorProps,\n type InlineTextEditorProps,\n InlineSelectEditor as UiInlineSelectEditor,\n INLINE_TRIGGER_HIDDEN_CLASSES,\n type InlineSelectOption,\n} from '@open-mercato/ui/backend/detail/InlineEditors'\nimport {\n DictionaryValue,\n ICON_SUGGESTIONS,\n renderDictionaryColor,\n renderDictionaryIcon,\n type CustomerDictionaryKind,\n} from '../../lib/dictionaries'\nimport { DictionarySelectField } from '../formConfig'\nimport { AppearanceSelector } from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport { createDictionarySelectLabels } from './utils'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport {\n invalidateCustomerDictionary,\n useCustomerDictionary,\n} from './hooks/useCustomerDictionary'\n\nexport type InlineFieldType = UiInlineFieldType\nexport type InlineFieldProps = InlineTextEditorProps\nexport type InlineMultilineDisplayRenderer = NonNullable<InlineMultilineEditorProps['renderDisplay']>\n\nexport function InlineTextEditor(props: InlineFieldProps) {\n const { type = 'text', validator, recordId } = props\n const t = useT()\n const normalizeText = React.useCallback((value: unknown) => {\n if (typeof value === 'string') return value\n if (value === null || value === undefined) return ''\n return String(value)\n }, [])\n const [draft, setDraft] = React.useState<string>(() => normalizeText(props.value))\n const setDraftValue = React.useCallback((value: unknown) => {\n setDraft(normalizeText(value))\n }, [normalizeText])\n const [editing, setEditing] = React.useState(false)\n const currentRecordId = React.useMemo(() => (typeof recordId === 'string' ? recordId : null), [recordId])\n const isEmailField = type === 'email'\n const isPhoneField = type === 'tel'\n const trimmedDraft = React.useMemo(() => draft.trim(), [draft])\n const validationError = React.useMemo(() => {\n if (!validator) return null\n return validator(trimmedDraft)\n }, [trimmedDraft, validator])\n const isValidEmailForLookup = React.useMemo(() => {\n if (!isEmailField) return false\n if (!trimmedDraft.length) return false\n return !validationError\n }, [isEmailField, trimmedDraft, validationError])\n const { duplicate: emailDuplicate, checking: emailChecking } = useEmailDuplicateCheck(draft, {\n recordId: currentRecordId,\n disabled: !editing || !isValidEmailForLookup,\n matchMode: 'prefix',\n })\n const [phoneDuplicate, setPhoneDuplicate] = React.useState<{ id: string; label: string; href?: string } | null>(null)\n const [phoneChecking, setPhoneChecking] = React.useState(false)\n\n React.useEffect(() => {\n if (!editing) {\n setDraftValue(props.value)\n }\n }, [editing, props.value, setDraftValue])\n\n React.useEffect(() => {\n if (!editing || !isPhoneField) {\n setPhoneDuplicate(null)\n setPhoneChecking(false)\n return\n }\n const digits = draft.replace(/\\\\D/g, '')\n if (digits.length < 7) {\n setPhoneDuplicate(null)\n setPhoneChecking(false)\n return\n }\n let cancelled = false\n setPhoneChecking(true)\n void lookupPhoneDuplicate(digits, { recordId: currentRecordId })\n .then((result) => {\n if (cancelled) return\n setPhoneDuplicate(result)\n })\n .catch(() => {\n if (cancelled) return\n setPhoneDuplicate(null)\n })\n .finally(() => {\n if (cancelled) return\n setPhoneChecking(false)\n })\n return () => {\n cancelled = true\n }\n }, [currentRecordId, draft, editing, isPhoneField])\n\n return (\n <UiInlineTextEditor\n {...props}\n type={type}\n validator={validator}\n value={normalizeText(props.value)}\n onDraftChange={setDraftValue}\n onEditingChange={setEditing}\n renderBelowInput={({ resolvedType, error }) => {\n if (resolvedType === 'email') {\n if (error || !editing || !isValidEmailForLookup) return null\n if (emailDuplicate) {\n return (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.people.detail.inline.emailDuplicate', undefined, { name: emailDuplicate.displayName })}{' '}\n <Link\n className=\"font-medium text-primary underline underline-offset-2\"\n href={`/backend/customers/people-v2/${emailDuplicate.id}`}\n >\n {t('customers.people.detail.inline.emailDuplicateLink')}\n </Link>\n </p>\n )\n }\n if (emailChecking) {\n return <p className=\"text-xs text-muted-foreground\">{t('customers.people.detail.inline.emailChecking')}</p>\n }\n }\n if (resolvedType === 'tel') {\n if (error || !editing) return null\n if (phoneDuplicate) {\n return (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.people.form.phoneDuplicateNotice', undefined, { name: phoneDuplicate.label })}{' '}\n {phoneDuplicate.href ? (\n <Link\n className=\"font-medium text-primary underline underline-offset-2\"\n href={phoneDuplicate.href}\n >\n {t('customers.people.form.phoneDuplicateLink')}\n </Link>\n ) : null}\n </p>\n )\n }\n if (phoneChecking) {\n return <p className=\"text-xs text-muted-foreground\">{t('customers.people.form.phoneChecking')}</p>\n }\n }\n return null\n }}\n />\n )\n}\nexport const InlineMultilineEditor = UiInlineMultilineEditor\nexport const InlineSelectEditor = UiInlineSelectEditor\n\nfunction createSocialRenderDisplay(IconComponent: typeof Briefcase): NonNullable<InlineFieldProps['renderDisplay']> {\n // eslint-disable-next-line react/display-name\n return ({ value, emptyLabel }) => {\n const raw = typeof value === 'string' ? value.trim() : ''\n if (!raw.length) {\n return <span className=\"text-sm text-muted-foreground\">{emptyLabel}</span>\n }\n const display = raw.replace(/^https?:\\/\\/(www\\.)?/i, '').replace(/\\/$/, '')\n return (\n <a\n className=\"inline-flex items-center gap-2 text-sm text-primary hover:text-primary/90 hover:underline\"\n href={raw}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconComponent aria-hidden className=\"h-4 w-4\" />\n <span className=\"truncate\">{display}</span>\n </a>\n )\n }\n}\n\nexport const renderLinkedInDisplay = createSocialRenderDisplay(Briefcase)\nexport const renderTwitterDisplay = createSocialRenderDisplay(AtSign)\n\nexport const renderMultilineMarkdownDisplay: InlineMultilineDisplayRenderer = ({ value, emptyLabel }) => {\n const raw = typeof value === 'string' ? value : ''\n const trimmed = raw.trim()\n if (!trimmed.length) {\n return <span className=\"text-muted-foreground\">{emptyLabel}</span>\n }\n return (\n <MarkdownContent\n format=\"markdown\"\n body={raw}\n className=\"text-sm text-foreground [&>*]:mb-2 [&>*:last-child]:mb-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs\"\n />\n )\n}\n\ntype DictionaryEditorProps = {\n label: string\n value: string | null | undefined\n emptyLabel: string\n onSave: (value: string | null) => Promise<void>\n kind: CustomerDictionaryKind\n variant?: 'default' | 'muted'\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n selectClassName?: string\n}\n\nexport function InlineDictionaryEditor({\n label,\n value,\n emptyLabel,\n onSave,\n kind,\n variant = 'default',\n activateOnClick = false,\n containerClassName,\n triggerClassName,\n selectClassName,\n}: DictionaryEditorProps) {\n const t = useT()\n const queryClient = useQueryClient()\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 const dictionaryLabels = React.useMemo(() => createDictionarySelectLabels(kind, translate), [kind, translate])\n const scopeVersion = useOrganizationScopeVersion()\n const dictionaryQuery = useCustomerDictionary(kind, scopeVersion)\n const dictionaryMap = dictionaryQuery.data?.map ?? null\n const selectOptions = React.useMemo<InlineSelectOption[]>(() => {\n if (!dictionaryMap) return []\n return Object.values(dictionaryMap).map((entry) => ({ value: entry.value, label: entry.label }))\n }, [dictionaryMap])\n\n const handleSave = React.useCallback(\n async (nextValue: string | null) => {\n try {\n await onSave(nextValue)\n await invalidateCustomerDictionary(queryClient, kind)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.inline.error')\n flash(message, 'error')\n }\n },\n [kind, onSave, queryClient, t],\n )\n\n return (\n <UiInlineSelectEditor\n label={label}\n value={value}\n emptyLabel={emptyLabel}\n options={selectOptions}\n onSave={handleSave}\n variant={variant}\n activateOnClick={activateOnClick}\n containerClassName={containerClassName}\n triggerClassName={triggerClassName}\n hideLabel={false}\n renderEditor={({ value: selectValue, onChange }) => (\n <>\n <DictionarySelectField\n kind={kind}\n value={selectValue.length ? selectValue : undefined}\n onChange={(next) => onChange(next ?? '')}\n labels={dictionaryLabels}\n selectClassName={selectClassName}\n />\n {dictionaryQuery.isError ? (\n <p className=\"text-xs text-status-error-text\">\n {dictionaryQuery.error instanceof Error\n ? dictionaryQuery.error.message\n : translate('customers.people.form.dictionary.errorLoad', 'Failed to load options')}\n </p>\n ) : null}\n </>\n )}\n renderDisplay={({ value: currentValue }) => {\n if (dictionaryMap) {\n return (\n <DictionaryValue\n value={currentValue}\n map={dictionaryMap}\n fallback={<span className=\"text-sm text-muted-foreground\">{emptyLabel}</span>}\n className=\"text-sm\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-card\"\n iconClassName=\"h-4 w-4\"\n colorClassName=\"h-3 w-3 rounded-full\"\n />\n )\n }\n if (currentValue && currentValue.length) {\n return <span className=\"break-words text-sm\">{currentValue}</span>\n }\n if (dictionaryQuery.isLoading) {\n return (\n <span className=\"text-sm text-muted-foreground\">\n {translate('customers.people.form.dictionary.loading', 'Loading\u2026')}\n </span>\n )\n }\n return <span className=\"text-sm text-muted-foreground\">{emptyLabel}</span>\n }}\n />\n )\n}\n\nexport type NextInteractionPayload = {\n at: string\n name: string\n refId?: string | null\n icon?: string | null\n color?: string | null\n}\n\ntype NextInteractionEditorProps = {\n label: string\n valueAt: string | null | undefined\n valueName: string | null | undefined\n valueRefId: string | null | undefined\n valueIcon: string | null | undefined\n valueColor: string | null | undefined\n emptyLabel: string\n onSave: (next: NextInteractionPayload | null) => Promise<void>\n activateOnClick?: boolean\n}\n\nexport function InlineNextInteractionEditor({\n label,\n valueAt,\n valueName,\n valueRefId,\n valueIcon,\n valueColor,\n emptyLabel,\n onSave,\n activateOnClick = false,\n}: NextInteractionEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draftDate, setDraftDate] = React.useState<string>(() => (valueAt ? valueAt.slice(0, 16) : ''))\n const [draftName, setDraftName] = React.useState(valueName ?? '')\n const [draftRefId, setDraftRefId] = React.useState(valueRefId ?? '')\n const [draftIcon, setDraftIcon] = React.useState(valueIcon ?? '')\n const [draftColor, setDraftColor] = React.useState<string | null>(valueColor ?? null)\n const [dateError, setDateError] = React.useState<string | null>(null)\n const [nameError, setNameError] = React.useState<string | null>(null)\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const formRef = React.useRef<HTMLFormElement | null>(null)\n const dateErrorId = React.useId()\n const nameErrorId = React.useId()\n const containerClasses = cn('group relative rounded-lg border p-4', activateOnClick && !editing ? 'cursor-pointer' : null)\n const triggerLabel = editing\n ? t('ui.detail.inline.cancel', 'Cancel')\n : t('ui.detail.inline.edit', 'Edit')\n const requiredMessage = React.useMemo(\n () => t('customers.people.detail.inline.required', 'This field is required'),\n [t],\n )\n\n React.useEffect(() => {\n if (!editing) {\n setDraftDate(valueAt ? valueAt.slice(0, 16) : '')\n setDraftName(valueName ?? '')\n setDraftRefId(valueRefId ?? '')\n setDraftIcon(valueIcon ?? '')\n setDraftColor(valueColor ?? null)\n setDateError(null)\n setNameError(null)\n setSubmitError(null)\n }\n }, [editing, valueAt, valueName, valueRefId, valueIcon, valueColor])\n\n const appearanceLabels = React.useMemo(\n () => ({\n colorLabel: t('customers.people.detail.inline.nextInteractionColorLabel'),\n colorHelp: t('customers.people.detail.inline.nextInteractionColorHelp'),\n colorClearLabel: t('customers.people.detail.inline.nextInteractionColorClear'),\n iconLabel: t('customers.people.detail.inline.nextInteractionIconLabel'),\n iconPlaceholder: t('customers.people.detail.inline.nextInteractionIconPlaceholder'),\n iconPickerTriggerLabel: t('customers.people.detail.inline.nextInteractionIconBrowse'),\n iconSearchPlaceholder: t('customers.people.detail.inline.nextInteractionIconSearchPlaceholder'),\n iconSearchEmptyLabel: t('customers.people.detail.inline.nextInteractionIconSearchEmpty'),\n iconSuggestionsLabel: t('customers.people.detail.inline.nextInteractionIconSuggestions'),\n iconClearLabel: t('customers.people.detail.inline.nextInteractionIconClear'),\n previewEmptyLabel: t('customers.people.detail.inline.nextInteractionAppearanceEmpty'),\n }),\n [t],\n )\n\n const handleSave = React.useCallback(async () => {\n setSubmitError(null)\n setDateError(null)\n setNameError(null)\n const trimmedName = draftName.trim()\n let hasError = false\n if (!draftDate) {\n setDateError(requiredMessage)\n hasError = true\n }\n if (!trimmedName.length) {\n setNameError(requiredMessage)\n hasError = true\n }\n if (hasError) return\n const parsedDate = new Date(draftDate)\n if (Number.isNaN(parsedDate.getTime())) {\n setDateError(t('customers.people.detail.inline.nextInteractionInvalid'))\n return\n }\n const iso = parsedDate.toISOString()\n const trimmedRef = draftRefId.trim()\n const trimmedIcon = draftIcon.trim()\n const normalizedColor = (() => {\n if (!draftColor) return null\n const trimmed = draftColor.trim().toLowerCase()\n return /^#([0-9a-f]{6})$/.test(trimmed) ? trimmed : null\n })()\n setSaving(true)\n try {\n await onSave({\n at: iso,\n name: trimmedName,\n refId: trimmedRef.length ? trimmedRef : null,\n icon: trimmedIcon.length ? trimmedIcon : null,\n color: normalizedColor,\n })\n setEditing(false)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.inline.error')\n setSubmitError(message)\n } finally {\n setSaving(false)\n }\n }, [draftColor, draftDate, draftIcon, draftName, draftRefId, onSave, requiredMessage, t])\n\n const handleFormSubmit = React.useCallback(\n (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n if (saving) return\n void handleSave()\n },\n [handleSave, saving],\n )\n\n const handleFormKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditing(false)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (saving) return\n try {\n formRef.current?.requestSubmit()\n } catch {\n void handleSave()\n }\n }\n },\n [handleSave, saving],\n )\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditing(true)\n }, [editing])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleInteractiveClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n const target = event.target as HTMLElement\n const interactiveElement = target.closest('button, input, select, textarea, a, [role=\\\"link\\\"]')\n if (interactiveElement) {\n if (interactiveElement.tagName.toLowerCase() === 'a') {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n event.preventDefault()\n } else {\n return\n }\n }\n handleActivate()\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const interactiveProps: React.HTMLAttributes<HTMLDivElement> =\n activateOnClick && !editing\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick: handleInteractiveClick,\n onKeyDown: handleKeyDown,\n }\n : {}\n\n return (\n <div className={containerClasses} onClick={handleInteractiveClick}>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={cn(\n 'absolute right-3 top-3 transition-opacity duration-150',\n editing ? 'opacity-100' : INLINE_TRIGGER_HIDDEN_CLASSES,\n )}\n onClick={(event) => {\n event.stopPropagation()\n setEditing((state) => !state)\n }}\n aria-label={triggerLabel}\n title={triggerLabel}\n >\n {editing ? <X className=\"h-4 w-4\" aria-hidden /> : <Pencil className=\"h-4 w-4\" aria-hidden />}\n </Button>\n <div className=\"flex items-start gap-2\" {...interactiveProps}>\n <div className=\"flex-1\">\n <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>\n {editing ? (\n <form\n ref={formRef}\n className=\"mt-2 space-y-4\"\n onSubmit={handleFormSubmit}\n onKeyDown={handleFormKeyDown}\n >\n <input\n type=\"datetime-local\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n dateError ? 'border-destructive aria-invalid:border-destructive aria-invalid:ring-destructive' : null,\n )}\n value={draftDate}\n aria-invalid={dateError ? 'true' : undefined}\n aria-required=\"true\"\n aria-describedby={dateError ? dateErrorId : undefined}\n onChange={(event) => {\n if (dateError) setDateError(null)\n if (submitError) setSubmitError(null)\n setDraftDate(event.target.value)\n }}\n />\n {dateError ? (\n <p id={dateErrorId} className=\"text-xs text-destructive\">\n {dateError}\n </p>\n ) : null}\n <input\n placeholder={t('customers.people.detail.inline.nextInteractionName')}\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n nameError ? 'border-destructive aria-invalid:border-destructive aria-invalid:ring-destructive' : null,\n )}\n value={draftName}\n aria-invalid={nameError ? 'true' : undefined}\n aria-required=\"true\"\n aria-describedby={nameError ? nameErrorId : undefined}\n onChange={(event) => {\n if (submitError) setSubmitError(null)\n if (nameError) setNameError(null)\n setDraftName(event.target.value)\n }}\n />\n {nameError ? (\n <p id={nameErrorId} className=\"text-xs text-destructive\">\n {nameError}\n </p>\n ) : null}\n <input\n placeholder={t('customers.people.detail.inline.nextInteractionRef')}\n className=\"w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={draftRefId}\n onChange={(event) => {\n if (submitError) setSubmitError(null)\n setDraftRefId(event.target.value)\n }}\n />\n <AppearanceSelector\n icon={draftIcon || null}\n color={draftColor}\n onIconChange={(next) => {\n if (submitError) setSubmitError(null)\n setDraftIcon(next ?? '')\n }}\n onColorChange={(next) => {\n if (submitError) setSubmitError(null)\n setDraftColor(next)\n }}\n iconSuggestions={ICON_SUGGESTIONS}\n disabled={saving}\n labels={appearanceLabels}\n />\n {submitError && !dateError && !nameError ? (\n <p className=\"text-xs text-destructive\">{submitError}</p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"submit\" size=\"sm\" disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('customers.people.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditing(false)} disabled={saving}>\n {t('customers.people.detail.inline.cancel')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n onClick={async () => {\n setDraftDate('')\n setDraftName('')\n setDraftRefId('')\n setDraftIcon('')\n setDraftColor(null)\n setDateError(null)\n setNameError(null)\n setSubmitError(null)\n setSaving(true)\n try {\n await onSave(null)\n setEditing(false)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.inline.error')\n setSubmitError(message)\n } finally {\n setSaving(false)\n }\n }}\n disabled={saving}\n >\n {t('customers.people.detail.inline.clear')}\n </Button>\n </div>\n </form>\n ) : (\n <div className=\"mt-1 text-sm\">\n {valueAt ? (\n <div className=\"flex items-start gap-3\">\n {valueIcon ? (\n <span className=\"inline-flex h-8 w-8 items-center justify-center rounded border border-border bg-card\">\n {renderDictionaryIcon(valueIcon, 'h-4 w-4')}\n </span>\n ) : null}\n <div className=\"flex-1\">\n <span className=\"block\">{formatDateTime(valueAt)}</span>\n {valueName ? <span className=\"text-xs text-muted-foreground\">{valueName}</span> : null}\n {valueRefId ? <span className=\"text-xs text-muted-foreground\">#{valueRefId}</span> : null}\n </div>\n {valueColor ? renderDictionaryColor(valueColor, 'h-3 w-3 rounded-full border border-border') : null}\n </div>\n ) : (\n <span className=\"text-muted-foreground\">{emptyLabel}</span>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -244,7 +244,7 @@ function PersonHighlights({
244
244
  setCompanyError(null);
245
245
  setCompanyDraftId(activeCompanyId ?? "");
246
246
  },
247
- className: editingCompany ? "opacity-100" : "opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:opacity-100 focus-visible:opacity-100",
247
+ className: editingCompany ? "opacity-100" : "opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-100",
248
248
  children: [
249
249
  editingCompany ? /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" }),
250
250
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: editingCompany ? t("ui.forms.actions.cancel") : t("ui.forms.actions.edit") })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/PersonHighlights.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Building2, Loader2, Pencil, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { CompanySelectField } from '../formConfig'\nimport {\n InlineTextEditor,\n InlineDictionaryEditor,\n InlineNextInteractionEditor,\n type InlineFieldProps,\n type NextInteractionPayload,\n} from './InlineEditors'\n\ntype PersonHighlightsPerson = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: 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}\n\ntype PersonHighlightsProfile = {\n id?: string\n companyEntityId?: string | null\n} | null\n\ntype PersonHighlightsValidators = {\n email: NonNullable<InlineFieldProps['validator']>\n phone: NonNullable<InlineFieldProps['validator']>\n displayName: NonNullable<InlineFieldProps['validator']>\n}\n\nexport type PersonHighlightsProps = {\n person: PersonHighlightsPerson\n profile: PersonHighlightsProfile\n validators: PersonHighlightsValidators\n onDisplayNameSave: (value: string | null) => Promise<void>\n onPrimaryEmailSave: (value: string | null) => Promise<void>\n onPrimaryPhoneSave: (value: string | null) => Promise<void>\n onStatusSave: (value: string | null) => Promise<void>\n onNextInteractionSave: (value: NextInteractionPayload | null) => Promise<void>\n onDelete: () => void\n isDeleting: boolean\n onCompanySave: (companyId: string | null) => Promise<void>\n utilityActions?: React.ReactNode\n}\n\ntype CompanyInfo = { id: string; name: string }\n\nexport function PersonHighlights({\n person,\n profile,\n validators,\n onDisplayNameSave,\n onPrimaryEmailSave,\n onPrimaryPhoneSave,\n onStatusSave,\n onNextInteractionSave,\n onDelete,\n isDeleting,\n onCompanySave,\n utilityActions,\n}: PersonHighlightsProps) {\n const router = useRouter()\n const t = useT()\n const runMutation = React.useCallback(async (operation: () => Promise<void>) => operation(), [])\n const [editingCompany, setEditingCompany] = React.useState(false)\n const [companyDraftId, setCompanyDraftId] = React.useState<string>('')\n const [company, setCompany] = React.useState<CompanyInfo | null>(null)\n const [companyLoading, setCompanyLoading] = React.useState(false)\n const [companyError, setCompanyError] = React.useState<string | null>(null)\n const [companySaving, setCompanySaving] = React.useState(false)\n const companyHref = React.useMemo(\n () => (company ? `/backend/customers/companies/${encodeURIComponent(company.id)}` : null),\n [company],\n )\n const isCompanyInteractive = !editingCompany && !companyLoading && !companyError && Boolean(companyHref)\n\n const navigateToCompany = React.useCallback(() => {\n if (!companyHref) return\n router.push(companyHref)\n }, [companyHref])\n\n const handleCompanyClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive || !companyHref) return\n const target = event.target as HTMLElement\n if (target.closest('button')) return\n if (event.defaultPrevented) return\n if (event.button !== 0) return\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n if (typeof window !== 'undefined') {\n window.open(companyHref, '_blank', 'noopener,noreferrer')\n }\n return\n }\n navigateToCompany()\n },\n [companyHref, isCompanyInteractive, navigateToCompany],\n )\n\n const handleCompanyKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n navigateToCompany()\n }\n },\n [isCompanyInteractive, navigateToCompany],\n )\n\n const activeCompanyId = profile?.companyEntityId ?? null\n const historyFallbackId =\n profile?.id && profile.id !== person.id ? profile.id : undefined\n\n const loadCompany = React.useCallback(async (companyId: string | null) => {\n if (!companyId) {\n setCompany(null)\n return\n }\n setCompanyLoading(true)\n setCompanyError(null)\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/companies?id=${encodeURIComponent(companyId)}`,\n undefined,\n { errorMessage: t('customers.people.detail.company.loadError', 'Unable to load company information.') },\n )\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, unknown>>) : []\n const item = items.find((entry) => {\n if (!entry) return false\n const rawId = (entry as Record<string, unknown>).id\n if (typeof rawId === 'string') return rawId === companyId\n if (typeof rawId === 'number') return String(rawId) === companyId\n return false\n }) as Record<string, unknown> | undefined\n if (item && typeof item.display_name === 'string') {\n setCompany({ id: companyId, name: item.display_name })\n } else if (item && typeof item.displayName === 'string') {\n setCompany({ id: companyId, name: item.displayName })\n } else {\n setCompany({ id: companyId, name: t('customers.people.detail.company.unknown', 'Unknown company') })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.company.loadError', 'Unable to load company.')\n setCompanyError(message)\n setCompany(null)\n } finally {\n setCompanyLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n setCompanyDraftId(activeCompanyId ?? '')\n loadCompany(activeCompanyId).catch(() => {})\n }, [activeCompanyId, loadCompany])\n\n const handleCompanySave = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n const nextId = companyDraftId.trim()\n try {\n await runMutation(async () => {\n await onCompanySave(nextId.length ? nextId : null)\n })\n await loadCompany(nextId.length ? nextId : null)\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companyDraftId, companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const handleCompanyClear = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n try {\n await runMutation(async () => {\n await onCompanySave(null)\n })\n await loadCompany(null)\n setCompanyDraftId('')\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const companyPanel = (\n <div\n className={cn(\n 'group rounded-lg border bg-muted/30 p-3',\n isCompanyInteractive\n ? 'cursor-pointer transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n : null,\n )}\n role={isCompanyInteractive ? 'link' : undefined}\n tabIndex={isCompanyInteractive ? 0 : undefined}\n onClick={handleCompanyClick}\n onKeyDown={handleCompanyKeyDown}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1 space-y-1\">\n <p className=\"flex items-center gap-2 text-xs uppercase tracking-wide text-muted-foreground\">\n <Building2 aria-hidden className=\"h-3.5 w-3.5\" />\n {t('customers.people.detail.company.label', 'Company')}\n </p>\n {editingCompany ? (\n <div\n className=\"space-y-3\"\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n if (!companySaving) {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!companySaving) {\n void handleCompanySave()\n }\n }\n }}\n >\n <CompanySelectField\n value={companyDraftId || undefined}\n onChange={(next) => setCompanyDraftId(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 {companyError ? <p className=\"text-xs text-status-error-text\">{companyError}</p> : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={handleCompanySave} disabled={companySaving}>\n {companySaving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.forms.actions.save')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }} disabled={companySaving}>\n {t('ui.forms.actions.cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={handleCompanyClear} disabled={companySaving}>\n {t('ui.forms.actions.clear')}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center gap-2 text-sm\">\n {companyLoading ? (\n <span className=\"inline-flex items-center gap-2 text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {t('customers.people.detail.company.loading', 'Loading company\u2026')}\n </span>\n ) : company ? (\n <span className=\"text-primary transition group-hover:underline\">\n {t('customers.people.detail.company.current', undefined, { company: company.name })}\n </span>\n ) : companyError ? (\n <span className=\"text-xs text-status-error-text\">{companyError}</span>\n ) : (\n <span className=\"text-muted-foreground\">\n {t('customers.people.detail.company.empty', 'No company assigned')}\n </span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (companySaving) return\n setEditingCompany((prev) => !prev)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }}\n className={\n editingCompany\n ? 'opacity-100'\n : 'opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:opacity-100 focus-visible:opacity-100'\n }\n >\n {editingCompany ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">\n {editingCompany ? t('ui.forms.actions.cancel') : t('ui.forms.actions.edit')}\n </span>\n </Button>\n </div>\n </div>\n )\n\n return (\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/people\"\n backLabel={t('customers.people.detail.actions.backToList')}\n utilityActions={(\n <>\n {utilityActions}\n <VersionHistoryAction\n config={{\n resourceKind: 'customers.person',\n resourceId: person.id,\n resourceIdFallback: historyFallbackId,\n organizationId: person.organizationId ?? undefined,\n }}\n t={t}\n />\n </>\n )}\n title={\n <InlineTextEditor\n label={t('customers.people.form.displayName.label')}\n value={person.displayName}\n placeholder={t('customers.people.form.displayName.placeholder')}\n emptyLabel={t('customers.people.detail.noValue')}\n validator={validators.displayName}\n onSave={onDisplayNameSave}\n hideLabel\n variant=\"plain\"\n activateOnClick\n triggerClassName=\"opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n containerClassName=\"max-w-full\"\n />\n }\n onDelete={() => {\n onDelete()\n }}\n isDeleting={isDeleting}\n deleteLabel={t('customers.people.list.actions.delete')}\n />\n\n {companyPanel}\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryEmail')}\n value={person.primaryEmail || ''}\n placeholder={t('customers.people.form.primaryEmail')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"email\"\n validator={validators.email}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryEmailSave}\n />\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryPhone')}\n value={person.primaryPhone || ''}\n placeholder={t('customers.people.form.primaryPhone')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"tel\"\n validator={validators.phone}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryPhoneSave}\n />\n <InlineDictionaryEditor\n label={t('customers.people.detail.highlights.status')}\n value={person.status ?? null}\n emptyLabel={t('customers.people.detail.noValue')}\n activateOnClick\n onSave={onStatusSave}\n kind=\"statuses\"\n />\n <InlineNextInteractionEditor\n label={t('customers.people.detail.highlights.nextInteraction')}\n valueAt={person.nextInteractionAt || null}\n valueName={person.nextInteractionName || null}\n valueRefId={person.nextInteractionRefId || null}\n valueIcon={person.nextInteractionIcon || null}\n valueColor={person.nextInteractionColor || null}\n emptyLabel={t('customers.people.detail.noValue')}\n onSave={onNextInteractionSave}\n activateOnClick\n />\n </div>\n </div>\n )\n}\n\nexport default PersonHighlights\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Building2, Loader2, Pencil, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { CompanySelectField } from '../formConfig'\nimport {\n InlineTextEditor,\n InlineDictionaryEditor,\n InlineNextInteractionEditor,\n type InlineFieldProps,\n type NextInteractionPayload,\n} from './InlineEditors'\n\ntype PersonHighlightsPerson = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: 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}\n\ntype PersonHighlightsProfile = {\n id?: string\n companyEntityId?: string | null\n} | null\n\ntype PersonHighlightsValidators = {\n email: NonNullable<InlineFieldProps['validator']>\n phone: NonNullable<InlineFieldProps['validator']>\n displayName: NonNullable<InlineFieldProps['validator']>\n}\n\nexport type PersonHighlightsProps = {\n person: PersonHighlightsPerson\n profile: PersonHighlightsProfile\n validators: PersonHighlightsValidators\n onDisplayNameSave: (value: string | null) => Promise<void>\n onPrimaryEmailSave: (value: string | null) => Promise<void>\n onPrimaryPhoneSave: (value: string | null) => Promise<void>\n onStatusSave: (value: string | null) => Promise<void>\n onNextInteractionSave: (value: NextInteractionPayload | null) => Promise<void>\n onDelete: () => void\n isDeleting: boolean\n onCompanySave: (companyId: string | null) => Promise<void>\n utilityActions?: React.ReactNode\n}\n\ntype CompanyInfo = { id: string; name: string }\n\nexport function PersonHighlights({\n person,\n profile,\n validators,\n onDisplayNameSave,\n onPrimaryEmailSave,\n onPrimaryPhoneSave,\n onStatusSave,\n onNextInteractionSave,\n onDelete,\n isDeleting,\n onCompanySave,\n utilityActions,\n}: PersonHighlightsProps) {\n const router = useRouter()\n const t = useT()\n const runMutation = React.useCallback(async (operation: () => Promise<void>) => operation(), [])\n const [editingCompany, setEditingCompany] = React.useState(false)\n const [companyDraftId, setCompanyDraftId] = React.useState<string>('')\n const [company, setCompany] = React.useState<CompanyInfo | null>(null)\n const [companyLoading, setCompanyLoading] = React.useState(false)\n const [companyError, setCompanyError] = React.useState<string | null>(null)\n const [companySaving, setCompanySaving] = React.useState(false)\n const companyHref = React.useMemo(\n () => (company ? `/backend/customers/companies/${encodeURIComponent(company.id)}` : null),\n [company],\n )\n const isCompanyInteractive = !editingCompany && !companyLoading && !companyError && Boolean(companyHref)\n\n const navigateToCompany = React.useCallback(() => {\n if (!companyHref) return\n router.push(companyHref)\n }, [companyHref])\n\n const handleCompanyClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive || !companyHref) return\n const target = event.target as HTMLElement\n if (target.closest('button')) return\n if (event.defaultPrevented) return\n if (event.button !== 0) return\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n if (typeof window !== 'undefined') {\n window.open(companyHref, '_blank', 'noopener,noreferrer')\n }\n return\n }\n navigateToCompany()\n },\n [companyHref, isCompanyInteractive, navigateToCompany],\n )\n\n const handleCompanyKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n navigateToCompany()\n }\n },\n [isCompanyInteractive, navigateToCompany],\n )\n\n const activeCompanyId = profile?.companyEntityId ?? null\n const historyFallbackId =\n profile?.id && profile.id !== person.id ? profile.id : undefined\n\n const loadCompany = React.useCallback(async (companyId: string | null) => {\n if (!companyId) {\n setCompany(null)\n return\n }\n setCompanyLoading(true)\n setCompanyError(null)\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/companies?id=${encodeURIComponent(companyId)}`,\n undefined,\n { errorMessage: t('customers.people.detail.company.loadError', 'Unable to load company information.') },\n )\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, unknown>>) : []\n const item = items.find((entry) => {\n if (!entry) return false\n const rawId = (entry as Record<string, unknown>).id\n if (typeof rawId === 'string') return rawId === companyId\n if (typeof rawId === 'number') return String(rawId) === companyId\n return false\n }) as Record<string, unknown> | undefined\n if (item && typeof item.display_name === 'string') {\n setCompany({ id: companyId, name: item.display_name })\n } else if (item && typeof item.displayName === 'string') {\n setCompany({ id: companyId, name: item.displayName })\n } else {\n setCompany({ id: companyId, name: t('customers.people.detail.company.unknown', 'Unknown company') })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.company.loadError', 'Unable to load company.')\n setCompanyError(message)\n setCompany(null)\n } finally {\n setCompanyLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n setCompanyDraftId(activeCompanyId ?? '')\n loadCompany(activeCompanyId).catch(() => {})\n }, [activeCompanyId, loadCompany])\n\n const handleCompanySave = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n const nextId = companyDraftId.trim()\n try {\n await runMutation(async () => {\n await onCompanySave(nextId.length ? nextId : null)\n })\n await loadCompany(nextId.length ? nextId : null)\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companyDraftId, companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const handleCompanyClear = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n try {\n await runMutation(async () => {\n await onCompanySave(null)\n })\n await loadCompany(null)\n setCompanyDraftId('')\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const companyPanel = (\n <div\n className={cn(\n 'group rounded-lg border bg-muted/30 p-3',\n isCompanyInteractive\n ? 'cursor-pointer transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n : null,\n )}\n role={isCompanyInteractive ? 'link' : undefined}\n tabIndex={isCompanyInteractive ? 0 : undefined}\n onClick={handleCompanyClick}\n onKeyDown={handleCompanyKeyDown}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1 space-y-1\">\n <p className=\"flex items-center gap-2 text-xs uppercase tracking-wide text-muted-foreground\">\n <Building2 aria-hidden className=\"h-3.5 w-3.5\" />\n {t('customers.people.detail.company.label', 'Company')}\n </p>\n {editingCompany ? (\n <div\n className=\"space-y-3\"\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n if (!companySaving) {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!companySaving) {\n void handleCompanySave()\n }\n }\n }}\n >\n <CompanySelectField\n value={companyDraftId || undefined}\n onChange={(next) => setCompanyDraftId(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 {companyError ? <p className=\"text-xs text-status-error-text\">{companyError}</p> : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={handleCompanySave} disabled={companySaving}>\n {companySaving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.forms.actions.save')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }} disabled={companySaving}>\n {t('ui.forms.actions.cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={handleCompanyClear} disabled={companySaving}>\n {t('ui.forms.actions.clear')}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center gap-2 text-sm\">\n {companyLoading ? (\n <span className=\"inline-flex items-center gap-2 text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {t('customers.people.detail.company.loading', 'Loading company\u2026')}\n </span>\n ) : company ? (\n <span className=\"text-primary transition group-hover:underline\">\n {t('customers.people.detail.company.current', undefined, { company: company.name })}\n </span>\n ) : companyError ? (\n <span className=\"text-xs text-status-error-text\">{companyError}</span>\n ) : (\n <span className=\"text-muted-foreground\">\n {t('customers.people.detail.company.empty', 'No company assigned')}\n </span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (companySaving) return\n setEditingCompany((prev) => !prev)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }}\n className={\n editingCompany\n ? 'opacity-100'\n // The enclosing panel only activates once a company is assigned, and then it\n // navigates to that company instead of opening this editor \u2014 so without the\n // coarse-pointer reveal the Company field cannot be set or changed on touch.\n : 'opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-100'\n }\n >\n {editingCompany ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">\n {editingCompany ? t('ui.forms.actions.cancel') : t('ui.forms.actions.edit')}\n </span>\n </Button>\n </div>\n </div>\n )\n\n return (\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/people\"\n backLabel={t('customers.people.detail.actions.backToList')}\n utilityActions={(\n <>\n {utilityActions}\n <VersionHistoryAction\n config={{\n resourceKind: 'customers.person',\n resourceId: person.id,\n resourceIdFallback: historyFallbackId,\n organizationId: person.organizationId ?? undefined,\n }}\n t={t}\n />\n </>\n )}\n title={\n <InlineTextEditor\n label={t('customers.people.form.displayName.label')}\n value={person.displayName}\n placeholder={t('customers.people.form.displayName.placeholder')}\n emptyLabel={t('customers.people.detail.noValue')}\n validator={validators.displayName}\n onSave={onDisplayNameSave}\n hideLabel\n variant=\"plain\"\n activateOnClick\n triggerClassName=\"opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n containerClassName=\"max-w-full\"\n />\n }\n onDelete={() => {\n onDelete()\n }}\n isDeleting={isDeleting}\n deleteLabel={t('customers.people.list.actions.delete')}\n />\n\n {companyPanel}\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryEmail')}\n value={person.primaryEmail || ''}\n placeholder={t('customers.people.form.primaryEmail')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"email\"\n validator={validators.email}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryEmailSave}\n />\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryPhone')}\n value={person.primaryPhone || ''}\n placeholder={t('customers.people.form.primaryPhone')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"tel\"\n validator={validators.phone}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryPhoneSave}\n />\n <InlineDictionaryEditor\n label={t('customers.people.detail.highlights.status')}\n value={person.status ?? null}\n emptyLabel={t('customers.people.detail.noValue')}\n activateOnClick\n onSave={onStatusSave}\n kind=\"statuses\"\n />\n <InlineNextInteractionEditor\n label={t('customers.people.detail.highlights.nextInteraction')}\n valueAt={person.nextInteractionAt || null}\n valueName={person.nextInteractionName || null}\n valueRefId={person.nextInteractionRefId || null}\n valueIcon={person.nextInteractionIcon || null}\n valueColor={person.nextInteractionColor || null}\n emptyLabel={t('customers.people.detail.noValue')}\n onSave={onNextInteractionSave}\n activateOnClick\n />\n </div>\n </div>\n )\n}\n\nexport default PersonHighlights\n"],
5
+ "mappings": ";AAsOU,SAoHA,UAnHE,KADF;AApOV,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,WAAW,SAAS,QAAQ,SAAS;AAC9C,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B;AACrC,SAAS,YAAY;AACrB,SAAS,4BAA4B;AACrC,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AA4CA,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,SAAS,UAAU;AACzB,QAAM,IAAI,KAAK;AACf,QAAM,cAAc,MAAM,YAAY,OAAO,cAAmC,UAAU,GAAG,CAAC,CAAC;AAC/F,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAS,KAAK;AAChE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAiB,EAAE;AACrE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAA6B,IAAI;AACrE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAS,KAAK;AAChE,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAwB,IAAI;AAC1E,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAS,KAAK;AAC9D,QAAM,cAAc,MAAM;AAAA,IACxB,MAAO,UAAU,gCAAgC,mBAAmB,QAAQ,EAAE,CAAC,KAAK;AAAA,IACpF,CAAC,OAAO;AAAA,EACV;AACA,QAAM,uBAAuB,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,gBAAgB,QAAQ,WAAW;AAEvG,QAAM,oBAAoB,MAAM,YAAY,MAAM;AAChD,QAAI,CAAC,YAAa;AAClB,WAAO,KAAK,WAAW;AAAA,EACzB,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,qBAAqB,MAAM;AAAA,IAC/B,CAAC,UAA4C;AAC3C,UAAI,CAAC,wBAAwB,CAAC,YAAa;AAC3C,YAAM,SAAS,MAAM;AACrB,UAAI,OAAO,QAAQ,QAAQ,EAAG;AAC9B,UAAI,MAAM,iBAAkB;AAC5B,UAAI,MAAM,WAAW,EAAG;AACxB,UAAI,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY,MAAM,QAAQ;AACpE,YAAI,OAAO,WAAW,aAAa;AACjC,iBAAO,KAAK,aAAa,UAAU,qBAAqB;AAAA,QAC1D;AACA;AAAA,MACF;AACA,wBAAkB;AAAA,IACpB;AAAA,IACA,CAAC,aAAa,sBAAsB,iBAAiB;AAAA,EACvD;AAEA,QAAM,uBAAuB,MAAM;AAAA,IACjC,CAAC,UAA+C;AAC9C,UAAI,CAAC,qBAAsB;AAC3B,UAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;AAC9C,cAAM,eAAe;AACrB,0BAAkB;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAAC,sBAAsB,iBAAiB;AAAA,EAC1C;AAEA,QAAM,kBAAkB,SAAS,mBAAmB;AACpD,QAAM,oBACJ,SAAS,MAAM,QAAQ,OAAO,OAAO,KAAK,QAAQ,KAAK;AAEzD,QAAM,cAAc,MAAM,YAAY,OAAO,cAA6B;AACxE,QAAI,CAAC,WAAW;AACd,iBAAW,IAAI;AACf;AAAA,IACF;AACA,sBAAkB,IAAI;AACtB,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAM,UAAU,MAAM;AAAA,QACpB,+BAA+B,mBAAmB,SAAS,CAAC;AAAA,QAC5D;AAAA,QACA,EAAE,cAAc,EAAE,6CAA6C,qCAAqC,EAAE;AAAA,MACxG;AACA,YAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK,IAAK,QAAQ,QAA2C,CAAC;AACnG,YAAM,OAAO,MAAM,KAAK,CAAC,UAAU;AACjC,YAAI,CAAC,MAAO,QAAO;AACnB,cAAM,QAAS,MAAkC;AACjD,YAAI,OAAO,UAAU,SAAU,QAAO,UAAU;AAChD,YAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,MAAM;AACxD,eAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ,OAAO,KAAK,iBAAiB,UAAU;AACjD,mBAAW,EAAE,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC;AAAA,MACvD,WAAW,QAAQ,OAAO,KAAK,gBAAgB,UAAU;AACvD,mBAAW,EAAE,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AAAA,MACtD,OAAO;AACL,mBAAW,EAAE,IAAI,WAAW,MAAM,EAAE,2CAA2C,iBAAiB,EAAE,CAAC;AAAA,MACrG;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,EAAE,6CAA6C,yBAAyB;AAC7H,sBAAgB,OAAO;AACvB,iBAAW,IAAI;AAAA,IACjB,UAAE;AACA,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,sBAAkB,mBAAmB,EAAE;AACvC,gBAAY,eAAe,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7C,GAAG,CAAC,iBAAiB,WAAW,CAAC;AAEjC,QAAM,oBAAoB,MAAM,YAAY,YAAY;AACtD,QAAI,cAAe;AACnB,qBAAiB,IAAI;AACrB,oBAAgB,IAAI;AACpB,UAAM,SAAS,eAAe,KAAK;AACnC,QAAI;AACF,YAAM,YAAY,YAAY;AAC5B,cAAM,cAAc,OAAO,SAAS,SAAS,IAAI;AAAA,MACnD,CAAC;AACD,YAAM,YAAY,OAAO,SAAS,SAAS,IAAI;AAC/C,wBAAkB,KAAK;AAAA,IACzB,SAAS,KAAK;AACZ,YAAM,UACJ,eAAe,QACX,IAAI,UACJ,EAAE,6CAA6C,2BAA2B;AAChF,sBAAgB,OAAO;AAAA,IACzB,UAAE;AACA,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,gBAAgB,eAAe,aAAa,eAAe,aAAa,CAAC,CAAC;AAE9E,QAAM,qBAAqB,MAAM,YAAY,YAAY;AACvD,QAAI,cAAe;AACnB,qBAAiB,IAAI;AACrB,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAM,YAAY,YAAY;AAC5B,cAAM,cAAc,IAAI;AAAA,MAC1B,CAAC;AACD,YAAM,YAAY,IAAI;AACtB,wBAAkB,EAAE;AACpB,wBAAkB,KAAK;AAAA,IACzB,SAAS,KAAK;AACZ,YAAM,UACJ,eAAe,QACX,IAAI,UACJ,EAAE,6CAA6C,2BAA2B;AAChF,sBAAgB,OAAO;AAAA,IACzB,UAAE;AACA,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,eAAe,aAAa,eAAe,aAAa,CAAC,CAAC;AAE9D,QAAM,eACJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,uBACI,+HACA;AAAA,MACN;AAAA,MACA,MAAM,uBAAuB,SAAS;AAAA,MACtC,UAAU,uBAAuB,IAAI;AAAA,MACrC,SAAS;AAAA,MACT,WAAW;AAAA,MAEX,+BAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,SAAI,WAAU,oBACb;AAAA,+BAAC,OAAE,WAAU,iFACX;AAAA,gCAAC,aAAU,eAAW,MAAC,WAAU,eAAc;AAAA,YAC9C,EAAE,yCAAyC,SAAS;AAAA,aACvD;AAAA,UACC,iBACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,WAAW,CAAC,UAAU;AACpB,oBAAI,MAAM,QAAQ,UAAU;AAC1B,wBAAM,eAAe;AACrB,sBAAI,CAAC,eAAe;AAClB,sCAAkB,KAAK;AACvB,oCAAgB,IAAI;AACpB,sCAAkB,mBAAmB,EAAE;AAAA,kBACzC;AAAA,gBACF;AACA,oBAAI,MAAM,QAAQ,YAAY,MAAM,WAAW,MAAM,UAAU;AAC7D,wBAAM,eAAe;AACrB,sBAAI,CAAC,eAAe;AAClB,yBAAK,kBAAkB;AAAA,kBACzB;AAAA,gBACF;AAAA,cACF;AAAA,cAEA;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO,kBAAkB;AAAA,oBACzB,UAAU,CAAC,SAAS,kBAAkB,QAAQ,EAAE;AAAA,oBAChD,QAAQ;AAAA,sBACN,aAAa,EAAE,2CAA2C;AAAA,sBAC1D,UAAU,EAAE,mCAAmC;AAAA,sBAC/C,WAAW,EAAE,sCAAsC;AAAA,sBACnD,aAAa,EAAE,2CAA2C;AAAA,sBAC1D,YAAY,EAAE,0CAA0C;AAAA,sBACxD,kBAAkB,EAAE,gDAAgD;AAAA,sBACpE,YAAY,EAAE,gDAAgD;AAAA,sBAC9D,aAAa,EAAE,yCAAyC;AAAA,sBACxD,WAAW,EAAE,uCAAuC;AAAA,sBACpD,WAAW,EAAE,4CAA4C;AAAA,sBACzD,WAAW,EAAE,wCAAwC;AAAA,sBACrD,cAAc,EAAE,uCAAuC;AAAA,oBACzD;AAAA;AAAA,gBACF;AAAA,gBACC,eAAe,oBAAC,OAAE,WAAU,kCAAkC,wBAAa,IAAO;AAAA,gBACnF,qBAAC,SAAI,WAAU,qCACb;AAAA,uCAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAS,mBAAmB,UAAU,eACnE;AAAA,oCAAgB,oBAAC,WAAQ,WAAU,iCAAgC,IAAK;AAAA,oBACxE,EAAE,uBAAuB;AAAA,qBAC5B;AAAA,kBACA,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,SAAQ,SAAS,MAAM;AAC7D,sCAAkB,KAAK;AACvB,oCAAgB,IAAI;AACpB,sCAAkB,mBAAmB,EAAE;AAAA,kBACzC,GAAG,UAAU,eACV,YAAE,yBAAyB,GAC9B;AAAA,kBACA,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,aAAY,SAAS,oBAAoB,UAAU,eACxF,YAAE,wBAAwB,GAC7B;AAAA,mBACF;AAAA;AAAA;AAAA,UACF,IAEA,oBAAC,SAAI,WAAU,mCACZ,2BACC,qBAAC,UAAK,WAAU,wDACd;AAAA,gCAAC,WAAQ,WAAU,wBAAuB;AAAA,YACzC,EAAE,2CAA2C,uBAAkB;AAAA,aAClE,IACE,UACF,oBAAC,UAAK,WAAU,iDACb,YAAE,2CAA2C,QAAW,EAAE,SAAS,QAAQ,KAAK,CAAC,GACpF,IACE,eACF,oBAAC,UAAK,WAAU,kCAAkC,wBAAa,IAE/D,oBAAC,UAAK,WAAU,yBACb,YAAE,yCAAyC,qBAAqB,GACnE,GAEJ;AAAA,WAEJ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM;AACb,kBAAI,cAAe;AACnB,gCAAkB,CAAC,SAAS,CAAC,IAAI;AACjC,8BAAgB,IAAI;AACpB,gCAAkB,mBAAmB,EAAE;AAAA,YACzC;AAAA,YACA,WACE,iBACI,gBAIA;AAAA,YAGL;AAAA,+BAAiB,oBAAC,KAAE,WAAU,WAAU,IAAK,oBAAC,UAAO,WAAU,WAAU;AAAA,cAC1E,oBAAC,UAAK,WAAU,WACb,2BAAiB,EAAE,yBAAyB,IAAI,EAAE,uBAAuB,GAC5E;AAAA;AAAA;AAAA,QACF;AAAA,SACF;AAAA;AAAA,EACF;AAGF,SACE,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAS;AAAA,QACT,WAAW,EAAE,4CAA4C;AAAA,QACzD,gBACE,iCACG;AAAA;AAAA,UACD;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,gBACN,cAAc;AAAA,gBACd,YAAY,OAAO;AAAA,gBACnB,oBAAoB;AAAA,gBACpB,gBAAgB,OAAO,kBAAkB;AAAA,cAC3C;AAAA,cACA;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEF,OACE;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,EAAE,yCAAyC;AAAA,YAClD,OAAO,OAAO;AAAA,YACd,aAAa,EAAE,+CAA+C;AAAA,YAC9D,YAAY,EAAE,iCAAiC;AAAA,YAC/C,WAAW,WAAW;AAAA,YACtB,QAAQ;AAAA,YACR,WAAS;AAAA,YACT,SAAQ;AAAA,YACR,iBAAe;AAAA,YACf,kBAAiB;AAAA,YACjB,oBAAmB;AAAA;AAAA,QACrB;AAAA,QAEF,UAAU,MAAM;AACd,mBAAS;AAAA,QACX;AAAA,QACA;AAAA,QACA,aAAa,EAAE,sCAAsC;AAAA;AAAA,IACvD;AAAA,IAEC;AAAA,IAED,qBAAC,SAAI,WAAU,4CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,iDAAiD;AAAA,UAC1D,OAAO,OAAO,gBAAgB;AAAA,UAC9B,aAAa,EAAE,oCAAoC;AAAA,UACnD,YAAY,EAAE,iCAAiC;AAAA,UAC/C,MAAK;AAAA,UACL,WAAW,WAAW;AAAA,UACtB,UAAU,OAAO;AAAA,UACjB,iBAAe;AAAA,UACf,QAAQ;AAAA;AAAA,MACV;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,iDAAiD;AAAA,UAC1D,OAAO,OAAO,gBAAgB;AAAA,UAC9B,aAAa,EAAE,oCAAoC;AAAA,UACnD,YAAY,EAAE,iCAAiC;AAAA,UAC/C,MAAK;AAAA,UACL,WAAW,WAAW;AAAA,UACtB,UAAU,OAAO;AAAA,UACjB,iBAAe;AAAA,UACf,QAAQ;AAAA;AAAA,MACV;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,2CAA2C;AAAA,UACpD,OAAO,OAAO,UAAU;AAAA,UACxB,YAAY,EAAE,iCAAiC;AAAA,UAC/C,iBAAe;AAAA,UACf,QAAQ;AAAA,UACR,MAAK;AAAA;AAAA,MACP;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,oDAAoD;AAAA,UAC7D,SAAS,OAAO,qBAAqB;AAAA,UACrC,WAAW,OAAO,uBAAuB;AAAA,UACzC,YAAY,OAAO,wBAAwB;AAAA,UAC3C,WAAW,OAAO,uBAAuB;AAAA,UACzC,YAAY,OAAO,wBAAwB;AAAA,UAC3C,YAAY,EAAE,iCAAiC;AAAA,UAC/C,QAAQ;AAAA,UACR,iBAAe;AAAA;AAAA,MACjB;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,IAAO,2BAAQ;",
6
6
  "names": []
7
7
  }
@@ -139,7 +139,7 @@ function PlannedActivitiesSection({ activities, onComplete, onSchedule, onEdit,
139
139
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
140
140
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium block truncate", children: activity.title ?? activity.body ?? activity.interactionType }),
141
141
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
142
- /* @__PURE__ */ jsx("span", { children: activity.scheduledAt ? formatScheduledDate(activity.scheduledAt) : "" }),
142
+ /* @__PURE__ */ jsx("span", { children: activity.scheduledAt ? formatScheduledDate(activity.scheduledAt, t) : "" }),
143
143
  activity.authorName && /* @__PURE__ */ jsxs(Fragment, { children: [
144
144
  /* @__PURE__ */ jsx("span", { children: "\xB7" }),
145
145
  /* @__PURE__ */ jsx("span", { children: activity.authorName })
@@ -200,17 +200,16 @@ function formatRelativeOverdue(isoString, t) {
200
200
  return "";
201
201
  }
202
202
  }
203
- function formatScheduledDate(isoString) {
203
+ function formatScheduledDate(isoString, t) {
204
204
  try {
205
205
  const date = new Date(isoString);
206
- const now = /* @__PURE__ */ new Date();
207
- const tomorrow = new Date(now);
206
+ const tomorrow = /* @__PURE__ */ new Date();
208
207
  tomorrow.setDate(tomorrow.getDate() + 1);
209
208
  const dayName = date.toLocaleDateString(void 0, { weekday: "short" });
210
209
  const dateStr = date.toLocaleDateString(void 0, { day: "numeric", month: "short" });
211
210
  const timeStr = date.toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" });
212
211
  if (isSameDay(date, tomorrow)) {
213
- return `Tomorrow ${timeStr}`;
212
+ return t("customers.timeline.planned.tomorrow", "Tomorrow {{time}}", { time: timeStr });
214
213
  }
215
214
  return `${dayName}, ${dateStr} \xB7 ${timeStr}`;
216
215
  } catch {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/PlannedActivitiesSection.tsx"],
4
- "sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, Clock, AlertCircle, CalendarClock, Check, MoreHorizontal, Plus } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'\nimport type { InteractionSummary } from './types'\nimport { isSameDay } from '../../lib/localDay'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n}\n\ninterface PlannedActivitiesSectionProps {\n activities: InteractionSummary[]\n onComplete?: (id: string) => void\n onSchedule?: () => void\n onEdit?: (activity: InteractionSummary) => void\n onCancel?: (id: string) => void\n}\n\nexport function PlannedActivitiesSection({ activities, onComplete, onSchedule, onEdit, onCancel }: PlannedActivitiesSectionProps) {\n const t = useT()\n\n if (activities.length === 0) return null\n\n const now = new Date()\n\n const classified = activities.map((activity) => {\n const scheduledDate = activity.scheduledAt ? new Date(activity.scheduledAt) : null\n const isOverdue = scheduledDate ? scheduledDate < now : false\n return { ...activity, isOverdue }\n })\n\n const overdue = classified.filter((a) => a.isOverdue)\n const upcoming = classified.filter((a) => !a.isOverdue)\n\n return (\n <div className=\"rounded-lg border bg-card\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b\">\n <div className=\"flex items-center gap-2 text-sm font-medium\">\n <CalendarClock className=\"size-4 text-muted-foreground\" />\n {t('customers.timeline.planned.title', 'Planned activities')}\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground\">\n {activities.length}\n </span>\n {overdue.length > 0 && (\n <span className=\"flex items-center gap-1 text-xs font-medium text-destructive\">\n <AlertCircle className=\"size-3\" />\n {overdue.length} {t('customers.timeline.planned.overdueCount', 'overdue')}\n </span>\n )}\n </div>\n {onSchedule && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"h-7 text-xs\" onClick={onSchedule}>\n <Plus className=\"mr-1 size-3\" />\n {t('customers.timeline.planned.schedule', 'Schedule')}\n </Button>\n )}\n </div>\n\n {/* Items */}\n <div className=\"divide-y\">\n {overdue.map((activity) => {\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n return (\n <div\n key={activity.id}\n className=\"flex items-center gap-3 border-l-2 border-l-destructive px-4 py-3 cursor-pointer hover:bg-accent/50 transition-colors\"\n onClick={() => onEdit?.(activity)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => { if (e.key === 'Enter') onEdit?.(activity) }}\n >\n <div className=\"flex items-center justify-center size-8 rounded-full bg-destructive/10 shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-4 text-destructive\" /> : <AlertCircle className=\"size-4 text-destructive\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-sm font-medium block truncate\">\n {activity.title ?? activity.body ?? activity.interactionType}\n </span>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span className=\"inline-flex items-center gap-1 font-medium text-destructive\">\n {t('customers.timeline.planned.overdue', 'Overdue')}\n </span>\n <span>\n {activity.scheduledAt ? formatRelativeOverdue(activity.scheduledAt, t) : ''}\n </span>\n {activity.authorName && (\n <>\n <span>\u00B7</span>\n <span>{activity.authorName}</span>\n </>\n )}\n </div>\n </div>\n {onComplete && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 shrink-0 text-xs\"\n onClick={(event) => {\n event.stopPropagation()\n onComplete(activity.id)\n }}\n >\n <Check className=\"mr-1 size-3\" />\n {t('customers.timeline.planned.markDone', 'Mark done')}\n </Button>\n )}\n <Popover>\n <PopoverTrigger asChild>\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={t('customers.timeline.more', 'More')} onClick={(e) => e.stopPropagation()}>\n <MoreHorizontal className=\"size-3.5\" />\n </IconButton>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-40 p-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs\"\n onClick={(event) => {\n event.stopPropagation()\n onEdit?.(activity)\n }}\n >\n {t('customers.timeline.planned.reschedule', 'Reschedule')}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs text-destructive hover:text-destructive\"\n onClick={(event) => {\n event.stopPropagation()\n onCancel?.(activity.id)\n }}\n >\n {t('customers.timeline.planned.cancel', 'Cancel')}\n </Button>\n </PopoverContent>\n </Popover>\n </div>\n )\n })}\n\n {upcoming.map((activity) => {\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n return (\n <div\n key={activity.id}\n className=\"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-accent/50 transition-colors\"\n onClick={() => onEdit?.(activity)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => { if (e.key === 'Enter') onEdit?.(activity) }}\n >\n <div className=\"flex items-center justify-center size-8 rounded-full bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-4 text-muted-foreground\" /> : <Clock className=\"size-4 text-muted-foreground\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-sm font-medium block truncate\">\n {activity.title ?? activity.body ?? activity.interactionType}\n </span>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{activity.scheduledAt ? formatScheduledDate(activity.scheduledAt) : ''}</span>\n {activity.authorName && (\n <>\n <span>\u00B7</span>\n <span>{activity.authorName}</span>\n </>\n )}\n </div>\n </div>\n <Popover>\n <PopoverTrigger asChild>\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={t('customers.timeline.more', 'More')} onClick={(e) => e.stopPropagation()}>\n <MoreHorizontal className=\"size-3.5\" />\n </IconButton>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-40 p-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs\"\n onClick={(event) => {\n event.stopPropagation()\n onEdit?.(activity)\n }}\n >\n {t('customers.timeline.planned.reschedule', 'Reschedule')}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs text-destructive hover:text-destructive\"\n onClick={(event) => {\n event.stopPropagation()\n onCancel?.(activity.id)\n }}\n >\n {t('customers.timeline.planned.cancel', 'Cancel')}\n </Button>\n </PopoverContent>\n </Popover>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\nfunction formatRelativeOverdue(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n if (diffDays <= 0) return t('customers.timeline.planned.overdueToday', 'due today')\n if (diffDays === 1) return t('customers.timeline.planned.overdueSince', 'since yesterday')\n return t('customers.timeline.planned.overdueDays', 'overdue {{days}} days', { days: diffDays })\n } catch {\n return ''\n }\n}\n\nfunction formatScheduledDate(isoString: string): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n const tomorrow = new Date(now)\n tomorrow.setDate(tomorrow.getDate() + 1)\n\n const dayName = date.toLocaleDateString(undefined, { weekday: 'short' })\n const dateStr = date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n const timeStr = date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n\n if (isSameDay(date, tomorrow)) {\n return `Tomorrow ${timeStr}`\n }\n return `${dayName}, ${dateStr} \u00B7 ${timeStr}`\n } catch {\n return isoString\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, Clock, AlertCircle, CalendarClock, Check, MoreHorizontal, Plus } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'\nimport type { InteractionSummary } from './types'\nimport { isSameDay } from '../../lib/localDay'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n}\n\ninterface PlannedActivitiesSectionProps {\n activities: InteractionSummary[]\n onComplete?: (id: string) => void\n onSchedule?: () => void\n onEdit?: (activity: InteractionSummary) => void\n onCancel?: (id: string) => void\n}\n\nexport function PlannedActivitiesSection({ activities, onComplete, onSchedule, onEdit, onCancel }: PlannedActivitiesSectionProps) {\n const t = useT()\n\n if (activities.length === 0) return null\n\n const now = new Date()\n\n const classified = activities.map((activity) => {\n const scheduledDate = activity.scheduledAt ? new Date(activity.scheduledAt) : null\n const isOverdue = scheduledDate ? scheduledDate < now : false\n return { ...activity, isOverdue }\n })\n\n const overdue = classified.filter((a) => a.isOverdue)\n const upcoming = classified.filter((a) => !a.isOverdue)\n\n return (\n <div className=\"rounded-lg border bg-card\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b\">\n <div className=\"flex items-center gap-2 text-sm font-medium\">\n <CalendarClock className=\"size-4 text-muted-foreground\" />\n {t('customers.timeline.planned.title', 'Planned activities')}\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground\">\n {activities.length}\n </span>\n {overdue.length > 0 && (\n <span className=\"flex items-center gap-1 text-xs font-medium text-destructive\">\n <AlertCircle className=\"size-3\" />\n {overdue.length} {t('customers.timeline.planned.overdueCount', 'overdue')}\n </span>\n )}\n </div>\n {onSchedule && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"h-7 text-xs\" onClick={onSchedule}>\n <Plus className=\"mr-1 size-3\" />\n {t('customers.timeline.planned.schedule', 'Schedule')}\n </Button>\n )}\n </div>\n\n {/* Items */}\n <div className=\"divide-y\">\n {overdue.map((activity) => {\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n return (\n <div\n key={activity.id}\n className=\"flex items-center gap-3 border-l-2 border-l-destructive px-4 py-3 cursor-pointer hover:bg-accent/50 transition-colors\"\n onClick={() => onEdit?.(activity)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => { if (e.key === 'Enter') onEdit?.(activity) }}\n >\n <div className=\"flex items-center justify-center size-8 rounded-full bg-destructive/10 shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-4 text-destructive\" /> : <AlertCircle className=\"size-4 text-destructive\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-sm font-medium block truncate\">\n {activity.title ?? activity.body ?? activity.interactionType}\n </span>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span className=\"inline-flex items-center gap-1 font-medium text-destructive\">\n {t('customers.timeline.planned.overdue', 'Overdue')}\n </span>\n <span>\n {activity.scheduledAt ? formatRelativeOverdue(activity.scheduledAt, t) : ''}\n </span>\n {activity.authorName && (\n <>\n <span>\u00B7</span>\n <span>{activity.authorName}</span>\n </>\n )}\n </div>\n </div>\n {onComplete && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 shrink-0 text-xs\"\n onClick={(event) => {\n event.stopPropagation()\n onComplete(activity.id)\n }}\n >\n <Check className=\"mr-1 size-3\" />\n {t('customers.timeline.planned.markDone', 'Mark done')}\n </Button>\n )}\n <Popover>\n <PopoverTrigger asChild>\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={t('customers.timeline.more', 'More')} onClick={(e) => e.stopPropagation()}>\n <MoreHorizontal className=\"size-3.5\" />\n </IconButton>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-40 p-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs\"\n onClick={(event) => {\n event.stopPropagation()\n onEdit?.(activity)\n }}\n >\n {t('customers.timeline.planned.reschedule', 'Reschedule')}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs text-destructive hover:text-destructive\"\n onClick={(event) => {\n event.stopPropagation()\n onCancel?.(activity.id)\n }}\n >\n {t('customers.timeline.planned.cancel', 'Cancel')}\n </Button>\n </PopoverContent>\n </Popover>\n </div>\n )\n })}\n\n {upcoming.map((activity) => {\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n return (\n <div\n key={activity.id}\n className=\"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-accent/50 transition-colors\"\n onClick={() => onEdit?.(activity)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => { if (e.key === 'Enter') onEdit?.(activity) }}\n >\n <div className=\"flex items-center justify-center size-8 rounded-full bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-4 text-muted-foreground\" /> : <Clock className=\"size-4 text-muted-foreground\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-sm font-medium block truncate\">\n {activity.title ?? activity.body ?? activity.interactionType}\n </span>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{activity.scheduledAt ? formatScheduledDate(activity.scheduledAt, t) : ''}</span>\n {activity.authorName && (\n <>\n <span>\u00B7</span>\n <span>{activity.authorName}</span>\n </>\n )}\n </div>\n </div>\n <Popover>\n <PopoverTrigger asChild>\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={t('customers.timeline.more', 'More')} onClick={(e) => e.stopPropagation()}>\n <MoreHorizontal className=\"size-3.5\" />\n </IconButton>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-40 p-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs\"\n onClick={(event) => {\n event.stopPropagation()\n onEdit?.(activity)\n }}\n >\n {t('customers.timeline.planned.reschedule', 'Reschedule')}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs text-destructive hover:text-destructive\"\n onClick={(event) => {\n event.stopPropagation()\n onCancel?.(activity.id)\n }}\n >\n {t('customers.timeline.planned.cancel', 'Cancel')}\n </Button>\n </PopoverContent>\n </Popover>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\nfunction formatRelativeOverdue(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n if (diffDays <= 0) return t('customers.timeline.planned.overdueToday', 'due today')\n if (diffDays === 1) return t('customers.timeline.planned.overdueSince', 'since yesterday')\n return t('customers.timeline.planned.overdueDays', 'overdue {{days}} days', { days: diffDays })\n } catch {\n return ''\n }\n}\n\nfunction formatScheduledDate(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const tomorrow = new Date()\n tomorrow.setDate(tomorrow.getDate() + 1)\n\n const dayName = date.toLocaleDateString(undefined, { weekday: 'short' })\n const dateStr = date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n const timeStr = date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n\n if (isSameDay(date, tomorrow)) {\n return t('customers.timeline.planned.tomorrow', 'Tomorrow {{time}}', { time: timeStr })\n }\n return `${dayName}, ${dateStr} \u00B7 ${timeStr}`\n } catch {\n return isoString\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/data_sync/di.ts"],
4
- "sourcesContent": ["import { asFunction, asValue } from 'awilix'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport type { CredentialsService } from '../integrations/lib/credentials-service'\nimport type { IntegrationLogService } from '../integrations/lib/log-service'\nimport type { IntegrationStateService } from '../integrations/lib/state-service'\nimport type { ProgressService } from '../progress/lib/progressService'\nimport { SyncCursor, SyncMapping, SyncRun, SyncSchedule } from './data/entities'\nimport { createExternalIdMappingService } from './lib/id-mapping'\nimport { createSyncRunService } from './lib/sync-run-service'\nimport { createSyncScheduleService } from './lib/sync-schedule-service'\nimport { createSyncEngine } from './lib/sync-engine'\n\ntype Cradle = {\n em: EntityManager\n integrationCredentialsService: CredentialsService\n integrationLogService: IntegrationLogService\n integrationStateService: IntegrationStateService\n progressService: ProgressService\n schedulerService?: {\n register: (registration: Record<string, unknown>) => Promise<void>\n unregister: (scheduleId: string) => Promise<void>\n }\n}\n\nexport function register(container: AppContainer) {\n container.register({\n externalIdMappingService: asFunction(({ em }: Cradle) => createExternalIdMappingService(em)).scoped().proxy(),\n dataSyncRunService: asFunction(({ em }: Cradle) => createSyncRunService(em)).scoped().proxy(),\n dataSyncScheduleService: asFunction(({ em, schedulerService }: Cradle) => createSyncScheduleService(em, schedulerService)).scoped().proxy(),\n dataSyncEngine: asFunction(({ em, dataSyncRunService, integrationCredentialsService, integrationLogService, integrationStateService, progressService }: Cradle & {\n dataSyncRunService: ReturnType<typeof createSyncRunService>\n }) => createSyncEngine({\n em,\n syncRunService: dataSyncRunService,\n integrationCredentialsService,\n integrationLogService,\n integrationStateService,\n progressService,\n })).scoped().proxy(),\n\n SyncRun: asValue(SyncRun),\n SyncCursor: asValue(SyncCursor),\n SyncMapping: asValue(SyncMapping),\n SyncSchedule: asValue(SyncSchedule),\n })\n}\n"],
5
- "mappings": "AAAA,SAAS,YAAY,eAAe;AAOpC,SAAS,YAAY,aAAa,SAAS,oBAAoB;AAC/D,SAAS,sCAAsC;AAC/C,SAAS,4BAA4B;AACrC,SAAS,iCAAiC;AAC1C,SAAS,wBAAwB;AAc1B,SAAS,SAAS,WAAyB;AAChD,YAAU,SAAS;AAAA,IACjB,0BAA0B,WAAW,CAAC,EAAE,GAAG,MAAc,+BAA+B,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAC5G,oBAAoB,WAAW,CAAC,EAAE,GAAG,MAAc,qBAAqB,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAC5F,yBAAyB,WAAW,CAAC,EAAE,IAAI,iBAAiB,MAAc,0BAA0B,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAC1I,gBAAgB,WAAW,CAAC,EAAE,IAAI,oBAAoB,+BAA+B,uBAAuB,yBAAyB,gBAAgB,MAE/I,iBAAiB;AAAA,MACrB;AAAA,MACA,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAEnB,SAAS,QAAQ,OAAO;AAAA,IACxB,YAAY,QAAQ,UAAU;AAAA,IAC9B,aAAa,QAAQ,WAAW;AAAA,IAChC,cAAc,QAAQ,YAAY;AAAA,EACpC,CAAC;AACH;",
4
+ "sourcesContent": ["import { asFunction, asValue } from 'awilix'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport type { CredentialsService } from '../integrations/lib/credentials-service'\nimport type { IntegrationLogService } from '../integrations/lib/log-service'\nimport type { IntegrationStateService } from '../integrations/lib/state-service'\nimport type { ProgressService } from '../progress/lib/progressService'\nimport { SyncCursor, SyncMapping, SyncRun, SyncSchedule } from './data/entities'\nimport { createExternalIdMappingService } from './lib/id-mapping'\nimport { createSyncRunService } from './lib/sync-run-service'\nimport { createSyncScheduleService } from './lib/sync-schedule-service'\nimport { createSyncEngine } from './lib/sync-engine'\n\ntype Cradle = {\n em: EntityManager\n integrationCredentialsService: CredentialsService\n integrationLogService: IntegrationLogService\n integrationStateService: IntegrationStateService\n progressService: ProgressService\n schedulerService?: {\n register: (registration: Record<string, unknown>) => Promise<void>\n unregister: (scheduleId: string) => Promise<void>\n exists?: (scheduleId: string) => Promise<boolean>\n }\n}\n\nexport function register(container: AppContainer) {\n container.register({\n externalIdMappingService: asFunction(({ em }: Cradle) => createExternalIdMappingService(em)).scoped().proxy(),\n dataSyncRunService: asFunction(({ em }: Cradle) => createSyncRunService(em)).scoped().proxy(),\n dataSyncScheduleService: asFunction(({ em, schedulerService }: Cradle) => createSyncScheduleService(em, schedulerService)).scoped().proxy(),\n dataSyncEngine: asFunction(({ em, dataSyncRunService, integrationCredentialsService, integrationLogService, integrationStateService, progressService }: Cradle & {\n dataSyncRunService: ReturnType<typeof createSyncRunService>\n }) => createSyncEngine({\n em,\n syncRunService: dataSyncRunService,\n integrationCredentialsService,\n integrationLogService,\n integrationStateService,\n progressService,\n })).scoped().proxy(),\n\n SyncRun: asValue(SyncRun),\n SyncCursor: asValue(SyncCursor),\n SyncMapping: asValue(SyncMapping),\n SyncSchedule: asValue(SyncSchedule),\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,YAAY,eAAe;AAOpC,SAAS,YAAY,aAAa,SAAS,oBAAoB;AAC/D,SAAS,sCAAsC;AAC/C,SAAS,4BAA4B;AACrC,SAAS,iCAAiC;AAC1C,SAAS,wBAAwB;AAe1B,SAAS,SAAS,WAAyB;AAChD,YAAU,SAAS;AAAA,IACjB,0BAA0B,WAAW,CAAC,EAAE,GAAG,MAAc,+BAA+B,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAC5G,oBAAoB,WAAW,CAAC,EAAE,GAAG,MAAc,qBAAqB,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAC5F,yBAAyB,WAAW,CAAC,EAAE,IAAI,iBAAiB,MAAc,0BAA0B,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAC1I,gBAAgB,WAAW,CAAC,EAAE,IAAI,oBAAoB,+BAA+B,uBAAuB,yBAAyB,gBAAgB,MAE/I,iBAAiB;AAAA,MACrB;AAAA,MACA,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM;AAAA,IAEnB,SAAS,QAAQ,OAAO;AAAA,IACxB,YAAY,QAAQ,UAAU;AAAA,IAC9B,aAAa,QAAQ,WAAW;AAAA,IAChC,cAAc,QAAQ,YAAY;AAAA,EACpC,CAAC;AACH;",
6
6
  "names": []
7
7
  }