@open-mercato/core 0.6.6-develop.6176.1.4507b99c2f → 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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/auth/frontend/login.js +5 -5
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +3 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +26 -14
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +169 -149
- package/dist/modules/customers/api/deals/[id]/route.js.map +3 -3
- package/dist/modules/customers/components/detail/InlineEditors.js +9 -4
- package/dist/modules/customers/components/detail/InlineEditors.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +13 -9
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/detail-page-refresh.js +17 -0
- package/dist/modules/integrations/backend/integrations/detail-page-refresh.js.map +7 -0
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +299 -297
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/workflows/components/EdgeEditDialog.js +120 -141
- package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +114 -118
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +155 -260
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/frontend/login.tsx +5 -5
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +4 -3
- package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +27 -17
- package/src/modules/customers/api/deals/[id]/route.ts +208 -174
- package/src/modules/customers/components/detail/InlineEditors.tsx +6 -10
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +13 -9
- package/src/modules/integrations/backend/integrations/detail-page-refresh.ts +36 -0
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +351 -327
- package/src/modules/workflows/components/EdgeEditDialog.tsx +132 -157
- package/src/modules/workflows/components/NodeEditDialog.tsx +116 -121
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +172 -239
- package/src/modules/workflows/i18n/de.json +2 -0
- package/src/modules/workflows/i18n/en.json +2 -0
- package/src/modules/workflows/i18n/es.json +2 -0
- 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
|
|
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
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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());
|