@open-mercato/core 0.10.1-develop.7761.1.9dfaf470ed → 0.10.1-develop.7763.1.caea616ebf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/api/profile/route.js +16 -2
  3. package/dist/modules/auth/api/profile/route.js.map +2 -2
  4. package/dist/modules/auth/lib/userDataSubject.js +26 -0
  5. package/dist/modules/auth/lib/userDataSubject.js.map +7 -0
  6. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +1 -0
  7. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  8. package/dist/modules/customers/api/companies/[id]/route.js +3 -2
  9. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  10. package/dist/modules/customers/api/deals/[id]/route.js +11 -12
  11. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  12. package/dist/modules/customers/api/people/[id]/route.js +3 -2
  13. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  14. package/dist/modules/customers/backend/customers/companies/create/page.js +6 -0
  15. package/dist/modules/customers/backend/customers/companies/create/page.js.map +2 -2
  16. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +25 -25
  17. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  18. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js +8 -27
  19. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js.map +2 -2
  20. package/dist/modules/customers/backend/customers/deals/[id]/page.js +175 -171
  21. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  22. package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js +25 -24
  23. package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js.map +2 -2
  24. package/dist/modules/customers/backend/customers/people/create/page.js +9 -0
  25. package/dist/modules/customers/backend/customers/people/create/page.js.map +2 -2
  26. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +140 -144
  27. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  28. package/dist/modules/customers/components/detail/CompanyDetailHeader.js +2 -0
  29. package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +2 -2
  30. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +13 -4
  31. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
  32. package/dist/modules/customers/components/detail/CreatePersonDialog.js +13 -3
  33. package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +2 -2
  34. package/dist/modules/customers/components/detail/CustomerDetailSidebar.js +29 -0
  35. package/dist/modules/customers/components/detail/CustomerDetailSidebar.js.map +7 -0
  36. package/dist/modules/customers/components/detail/DealDetailHeader.js +4 -2
  37. package/dist/modules/customers/components/detail/DealDetailHeader.js.map +2 -2
  38. package/dist/modules/customers/components/detail/DealDetailTabs.js +9 -1
  39. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
  40. package/dist/modules/customers/components/detail/DealForm.js +5 -0
  41. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  42. package/dist/modules/customers/components/detail/PersonDetailHeader.js +2 -0
  43. package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +2 -2
  44. package/dist/modules/customers/components/detail/PersonDetailTabs.js +9 -1
  45. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  46. package/dist/modules/customers/components/detail/create/CreateDealForm.js +160 -176
  47. package/dist/modules/customers/components/detail/create/CreateDealForm.js.map +2 -2
  48. package/dist/modules/customers/components/detail/useCustomerInjectedTabs.js +47 -0
  49. package/dist/modules/customers/components/detail/useCustomerInjectedTabs.js.map +7 -0
  50. package/dist/modules/customers/components/formConfig.js +3 -0
  51. package/dist/modules/customers/components/formConfig.js.map +2 -2
  52. package/dist/modules/customers/extension-points.js +14 -4
  53. package/dist/modules/customers/extension-points.js.map +2 -2
  54. package/dist/modules/customers/lib/detailResponseEnrichment.js +38 -0
  55. package/dist/modules/customers/lib/detailResponseEnrichment.js.map +7 -0
  56. package/dist/modules/dashboards/api/layout/[itemId]/route.js +11 -4
  57. package/dist/modules/dashboards/api/layout/[itemId]/route.js.map +2 -2
  58. package/dist/modules/dashboards/api/layout/route.js +25 -13
  59. package/dist/modules/dashboards/api/layout/route.js.map +2 -2
  60. package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +4 -4
  61. package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +2 -2
  62. package/package.json +7 -7
  63. package/src/modules/auth/api/profile/route.ts +15 -1
  64. package/src/modules/auth/lib/userDataSubject.ts +30 -0
  65. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -0
  66. package/src/modules/customers/api/companies/[id]/route.ts +3 -2
  67. package/src/modules/customers/api/deals/[id]/route.ts +12 -12
  68. package/src/modules/customers/api/people/[id]/route.ts +3 -2
  69. package/src/modules/customers/backend/customers/companies/create/page.tsx +6 -0
  70. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -30
  71. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx +9 -44
  72. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -3
  73. package/src/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.tsx +25 -27
  74. package/src/modules/customers/backend/customers/people/create/page.tsx +9 -0
  75. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +21 -33
  76. package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +3 -0
  77. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +15 -4
  78. package/src/modules/customers/components/detail/CreatePersonDialog.tsx +15 -4
  79. package/src/modules/customers/components/detail/CustomerDetailSidebar.tsx +41 -0
  80. package/src/modules/customers/components/detail/DealDetailHeader.tsx +4 -1
  81. package/src/modules/customers/components/detail/DealDetailTabs.tsx +11 -1
  82. package/src/modules/customers/components/detail/DealForm.tsx +5 -0
  83. package/src/modules/customers/components/detail/PersonDetailHeader.tsx +3 -0
  84. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +11 -1
  85. package/src/modules/customers/components/detail/create/CreateDealForm.tsx +126 -209
  86. package/src/modules/customers/components/detail/useCustomerInjectedTabs.tsx +64 -0
  87. package/src/modules/customers/components/formConfig.tsx +3 -0
  88. package/src/modules/customers/extension-points.ts +14 -4
  89. package/src/modules/customers/lib/detailResponseEnrichment.ts +53 -0
  90. package/src/modules/dashboards/api/layout/[itemId]/route.ts +12 -4
  91. package/src/modules/dashboards/api/layout/route.ts +25 -12
  92. package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +4 -4
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/detail/create/CreateDealForm.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Briefcase, Save } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { dealFormSchema } from '../DealForm'\nimport { createDictionarySelectLabels } from '../utils'\nimport { DealSectionCard } from './DealSectionCard'\nimport { DealDetailsFields } from './DealDetailsFields'\nimport { DealAssociationsSection } from './DealAssociationsSection'\nimport { DealCreateSidebar } from './DealCreateSidebar'\nimport { useDealPipelines } from './useDealPipelines'\nimport { useDealCustomFields } from './useDealCustomFields'\nimport { EMPTY_VALUES, type BaseValues } from './dealFormTypes'\n\nconst CONTEXT_ID = 'customers.deals.create'\nconst DEAL_ENTITY_ID = 'customers:customer_deal'\nconst CUSTOM_FIELDS_MANAGE_HREF = `/backend/entities/system/${encodeURIComponent(DEAL_ENTITY_ID)}`\n\nexport type CreateDealFormProps = {\n returnTo: string\n /** Seed values merged over EMPTY_VALUES for the initial form state. Entries set to `undefined` are ignored (the EMPTY_VALUES default wins), so a sparse `Partial<BaseValues>` can never unset a required field. Additive: omitting it preserves current behavior. */\n initialValues?: Partial<BaseValues>\n}\n\nexport function CreateDealForm({ returnTo, initialValues }: CreateDealFormProps) {\n const t = useT()\n const router = useRouter()\n const tr = React.useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>) =>\n translateWithFallback(t, key, fallback, params),\n [t],\n )\n\n const [values, setValues] = React.useState<BaseValues>(() => {\n const definedSeedEntries = Object.entries(initialValues ?? {}).filter(([, seedValue]) => seedValue !== undefined)\n return { ...EMPTY_VALUES, ...Object.fromEntries(definedSeedEntries) }\n })\n const [errors, setErrors] = React.useState<Record<string, string>>({})\n const [isSubmitting, setIsSubmitting] = React.useState(false)\n\n // Default the owner to the current user, matching the pipeline quick-create dialog so a\n // deal created here does not start unowned (an unowned deal notifies nobody when it closes).\n // useCurrentUserId resolves asynchronously, so this seeds once the id arrives and never\n // overrides an explicit seed or a choice the user has already made.\n const currentUserId = useCurrentUserId()\n // Seeds the picker for the self-assigned id, which may not be on the assignable roster\n // (an admin who is not a staff team member, or any user when the `staff` module is off).\n const ownerInitialOption = React.useMemo(\n () => (currentUserId\n ? { id: currentUserId, name: tr('customers.filters.currentUser', 'Current user') }\n : null),\n [currentUserId, tr],\n )\n const ownerSeeded = React.useRef(false)\n React.useEffect(() => {\n if (ownerSeeded.current || !currentUserId) return\n ownerSeeded.current = true\n if (initialValues?.ownerUserId) return\n setValues((current) => (current.ownerUserId ? current : { ...current, ownerUserId: currentUserId }))\n }, [currentUserId, initialValues?.ownerUserId])\n\n const { pipelines, stages, loadStages } = useDealPipelines()\n const {\n customValues,\n customFieldsLoaded,\n customCount,\n handleCustomChange,\n handleCustomAttributesLoaded,\n validateCustomFields,\n collectNormalizedCustomValues,\n } = useDealCustomFields(tr)\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: CONTEXT_ID,\n blockedMessage: tr('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const statusLabels = React.useMemo(\n () => createDictionarySelectLabels('deal-statuses', (key, fallback) => tr(key, fallback ?? key)),\n [tr],\n )\n\n const patch = React.useCallback((partial: Partial<BaseValues>) => {\n // A user touching the owner before useCurrentUserId resolves must not be overridden by\n // the seeding effect below.\n if ('ownerUserId' in partial) ownerSeeded.current = true\n setValues((current) => ({ ...current, ...partial }))\n }, [])\n\n const handlePipelineChange = React.useCallback(\n (id: string) => {\n patch({ pipelineId: id, pipelineStageId: '' })\n // loadStages resets stages to [] on failure; the rejection is intentionally ignored here.\n loadStages(id).catch(() => {})\n },\n [loadStages, patch],\n )\n\n const handleCancel = React.useCallback(() => {\n router.push(returnTo)\n }, [returnTo, router])\n\n const handleSubmit = React.useCallback(async () => {\n if (isSubmitting) return\n if (!customFieldsLoaded) {\n flash(tr('customers.deals.create.sections.custom.loading', 'Loading custom fields...'), 'error')\n return\n }\n const merged = { ...values, ...customValues }\n const parsed = dealFormSchema.safeParse(merged)\n if (!parsed.success) {\n const fieldErrors: Record<string, string> = {}\n for (const issue of parsed.error.issues) {\n const key = typeof issue.path[0] === 'string' ? issue.path[0] : undefined\n if (key && !fieldErrors[key]) fieldErrors[key] = tr(issue.message, issue.message)\n }\n setErrors(fieldErrors)\n const firstMessage = Object.values(fieldErrors)[0]\n if (firstMessage) flash(firstMessage, 'error')\n return\n }\n\n const customFieldErrors = validateCustomFields(merged)\n if (Object.keys(customFieldErrors).length) {\n setErrors(customFieldErrors)\n const firstMessage = Object.values(customFieldErrors)[0]\n if (firstMessage) flash(firstMessage, 'error')\n return\n }\n\n setErrors({})\n setIsSubmitting(true)\n try {\n const data = parsed.data\n const expectedCloseAt =\n data.expectedCloseAt && data.expectedCloseAt.length\n ? new Date(data.expectedCloseAt).toISOString()\n : undefined\n const payload: Record<string, unknown> = {\n title: data.title,\n status: data.status || undefined,\n pipelineId: data.pipelineId || undefined,\n pipelineStageId: data.pipelineStageId || undefined,\n valueAmount: typeof data.valueAmount === 'number' ? data.valueAmount : undefined,\n valueCurrency: data.valueCurrency || undefined,\n probability: typeof data.probability === 'number' ? data.probability : undefined,\n expectedCloseAt,\n description: data.description && data.description.length ? data.description : undefined,\n // `null`, not omitted \u2014 matching DealForm, so both create surfaces send the same\n // shape. `dealCreateSchema.ownerUserId` is `.optional().nullable()` (validators.ts:183)\n // and createDealCommand maps null to null (commands/deals.ts:591).\n ownerUserId: data.ownerUserId && data.ownerUserId.length ? data.ownerUserId : null,\n personIds: values.personIds.length ? values.personIds : undefined,\n companyIds: values.companyIds.length ? values.companyIds : undefined,\n }\n const custom = collectNormalizedCustomValues(merged)\n if (Object.keys(custom).length) payload.customFields = custom\n\n await runMutation({\n operation: () =>\n createCrud('customers/deals', payload, {\n errorMessage: tr('customers.deals.create.error', 'Failed to create deal.'),\n }),\n context: { formId: CONTEXT_ID, resourceKind: 'customers.deal', retryLastMutation },\n mutationPayload: payload,\n })\n flash(tr('customers.people.detail.deals.success', 'Deal created.'), 'success')\n router.push(returnTo)\n } catch (err) {\n const message = err instanceof Error ? err.message : tr('customers.deals.create.error', 'Failed to create deal.')\n flash(message, 'error')\n } finally {\n setIsSubmitting(false)\n }\n }, [\n collectNormalizedCustomValues,\n customFieldsLoaded,\n customValues,\n isSubmitting,\n retryLastMutation,\n returnTo,\n router,\n runMutation,\n tr,\n validateCustomFields,\n values,\n ])\n\n const onKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n handleSubmit()\n }\n },\n [handleSubmit],\n )\n\n const onFormSubmit = React.useCallback(\n (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n handleSubmit()\n },\n [handleSubmit],\n )\n\n const cancelLabel = tr('customers.deals.create.cancel', 'Cancel')\n const submitLabel = tr('customers.deals.create.submit', 'Create deal')\n const submitDisabled = !customFieldsLoaded\n\n return (\n <form className=\"mx-auto max-w-screen-2xl\" onKeyDown={onKeyDown} onSubmit={onFormSubmit} noValidate>\n <FormHeader\n backHref={returnTo}\n backLabel={tr('customers.deals.create.back', 'Back to deals')}\n />\n\n <div className=\"mt-6 grid grid-cols-1 gap-5 lg:grid-cols-[minmax(0,1fr)_330px]\">\n <div className=\"space-y-4\">\n <DealSectionCard\n icon={Briefcase}\n title={tr('customers.deals.create.title', 'Create deal')}\n subtitle={tr('customers.deals.create.sections.details.subtitle', 'Core opportunity info')}\n actions={\n <>\n <Button type=\"button\" variant=\"outline\" onClick={handleCancel} disabled={isSubmitting}>\n {cancelLabel}\n </Button>\n <Button type=\"button\" onClick={handleSubmit} disabled={isSubmitting || submitDisabled}>\n {isSubmitting ? <Spinner className=\"size-4\" /> : <Save className=\"size-4\" />}\n {submitLabel}\n </Button>\n </>\n }\n >\n <DealDetailsFields\n values={values}\n errors={errors}\n isSubmitting={isSubmitting}\n patch={patch}\n onPipelineChange={handlePipelineChange}\n pipelines={pipelines}\n stages={stages}\n statusLabels={statusLabels}\n ownerInitialOption={ownerInitialOption}\n tr={tr}\n />\n </DealSectionCard>\n\n <DealAssociationsSection\n tr={tr}\n personIds={values.personIds}\n companyIds={values.companyIds}\n onPeopleChange={(next) => patch({ personIds: next })}\n onCompaniesChange={(next) => patch({ companyIds: next })}\n disabled={isSubmitting}\n />\n </div>\n\n <DealCreateSidebar\n tr={tr}\n customValues={customValues}\n onCustomChange={handleCustomChange}\n errors={errors}\n disabled={isSubmitting}\n customCount={customCount}\n manageHref={CUSTOM_FIELDS_MANAGE_HREF}\n onCustomLoaded={handleCustomAttributesLoaded}\n />\n </div>\n </form>\n )\n}\n\nexport default CreateDealForm\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Briefcase, Save } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { E } from '#generated/entities.ids.generated'\nimport { extensionPoints } from '../../../extension-points'\nimport { dealFormSchema } from '../DealForm'\nimport { createDictionarySelectLabels } from '../utils'\nimport { DealSectionCard } from './DealSectionCard'\nimport { DealDetailsFields } from './DealDetailsFields'\nimport { DealAssociationsSection } from './DealAssociationsSection'\nimport { DealCreateSidebar } from './DealCreateSidebar'\nimport { useDealPipelines } from './useDealPipelines'\nimport { useDealCustomFields } from './useDealCustomFields'\nimport { EMPTY_VALUES, type BaseValues } from './dealFormTypes'\n\nconst CONTEXT_ID = 'customers.deals.create'\nconst DEAL_ENTITY_ID = 'customers:customer_deal'\nconst CUSTOM_FIELDS_MANAGE_HREF = `/backend/entities/system/${encodeURIComponent(DEAL_ENTITY_ID)}`\n\nexport type CreateDealFormProps = {\n returnTo: string\n /** Seed values merged over EMPTY_VALUES for the initial form state. Entries set to `undefined` are ignored (the EMPTY_VALUES default wins), so a sparse `Partial<BaseValues>` can never unset a required field. Additive: omitting it preserves current behavior. */\n initialValues?: Partial<BaseValues>\n}\n\nfunction readCreateValues(values: Record<string, unknown>): BaseValues {\n const result = { ...EMPTY_VALUES }\n for (const key of Object.keys(EMPTY_VALUES) as Array<keyof BaseValues>) {\n if (key === 'personIds' || key === 'companyIds') {\n const raw = values[key]\n result[key] = Array.isArray(raw) ? raw.filter((value): value is string => typeof value === 'string') : []\n } else {\n const raw = values[key]\n result[key] = typeof raw === 'string' || typeof raw === 'number' ? String(raw) : ''\n }\n }\n return result\n}\n\nexport function CreateDealForm({ returnTo, initialValues }: CreateDealFormProps) {\n const t = useT()\n const router = useRouter()\n const tr = React.useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>) =>\n translateWithFallback(t, key, fallback, params),\n [t],\n )\n // Default the owner to the current user, matching the pipeline quick-create dialog so a\n // deal created here does not start unowned (an unowned deal notifies nobody when it closes).\n // useCurrentUserId resolves asynchronously; CrudForm merges the late seed without touching\n // an explicit seed or a field the user has already edited.\n const currentUserId = useCurrentUserId()\n // Seeds the picker for the self-assigned id, which may not be on the assignable roster\n // (an admin who is not a staff team member, or any user when the `staff` module is off).\n const ownerInitialOption = React.useMemo(\n () => (currentUserId\n ? { id: currentUserId, name: tr('customers.filters.currentUser', 'Current user') }\n : null),\n [currentUserId, tr],\n )\n const seedValues = React.useMemo(() => {\n const seeded: BaseValues = {\n ...EMPTY_VALUES,\n ...Object.fromEntries(Object.entries(initialValues ?? {}).filter(([, value]) => value !== undefined)),\n }\n return seeded.ownerUserId || !currentUserId ? seeded : { ...seeded, ownerUserId: currentUserId }\n }, [initialValues, currentUserId])\n const [isSubmitting, setIsSubmitting] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation({ contextId: CONTEXT_ID, blockedMessage: tr('ui.forms.flash.saveBlocked', 'Save blocked by validation') })\n const { pipelines, stages, loadStages } = useDealPipelines()\n const { customFieldsLoaded, customCount, handleCustomAttributesLoaded, collectNormalizedCustomValues } = useDealCustomFields(tr)\n const statusLabels = React.useMemo(\n () => createDictionarySelectLabels('deal-statuses', (key, fallback) => tr(key, fallback ?? key)),\n [tr],\n )\n const handleCancel = React.useCallback(() => router.push(returnTo), [returnTo, router])\n const handleSubmit = React.useCallback(async (values: Record<string, unknown>) => {\n const data = dealFormSchema.parse(values)\n const payload: Record<string, unknown> = {\n title: data.title,\n status: data.status || undefined,\n pipelineId: data.pipelineId || undefined,\n pipelineStageId: data.pipelineStageId || undefined,\n valueAmount: typeof data.valueAmount === 'number' ? data.valueAmount : undefined,\n valueCurrency: data.valueCurrency || undefined,\n probability: typeof data.probability === 'number' ? data.probability : undefined,\n expectedCloseAt: data.expectedCloseAt ? new Date(data.expectedCloseAt).toISOString() : undefined,\n description: data.description || undefined,\n // `null`, not omitted \u2014 matching DealForm, so both create surfaces send the same\n // shape. `dealCreateSchema.ownerUserId` is `.optional().nullable()` and\n // createDealCommand maps null to null.\n ownerUserId: data.ownerUserId && data.ownerUserId.length ? data.ownerUserId : null,\n personIds: data.personIds?.length ? data.personIds : undefined,\n companyIds: data.companyIds?.length ? data.companyIds : undefined,\n }\n const custom = collectNormalizedCustomValues(values)\n if (Object.keys(custom).length) payload.customFields = custom\n setIsSubmitting(true)\n try {\n const { result } = await runMutation({\n operation: () => createCrud<{ id?: string; entityId?: string }>('customers/deals', payload, {\n errorMessage: tr('customers.deals.create.error', 'Failed to create deal.'),\n }),\n context: { formId: CONTEXT_ID, resourceKind: 'customers.deal', retryLastMutation },\n mutationPayload: payload,\n })\n flash(tr('customers.people.detail.deals.success', 'Deal created.'), 'success')\n return { resourceId: result?.id ?? result?.entityId }\n } finally {\n setIsSubmitting(false)\n }\n }, [collectNormalizedCustomValues, tr, runMutation, retryLastMutation])\n const handleSubmitSuccess = React.useCallback(() => {\n router.push(returnTo)\n }, [router, returnTo])\n const fields = React.useMemo<CrudField[]>(() => Object.keys(EMPTY_VALUES).map((id) => ({\n id,\n label: tr(`customers.people.detail.deals.fields.${id}`, id),\n type: 'text',\n required: id === 'title',\n })), [tr])\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n {\n id: 'details',\n bare: true,\n column: 1,\n fields: Object.keys(EMPTY_VALUES).filter((id) => id !== 'personIds' && id !== 'companyIds'),\n component: ({ values, setValue, errors, injectedFields }) => {\n const patch = (partial: Partial<BaseValues>) => {\n for (const [key, value] of Object.entries(partial)) setValue(key, value)\n }\n return (\n <DealSectionCard\n icon={Briefcase}\n title={tr('customers.deals.create.title', 'Create deal')}\n subtitle={tr('customers.deals.create.sections.details.subtitle', 'Core opportunity info')}\n actions={<>\n <Button type=\"button\" variant=\"outline\" onClick={handleCancel} disabled={isSubmitting}>{tr('customers.deals.create.cancel', 'Cancel')}</Button>\n <Button type=\"submit\" form={CONTEXT_ID} disabled={isSubmitting || !customFieldsLoaded}>\n {isSubmitting ? <Spinner className=\"size-4\" /> : <Save className=\"size-4\" />}\n {tr('customers.deals.create.submit', 'Create deal')}\n </Button>\n </>}\n >\n <DealDetailsFields values={readCreateValues(values)} errors={errors} isSubmitting={isSubmitting} patch={patch}\n onPipelineChange={(pipelineId) => { patch({ pipelineId, pipelineStageId: '' }); void loadStages(pipelineId).catch(() => {}) }}\n pipelines={pipelines} stages={stages} statusLabels={statusLabels} ownerInitialOption={ownerInitialOption} tr={tr} />\n {injectedFields}\n </DealSectionCard>\n )\n },\n },\n {\n id: 'associations',\n bare: true,\n column: 1,\n fields: ['personIds', 'companyIds'],\n component: ({ values, setValue, injectedFields }) => <>\n <DealAssociationsSection tr={tr} personIds={readCreateValues(values).personIds} companyIds={readCreateValues(values).companyIds}\n onPeopleChange={(next) => setValue('personIds', next)} onCompaniesChange={(next) => setValue('companyIds', next)} disabled={isSubmitting} />\n {injectedFields}\n </>,\n },\n {\n id: 'custom',\n bare: true,\n column: 2,\n component: ({ values, setValue, errors, injectedFields }) => <>\n <DealCreateSidebar tr={tr} customValues={values} onCustomChange={setValue} errors={errors} disabled={isSubmitting}\n customCount={customCount} manageHref={CUSTOM_FIELDS_MANAGE_HREF} onCustomLoaded={handleCustomAttributesLoaded} />\n {injectedFields}\n </>,\n },\n ], [tr, handleCancel, isSubmitting, customFieldsLoaded, loadStages, pipelines, stages, statusLabels, ownerInitialOption, customCount, handleCustomAttributesLoaded])\n\n return (\n <div className=\"mx-auto max-w-screen-2xl\" onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!isSubmitting && customFieldsLoaded) document.getElementById(CONTEXT_ID)?.closest('form')?.requestSubmit()\n }\n }}>\n <FormHeader backHref={returnTo} backLabel={tr('customers.deals.create.back', 'Back to deals')} />\n <div className=\"mt-6\">\n <CrudForm<Record<string, unknown>> embedded hideFooterActions formId={CONTEXT_ID}\n entityId=\"customers.deal\" resourceKind=\"customers.deal\" entityIds={[E.customers.customer_deal]}\n injectionSpotId={extensionPoints.hosts.dealForm.spotId} fields={fields} groups={groups}\n initialValues={seedValues} schema={dealFormSchema} onSubmit={handleSubmit} onSubmitSuccess={handleSubmitSuccess} />\n </div>\n </div>\n )\n}\n\nexport default CreateDealForm\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
5
+ import { InjectionSpot, useInjectionWidgets } from "@open-mercato/ui/backend/injection/InjectionSpot";
6
+ function groupCustomerInjectedTabs(widgets, translate) {
7
+ const groups = /* @__PURE__ */ new Map();
8
+ const seen = /* @__PURE__ */ new Set();
9
+ for (const widget of widgets) {
10
+ if (seen.has(widget.widgetId) || widget.placement?.kind === "stack") continue;
11
+ seen.add(widget.widgetId);
12
+ const id = widget.placement?.groupId ?? widget.widgetId;
13
+ const declaredPriority = widget.placement?.priority ?? widget.module.metadata.priority;
14
+ const priority = typeof declaredPriority === "number" ? declaredPriority : 0;
15
+ const group = groups.get(id);
16
+ if (group) {
17
+ group.widgets.push(widget);
18
+ group.priority = Math.max(group.priority, priority);
19
+ } else {
20
+ const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? id;
21
+ groups.set(id, { id, label: translate(label, label), priority, widgets: [widget] });
22
+ }
23
+ }
24
+ return Array.from(groups.values()).sort((left, right) => right.priority - left.priority);
25
+ }
26
+ function useCustomerInjectedTabs({
27
+ spotId,
28
+ context,
29
+ data,
30
+ onDataChange,
31
+ nativeTabIds
32
+ }) {
33
+ const t = useT();
34
+ const { widgets, loading } = useInjectionWidgets(spotId, { context, triggerOnLoad: true });
35
+ const groups = React.useMemo(() => groupCustomerInjectedTabs(widgets, t), [widgets, t]);
36
+ const injectedTabs = React.useMemo(
37
+ () => groups.filter((group) => !nativeTabIds.includes(group.id)),
38
+ [groups, nativeTabIds]
39
+ );
40
+ const injectedTabMap = React.useMemo(() => new Map(groups.map((group) => [group.id, () => /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(InjectionSpot, { spotId, context, data, onDataChange, widgetsOverride: group.widgets }) })])), [groups, spotId, context, data, onDataChange]);
41
+ return { injectedTabs, injectedTabMap, loading };
42
+ }
43
+ export {
44
+ groupCustomerInjectedTabs,
45
+ useCustomerInjectedTabs
46
+ };
47
+ //# sourceMappingURL=useCustomerInjectedTabs.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/customers/components/detail/useCustomerInjectedTabs.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { InjectionSpot, useInjectionWidgets, type LoadedInjectionSpotWidget } from '@open-mercato/ui/backend/injection/InjectionSpot'\n\nexport type CustomerInjectedTab = {\n id: string\n label: string\n priority: number\n widgets: LoadedInjectionSpotWidget[]\n}\n\nexport function groupCustomerInjectedTabs(\n widgets: LoadedInjectionSpotWidget[],\n translate: (key: string, fallback: string) => string,\n): CustomerInjectedTab[] {\n const groups = new Map<string, CustomerInjectedTab>()\n const seen = new Set<string>()\n for (const widget of widgets) {\n if (seen.has(widget.widgetId) || widget.placement?.kind === 'stack') continue\n seen.add(widget.widgetId)\n const id = widget.placement?.groupId ?? widget.widgetId\n const declaredPriority = widget.placement?.priority ?? widget.module.metadata.priority\n const priority = typeof declaredPriority === 'number' ? declaredPriority : 0\n const group = groups.get(id)\n if (group) {\n group.widgets.push(widget)\n group.priority = Math.max(group.priority, priority)\n } else {\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? id\n groups.set(id, { id, label: translate(label, label), priority, widgets: [widget] })\n }\n }\n return Array.from(groups.values()).sort((left, right) => right.priority - left.priority)\n}\n\nexport function useCustomerInjectedTabs<TData>({\n spotId,\n context,\n data,\n onDataChange,\n nativeTabIds,\n}: {\n spotId: string\n context: unknown\n data: TData\n onDataChange?: (data: TData) => void\n nativeTabIds: readonly string[]\n}) {\n const t = useT()\n const { widgets, loading } = useInjectionWidgets(spotId, { context, triggerOnLoad: true })\n const groups = React.useMemo(() => groupCustomerInjectedTabs(widgets, t), [widgets, t])\n const injectedTabs = React.useMemo(\n () => groups.filter((group) => !nativeTabIds.includes(group.id)),\n [groups, nativeTabIds],\n )\n const injectedTabMap = React.useMemo(() => new Map(groups.map((group) => [group.id, () => (\n <div className=\"space-y-4\">\n <InjectionSpot spotId={spotId} context={context} data={data} onDataChange={onDataChange} widgetsOverride={group.widgets} />\n </div>\n )])), [groups, spotId, context, data, onDataChange])\n return { injectedTabs, injectedTabMap, loading }\n}\n"],
5
+ "mappings": ";AA2DM;AAzDN,YAAY,WAAW;AACvB,SAAS,YAAY;AACrB,SAAS,eAAe,2BAA2D;AAS5E,SAAS,0BACd,SACA,WACuB;AACvB,QAAM,SAAS,oBAAI,IAAiC;AACpD,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,UAAU,SAAS;AAC5B,QAAI,KAAK,IAAI,OAAO,QAAQ,KAAK,OAAO,WAAW,SAAS,QAAS;AACrE,SAAK,IAAI,OAAO,QAAQ;AACxB,UAAM,KAAK,OAAO,WAAW,WAAW,OAAO;AAC/C,UAAM,mBAAmB,OAAO,WAAW,YAAY,OAAO,OAAO,SAAS;AAC9E,UAAM,WAAW,OAAO,qBAAqB,WAAW,mBAAmB;AAC3E,UAAM,QAAQ,OAAO,IAAI,EAAE;AAC3B,QAAI,OAAO;AACT,YAAM,QAAQ,KAAK,MAAM;AACzB,YAAM,WAAW,KAAK,IAAI,MAAM,UAAU,QAAQ;AAAA,IACpD,OAAO;AACL,YAAM,QAAQ,OAAO,WAAW,cAAc,OAAO,OAAO,SAAS,SAAS;AAC9E,aAAO,IAAI,IAAI,EAAE,IAAI,OAAO,UAAU,OAAO,KAAK,GAAG,UAAU,SAAS,CAAC,MAAM,EAAE,CAAC;AAAA,IACpF;AAAA,EACF;AACA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,UAAU,MAAM,WAAW,KAAK,QAAQ;AACzF;AAEO,SAAS,wBAA+B;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,EAAE,SAAS,QAAQ,IAAI,oBAAoB,QAAQ,EAAE,SAAS,eAAe,KAAK,CAAC;AACzF,QAAM,SAAS,MAAM,QAAQ,MAAM,0BAA0B,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACtF,QAAM,eAAe,MAAM;AAAA,IACzB,MAAM,OAAO,OAAO,CAAC,UAAU,CAAC,aAAa,SAAS,MAAM,EAAE,CAAC;AAAA,IAC/D,CAAC,QAAQ,YAAY;AAAA,EACvB;AACA,QAAM,iBAAiB,MAAM,QAAQ,MAAM,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAClF,oBAAC,SAAI,WAAU,aACb,8BAAC,iBAAc,QAAgB,SAAkB,MAAY,cAA4B,iBAAiB,MAAM,SAAS,GAC3H,CACD,CAAC,CAAC,GAAG,CAAC,QAAQ,QAAQ,SAAS,MAAM,YAAY,CAAC;AACnD,SAAO,EAAE,cAAc,gBAAgB,QAAQ;AACjD;",
6
+ "names": []
7
+ }
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { extractResponseEnricherNamespaces } from "@open-mercato/shared/lib/crud/response-enricher-namespaces";
3
4
  import * as React from "react";
4
5
  import { z } from "zod";
5
6
  import Link from "next/link";
@@ -1461,6 +1462,7 @@ function mapCompanyOverviewToFormValues(overview) {
1461
1462
  const rawPhone = overview.company.primaryPhone;
1462
1463
  const phoneValue = rawPhone == null ? "" : String(rawPhone);
1463
1464
  return {
1465
+ ...extractResponseEnricherNamespaces(overview.company),
1464
1466
  id: overview.company.id,
1465
1467
  organizationId: overview.company.organizationId ?? null,
1466
1468
  displayName: coerceDisplayName(overview.company.displayName),
@@ -1484,6 +1486,7 @@ function mapPersonOverviewToFormValues(overview) {
1484
1486
  const rawPhone = overview.person.primaryPhone;
1485
1487
  const phoneValue = rawPhone == null ? "" : String(rawPhone);
1486
1488
  return {
1489
+ ...extractResponseEnricherNamespaces(overview.person),
1487
1490
  id: overview.person.id,
1488
1491
  organizationId: overview.person.organizationId ?? null,
1489
1492
  displayName: coerceDisplayName(overview.person.displayName),