@open-mercato/core 0.4.5-develop-7f44fcf045 → 0.4.5-develop-8f98466993
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/generated/entities/customer_deal/index.js +4 -0
- package/dist/generated/entities/customer_deal/index.js.map +2 -2
- package/dist/generated/entities/customer_pipeline/index.js +17 -0
- package/dist/generated/entities/customer_pipeline/index.js.map +7 -0
- package/dist/generated/entities/customer_pipeline_stage/index.js +19 -0
- package/dist/generated/entities/customer_pipeline_stage/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +2 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +4 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/currencies/api/currencies/route.js +6 -0
- package/dist/modules/currencies/api/currencies/route.js.map +2 -2
- package/dist/modules/currencies/api/exchange-rates/route.js +5 -1
- package/dist/modules/currencies/api/exchange-rates/route.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +5 -4
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/currencies/commands/exchange-rates.js +5 -4
- package/dist/modules/currencies/commands/exchange-rates.js.map +2 -2
- package/dist/modules/customers/acl.js +2 -0
- package/dist/modules/customers/acl.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +4 -0
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +12 -0
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +20 -1
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js +69 -0
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +7 -0
- package/dist/modules/customers/api/pipeline-stages/route.js +275 -0
- package/dist/modules/customers/api/pipeline-stages/route.js.map +7 -0
- package/dist/modules/customers/api/pipelines/route.js +245 -0
- package/dist/modules/customers/api/pipelines/route.js.map +7 -0
- package/dist/modules/customers/backend/config/customers/page.js +2 -0
- package/dist/modules/customers/backend/config/customers/page.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +439 -0
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +7 -0
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js +17 -0
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +35 -1
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +102 -74
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/cli.js +28 -2
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +34 -2
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/index.js +2 -0
- package/dist/modules/customers/commands/index.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +126 -0
- package/dist/modules/customers/commands/pipeline-stages.js.map +7 -0
- package/dist/modules/customers/commands/pipelines.js +87 -0
- package/dist/modules/customers/commands/pipelines.js.map +7 -0
- package/dist/modules/customers/components/DictionarySettings.js +0 -5
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +474 -0
- package/dist/modules/customers/components/PipelineSettings.js.map +7 -0
- package/dist/modules/customers/components/detail/DealForm.js +84 -12
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/data/entities.js +78 -0
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/data/validators.js +44 -0
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260218191730.js +77 -0
- package/dist/modules/customers/migrations/Migration20260218191730.js.map +7 -0
- package/dist/modules/customers/setup.js +7 -3
- package/dist/modules/customers/setup.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260222205305.js +14 -0
- package/dist/modules/workflows/migrations/Migration20260222205305.js.map +7 -0
- package/generated/entities/customer_deal/index.ts +2 -0
- package/generated/entities/customer_pipeline/index.ts +7 -0
- package/generated/entities/customer_pipeline_stage/index.ts +8 -0
- package/generated/entities.ids.generated.ts +2 -0
- package/generated/entity-fields-registry.ts +4 -0
- package/package.json +2 -2
- package/src/modules/currencies/api/currencies/route.ts +6 -0
- package/src/modules/currencies/api/exchange-rates/route.ts +5 -1
- package/src/modules/currencies/commands/currencies.ts +5 -4
- package/src/modules/currencies/commands/exchange-rates.ts +5 -4
- package/src/modules/customers/acl.ts +2 -0
- package/src/modules/customers/api/deals/[id]/route.ts +4 -0
- package/src/modules/customers/api/deals/route.ts +12 -0
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +21 -1
- package/src/modules/customers/api/pipeline-stages/reorder/route.ts +71 -0
- package/src/modules/customers/api/pipeline-stages/route.ts +296 -0
- package/src/modules/customers/api/pipelines/route.ts +261 -0
- package/src/modules/customers/backend/config/customers/page.tsx +2 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.meta.ts +13 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +512 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
- package/src/modules/customers/backend/customers/deals/page.tsx +33 -1
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +119 -79
- package/src/modules/customers/cli.ts +29 -1
- package/src/modules/customers/commands/deals.ts +44 -1
- package/src/modules/customers/commands/index.ts +2 -0
- package/src/modules/customers/commands/pipeline-stages.ts +156 -0
- package/src/modules/customers/commands/pipelines.ts +105 -0
- package/src/modules/customers/components/DictionarySettings.tsx +0 -5
- package/src/modules/customers/components/PipelineSettings.tsx +570 -0
- package/src/modules/customers/components/detail/DealForm.tsx +89 -11
- package/src/modules/customers/data/entities.ts +64 -0
- package/src/modules/customers/data/validators.ts +57 -0
- package/src/modules/customers/i18n/de.json +4 -0
- package/src/modules/customers/i18n/en.json +4 -0
- package/src/modules/customers/i18n/es.json +4 -0
- package/src/modules/customers/i18n/pl.json +5 -1
- package/src/modules/customers/migrations/Migration20260218191730.ts +84 -0
- package/src/modules/customers/setup.ts +5 -1
- package/src/modules/workflows/migrations/Migration20260222205305.ts +13 -0
|
@@ -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 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 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 pipelineLabel = resolveDictionaryLabel(data.deal.pipelineStage, pipelineDictionaryMap)\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 }}\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.pipeline', 'Pipeline stage')}\n </p>\n <p className=\"text-base text-foreground\">\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/${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/${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 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\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 }}\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/${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/${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
|
}
|
|
@@ -355,6 +355,7 @@ function CustomersDealsPage() {
|
|
|
355
355
|
"deal-statuses": {},
|
|
356
356
|
"pipeline-stages": {}
|
|
357
357
|
});
|
|
358
|
+
const [pipelineNames, setPipelineNames] = React.useState({});
|
|
358
359
|
const fetchDictionaryEntries = React.useCallback(
|
|
359
360
|
async (kind) => {
|
|
360
361
|
try {
|
|
@@ -378,6 +379,27 @@ function CustomersDealsPage() {
|
|
|
378
379
|
cancelled = true;
|
|
379
380
|
};
|
|
380
381
|
}, [fetchDictionaryEntries, reloadToken]);
|
|
382
|
+
React.useEffect(() => {
|
|
383
|
+
let cancelled = false;
|
|
384
|
+
async function loadPipelines() {
|
|
385
|
+
try {
|
|
386
|
+
const call = await apiCall("/api/customers/pipelines");
|
|
387
|
+
if (cancelled || !call.ok) return;
|
|
388
|
+
const items = Array.isArray(call.result?.items) ? call.result.items : [];
|
|
389
|
+
const map = {};
|
|
390
|
+
items.forEach((p) => {
|
|
391
|
+
if (p.id && p.name) map[p.id] = p.name;
|
|
392
|
+
});
|
|
393
|
+
setPipelineNames(map);
|
|
394
|
+
} catch {
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
loadPipelines().catch(() => {
|
|
398
|
+
});
|
|
399
|
+
return () => {
|
|
400
|
+
cancelled = true;
|
|
401
|
+
};
|
|
402
|
+
}, [reloadToken, scopeVersion]);
|
|
381
403
|
React.useEffect(() => {
|
|
382
404
|
peopleCacheRef.current.clear();
|
|
383
405
|
companiesCacheRef.current.clear();
|
|
@@ -674,6 +696,14 @@ function CustomersDealsPage() {
|
|
|
674
696
|
header: t("customers.deals.list.columns.pipelineStage"),
|
|
675
697
|
cell: ({ row }) => renderDictionaryCell("pipeline-stages", row.original.pipelineStage)
|
|
676
698
|
},
|
|
699
|
+
{
|
|
700
|
+
accessorKey: "pipelineId",
|
|
701
|
+
header: t("customers.deals.list.columns.pipeline", "Pipeline"),
|
|
702
|
+
cell: ({ row }) => {
|
|
703
|
+
const name = row.original.pipelineId ? pipelineNames[row.original.pipelineId] : null;
|
|
704
|
+
return name ? /* @__PURE__ */ jsx("span", { className: "text-sm", children: name }) : noValue;
|
|
705
|
+
}
|
|
706
|
+
},
|
|
677
707
|
{
|
|
678
708
|
accessorKey: "valueAmount",
|
|
679
709
|
header: t("customers.deals.list.columns.value"),
|
|
@@ -712,7 +742,7 @@ function CustomersDealsPage() {
|
|
|
712
742
|
},
|
|
713
743
|
...customColumns
|
|
714
744
|
];
|
|
715
|
-
}, [customFieldDefs, dictionaryMaps, t]);
|
|
745
|
+
}, [customFieldDefs, dictionaryMaps, pipelineNames, t]);
|
|
716
746
|
return /* @__PURE__ */ jsxs(Page, { children: [
|
|
717
747
|
/* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
718
748
|
DataTable,
|
|
@@ -790,6 +820,8 @@ function mapDeal(item) {
|
|
|
790
820
|
const title = typeof item.title === "string" ? item.title : "";
|
|
791
821
|
const status = typeof item.status === "string" ? item.status : null;
|
|
792
822
|
const pipelineStage = typeof item.pipeline_stage === "string" ? item.pipeline_stage : null;
|
|
823
|
+
const pipelineStageId = typeof item.pipeline_stage_id === "string" ? item.pipeline_stage_id : null;
|
|
824
|
+
const pipelineId = typeof item.pipeline_id === "string" ? item.pipeline_id : null;
|
|
793
825
|
const valueAmountRaw = item.value_amount;
|
|
794
826
|
const valueAmount = typeof valueAmountRaw === "number" ? valueAmountRaw : typeof valueAmountRaw === "string" && valueAmountRaw.trim() ? Number(valueAmountRaw) : null;
|
|
795
827
|
const valueCurrency = typeof item.value_currency === "string" && item.value_currency.trim().length ? item.value_currency.trim().toUpperCase() : null;
|
|
@@ -824,6 +856,8 @@ function mapDeal(item) {
|
|
|
824
856
|
title,
|
|
825
857
|
status,
|
|
826
858
|
pipelineStage,
|
|
859
|
+
pipelineStageId,
|
|
860
|
+
pipelineId,
|
|
827
861
|
valueAmount,
|
|
828
862
|
valueCurrency,
|
|
829
863
|
probability,
|