@open-mercato/core 0.6.6-develop.6184.1.b7e55f8d61 → 0.6.6-develop.6198.1.0822f97cc6

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 (39) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/frontend/login.js +5 -5
  3. package/dist/modules/auth/frontend/login.js.map +2 -2
  4. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +3 -2
  5. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  6. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +26 -14
  7. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
  8. package/dist/modules/customers/api/deals/[id]/route.js +169 -149
  9. package/dist/modules/customers/api/deals/[id]/route.js.map +3 -3
  10. package/dist/modules/customers/components/detail/InlineEditors.js +9 -4
  11. package/dist/modules/customers/components/detail/InlineEditors.js.map +2 -2
  12. package/dist/modules/integrations/backend/integrations/[id]/page.js +13 -9
  13. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  14. package/dist/modules/integrations/backend/integrations/detail-page-refresh.js +17 -0
  15. package/dist/modules/integrations/backend/integrations/detail-page-refresh.js.map +7 -0
  16. package/dist/modules/sales/components/documents/SalesDocumentForm.js +299 -297
  17. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  18. package/dist/modules/workflows/components/EdgeEditDialog.js +120 -141
  19. package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
  20. package/dist/modules/workflows/components/NodeEditDialog.js +114 -118
  21. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  22. package/dist/modules/workflows/frontend/checkout-demo/page.js +155 -260
  23. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  24. package/package.json +7 -7
  25. package/src/modules/auth/frontend/login.tsx +5 -5
  26. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +4 -3
  27. package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +27 -17
  28. package/src/modules/customers/api/deals/[id]/route.ts +208 -174
  29. package/src/modules/customers/components/detail/InlineEditors.tsx +6 -10
  30. package/src/modules/integrations/backend/integrations/[id]/page.tsx +13 -9
  31. package/src/modules/integrations/backend/integrations/detail-page-refresh.ts +36 -0
  32. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +351 -327
  33. package/src/modules/workflows/components/EdgeEditDialog.tsx +132 -157
  34. package/src/modules/workflows/components/NodeEditDialog.tsx +116 -121
  35. package/src/modules/workflows/frontend/checkout-demo/page.tsx +172 -239
  36. package/src/modules/workflows/i18n/de.json +2 -0
  37. package/src/modules/workflows/i18n/en.json +2 -0
  38. package/src/modules/workflows/i18n/es.json +2 -0
  39. package/src/modules/workflows/i18n/pl.json +2 -0
@@ -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 ReactMarkdown from 'react-markdown'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport type { PluggableList } from 'unified'\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 remarkGfm from 'remark-gfm'\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\nconst MARKDOWN_PREVIEW_PLUGINS: PluggableList = [remarkGfm]\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 <div 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 <ReactMarkdown remarkPlugins={MARKDOWN_PREVIEW_PLUGINS}>\n {raw}\n </ReactMarkdown>\n </div>\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 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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",
6
6
  "names": []
7
7
  }
@@ -43,6 +43,10 @@ import {
43
43
  resolveIntegrationDetailWidgetSpotId,
44
44
  resolveRequestedIntegrationDetailTab
45
45
  } from "../detail-page-widgets.js";
46
+ import {
47
+ refreshIntegrationDetailPanels,
48
+ refreshIntegrationRunActivityPanels
49
+ } from "../detail-page-refresh.js";
46
50
  import { isValidCredentialUrl } from "../../../lib/credentials-field-validation.js";
47
51
  const UNSUPPORTED_CREDENTIAL_FIELD_TYPES = /* @__PURE__ */ new Set(["oauth", "ssh_keypair"]);
48
52
  function isEditableCredentialField(field) {
@@ -377,8 +381,7 @@ function IntegrationDetailPage({ params }) {
377
381
  spotId: detailWidgetSpotId
378
382
  });
379
383
  const refreshDetail = React.useCallback(async () => {
380
- await loadDetail({ showLoading: false });
381
- await loadCredentials();
384
+ await refreshIntegrationDetailPanels({ loadDetail, loadCredentials });
382
385
  }, [loadCredentials, loadDetail]);
383
386
  const refreshLogs = React.useCallback(async () => {
384
387
  await loadLogs();
@@ -395,13 +398,14 @@ function IntegrationDetailPage({ params }) {
395
398
  }
396
399
  if (options?.showLoading) setIsRefreshingRunActivity(true);
397
400
  try {
398
- const call = await apiCall(
399
- `/api/data_sync/runs/${encodeURIComponent(runIdFromUrl)}`,
400
- void 0,
401
- { fallback: null }
402
- );
403
- await loadLogs();
404
- await loadDetail({ showLoading: false });
401
+ const [call] = await Promise.all([
402
+ apiCall(
403
+ `/api/data_sync/runs/${encodeURIComponent(runIdFromUrl)}`,
404
+ void 0,
405
+ { fallback: null }
406
+ ),
407
+ refreshIntegrationRunActivityPanels({ loadLogs, loadDetail })
408
+ ]);
405
409
  if (call.ok && call.result) {
406
410
  setActiveRunDetail(call.result);
407
411
  setActiveRunRefreshedAt((/* @__PURE__ */ new Date()).toISOString());