@open-mercato/core 0.4.11-develop.1418.27a299bdaf → 0.4.11-develop.1446.d277f8b435
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/dist/modules/customers/backend/customers/deals/[id]/page.js +221 -226
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +1 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/package.json +3 -3
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -1
- package/src/modules/query_index/lib/engine.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/customers/backend/customers/deals/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Pencil, MousePointerClick } from 'lucide-react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { NotesSection, type SectionAction } from '@open-mercato/ui/backend/detail'\nimport { ActivitiesSection } from '../../../../components/detail/ActivitiesSection'\nimport { DealForm, type DealFormSubmitPayload } from '../../../../components/detail/DealForm'\nimport { useCustomerDictionary } from '../../../../components/detail/hooks/useCustomerDictionary'\nimport type { CustomerDictionaryMap } from '../../../../lib/dictionaries'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { renderDictionaryColor, renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { ICON_SUGGESTIONS } from '../../../../lib/dictionaries'\nimport { createCustomerNotesAdapter } from '../../../../components/detail/notesAdapter'\nimport { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '../../../../lib/markdownPreference'\n\ntype DealAssociation = {\n id: string\n label: string\n subtitle: string | null\n kind: 'person' | 'company'\n}\n\ntype DealDetailPayload = {\n deal: {\n id: string\n title: string\n description: string | null\n status: string | null\n pipelineStage: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: string | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: string | null\n ownerUserId: string | null\n source: string | null\n organizationId: string | null\n tenantId: string | null\n createdAt: string\n updatedAt: string\n }\n people: DealAssociation[]\n companies: DealAssociation[]\n customFields: Record<string, unknown>\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\nconst CRUD_FOCUSABLE_SELECTOR =\n '[data-crud-focus-target], input:not([type=\"hidden\"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction formatCurrency(amount: string | null, currency: string | null): string | null {\n if (!amount) return null\n const value = Number(amount)\n if (!Number.isFinite(value)) return currency ? `${amount} ${currency}` : amount\n if (!currency) return value.toLocaleString()\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(value)\n } catch {\n return `${value.toLocaleString()} ${currency}`\n }\n}\n\nfunction formatDate(value: string | null, fallback: string): string {\n if (!value) return fallback\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return fallback\n return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })\n}\n\nfunction resolveDictionaryLabel(\n value: string | null | undefined,\n map: CustomerDictionaryMap | null | undefined,\n): string | null {\n if (!value) return null\n const entry = map?.[value]\n if (entry && entry.label && entry.label.length) return entry.label\n return value\n}\n\nexport default function DealDetailPage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n const notesAdapter = React.useMemo(() => createCustomerNotesAdapter(detailTranslator), [detailTranslator])\n const router = useRouter()\n const id = params?.id ?? ''\n const scopeVersion = useOrganizationScopeVersion()\n const statusDictionaryQuery = useCustomerDictionary('deal-statuses', scopeVersion)\n const pipelineDictionaryQuery = useCustomerDictionary('pipeline-stages', scopeVersion)\n const statusDictionaryMap = statusDictionaryQuery.data?.map ?? null\n const pipelineDictionaryMap = pipelineDictionaryQuery.data?.map ?? null\n const [data, setData] = React.useState<DealDetailPayload | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isSaving, setIsSaving] = React.useState(false)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [activeTab, setActiveTab] = React.useState<'notes' | 'activities'>('notes')\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const handleNotesLoadingChange = React.useCallback(() => {}, [])\n const handleActivitiesLoadingChange = React.useCallback(() => {}, [])\n const focusDealField = React.useCallback(\n (fieldId: 'title' | 'personIds' | 'companyIds') => {\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n const focusOnce = () => {\n const container = document.querySelector<HTMLElement>(`[data-crud-field-id=\"${fieldId}\"]`)\n if (!container) return false\n const target =\n container.querySelector<HTMLElement>(CRUD_FOCUSABLE_SELECTOR) ?? container\n if (!target || typeof target.focus !== 'function') return false\n if (typeof container.scrollIntoView === 'function') {\n container.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n target.focus()\n if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {\n try {\n target.select()\n } catch {}\n }\n return true\n }\n\n const schedule = () => {\n const focused = focusOnce()\n if (focused) return\n window.setTimeout(() => {\n focusOnce()\n }, 60)\n }\n\n if (typeof window.requestAnimationFrame === 'function') {\n window.requestAnimationFrame(schedule)\n } else {\n schedule()\n }\n },\n [],\n )\n const dealSettingsRef = React.useRef<HTMLDivElement | null>(null)\n const scrollToDealSettings = React.useCallback(() => {\n if (typeof window === 'undefined') return\n if (dealSettingsRef.current && typeof dealSettingsRef.current.scrollIntoView === 'function') {\n dealSettingsRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' })\n }\n window.setTimeout(() => {\n focusDealField('title')\n }, 160)\n }, [focusDealField])\n\n React.useEffect(() => {\n if (!id) {\n setError(t('customers.deals.detail.missingId', 'Deal id is required.'))\n setIsLoading(false)\n return\n }\n let cancelled = false\n async function loadDeal() {\n setIsLoading(true)\n setError(null)\n try {\n const payload = await readApiResultOrThrow<DealDetailPayload>(\n `/api/customers/deals/${encodeURIComponent(id)}`,\n undefined,\n { errorMessage: t('customers.deals.detail.loadError', 'Failed to load deal.') },\n )\n if (cancelled) return\n setData(payload as DealDetailPayload)\n } catch (err) {\n if (cancelled) return\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.detail.loadError', 'Failed to load deal.')\n setError(message)\n setData(null)\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n loadDeal().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [id, reloadToken, t])\n\n const handleFormSubmit = React.useCallback(\n async ({ base, custom }: DealFormSubmitPayload) => {\n if (!data || isSaving) return\n setIsSaving(true)\n try {\n const payload: Record<string, unknown> = {\n id: data.deal.id,\n title: base.title,\n status: base.status ?? undefined,\n pipelineStage: base.pipelineStage ?? undefined,\n pipelineId: base.pipelineId ?? undefined,\n pipelineStageId: base.pipelineStageId ?? undefined,\n valueAmount: typeof base.valueAmount === 'number' ? base.valueAmount : undefined,\n valueCurrency: base.valueCurrency ?? undefined,\n probability: typeof base.probability === 'number' ? base.probability : undefined,\n expectedCloseAt: base.expectedCloseAt ?? undefined,\n description: base.description ?? undefined,\n personIds: base.personIds && base.personIds.length ? base.personIds : undefined,\n companyIds: base.companyIds && base.companyIds.length ? base.companyIds : undefined,\n }\n if (Object.keys(custom).length) payload.customFields = custom\n\n await apiCallOrThrow(\n '/api/customers/deals',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: t('customers.deals.detail.saveError', 'Failed to update deal.') },\n )\n flash(t('customers.deals.detail.saveSuccess', 'Deal updated.'), 'success')\n setReloadToken((token) => token + 1)\n } catch (err) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.detail.saveError', 'Failed to update deal.')\n flash(message, 'error')\n throw err instanceof Error ? err : new Error(message)\n } finally {\n setIsSaving(false)\n }\n },\n [data, isSaving, t],\n )\n\n const handleDelete = React.useCallback(async () => {\n if (!data || isDeleting) return\n const confirmed = await confirm({\n title: t(\n 'customers.deals.detail.deleteConfirm',\n 'Delete this deal? This action cannot be undone.',\n ),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n setIsDeleting(true)\n try {\n await apiCallOrThrow(\n '/api/customers/deals',\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: data.deal.id }),\n },\n { errorMessage: t('customers.deals.detail.deleteError', 'Failed to delete deal.') },\n )\n flash(t('customers.deals.detail.deleteSuccess', 'Deal deleted.'), 'success')\n router.push('/backend/customers/deals')\n } catch (err) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.detail.deleteError', 'Failed to delete deal.')\n flash(message, 'error')\n } finally {\n setIsDeleting(false)\n }\n }, [confirm, data, isDeleting, router, t])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n const handleSectionAction = React.useCallback(() => {\n if (!sectionAction || sectionAction.disabled) return\n sectionAction.onClick()\n }, [sectionAction])\n\n const dealOptions = React.useMemo(\n () =>\n data\n ? [\n {\n id: data.deal.id,\n label:\n data.deal.title && data.deal.title.length\n ? data.deal.title\n : t('customers.deals.detail.untitled', 'Untitled deal'),\n },\n ]\n : [],\n [data, t],\n )\n\n const entityOptions = React.useMemo(() => {\n if (!data) return []\n const entries: { id: string; label: string }[] = []\n data.people.forEach((person) => {\n if (!person.id) return\n const suffix = person.subtitle ? ` \u00B7 ${person.subtitle}` : ''\n entries.push({ id: person.id, label: `${person.label}${suffix}` })\n })\n data.companies.forEach((company) => {\n if (!company.id) return\n const suffix = company.subtitle ? ` \u00B7 ${company.subtitle}` : ''\n entries.push({ id: company.id, label: `${company.label}${suffix}` })\n })\n return entries\n }, [data])\n\n const defaultEntityId = React.useMemo(() => {\n if (entityOptions.length) return entityOptions[0].id\n return null\n }, [entityOptions])\n\n const tabs = React.useMemo(\n () => [\n { id: 'notes' as const, label: t('customers.deals.detail.tabs.notes', 'Notes') },\n { id: 'activities' as const, label: t('customers.deals.detail.tabs.activities', 'Activities') },\n ],\n [t],\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('customers.deals.detail.loading', 'Loading deal\u2026')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-3 text-muted-foreground\">\n <p>{error || t('customers.deals.detail.notFound', 'Deal not found.')}</p>\n <Button variant=\"outline\" asChild>\n <Link href=\"/backend/customers/deals\">\n {t('customers.deals.detail.backToList', 'Back to deals')}\n </Link>\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const probabilityLabel = data.deal.probability !== null && data.deal.probability !== undefined\n ? `${data.deal.probability}%`\n : t('customers.deals.detail.noValue', 'Not provided')\n const valueLabel =\n formatCurrency(data.deal.valueAmount, data.deal.valueCurrency) ??\n t('customers.deals.detail.noValue', 'Not provided')\n const expectedCloseLabel = formatDate(data.deal.expectedCloseAt, t('customers.deals.detail.noValue', 'Not provided'))\n const statusLabel =\n resolveDictionaryLabel(data.deal.status, statusDictionaryMap) ??\n t('customers.deals.detail.noStatus', 'No status')\n const statusDictEntry = data.deal.status ? statusDictionaryMap?.[data.deal.status] ?? null : null\n const pipelineLabel = resolveDictionaryLabel(data.deal.pipelineStage, pipelineDictionaryMap)\n const pipelineDictEntry = data.deal.pipelineStage ? pipelineDictionaryMap?.[data.deal.pipelineStage] ?? null : null\n const previewValueAmount = formatCurrency(data.deal.valueAmount, data.deal.valueCurrency)\n const previewProbability = data.deal.probability !== null && data.deal.probability !== undefined\n ? `${data.deal.probability}%`\n : null\n const dealPreviewMetadata: Record<string, string> = {}\n if (previewValueAmount) dealPreviewMetadata[t('customers.deals.detail.fields.value')] = previewValueAmount\n if (previewProbability) dealPreviewMetadata[t('customers.deals.detail.fields.probability')] = previewProbability\n\n const peopleSummaryLabel =\n data.people.length === 1\n ? t('customers.deals.detail.peopleSummaryOne')\n : t('customers.deals.detail.peopleSummaryMany', undefined, { count: data.people.length })\n const companiesSummaryLabel =\n data.companies.length === 1\n ? t('customers.deals.detail.companiesSummaryOne')\n : t('customers.deals.detail.companiesSummaryMany', undefined, { count: data.companies.length })\n\n const viewer = data.viewer ?? null\n\n return (\n <Page>\n <PageBody>Piotr nie jest pizd\u0105, tylko zajebistym go\u015Bciem, kt\u00F3ry robi \u015Bwietn\u0105 robot\u0119 w Mercato i jest super mi\u0142y dla wszystkich dooko\u0142a. Dzi\u0119ki Piotrze za wszystko co robisz! <br/><br/>\n <div className=\"flex flex-col gap-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/deals\"\n backLabel={t('customers.deals.detail.backToList', 'Back to deals')}\n utilityActions={(\n <>\n <SendObjectMessageDialog\n object={{\n entityModule: 'customers',\n entityType: 'deal',\n entityId: data.deal.id,\n sourceEntityType: 'customers.deal',\n sourceEntityId: data.deal.id,\n previewData: {\n title: data.deal.title || t('customers.deals.detail.untitled', 'Untitled deal'),\n status: data.deal.status ? statusLabel : undefined,\n metadata: Object.keys(dealPreviewMetadata).length > 0 ? dealPreviewMetadata : undefined,\n },\n }}\n viewHref={`/backend/customers/deals/${data.deal.id}`}\n defaultValues={{\n sourceEntityType: 'customers.deal',\n sourceEntityId: data.deal.id,\n }}\n />\n <VersionHistoryAction\n config={{ resourceKind: 'customers.deal', resourceId: data.deal.id }}\n t={t}\n />\n </>\n )}\n title={\n <div className=\"flex flex-wrap items-center gap-2\">\n <span>{data.deal.title || t('customers.deals.detail.untitled', 'Untitled deal')}</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"gap-1 text-muted-foreground hover:text-foreground\"\n onClick={scrollToDealSettings}\n >\n <Pencil className=\"h-4 w-4\" aria-hidden />\n <MousePointerClick className=\"h-4 w-4\" aria-hidden />\n <span>{t('customers.deals.detail.goToSettings', 'Edit deal details')}</span>\n </Button>\n </div>\n }\n subtitle={t('customers.deals.detail.summary', undefined, {\n status: statusLabel,\n pipeline: pipelineLabel ?? t('customers.deals.detail.noPipeline', 'No pipeline'),\n })}\n onDelete={handleDelete}\n isDeleting={isDeleting}\n deleteLabel={t('ui.actions.delete', 'Delete')}\n />\n <div className=\"grid gap-6 lg:grid-cols-[minmax(0,2fr),minmax(0,1.1fr)]\">\n <div className=\"space-y-6\">\n <div className=\"rounded-lg border bg-card p-4\">\n <h2 className=\"mb-4 text-sm font-semibold uppercase text-muted-foreground\">\n {t('customers.deals.detail.highlights', 'Highlights')}\n </h2>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.value', 'Deal value')}\n </p>\n <p className=\"text-base font-semibold text-foreground\">{valueLabel}</p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.probability', 'Probability')}\n </p>\n <p className=\"text-base font-semibold text-foreground\">{probabilityLabel}</p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.status', 'Status')}\n </p>\n <p className=\"text-base text-foreground flex items-center gap-2\">\n {statusDictEntry?.color ? renderDictionaryColor(statusDictEntry.color) : null}\n {statusDictEntry?.icon ? renderDictionaryIcon(statusDictEntry.icon) : null}\n {statusLabel}\n </p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.pipeline', 'Pipeline stage')}\n </p>\n <p className=\"text-base text-foreground flex items-center gap-2\">\n {pipelineDictEntry?.color ? renderDictionaryColor(pipelineDictEntry.color) : null}\n {pipelineDictEntry?.icon ? renderDictionaryIcon(pipelineDictEntry.icon) : null}\n {pipelineLabel ?? t('customers.deals.detail.noValue', 'Not provided')}\n </p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.expectedClose', 'Expected close')}\n </p>\n <p className=\"text-base text-foreground\">{expectedCloseLabel}</p>\n </div>\n </div>\n </div>\n\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex gap-2\">\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setActiveTab(tab.id)}\n className={`h-auto rounded-none border-b-2 px-0 py-1 ${\n activeTab === tab.id\n ? 'border-primary text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent'\n }`}\n >\n {tab.label}\n </Button>\n ))}\n </div>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={sectionAction.disabled}\n onClick={handleSectionAction}\n >\n {sectionAction.icon ?? null}\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n {activeTab === 'notes' ? (\n <NotesSection\n entityId={null}\n dealId={data.deal.id}\n dealOptions={dealOptions}\n entityOptions={entityOptions}\n emptyLabel={t('customers.deals.detail.notesEmpty', 'No notes yet.')}\n viewerUserId={viewer?.userId ?? null}\n viewerName={viewer?.name ?? null}\n viewerEmail={viewer?.email ?? null}\n addActionLabel={t('customers.deals.detail.notesAdd', 'Add note')}\n emptyState={{\n title: t('customers.deals.detail.notesEmptyTitle', 'Keep everyone in the loop'),\n actionLabel: t('customers.deals.detail.notesEmptyAction', 'Add a note'),\n }}\n onActionChange={setSectionAction}\n translator={detailTranslator}\n onLoadingChange={handleNotesLoadingChange}\n dataAdapter={notesAdapter}\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n iconSuggestions={ICON_SUGGESTIONS}\n readMarkdownPreference={readMarkdownPreferenceCookie}\n writeMarkdownPreference={writeMarkdownPreferenceCookie}\n />\n ) : null}\n {activeTab === 'activities' ? (\n <ActivitiesSection\n entityId={null}\n dealId={data.deal.id}\n dealOptions={dealOptions}\n entityOptions={entityOptions}\n defaultEntityId={defaultEntityId ?? undefined}\n addActionLabel={t('customers.deals.detail.activitiesAdd', 'Log activity')}\n emptyState={{\n title: t('customers.deals.detail.activitiesEmptyTitle', 'No activities yet'),\n actionLabel: t('customers.deals.detail.activitiesEmptyAction', 'Add an activity'),\n }}\n onActionChange={setSectionAction}\n onLoadingChange={handleActivitiesLoadingChange}\n />\n ) : null}\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"mb-3 space-y-1\">\n <h3 className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.peopleSection', 'People')}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {peopleSummaryLabel}\n </p>\n </div>\n {data.people.length ? (\n <ul className=\"space-y-2 text-sm\">\n {data.people.map((person) => (\n <li key={person.id} className=\"flex flex-col gap-1\">\n <Link href={`/backend/customers/people-v2/${encodeURIComponent(person.id)}`} className=\"font-medium text-foreground hover:underline\">\n {person.label}\n </Link>\n <span className=\"text-xs text-muted-foreground\">\n {person.subtitle ?? t('customers.deals.detail.peopleNoDetails', 'No additional details')}\n </span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.deals.detail.noPeople', 'No people linked to this deal yet.')}\n </p>\n )}\n </div>\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"mb-3 space-y-1\">\n <h3 className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.companiesSection', 'Companies')}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {companiesSummaryLabel}\n </p>\n </div>\n {data.companies.length ? (\n <ul className=\"space-y-2 text-sm\">\n {data.companies.map((company) => (\n <li key={company.id} className=\"flex flex-col gap-1\">\n <Link href={`/backend/customers/companies-v2/${encodeURIComponent(company.id)}`} className=\"font-medium text-foreground hover:underline\">\n {company.label}\n </Link>\n <span className=\"text-xs text-muted-foreground\">\n {company.subtitle ?? t('customers.deals.detail.companiesNoDetails', 'No additional details')}\n </span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.deals.detail.noCompanies', 'No companies linked to this deal yet.')}\n </p>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"space-y-6\">\n <div\n ref={dealSettingsRef}\n id=\"deal-settings\"\n className=\"rounded-lg border bg-card p-4\"\n >\n <h2 className=\"mb-4 text-sm font-semibold uppercase text-muted-foreground\">\n {t('customers.deals.detail.formTitle', 'Deal settings')}\n </h2>\n <DealForm\n key={data.deal.updatedAt}\n mode=\"edit\"\n initialValues={{\n id: data.deal.id,\n title: data.deal.title ?? '',\n status: data.deal.status ?? '',\n pipelineStage: data.deal.pipelineStage ?? '',\n pipelineId: data.deal.pipelineId ?? '',\n pipelineStageId: data.deal.pipelineStageId ?? '',\n valueAmount: data.deal.valueAmount ? Number(data.deal.valueAmount) : null,\n valueCurrency: data.deal.valueCurrency ?? undefined,\n probability: data.deal.probability ?? null,\n expectedCloseAt: data.deal.expectedCloseAt ?? null,\n description: data.deal.description ?? '',\n personIds: data.people.map((person) => person.id),\n companyIds: data.companies.map((company) => company.id),\n people: data.people.map((person) => ({ id: person.id, label: person.label })),\n companies: data.companies.map((company) => ({ id: company.id, label: company.label })),\n ...Object.fromEntries(\n Object.entries(data.customFields)\n .filter(([key]) => key.startsWith('cf_'))\n .map(([key, value]) => [key, value]),\n ),\n }}\n onSubmit={handleFormSubmit}\n onCancel={() => setReloadToken((token) => token + 1)}\n onDelete={handleDelete}\n isSubmitting={isSaving || isDeleting}\n />\n </div>\n </div>\n </div>\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Pencil, MousePointerClick } from 'lucide-react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { NotesSection, type SectionAction } from '@open-mercato/ui/backend/detail'\nimport { ActivitiesSection } from '../../../../components/detail/ActivitiesSection'\nimport { DealForm, type DealFormSubmitPayload } from '../../../../components/detail/DealForm'\nimport { useCustomerDictionary } from '../../../../components/detail/hooks/useCustomerDictionary'\nimport type { CustomerDictionaryMap } from '../../../../lib/dictionaries'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { renderDictionaryColor, renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { ICON_SUGGESTIONS } from '../../../../lib/dictionaries'\nimport { createCustomerNotesAdapter } from '../../../../components/detail/notesAdapter'\nimport { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '../../../../lib/markdownPreference'\n\ntype DealAssociation = {\n id: string\n label: string\n subtitle: string | null\n kind: 'person' | 'company'\n}\n\ntype DealDetailPayload = {\n deal: {\n id: string\n title: string\n description: string | null\n status: string | null\n pipelineStage: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: string | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: string | null\n ownerUserId: string | null\n source: string | null\n organizationId: string | null\n tenantId: string | null\n createdAt: string\n updatedAt: string\n }\n people: DealAssociation[]\n companies: DealAssociation[]\n customFields: Record<string, unknown>\n viewer?: {\n userId: string | null\n name?: string | null\n email?: string | null\n } | null\n}\n\nconst CRUD_FOCUSABLE_SELECTOR =\n '[data-crud-focus-target], input:not([type=\"hidden\"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction formatCurrency(amount: string | null, currency: string | null): string | null {\n if (!amount) return null\n const value = Number(amount)\n if (!Number.isFinite(value)) return currency ? `${amount} ${currency}` : amount\n if (!currency) return value.toLocaleString()\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(value)\n } catch {\n return `${value.toLocaleString()} ${currency}`\n }\n}\n\nfunction formatDate(value: string | null, fallback: string): string {\n if (!value) return fallback\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return fallback\n return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })\n}\n\nfunction resolveDictionaryLabel(\n value: string | null | undefined,\n map: CustomerDictionaryMap | null | undefined,\n): string | null {\n if (!value) return null\n const entry = map?.[value]\n if (entry && entry.label && entry.label.length) return entry.label\n return value\n}\n\nexport default function DealDetailPage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n const notesAdapter = React.useMemo(() => createCustomerNotesAdapter(detailTranslator), [detailTranslator])\n const router = useRouter()\n const id = params?.id ?? ''\n const scopeVersion = useOrganizationScopeVersion()\n const statusDictionaryQuery = useCustomerDictionary('deal-statuses', scopeVersion)\n const pipelineDictionaryQuery = useCustomerDictionary('pipeline-stages', scopeVersion)\n const statusDictionaryMap = statusDictionaryQuery.data?.map ?? null\n const pipelineDictionaryMap = pipelineDictionaryQuery.data?.map ?? null\n const [data, setData] = React.useState<DealDetailPayload | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isSaving, setIsSaving] = React.useState(false)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [activeTab, setActiveTab] = React.useState<'notes' | 'activities'>('notes')\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const handleNotesLoadingChange = React.useCallback(() => {}, [])\n const handleActivitiesLoadingChange = React.useCallback(() => {}, [])\n const focusDealField = React.useCallback(\n (fieldId: 'title' | 'personIds' | 'companyIds') => {\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n const focusOnce = () => {\n const container = document.querySelector<HTMLElement>(`[data-crud-field-id=\"${fieldId}\"]`)\n if (!container) return false\n const target =\n container.querySelector<HTMLElement>(CRUD_FOCUSABLE_SELECTOR) ?? container\n if (!target || typeof target.focus !== 'function') return false\n if (typeof container.scrollIntoView === 'function') {\n container.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n target.focus()\n if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {\n try {\n target.select()\n } catch {}\n }\n return true\n }\n\n const schedule = () => {\n const focused = focusOnce()\n if (focused) return\n window.setTimeout(() => {\n focusOnce()\n }, 60)\n }\n\n if (typeof window.requestAnimationFrame === 'function') {\n window.requestAnimationFrame(schedule)\n } else {\n schedule()\n }\n },\n [],\n )\n const dealSettingsRef = React.useRef<HTMLDivElement | null>(null)\n const scrollToDealSettings = React.useCallback(() => {\n if (typeof window === 'undefined') return\n if (dealSettingsRef.current && typeof dealSettingsRef.current.scrollIntoView === 'function') {\n dealSettingsRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' })\n }\n window.setTimeout(() => {\n focusDealField('title')\n }, 160)\n }, [focusDealField])\n\n React.useEffect(() => {\n if (!id) {\n setError(t('customers.deals.detail.missingId', 'Deal id is required.'))\n setIsLoading(false)\n return\n }\n let cancelled = false\n async function loadDeal() {\n setIsLoading(true)\n setError(null)\n try {\n const payload = await readApiResultOrThrow<DealDetailPayload>(\n `/api/customers/deals/${encodeURIComponent(id)}`,\n undefined,\n { errorMessage: t('customers.deals.detail.loadError', 'Failed to load deal.') },\n )\n if (cancelled) return\n setData(payload as DealDetailPayload)\n } catch (err) {\n if (cancelled) return\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.detail.loadError', 'Failed to load deal.')\n setError(message)\n setData(null)\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n loadDeal().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [id, reloadToken, t])\n\n const handleFormSubmit = React.useCallback(\n async ({ base, custom }: DealFormSubmitPayload) => {\n if (!data || isSaving) return\n setIsSaving(true)\n try {\n const payload: Record<string, unknown> = {\n id: data.deal.id,\n title: base.title,\n status: base.status ?? undefined,\n pipelineStage: base.pipelineStage ?? undefined,\n pipelineId: base.pipelineId ?? undefined,\n pipelineStageId: base.pipelineStageId ?? undefined,\n valueAmount: typeof base.valueAmount === 'number' ? base.valueAmount : undefined,\n valueCurrency: base.valueCurrency ?? undefined,\n probability: typeof base.probability === 'number' ? base.probability : undefined,\n expectedCloseAt: base.expectedCloseAt ?? undefined,\n description: base.description ?? undefined,\n personIds: base.personIds && base.personIds.length ? base.personIds : undefined,\n companyIds: base.companyIds && base.companyIds.length ? base.companyIds : undefined,\n }\n if (Object.keys(custom).length) payload.customFields = custom\n\n await apiCallOrThrow(\n '/api/customers/deals',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: t('customers.deals.detail.saveError', 'Failed to update deal.') },\n )\n flash(t('customers.deals.detail.saveSuccess', 'Deal updated.'), 'success')\n setReloadToken((token) => token + 1)\n } catch (err) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.detail.saveError', 'Failed to update deal.')\n flash(message, 'error')\n throw err instanceof Error ? err : new Error(message)\n } finally {\n setIsSaving(false)\n }\n },\n [data, isSaving, t],\n )\n\n const handleDelete = React.useCallback(async () => {\n if (!data || isDeleting) return\n const confirmed = await confirm({\n title: t(\n 'customers.deals.detail.deleteConfirm',\n 'Delete this deal? This action cannot be undone.',\n ),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n setIsDeleting(true)\n try {\n await apiCallOrThrow(\n '/api/customers/deals',\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: data.deal.id }),\n },\n { errorMessage: t('customers.deals.detail.deleteError', 'Failed to delete deal.') },\n )\n flash(t('customers.deals.detail.deleteSuccess', 'Deal deleted.'), 'success')\n router.push('/backend/customers/deals')\n } catch (err) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.detail.deleteError', 'Failed to delete deal.')\n flash(message, 'error')\n } finally {\n setIsDeleting(false)\n }\n }, [confirm, data, isDeleting, router, t])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n const handleSectionAction = React.useCallback(() => {\n if (!sectionAction || sectionAction.disabled) return\n sectionAction.onClick()\n }, [sectionAction])\n\n const dealOptions = React.useMemo(\n () =>\n data\n ? [\n {\n id: data.deal.id,\n label:\n data.deal.title && data.deal.title.length\n ? data.deal.title\n : t('customers.deals.detail.untitled', 'Untitled deal'),\n },\n ]\n : [],\n [data, t],\n )\n\n const entityOptions = React.useMemo(() => {\n if (!data) return []\n const entries: { id: string; label: string }[] = []\n data.people.forEach((person) => {\n if (!person.id) return\n const suffix = person.subtitle ? ` \u00B7 ${person.subtitle}` : ''\n entries.push({ id: person.id, label: `${person.label}${suffix}` })\n })\n data.companies.forEach((company) => {\n if (!company.id) return\n const suffix = company.subtitle ? ` \u00B7 ${company.subtitle}` : ''\n entries.push({ id: company.id, label: `${company.label}${suffix}` })\n })\n return entries\n }, [data])\n\n const defaultEntityId = React.useMemo(() => {\n if (entityOptions.length) return entityOptions[0].id\n return null\n }, [entityOptions])\n\n const tabs = React.useMemo(\n () => [\n { id: 'notes' as const, label: t('customers.deals.detail.tabs.notes', 'Notes') },\n { id: 'activities' as const, label: t('customers.deals.detail.tabs.activities', 'Activities') },\n ],\n [t],\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('customers.deals.detail.loading', 'Loading deal\u2026')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-3 text-muted-foreground\">\n <p>{error || t('customers.deals.detail.notFound', 'Deal not found.')}</p>\n <Button variant=\"outline\" asChild>\n <Link href=\"/backend/customers/deals\">\n {t('customers.deals.detail.backToList', 'Back to deals')}\n </Link>\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const probabilityLabel = data.deal.probability !== null && data.deal.probability !== undefined\n ? `${data.deal.probability}%`\n : t('customers.deals.detail.noValue', 'Not provided')\n const valueLabel =\n formatCurrency(data.deal.valueAmount, data.deal.valueCurrency) ??\n t('customers.deals.detail.noValue', 'Not provided')\n const expectedCloseLabel = formatDate(data.deal.expectedCloseAt, t('customers.deals.detail.noValue', 'Not provided'))\n const statusLabel =\n resolveDictionaryLabel(data.deal.status, statusDictionaryMap) ??\n t('customers.deals.detail.noStatus', 'No status')\n const statusDictEntry = data.deal.status ? statusDictionaryMap?.[data.deal.status] ?? null : null\n const pipelineLabel = resolveDictionaryLabel(data.deal.pipelineStage, pipelineDictionaryMap)\n const pipelineDictEntry = data.deal.pipelineStage ? pipelineDictionaryMap?.[data.deal.pipelineStage] ?? null : null\n const previewValueAmount = formatCurrency(data.deal.valueAmount, data.deal.valueCurrency)\n const previewProbability = data.deal.probability !== null && data.deal.probability !== undefined\n ? `${data.deal.probability}%`\n : null\n const dealPreviewMetadata: Record<string, string> = {}\n if (previewValueAmount) dealPreviewMetadata[t('customers.deals.detail.fields.value')] = previewValueAmount\n if (previewProbability) dealPreviewMetadata[t('customers.deals.detail.fields.probability')] = previewProbability\n\n const peopleSummaryLabel =\n data.people.length === 1\n ? t('customers.deals.detail.peopleSummaryOne')\n : t('customers.deals.detail.peopleSummaryMany', undefined, { count: data.people.length })\n const companiesSummaryLabel =\n data.companies.length === 1\n ? t('customers.deals.detail.companiesSummaryOne')\n : t('customers.deals.detail.companiesSummaryMany', undefined, { count: data.companies.length })\n\n const viewer = data.viewer ?? null\n\n return (\n <Page>\n <PageBody>\n <div className=\"flex flex-col gap-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/deals\"\n backLabel={t('customers.deals.detail.backToList', 'Back to deals')}\n utilityActions={(\n <>\n <SendObjectMessageDialog\n object={{\n entityModule: 'customers',\n entityType: 'deal',\n entityId: data.deal.id,\n sourceEntityType: 'customers.deal',\n sourceEntityId: data.deal.id,\n previewData: {\n title: data.deal.title || t('customers.deals.detail.untitled', 'Untitled deal'),\n status: data.deal.status ? statusLabel : undefined,\n metadata: Object.keys(dealPreviewMetadata).length > 0 ? dealPreviewMetadata : undefined,\n },\n }}\n viewHref={`/backend/customers/deals/${data.deal.id}`}\n defaultValues={{\n sourceEntityType: 'customers.deal',\n sourceEntityId: data.deal.id,\n }}\n />\n <VersionHistoryAction\n config={{ resourceKind: 'customers.deal', resourceId: data.deal.id }}\n t={t}\n />\n </>\n )}\n title={\n <div className=\"flex flex-wrap items-center gap-2\">\n <span>{data.deal.title || t('customers.deals.detail.untitled', 'Untitled deal')}</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"gap-1 text-muted-foreground hover:text-foreground\"\n onClick={scrollToDealSettings}\n >\n <Pencil className=\"h-4 w-4\" aria-hidden />\n <MousePointerClick className=\"h-4 w-4\" aria-hidden />\n <span>{t('customers.deals.detail.goToSettings', 'Edit deal details')}</span>\n </Button>\n </div>\n }\n subtitle={t('customers.deals.detail.summary', undefined, {\n status: statusLabel,\n pipeline: pipelineLabel ?? t('customers.deals.detail.noPipeline', 'No pipeline'),\n })}\n onDelete={handleDelete}\n isDeleting={isDeleting}\n deleteLabel={t('ui.actions.delete', 'Delete')}\n />\n <div className=\"grid gap-6 lg:grid-cols-[minmax(0,2fr),minmax(0,1.1fr)]\">\n <div className=\"space-y-6\">\n <div className=\"rounded-lg border bg-card p-4\">\n <h2 className=\"mb-4 text-sm font-semibold uppercase text-muted-foreground\">\n {t('customers.deals.detail.highlights', 'Highlights')}\n </h2>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.value', 'Deal value')}\n </p>\n <p className=\"text-base font-semibold text-foreground\">{valueLabel}</p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.probability', 'Probability')}\n </p>\n <p className=\"text-base font-semibold text-foreground\">{probabilityLabel}</p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.status', 'Status')}\n </p>\n <p className=\"text-base text-foreground flex items-center gap-2\">\n {statusDictEntry?.color ? renderDictionaryColor(statusDictEntry.color) : null}\n {statusDictEntry?.icon ? renderDictionaryIcon(statusDictEntry.icon) : null}\n {statusLabel}\n </p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.pipeline', 'Pipeline stage')}\n </p>\n <p className=\"text-base text-foreground flex items-center gap-2\">\n {pipelineDictEntry?.color ? renderDictionaryColor(pipelineDictEntry.color) : null}\n {pipelineDictEntry?.icon ? renderDictionaryIcon(pipelineDictEntry.icon) : null}\n {pipelineLabel ?? t('customers.deals.detail.noValue', 'Not provided')}\n </p>\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase text-muted-foreground\">\n {t('customers.deals.detail.fields.expectedClose', 'Expected close')}\n </p>\n <p className=\"text-base text-foreground\">{expectedCloseLabel}</p>\n </div>\n </div>\n </div>\n\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex gap-2\">\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setActiveTab(tab.id)}\n className={`h-auto rounded-none border-b-2 px-0 py-1 ${\n activeTab === tab.id\n ? 'border-primary text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent'\n }`}\n >\n {tab.label}\n </Button>\n ))}\n </div>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={sectionAction.disabled}\n onClick={handleSectionAction}\n >\n {sectionAction.icon ?? null}\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n {activeTab === 'notes' ? (\n <NotesSection\n entityId={null}\n dealId={data.deal.id}\n dealOptions={dealOptions}\n entityOptions={entityOptions}\n emptyLabel={t('customers.deals.detail.notesEmpty', 'No notes yet.')}\n viewerUserId={viewer?.userId ?? null}\n viewerName={viewer?.name ?? null}\n viewerEmail={viewer?.email ?? null}\n addActionLabel={t('customers.deals.detail.notesAdd', 'Add note')}\n emptyState={{\n title: t('customers.deals.detail.notesEmptyTitle', 'Keep everyone in the loop'),\n actionLabel: t('customers.deals.detail.notesEmptyAction', 'Add a note'),\n }}\n onActionChange={setSectionAction}\n translator={detailTranslator}\n onLoadingChange={handleNotesLoadingChange}\n dataAdapter={notesAdapter}\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n iconSuggestions={ICON_SUGGESTIONS}\n readMarkdownPreference={readMarkdownPreferenceCookie}\n writeMarkdownPreference={writeMarkdownPreferenceCookie}\n />\n ) : null}\n {activeTab === 'activities' ? (\n <ActivitiesSection\n entityId={null}\n dealId={data.deal.id}\n dealOptions={dealOptions}\n entityOptions={entityOptions}\n defaultEntityId={defaultEntityId ?? undefined}\n addActionLabel={t('customers.deals.detail.activitiesAdd', 'Log activity')}\n emptyState={{\n title: t('customers.deals.detail.activitiesEmptyTitle', 'No activities yet'),\n actionLabel: t('customers.deals.detail.activitiesEmptyAction', 'Add an activity'),\n }}\n onActionChange={setSectionAction}\n onLoadingChange={handleActivitiesLoadingChange}\n />\n ) : null}\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"mb-3 space-y-1\">\n <h3 className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.peopleSection', 'People')}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {peopleSummaryLabel}\n </p>\n </div>\n {data.people.length ? (\n <ul className=\"space-y-2 text-sm\">\n {data.people.map((person) => (\n <li key={person.id} className=\"flex flex-col gap-1\">\n <Link href={`/backend/customers/people-v2/${encodeURIComponent(person.id)}`} className=\"font-medium text-foreground hover:underline\">\n {person.label}\n </Link>\n <span className=\"text-xs text-muted-foreground\">\n {person.subtitle ?? t('customers.deals.detail.peopleNoDetails', 'No additional details')}\n </span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.deals.detail.noPeople', 'No people linked to this deal yet.')}\n </p>\n )}\n </div>\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"mb-3 space-y-1\">\n <h3 className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.companiesSection', 'Companies')}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {companiesSummaryLabel}\n </p>\n </div>\n {data.companies.length ? (\n <ul className=\"space-y-2 text-sm\">\n {data.companies.map((company) => (\n <li key={company.id} className=\"flex flex-col gap-1\">\n <Link href={`/backend/customers/companies-v2/${encodeURIComponent(company.id)}`} className=\"font-medium text-foreground hover:underline\">\n {company.label}\n </Link>\n <span className=\"text-xs text-muted-foreground\">\n {company.subtitle ?? t('customers.deals.detail.companiesNoDetails', 'No additional details')}\n </span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.deals.detail.noCompanies', 'No companies linked to this deal yet.')}\n </p>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"space-y-6\">\n <div\n ref={dealSettingsRef}\n id=\"deal-settings\"\n className=\"rounded-lg border bg-card p-4\"\n >\n <h2 className=\"mb-4 text-sm font-semibold uppercase text-muted-foreground\">\n {t('customers.deals.detail.formTitle', 'Deal settings')}\n </h2>\n <DealForm\n key={data.deal.updatedAt}\n mode=\"edit\"\n initialValues={{\n id: data.deal.id,\n title: data.deal.title ?? '',\n status: data.deal.status ?? '',\n pipelineStage: data.deal.pipelineStage ?? '',\n pipelineId: data.deal.pipelineId ?? '',\n pipelineStageId: data.deal.pipelineStageId ?? '',\n valueAmount: data.deal.valueAmount ? Number(data.deal.valueAmount) : null,\n valueCurrency: data.deal.valueCurrency ?? undefined,\n probability: data.deal.probability ?? null,\n expectedCloseAt: data.deal.expectedCloseAt ?? null,\n description: data.deal.description ?? '',\n personIds: data.people.map((person) => person.id),\n companyIds: data.companies.map((company) => company.id),\n people: data.people.map((person) => ({ id: person.id, label: person.label })),\n companies: data.companies.map((company) => ({ id: company.id, label: company.label })),\n ...Object.fromEntries(\n Object.entries(data.customFields)\n .filter(([key]) => key.startsWith('cf_'))\n .map(([key, value]) => [key, value]),\n ),\n }}\n onSubmit={handleFormSubmit}\n onCancel={() => setReloadToken((token) => token + 1)}\n onDelete={handleDelete}\n isSubmitting={isSaving || isDeleting}\n />\n </div>\n </div>\n </div>\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -631,7 +631,7 @@ class HybridQueryEngine {
|
|
|
631
631
|
};
|
|
632
632
|
const applyJoinSearchFilterOp = async (target, filter, _qualified, join) => {
|
|
633
633
|
if (!searchEnabled || !join.entityId) return false;
|
|
634
|
-
if (!["
|
|
634
|
+
if (!["like", "ilike"].includes(filter.op)) return false;
|
|
635
635
|
if (typeof filter.value !== "string" || filter.value.trim().length === 0) return false;
|
|
636
636
|
let searchAvailable = joinSearchAvailability.get(join.entityId);
|
|
637
637
|
if (searchAvailable === void 0) {
|