@open-mercato/core 0.4.5-develop-636d33c995 → 0.4.5-develop-811deeb983
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +17 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +30 -0
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/lib/messageObjectPreviews.js +146 -0
- package/dist/modules/catalog/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/catalog/message-objects.js +95 -0
- package/dist/modules/catalog/message-objects.js.map +7 -0
- package/dist/modules/currencies/backend/currencies/[id]/page.js +21 -0
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/lib/messageObjectPreviews.js +51 -0
- package/dist/modules/currencies/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/currencies/message-objects.js +41 -0
- package/dist/modules/currencies/message-objects.js.map +7 -0
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +20 -0
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +20 -0
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyHighlights.js +18 -14
- package/dist/modules/customers/components/detail/CompanyHighlights.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonHighlights.js +18 -14
- package/dist/modules/customers/components/detail/PersonHighlights.js.map +2 -2
- package/dist/modules/customers/lib/messageObjectPreviews.js +41 -5
- package/dist/modules/customers/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/customers/message-objects.js +31 -11
- package/dist/modules/customers/message-objects.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +3 -0
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js +6 -1
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +4 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/frontend/messages/view/[token]/page.js +1 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -7
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/lib/messageObjectPreviews.js +43 -0
- package/dist/modules/resources/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/resources/message-objects.js +37 -0
- package/dist/modules/resources/message-objects.js.map +7 -0
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +19 -0
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +23 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/quotes/[id]/page.js +1 -1
- package/dist/modules/sales/backend/sales/quotes/[id]/page.js.map +2 -2
- package/dist/modules/sales/lib/messageObjectPreviews.js +49 -4
- package/dist/modules/sales/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/sales/message-objects.js +44 -2
- package/dist/modules/sales/message-objects.js.map +2 -2
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +59 -30
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +2 -2
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +1 -1
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +8 -30
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-availability/page.js +13 -0
- package/dist/modules/staff/backend/staff/my-availability/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +8 -31
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +32 -10
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +14 -1
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +4 -2
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamRoleForm.js +4 -2
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/dist/modules/staff/lib/messageObjectPreviews.js +111 -2
- package/dist/modules/staff/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/staff/message-objects.js +79 -8
- package/dist/modules/staff/message-objects.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +19 -5
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +14 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +40 -0
- package/src/modules/catalog/lib/messageObjectPreviews.ts +176 -0
- package/src/modules/catalog/message-objects.ts +102 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -0
- package/src/modules/currencies/lib/messageObjectPreviews.ts +65 -0
- package/src/modules/currencies/message-objects.ts +40 -0
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +19 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +13 -0
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +19 -0
- package/src/modules/customers/components/detail/CompanyHighlights.tsx +14 -9
- package/src/modules/customers/components/detail/PersonHighlights.tsx +14 -9
- package/src/modules/customers/lib/messageObjectPreviews.ts +43 -3
- package/src/modules/customers/message-objects.ts +31 -11
- package/src/modules/messages/commands/messages.ts +4 -0
- package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +8 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +3 -0
- package/src/modules/messages/frontend/messages/view/[token]/page.tsx +1 -0
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +20 -4
- package/src/modules/resources/lib/messageObjectPreviews.ts +55 -0
- package/src/modules/resources/message-objects.ts +36 -0
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +18 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -0
- package/src/modules/sales/backend/sales/quotes/[id]/page.tsx +1 -1
- package/src/modules/sales/lib/messageObjectPreviews.ts +54 -4
- package/src/modules/sales/message-objects.ts +44 -2
- package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +72 -34
- package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +1 -1
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +7 -29
- package/src/modules/staff/backend/staff/my-availability/page.tsx +14 -0
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +8 -30
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +28 -7
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +12 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +12 -0
- package/src/modules/staff/components/TeamForm.tsx +3 -0
- package/src/modules/staff/components/TeamRoleForm.tsx +3 -0
- package/src/modules/staff/lib/messageObjectPreviews.ts +133 -2
- package/src/modules/staff/message-objects.ts +79 -8
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +0 -51
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +0 -7
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +0 -35
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +0 -7
- package/dist/modules/customers/widgets/messages/index.js +0 -7
- package/dist/modules/customers/widgets/messages/index.js.map +0 -7
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +0 -51
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +0 -7
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +0 -34
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +0 -7
- package/dist/modules/staff/widgets/messages/index.js +0 -7
- package/dist/modules/staff/widgets/messages/index.js.map +0 -7
- package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +0 -57
- package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +0 -49
- package/src/modules/customers/widgets/messages/index.ts +0 -2
- package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +0 -57
- package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +0 -44
- package/src/modules/staff/widgets/messages/index.ts +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/CompanyHighlights.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n InlineTextEditor,\n InlineDictionaryEditor,\n InlineNextInteractionEditor,\n type InlineFieldProps,\n type NextInteractionPayload,\n} from './InlineEditors'\n\ntype CompanyHighlightsCompany = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n}\n\ntype CompanyHighlightsProfile = {\n id?: string\n brandName?: string | null\n legalName?: string | null\n websiteUrl?: string | null\n industry?: string | null\n annualRevenue?: string | null\n} | null\n\ntype CompanyHighlightsValidators = {\n email: NonNullable<InlineFieldProps['validator']>\n phone: NonNullable<InlineFieldProps['validator']>\n displayName: NonNullable<InlineFieldProps['validator']>\n}\n\nexport type CompanyHighlightsProps = {\n company: CompanyHighlightsCompany\n profile?: CompanyHighlightsProfile\n validators: CompanyHighlightsValidators\n onDisplayNameSave: (value: string | null) => Promise<void>\n onPrimaryEmailSave: (value: string | null) => Promise<void>\n onPrimaryPhoneSave: (value: string | null) => Promise<void>\n onStatusSave: (value: string | null) => Promise<void>\n onNextInteractionSave: (payload: NextInteractionPayload | null) => Promise<void>\n onDelete: () => void\n isDeleting: boolean\n}\n\nexport function CompanyHighlights({\n company,\n profile,\n validators,\n onDisplayNameSave,\n onPrimaryEmailSave,\n onPrimaryPhoneSave,\n onStatusSave,\n onNextInteractionSave,\n onDelete,\n isDeleting,\n}: CompanyHighlightsProps) {\n const t = useT()\n const historyFallbackId =\n profile?.id && profile.id !== company.id ? profile.id : undefined\n\n return (\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/companies\"\n backLabel={t('customers.companies.detail.actions.backToList', 'Back to companies')}\n utilityActions={(\n <VersionHistoryAction\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n InlineTextEditor,\n InlineDictionaryEditor,\n InlineNextInteractionEditor,\n type InlineFieldProps,\n type NextInteractionPayload,\n} from './InlineEditors'\n\ntype CompanyHighlightsCompany = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n}\n\ntype CompanyHighlightsProfile = {\n id?: string\n brandName?: string | null\n legalName?: string | null\n websiteUrl?: string | null\n industry?: string | null\n annualRevenue?: string | null\n} | null\n\ntype CompanyHighlightsValidators = {\n email: NonNullable<InlineFieldProps['validator']>\n phone: NonNullable<InlineFieldProps['validator']>\n displayName: NonNullable<InlineFieldProps['validator']>\n}\n\nexport type CompanyHighlightsProps = {\n company: CompanyHighlightsCompany\n profile?: CompanyHighlightsProfile\n validators: CompanyHighlightsValidators\n onDisplayNameSave: (value: string | null) => Promise<void>\n onPrimaryEmailSave: (value: string | null) => Promise<void>\n onPrimaryPhoneSave: (value: string | null) => Promise<void>\n onStatusSave: (value: string | null) => Promise<void>\n onNextInteractionSave: (payload: NextInteractionPayload | null) => Promise<void>\n onDelete: () => void\n isDeleting: boolean\n utilityActions?: React.ReactNode\n}\n\nexport function CompanyHighlights({\n company,\n profile,\n validators,\n onDisplayNameSave,\n onPrimaryEmailSave,\n onPrimaryPhoneSave,\n onStatusSave,\n onNextInteractionSave,\n onDelete,\n isDeleting,\n utilityActions,\n}: CompanyHighlightsProps) {\n const t = useT()\n const historyFallbackId =\n profile?.id && profile.id !== company.id ? profile.id : undefined\n\n return (\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/companies\"\n backLabel={t('customers.companies.detail.actions.backToList', 'Back to companies')}\n utilityActions={(\n <>\n {utilityActions}\n <VersionHistoryAction\n config={{\n resourceKind: 'customers.company',\n resourceId: company.id,\n resourceIdFallback: historyFallbackId,\n organizationId: company.organizationId ?? undefined,\n }}\n t={t}\n />\n </>\n )}\n title={\n <InlineTextEditor\n label={t('customers.companies.form.displayName.label', 'Display name')}\n value={company.displayName}\n placeholder={t('customers.companies.form.displayName.placeholder', 'Enter company name')}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n validator={validators.displayName}\n onSave={onDisplayNameSave}\n hideLabel\n variant=\"plain\"\n activateOnClick\n triggerClassName=\"opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n containerClassName=\"max-w-full\"\n />\n }\n onDelete={() => {\n onDelete()\n }}\n isDeleting={isDeleting}\n deleteLabel={t('customers.companies.detail.actions.delete', 'Delete company')}\n />\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <InlineTextEditor\n label={t('customers.companies.detail.highlights.primaryEmail', 'Primary email')}\n value={company.primaryEmail || ''}\n placeholder={t('customers.companies.form.primaryEmail', 'Add email')}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n type=\"email\"\n validator={validators.email}\n recordId={company.id}\n activateOnClick\n onSave={onPrimaryEmailSave}\n />\n <InlineTextEditor\n label={t('customers.companies.detail.highlights.primaryPhone', 'Primary phone')}\n value={company.primaryPhone || ''}\n placeholder={t('customers.companies.form.primaryPhone', 'Add phone')}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n type=\"tel\"\n validator={validators.phone}\n recordId={company.id}\n activateOnClick\n onSave={onPrimaryPhoneSave}\n />\n <InlineDictionaryEditor\n label={t('customers.companies.detail.highlights.status', 'Status')}\n value={company.status ?? null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n activateOnClick\n onSave={onStatusSave}\n kind=\"statuses\"\n />\n <InlineNextInteractionEditor\n label={t('customers.companies.detail.highlights.nextInteraction', 'Next interaction')}\n valueAt={company.nextInteractionAt || null}\n valueName={company.nextInteractionName || null}\n valueRefId={company.nextInteractionRefId || null}\n valueIcon={company.nextInteractionIcon || null}\n valueColor={company.nextInteractionColor || null}\n emptyLabel={t('customers.companies.detail.noValue', 'Not provided')}\n onSave={onNextInteractionSave}\n activateOnClick\n />\n </div>\n </div>\n )\n}\n\nexport default CompanyHighlights\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
5
|
import { Building2, Loader2, Pencil, X } from "lucide-react";
|
|
@@ -26,7 +26,8 @@ function PersonHighlights({
|
|
|
26
26
|
onNextInteractionSave,
|
|
27
27
|
onDelete,
|
|
28
28
|
isDeleting,
|
|
29
|
-
onCompanySave
|
|
29
|
+
onCompanySave,
|
|
30
|
+
utilityActions
|
|
30
31
|
}) {
|
|
31
32
|
const router = useRouter();
|
|
32
33
|
const t = useT();
|
|
@@ -260,18 +261,21 @@ function PersonHighlights({
|
|
|
260
261
|
mode: "detail",
|
|
261
262
|
backHref: "/backend/customers/people",
|
|
262
263
|
backLabel: t("customers.people.detail.actions.backToList"),
|
|
263
|
-
utilityActions: /* @__PURE__ */
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
264
|
+
utilityActions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
265
|
+
utilityActions,
|
|
266
|
+
/* @__PURE__ */ jsx(
|
|
267
|
+
VersionHistoryAction,
|
|
268
|
+
{
|
|
269
|
+
config: {
|
|
270
|
+
resourceKind: "customers.person",
|
|
271
|
+
resourceId: person.id,
|
|
272
|
+
resourceIdFallback: historyFallbackId,
|
|
273
|
+
organizationId: person.organizationId ?? void 0
|
|
274
|
+
},
|
|
275
|
+
t
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
] }),
|
|
275
279
|
title: /* @__PURE__ */ jsx(
|
|
276
280
|
InlineTextEditor,
|
|
277
281
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/PersonHighlights.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Building2, Loader2, Pencil, X } from 'lucide-react'\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 { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { CompanySelectField } from '../formConfig'\nimport {\n InlineTextEditor,\n InlineDictionaryEditor,\n InlineNextInteractionEditor,\n type InlineFieldProps,\n type NextInteractionPayload,\n} from './InlineEditors'\n\ntype PersonHighlightsPerson = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n}\n\ntype PersonHighlightsProfile = {\n id?: string\n companyEntityId?: string | null\n} | null\n\ntype PersonHighlightsValidators = {\n email: NonNullable<InlineFieldProps['validator']>\n phone: NonNullable<InlineFieldProps['validator']>\n displayName: NonNullable<InlineFieldProps['validator']>\n}\n\nexport type PersonHighlightsProps = {\n person: PersonHighlightsPerson\n profile: PersonHighlightsProfile\n validators: PersonHighlightsValidators\n onDisplayNameSave: (value: string | null) => Promise<void>\n onPrimaryEmailSave: (value: string | null) => Promise<void>\n onPrimaryPhoneSave: (value: string | null) => Promise<void>\n onStatusSave: (value: string | null) => Promise<void>\n onNextInteractionSave: (value: NextInteractionPayload | null) => Promise<void>\n onDelete: () => void\n isDeleting: boolean\n onCompanySave: (companyId: string | null) => Promise<void>\n}\n\ntype CompanyInfo = { id: string; name: string }\n\nexport function PersonHighlights({\n person,\n profile,\n validators,\n onDisplayNameSave,\n onPrimaryEmailSave,\n onPrimaryPhoneSave,\n onStatusSave,\n onNextInteractionSave,\n onDelete,\n isDeleting,\n onCompanySave,\n}: PersonHighlightsProps) {\n const router = useRouter()\n const t = useT()\n const runMutation = React.useCallback(async (operation: () => Promise<void>) => operation(), [])\n const [editingCompany, setEditingCompany] = React.useState(false)\n const [companyDraftId, setCompanyDraftId] = React.useState<string>('')\n const [company, setCompany] = React.useState<CompanyInfo | null>(null)\n const [companyLoading, setCompanyLoading] = React.useState(false)\n const [companyError, setCompanyError] = React.useState<string | null>(null)\n const [companySaving, setCompanySaving] = React.useState(false)\n const companyHref = React.useMemo(\n () => (company ? `/backend/customers/companies/${encodeURIComponent(company.id)}` : null),\n [company],\n )\n const isCompanyInteractive = !editingCompany && !companyLoading && !companyError && Boolean(companyHref)\n\n const navigateToCompany = React.useCallback(() => {\n if (!companyHref) return\n router.push(companyHref)\n }, [companyHref])\n\n const handleCompanyClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive || !companyHref) return\n const target = event.target as HTMLElement\n if (target.closest('button')) return\n if (event.defaultPrevented) return\n if (event.button !== 0) return\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n if (typeof window !== 'undefined') {\n window.open(companyHref, '_blank', 'noopener,noreferrer')\n }\n return\n }\n navigateToCompany()\n },\n [companyHref, isCompanyInteractive, navigateToCompany],\n )\n\n const handleCompanyKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n navigateToCompany()\n }\n },\n [isCompanyInteractive, navigateToCompany],\n )\n\n const activeCompanyId = profile?.companyEntityId ?? null\n const historyFallbackId =\n profile?.id && profile.id !== person.id ? profile.id : undefined\n\n const loadCompany = React.useCallback(async (companyId: string | null) => {\n if (!companyId) {\n setCompany(null)\n return\n }\n setCompanyLoading(true)\n setCompanyError(null)\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/companies?id=${encodeURIComponent(companyId)}`,\n undefined,\n { errorMessage: t('customers.people.detail.company.loadError', 'Unable to load company information.') },\n )\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, unknown>>) : []\n const item = items.find((entry) => {\n if (!entry) return false\n const rawId = (entry as Record<string, unknown>).id\n if (typeof rawId === 'string') return rawId === companyId\n if (typeof rawId === 'number') return String(rawId) === companyId\n return false\n }) as Record<string, unknown> | undefined\n if (item && typeof item.display_name === 'string') {\n setCompany({ id: companyId, name: item.display_name })\n } else if (item && typeof item.displayName === 'string') {\n setCompany({ id: companyId, name: item.displayName })\n } else {\n setCompany({ id: companyId, name: t('customers.people.detail.company.unknown', 'Unknown company') })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.company.loadError', 'Unable to load company.')\n setCompanyError(message)\n setCompany(null)\n } finally {\n setCompanyLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n setCompanyDraftId(activeCompanyId ?? '')\n loadCompany(activeCompanyId).catch(() => {})\n }, [activeCompanyId, loadCompany])\n\n const handleCompanySave = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n const nextId = companyDraftId.trim()\n try {\n await runMutation(async () => {\n await onCompanySave(nextId.length ? nextId : null)\n })\n await loadCompany(nextId.length ? nextId : null)\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companyDraftId, companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const handleCompanyClear = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n try {\n await runMutation(async () => {\n await onCompanySave(null)\n })\n await loadCompany(null)\n setCompanyDraftId('')\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const companyPanel = (\n <div\n className={cn(\n 'group rounded-lg border bg-muted/30 p-3',\n isCompanyInteractive\n ? 'cursor-pointer transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n : null,\n )}\n role={isCompanyInteractive ? 'link' : undefined}\n tabIndex={isCompanyInteractive ? 0 : undefined}\n onClick={handleCompanyClick}\n onKeyDown={handleCompanyKeyDown}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1 space-y-1\">\n <p className=\"flex items-center gap-2 text-xs uppercase tracking-wide text-muted-foreground\">\n <Building2 aria-hidden className=\"h-3.5 w-3.5\" />\n {t('customers.people.detail.company.label', 'Company')}\n </p>\n {editingCompany ? (\n <div\n className=\"space-y-3\"\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n if (!companySaving) {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!companySaving) {\n void handleCompanySave()\n }\n }\n }}\n >\n <CompanySelectField\n value={companyDraftId || undefined}\n onChange={(next) => setCompanyDraftId(next ?? '')}\n labels={{\n placeholder: t('customers.people.form.company.placeholder'),\n addLabel: t('customers.people.form.company.add'),\n addPrompt: t('customers.people.form.company.prompt'),\n dialogTitle: t('customers.people.form.company.dialogTitle'),\n inputLabel: t('customers.people.form.company.inputLabel'),\n inputPlaceholder: t('customers.people.form.company.inputPlaceholder'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.company.loading'),\n }}\n />\n {companyError ? <p className=\"text-xs text-red-600\">{companyError}</p> : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={handleCompanySave} disabled={companySaving}>\n {companySaving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.forms.actions.save')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }} disabled={companySaving}>\n {t('ui.forms.actions.cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={handleCompanyClear} disabled={companySaving}>\n {t('ui.forms.actions.clear')}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center gap-2 text-sm\">\n {companyLoading ? (\n <span className=\"inline-flex items-center gap-2 text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {t('customers.people.detail.company.loading', 'Loading company\u2026')}\n </span>\n ) : company ? (\n <span className=\"text-primary transition group-hover:underline\">\n {t('customers.people.detail.company.current', undefined, { company: company.name })}\n </span>\n ) : companyError ? (\n <span className=\"text-xs text-red-600\">{companyError}</span>\n ) : (\n <span className=\"text-muted-foreground\">\n {t('customers.people.detail.company.empty', 'No company assigned')}\n </span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (companySaving) return\n setEditingCompany((prev) => !prev)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }}\n className={\n editingCompany\n ? 'opacity-100'\n : 'opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:opacity-100 focus-visible:opacity-100'\n }\n >\n {editingCompany ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">\n {editingCompany ? t('ui.forms.actions.cancel') : t('ui.forms.actions.edit')}\n </span>\n </Button>\n </div>\n </div>\n )\n\n return (\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/people\"\n backLabel={t('customers.people.detail.actions.backToList')}\n utilityActions={(\n <VersionHistoryAction\n config={{\n resourceKind: 'customers.person',\n resourceId: person.id,\n resourceIdFallback: historyFallbackId,\n organizationId: person.organizationId ?? undefined,\n }}\n t={t}\n />\n )}\n title={\n <InlineTextEditor\n label={t('customers.people.form.displayName.label')}\n value={person.displayName}\n placeholder={t('customers.people.form.displayName.placeholder')}\n emptyLabel={t('customers.people.detail.noValue')}\n validator={validators.displayName}\n onSave={onDisplayNameSave}\n hideLabel\n variant=\"plain\"\n activateOnClick\n triggerClassName=\"opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n containerClassName=\"max-w-full\"\n />\n }\n onDelete={() => {\n onDelete()\n }}\n isDeleting={isDeleting}\n deleteLabel={t('customers.people.list.actions.delete')}\n />\n\n {companyPanel}\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryEmail')}\n value={person.primaryEmail || ''}\n placeholder={t('customers.people.form.primaryEmail')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"email\"\n validator={validators.email}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryEmailSave}\n />\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryPhone')}\n value={person.primaryPhone || ''}\n placeholder={t('customers.people.form.primaryPhone')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"tel\"\n validator={validators.phone}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryPhoneSave}\n />\n <InlineDictionaryEditor\n label={t('customers.people.detail.highlights.status')}\n value={person.status ?? null}\n emptyLabel={t('customers.people.detail.noValue')}\n activateOnClick\n onSave={onStatusSave}\n kind=\"statuses\"\n />\n <InlineNextInteractionEditor\n label={t('customers.people.detail.highlights.nextInteraction')}\n valueAt={person.nextInteractionAt || null}\n valueName={person.nextInteractionName || null}\n valueRefId={person.nextInteractionRefId || null}\n valueIcon={person.nextInteractionIcon || null}\n valueColor={person.nextInteractionColor || null}\n emptyLabel={t('customers.people.detail.noValue')}\n onSave={onNextInteractionSave}\n activateOnClick\n />\n </div>\n </div>\n )\n}\n\nexport default PersonHighlights\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Building2, Loader2, Pencil, X } from 'lucide-react'\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 { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { CompanySelectField } from '../formConfig'\nimport {\n InlineTextEditor,\n InlineDictionaryEditor,\n InlineNextInteractionEditor,\n type InlineFieldProps,\n type NextInteractionPayload,\n} from './InlineEditors'\n\ntype PersonHighlightsPerson = {\n id: string\n displayName: string\n primaryEmail?: string | null\n primaryPhone?: string | null\n status?: string | null\n nextInteractionAt?: string | null\n nextInteractionName?: string | null\n nextInteractionRefId?: string | null\n nextInteractionIcon?: string | null\n nextInteractionColor?: string | null\n organizationId?: string | null\n}\n\ntype PersonHighlightsProfile = {\n id?: string\n companyEntityId?: string | null\n} | null\n\ntype PersonHighlightsValidators = {\n email: NonNullable<InlineFieldProps['validator']>\n phone: NonNullable<InlineFieldProps['validator']>\n displayName: NonNullable<InlineFieldProps['validator']>\n}\n\nexport type PersonHighlightsProps = {\n person: PersonHighlightsPerson\n profile: PersonHighlightsProfile\n validators: PersonHighlightsValidators\n onDisplayNameSave: (value: string | null) => Promise<void>\n onPrimaryEmailSave: (value: string | null) => Promise<void>\n onPrimaryPhoneSave: (value: string | null) => Promise<void>\n onStatusSave: (value: string | null) => Promise<void>\n onNextInteractionSave: (value: NextInteractionPayload | null) => Promise<void>\n onDelete: () => void\n isDeleting: boolean\n onCompanySave: (companyId: string | null) => Promise<void>\n utilityActions?: React.ReactNode\n}\n\ntype CompanyInfo = { id: string; name: string }\n\nexport function PersonHighlights({\n person,\n profile,\n validators,\n onDisplayNameSave,\n onPrimaryEmailSave,\n onPrimaryPhoneSave,\n onStatusSave,\n onNextInteractionSave,\n onDelete,\n isDeleting,\n onCompanySave,\n utilityActions,\n}: PersonHighlightsProps) {\n const router = useRouter()\n const t = useT()\n const runMutation = React.useCallback(async (operation: () => Promise<void>) => operation(), [])\n const [editingCompany, setEditingCompany] = React.useState(false)\n const [companyDraftId, setCompanyDraftId] = React.useState<string>('')\n const [company, setCompany] = React.useState<CompanyInfo | null>(null)\n const [companyLoading, setCompanyLoading] = React.useState(false)\n const [companyError, setCompanyError] = React.useState<string | null>(null)\n const [companySaving, setCompanySaving] = React.useState(false)\n const companyHref = React.useMemo(\n () => (company ? `/backend/customers/companies/${encodeURIComponent(company.id)}` : null),\n [company],\n )\n const isCompanyInteractive = !editingCompany && !companyLoading && !companyError && Boolean(companyHref)\n\n const navigateToCompany = React.useCallback(() => {\n if (!companyHref) return\n router.push(companyHref)\n }, [companyHref])\n\n const handleCompanyClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive || !companyHref) return\n const target = event.target as HTMLElement\n if (target.closest('button')) return\n if (event.defaultPrevented) return\n if (event.button !== 0) return\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n if (typeof window !== 'undefined') {\n window.open(companyHref, '_blank', 'noopener,noreferrer')\n }\n return\n }\n navigateToCompany()\n },\n [companyHref, isCompanyInteractive, navigateToCompany],\n )\n\n const handleCompanyKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!isCompanyInteractive) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n navigateToCompany()\n }\n },\n [isCompanyInteractive, navigateToCompany],\n )\n\n const activeCompanyId = profile?.companyEntityId ?? null\n const historyFallbackId =\n profile?.id && profile.id !== person.id ? profile.id : undefined\n\n const loadCompany = React.useCallback(async (companyId: string | null) => {\n if (!companyId) {\n setCompany(null)\n return\n }\n setCompanyLoading(true)\n setCompanyError(null)\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/companies?id=${encodeURIComponent(companyId)}`,\n undefined,\n { errorMessage: t('customers.people.detail.company.loadError', 'Unable to load company information.') },\n )\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, unknown>>) : []\n const item = items.find((entry) => {\n if (!entry) return false\n const rawId = (entry as Record<string, unknown>).id\n if (typeof rawId === 'string') return rawId === companyId\n if (typeof rawId === 'number') return String(rawId) === companyId\n return false\n }) as Record<string, unknown> | undefined\n if (item && typeof item.display_name === 'string') {\n setCompany({ id: companyId, name: item.display_name })\n } else if (item && typeof item.displayName === 'string') {\n setCompany({ id: companyId, name: item.displayName })\n } else {\n setCompany({ id: companyId, name: t('customers.people.detail.company.unknown', 'Unknown company') })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.people.detail.company.loadError', 'Unable to load company.')\n setCompanyError(message)\n setCompany(null)\n } finally {\n setCompanyLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n setCompanyDraftId(activeCompanyId ?? '')\n loadCompany(activeCompanyId).catch(() => {})\n }, [activeCompanyId, loadCompany])\n\n const handleCompanySave = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n const nextId = companyDraftId.trim()\n try {\n await runMutation(async () => {\n await onCompanySave(nextId.length ? nextId : null)\n })\n await loadCompany(nextId.length ? nextId : null)\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companyDraftId, companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const handleCompanyClear = React.useCallback(async () => {\n if (companySaving) return\n setCompanySaving(true)\n setCompanyError(null)\n try {\n await runMutation(async () => {\n await onCompanySave(null)\n })\n await loadCompany(null)\n setCompanyDraftId('')\n setEditingCompany(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.people.detail.company.saveError', 'Unable to update company.')\n setCompanyError(message)\n } finally {\n setCompanySaving(false)\n }\n }, [companySaving, loadCompany, onCompanySave, runMutation, t])\n\n const companyPanel = (\n <div\n className={cn(\n 'group rounded-lg border bg-muted/30 p-3',\n isCompanyInteractive\n ? 'cursor-pointer transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n : null,\n )}\n role={isCompanyInteractive ? 'link' : undefined}\n tabIndex={isCompanyInteractive ? 0 : undefined}\n onClick={handleCompanyClick}\n onKeyDown={handleCompanyKeyDown}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1 space-y-1\">\n <p className=\"flex items-center gap-2 text-xs uppercase tracking-wide text-muted-foreground\">\n <Building2 aria-hidden className=\"h-3.5 w-3.5\" />\n {t('customers.people.detail.company.label', 'Company')}\n </p>\n {editingCompany ? (\n <div\n className=\"space-y-3\"\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n if (!companySaving) {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!companySaving) {\n void handleCompanySave()\n }\n }\n }}\n >\n <CompanySelectField\n value={companyDraftId || undefined}\n onChange={(next) => setCompanyDraftId(next ?? '')}\n labels={{\n placeholder: t('customers.people.form.company.placeholder'),\n addLabel: t('customers.people.form.company.add'),\n addPrompt: t('customers.people.form.company.prompt'),\n dialogTitle: t('customers.people.form.company.dialogTitle'),\n inputLabel: t('customers.people.form.company.inputLabel'),\n inputPlaceholder: t('customers.people.form.company.inputPlaceholder'),\n emptyError: t('customers.people.form.dictionary.errorRequired'),\n cancelLabel: t('customers.people.form.dictionary.cancel'),\n saveLabel: t('customers.people.form.dictionary.save'),\n errorLoad: t('customers.people.form.dictionary.errorLoad'),\n errorSave: t('customers.people.form.dictionary.error'),\n loadingLabel: t('customers.people.form.company.loading'),\n }}\n />\n {companyError ? <p className=\"text-xs text-red-600\">{companyError}</p> : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={handleCompanySave} disabled={companySaving}>\n {companySaving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.forms.actions.save')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => {\n setEditingCompany(false)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }} disabled={companySaving}>\n {t('ui.forms.actions.cancel')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={handleCompanyClear} disabled={companySaving}>\n {t('ui.forms.actions.clear')}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center gap-2 text-sm\">\n {companyLoading ? (\n <span className=\"inline-flex items-center gap-2 text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {t('customers.people.detail.company.loading', 'Loading company\u2026')}\n </span>\n ) : company ? (\n <span className=\"text-primary transition group-hover:underline\">\n {t('customers.people.detail.company.current', undefined, { company: company.name })}\n </span>\n ) : companyError ? (\n <span className=\"text-xs text-red-600\">{companyError}</span>\n ) : (\n <span className=\"text-muted-foreground\">\n {t('customers.people.detail.company.empty', 'No company assigned')}\n </span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (companySaving) return\n setEditingCompany((prev) => !prev)\n setCompanyError(null)\n setCompanyDraftId(activeCompanyId ?? '')\n }}\n className={\n editingCompany\n ? 'opacity-100'\n : 'opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:opacity-100 focus-visible:opacity-100'\n }\n >\n {editingCompany ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">\n {editingCompany ? t('ui.forms.actions.cancel') : t('ui.forms.actions.edit')}\n </span>\n </Button>\n </div>\n </div>\n )\n\n return (\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/customers/people\"\n backLabel={t('customers.people.detail.actions.backToList')}\n utilityActions={(\n <>\n {utilityActions}\n <VersionHistoryAction\n config={{\n resourceKind: 'customers.person',\n resourceId: person.id,\n resourceIdFallback: historyFallbackId,\n organizationId: person.organizationId ?? undefined,\n }}\n t={t}\n />\n </>\n )}\n title={\n <InlineTextEditor\n label={t('customers.people.form.displayName.label')}\n value={person.displayName}\n placeholder={t('customers.people.form.displayName.placeholder')}\n emptyLabel={t('customers.people.detail.noValue')}\n validator={validators.displayName}\n onSave={onDisplayNameSave}\n hideLabel\n variant=\"plain\"\n activateOnClick\n triggerClassName=\"opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n containerClassName=\"max-w-full\"\n />\n }\n onDelete={() => {\n onDelete()\n }}\n isDeleting={isDeleting}\n deleteLabel={t('customers.people.list.actions.delete')}\n />\n\n {companyPanel}\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryEmail')}\n value={person.primaryEmail || ''}\n placeholder={t('customers.people.form.primaryEmail')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"email\"\n validator={validators.email}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryEmailSave}\n />\n <InlineTextEditor\n label={t('customers.people.detail.highlights.primaryPhone')}\n value={person.primaryPhone || ''}\n placeholder={t('customers.people.form.primaryPhone')}\n emptyLabel={t('customers.people.detail.noValue')}\n type=\"tel\"\n validator={validators.phone}\n recordId={person.id}\n activateOnClick\n onSave={onPrimaryPhoneSave}\n />\n <InlineDictionaryEditor\n label={t('customers.people.detail.highlights.status')}\n value={person.status ?? null}\n emptyLabel={t('customers.people.detail.noValue')}\n activateOnClick\n onSave={onStatusSave}\n kind=\"statuses\"\n />\n <InlineNextInteractionEditor\n label={t('customers.people.detail.highlights.nextInteraction')}\n valueAt={person.nextInteractionAt || null}\n valueName={person.nextInteractionName || null}\n valueRefId={person.nextInteractionRefId || null}\n valueIcon={person.nextInteractionIcon || null}\n valueColor={person.nextInteractionColor || null}\n emptyLabel={t('customers.people.detail.noValue')}\n onSave={onNextInteractionSave}\n activateOnClick\n />\n </div>\n </div>\n )\n}\n\nexport default PersonHighlights\n"],
|
|
5
|
+
"mappings": ";AAsOU,SAiHA,UAhHE,KADF;AApOV,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,WAAW,SAAS,QAAQ,SAAS;AAC9C,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B;AACrC,SAAS,YAAY;AACrB,SAAS,4BAA4B;AACrC,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AA4CA,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,SAAS,UAAU;AACzB,QAAM,IAAI,KAAK;AACf,QAAM,cAAc,MAAM,YAAY,OAAO,cAAmC,UAAU,GAAG,CAAC,CAAC;AAC/F,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAS,KAAK;AAChE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAiB,EAAE;AACrE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAA6B,IAAI;AACrE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAS,KAAK;AAChE,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAwB,IAAI;AAC1E,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAS,KAAK;AAC9D,QAAM,cAAc,MAAM;AAAA,IACxB,MAAO,UAAU,gCAAgC,mBAAmB,QAAQ,EAAE,CAAC,KAAK;AAAA,IACpF,CAAC,OAAO;AAAA,EACV;AACA,QAAM,uBAAuB,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,gBAAgB,QAAQ,WAAW;AAEvG,QAAM,oBAAoB,MAAM,YAAY,MAAM;AAChD,QAAI,CAAC,YAAa;AAClB,WAAO,KAAK,WAAW;AAAA,EACzB,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,qBAAqB,MAAM;AAAA,IAC/B,CAAC,UAA4C;AAC3C,UAAI,CAAC,wBAAwB,CAAC,YAAa;AAC3C,YAAM,SAAS,MAAM;AACrB,UAAI,OAAO,QAAQ,QAAQ,EAAG;AAC9B,UAAI,MAAM,iBAAkB;AAC5B,UAAI,MAAM,WAAW,EAAG;AACxB,UAAI,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY,MAAM,QAAQ;AACpE,YAAI,OAAO,WAAW,aAAa;AACjC,iBAAO,KAAK,aAAa,UAAU,qBAAqB;AAAA,QAC1D;AACA;AAAA,MACF;AACA,wBAAkB;AAAA,IACpB;AAAA,IACA,CAAC,aAAa,sBAAsB,iBAAiB;AAAA,EACvD;AAEA,QAAM,uBAAuB,MAAM;AAAA,IACjC,CAAC,UAA+C;AAC9C,UAAI,CAAC,qBAAsB;AAC3B,UAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;AAC9C,cAAM,eAAe;AACrB,0BAAkB;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAAC,sBAAsB,iBAAiB;AAAA,EAC1C;AAEA,QAAM,kBAAkB,SAAS,mBAAmB;AACpD,QAAM,oBACJ,SAAS,MAAM,QAAQ,OAAO,OAAO,KAAK,QAAQ,KAAK;AAEzD,QAAM,cAAc,MAAM,YAAY,OAAO,cAA6B;AACxE,QAAI,CAAC,WAAW;AACd,iBAAW,IAAI;AACf;AAAA,IACF;AACA,sBAAkB,IAAI;AACtB,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAM,UAAU,MAAM;AAAA,QACpB,+BAA+B,mBAAmB,SAAS,CAAC;AAAA,QAC5D;AAAA,QACA,EAAE,cAAc,EAAE,6CAA6C,qCAAqC,EAAE;AAAA,MACxG;AACA,YAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK,IAAK,QAAQ,QAA2C,CAAC;AACnG,YAAM,OAAO,MAAM,KAAK,CAAC,UAAU;AACjC,YAAI,CAAC,MAAO,QAAO;AACnB,cAAM,QAAS,MAAkC;AACjD,YAAI,OAAO,UAAU,SAAU,QAAO,UAAU;AAChD,YAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,MAAM;AACxD,eAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ,OAAO,KAAK,iBAAiB,UAAU;AACjD,mBAAW,EAAE,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC;AAAA,MACvD,WAAW,QAAQ,OAAO,KAAK,gBAAgB,UAAU;AACvD,mBAAW,EAAE,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AAAA,MACtD,OAAO;AACL,mBAAW,EAAE,IAAI,WAAW,MAAM,EAAE,2CAA2C,iBAAiB,EAAE,CAAC;AAAA,MACrG;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,EAAE,6CAA6C,yBAAyB;AAC7H,sBAAgB,OAAO;AACvB,iBAAW,IAAI;AAAA,IACjB,UAAE;AACA,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,sBAAkB,mBAAmB,EAAE;AACvC,gBAAY,eAAe,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7C,GAAG,CAAC,iBAAiB,WAAW,CAAC;AAEjC,QAAM,oBAAoB,MAAM,YAAY,YAAY;AACtD,QAAI,cAAe;AACnB,qBAAiB,IAAI;AACrB,oBAAgB,IAAI;AACpB,UAAM,SAAS,eAAe,KAAK;AACnC,QAAI;AACF,YAAM,YAAY,YAAY;AAC5B,cAAM,cAAc,OAAO,SAAS,SAAS,IAAI;AAAA,MACnD,CAAC;AACD,YAAM,YAAY,OAAO,SAAS,SAAS,IAAI;AAC/C,wBAAkB,KAAK;AAAA,IACzB,SAAS,KAAK;AACZ,YAAM,UACJ,eAAe,QACX,IAAI,UACJ,EAAE,6CAA6C,2BAA2B;AAChF,sBAAgB,OAAO;AAAA,IACzB,UAAE;AACA,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,gBAAgB,eAAe,aAAa,eAAe,aAAa,CAAC,CAAC;AAE9E,QAAM,qBAAqB,MAAM,YAAY,YAAY;AACvD,QAAI,cAAe;AACnB,qBAAiB,IAAI;AACrB,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAM,YAAY,YAAY;AAC5B,cAAM,cAAc,IAAI;AAAA,MAC1B,CAAC;AACD,YAAM,YAAY,IAAI;AACtB,wBAAkB,EAAE;AACpB,wBAAkB,KAAK;AAAA,IACzB,SAAS,KAAK;AACZ,YAAM,UACJ,eAAe,QACX,IAAI,UACJ,EAAE,6CAA6C,2BAA2B;AAChF,sBAAgB,OAAO;AAAA,IACzB,UAAE;AACA,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,eAAe,aAAa,eAAe,aAAa,CAAC,CAAC;AAE9D,QAAM,eACJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,uBACI,+HACA;AAAA,MACN;AAAA,MACA,MAAM,uBAAuB,SAAS;AAAA,MACtC,UAAU,uBAAuB,IAAI;AAAA,MACrC,SAAS;AAAA,MACT,WAAW;AAAA,MAEX,+BAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,SAAI,WAAU,oBACb;AAAA,+BAAC,OAAE,WAAU,iFACX;AAAA,gCAAC,aAAU,eAAW,MAAC,WAAU,eAAc;AAAA,YAC9C,EAAE,yCAAyC,SAAS;AAAA,aACvD;AAAA,UACC,iBACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,WAAW,CAAC,UAAU;AACpB,oBAAI,MAAM,QAAQ,UAAU;AAC1B,wBAAM,eAAe;AACrB,sBAAI,CAAC,eAAe;AAClB,sCAAkB,KAAK;AACvB,oCAAgB,IAAI;AACpB,sCAAkB,mBAAmB,EAAE;AAAA,kBACzC;AAAA,gBACF;AACA,oBAAI,MAAM,QAAQ,YAAY,MAAM,WAAW,MAAM,UAAU;AAC7D,wBAAM,eAAe;AACrB,sBAAI,CAAC,eAAe;AAClB,yBAAK,kBAAkB;AAAA,kBACzB;AAAA,gBACF;AAAA,cACF;AAAA,cAEA;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO,kBAAkB;AAAA,oBACzB,UAAU,CAAC,SAAS,kBAAkB,QAAQ,EAAE;AAAA,oBAChD,QAAQ;AAAA,sBACN,aAAa,EAAE,2CAA2C;AAAA,sBAC1D,UAAU,EAAE,mCAAmC;AAAA,sBAC/C,WAAW,EAAE,sCAAsC;AAAA,sBACnD,aAAa,EAAE,2CAA2C;AAAA,sBAC1D,YAAY,EAAE,0CAA0C;AAAA,sBACxD,kBAAkB,EAAE,gDAAgD;AAAA,sBACpE,YAAY,EAAE,gDAAgD;AAAA,sBAC9D,aAAa,EAAE,yCAAyC;AAAA,sBACxD,WAAW,EAAE,uCAAuC;AAAA,sBACpD,WAAW,EAAE,4CAA4C;AAAA,sBACzD,WAAW,EAAE,wCAAwC;AAAA,sBACrD,cAAc,EAAE,uCAAuC;AAAA,oBACzD;AAAA;AAAA,gBACF;AAAA,gBACC,eAAe,oBAAC,OAAE,WAAU,wBAAwB,wBAAa,IAAO;AAAA,gBACzE,qBAAC,SAAI,WAAU,qCACb;AAAA,uCAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAS,mBAAmB,UAAU,eACnE;AAAA,oCAAgB,oBAAC,WAAQ,WAAU,iCAAgC,IAAK;AAAA,oBACxE,EAAE,uBAAuB;AAAA,qBAC5B;AAAA,kBACA,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,SAAQ,SAAS,MAAM;AAC7D,sCAAkB,KAAK;AACvB,oCAAgB,IAAI;AACpB,sCAAkB,mBAAmB,EAAE;AAAA,kBACzC,GAAG,UAAU,eACV,YAAE,yBAAyB,GAC9B;AAAA,kBACA,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,aAAY,SAAS,oBAAoB,UAAU,eACxF,YAAE,wBAAwB,GAC7B;AAAA,mBACF;AAAA;AAAA;AAAA,UACF,IAEA,oBAAC,SAAI,WAAU,mCACZ,2BACC,qBAAC,UAAK,WAAU,wDACd;AAAA,gCAAC,WAAQ,WAAU,wBAAuB;AAAA,YACzC,EAAE,2CAA2C,uBAAkB;AAAA,aAClE,IACE,UACF,oBAAC,UAAK,WAAU,iDACb,YAAE,2CAA2C,QAAW,EAAE,SAAS,QAAQ,KAAK,CAAC,GACpF,IACE,eACF,oBAAC,UAAK,WAAU,wBAAwB,wBAAa,IAErD,oBAAC,UAAK,WAAU,yBACb,YAAE,yCAAyC,qBAAqB,GACnE,GAEJ;AAAA,WAEJ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM;AACb,kBAAI,cAAe;AACnB,gCAAkB,CAAC,SAAS,CAAC,IAAI;AACjC,8BAAgB,IAAI;AACpB,gCAAkB,mBAAmB,EAAE;AAAA,YACzC;AAAA,YACA,WACE,iBACI,gBACA;AAAA,YAGL;AAAA,+BAAiB,oBAAC,KAAE,WAAU,WAAU,IAAK,oBAAC,UAAO,WAAU,WAAU;AAAA,cAC1E,oBAAC,UAAK,WAAU,WACb,2BAAiB,EAAE,yBAAyB,IAAI,EAAE,uBAAuB,GAC5E;AAAA;AAAA;AAAA,QACF;AAAA,SACF;AAAA;AAAA,EACF;AAGF,SACE,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAS;AAAA,QACT,WAAW,EAAE,4CAA4C;AAAA,QACzD,gBACE,iCACG;AAAA;AAAA,UACD;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,gBACN,cAAc;AAAA,gBACd,YAAY,OAAO;AAAA,gBACnB,oBAAoB;AAAA,gBACpB,gBAAgB,OAAO,kBAAkB;AAAA,cAC3C;AAAA,cACA;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEF,OACE;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,EAAE,yCAAyC;AAAA,YAClD,OAAO,OAAO;AAAA,YACd,aAAa,EAAE,+CAA+C;AAAA,YAC9D,YAAY,EAAE,iCAAiC;AAAA,YAC/C,WAAW,WAAW;AAAA,YACtB,QAAQ;AAAA,YACR,WAAS;AAAA,YACT,SAAQ;AAAA,YACR,iBAAe;AAAA,YACf,kBAAiB;AAAA,YACjB,oBAAmB;AAAA;AAAA,QACrB;AAAA,QAEF,UAAU,MAAM;AACd,mBAAS;AAAA,QACX;AAAA,QACA;AAAA,QACA,aAAa,EAAE,sCAAsC;AAAA;AAAA,IACvD;AAAA,IAEC;AAAA,IAED,qBAAC,SAAI,WAAU,4CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,iDAAiD;AAAA,UAC1D,OAAO,OAAO,gBAAgB;AAAA,UAC9B,aAAa,EAAE,oCAAoC;AAAA,UACnD,YAAY,EAAE,iCAAiC;AAAA,UAC/C,MAAK;AAAA,UACL,WAAW,WAAW;AAAA,UACtB,UAAU,OAAO;AAAA,UACjB,iBAAe;AAAA,UACf,QAAQ;AAAA;AAAA,MACV;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,iDAAiD;AAAA,UAC1D,OAAO,OAAO,gBAAgB;AAAA,UAC9B,aAAa,EAAE,oCAAoC;AAAA,UACnD,YAAY,EAAE,iCAAiC;AAAA,UAC/C,MAAK;AAAA,UACL,WAAW,WAAW;AAAA,UACtB,UAAU,OAAO;AAAA,UACjB,iBAAe;AAAA,UACf,QAAQ;AAAA;AAAA,MACV;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,2CAA2C;AAAA,UACpD,OAAO,OAAO,UAAU;AAAA,UACxB,YAAY,EAAE,iCAAiC;AAAA,UAC/C,iBAAe;AAAA,UACf,QAAQ;AAAA,UACR,MAAK;AAAA;AAAA,MACP;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,oDAAoD;AAAA,UAC7D,SAAS,OAAO,qBAAqB;AAAA,UACrC,WAAW,OAAO,uBAAuB;AAAA,UACzC,YAAY,OAAO,wBAAwB;AAAA,UAC3C,WAAW,OAAO,uBAAuB;AAAA,UACzC,YAAY,OAAO,wBAAwB;AAAA,UAC3C,YAAY,EAAE,iCAAiC;AAAA,UAC/C,QAAQ;AAAA,UACR,iBAAe;AAAA;AAAA,MACjB;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,IAAO,2BAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
2
|
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
3
3
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
4
|
-
import { CustomerDeal, CustomerEntity } from "../data/entities.js";
|
|
4
|
+
import { CustomerCompanyProfile, CustomerDeal, CustomerEntity, CustomerPersonProfile } from "../data/entities.js";
|
|
5
5
|
function formatCurrency(amount, currency) {
|
|
6
6
|
if (!amount) return null;
|
|
7
7
|
const value = Number(amount);
|
|
@@ -48,12 +48,29 @@ async function loadCustomerPersonPreview(entityId, ctx) {
|
|
|
48
48
|
if (!entity) {
|
|
49
49
|
return { title: defaultTitle, subtitle: entityId, status: t("customers.messageObjects.notFound"), statusColor: "gray" };
|
|
50
50
|
}
|
|
51
|
+
const profile = await findOneWithDecryption(
|
|
52
|
+
em,
|
|
53
|
+
CustomerPersonProfile,
|
|
54
|
+
{
|
|
55
|
+
entity,
|
|
56
|
+
tenantId: ctx.tenantId,
|
|
57
|
+
organizationId: ctx.organizationId
|
|
58
|
+
},
|
|
59
|
+
void 0,
|
|
60
|
+
{ tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
61
|
+
);
|
|
51
62
|
const subtitleParts = [entity.primaryEmail, entity.primaryPhone].filter((part) => Boolean(part && part.trim().length > 0));
|
|
63
|
+
const metadata = {};
|
|
64
|
+
const phoneLabel = t("customers.people.detail.highlights.primaryPhone");
|
|
65
|
+
const jobTitleLabel = t("customers.people.detail.fields.jobTitle");
|
|
66
|
+
if (entity.primaryPhone && entity.primaryPhone.trim().length > 0) metadata[phoneLabel] = entity.primaryPhone;
|
|
67
|
+
if (profile?.jobTitle && profile.jobTitle.trim().length > 0) metadata[jobTitleLabel] = profile.jobTitle;
|
|
52
68
|
return {
|
|
53
69
|
title: entity.displayName,
|
|
54
70
|
subtitle: subtitleParts.join(" \u2022 ") || entityId,
|
|
55
71
|
status: entity.status ?? void 0,
|
|
56
|
-
statusColor: statusColor(entity.status)
|
|
72
|
+
statusColor: statusColor(entity.status),
|
|
73
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
57
74
|
};
|
|
58
75
|
}
|
|
59
76
|
async function loadCustomerCompanyPreview(entityId, ctx) {
|
|
@@ -79,12 +96,29 @@ async function loadCustomerCompanyPreview(entityId, ctx) {
|
|
|
79
96
|
if (!entity) {
|
|
80
97
|
return { title: defaultTitle, subtitle: entityId, status: t("customers.messageObjects.notFound"), statusColor: "gray" };
|
|
81
98
|
}
|
|
99
|
+
const profile = await findOneWithDecryption(
|
|
100
|
+
em,
|
|
101
|
+
CustomerCompanyProfile,
|
|
102
|
+
{
|
|
103
|
+
entity,
|
|
104
|
+
tenantId: ctx.tenantId,
|
|
105
|
+
organizationId: ctx.organizationId
|
|
106
|
+
},
|
|
107
|
+
void 0,
|
|
108
|
+
{ tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
109
|
+
);
|
|
82
110
|
const subtitleParts = [entity.primaryEmail, entity.primaryPhone].filter((part) => Boolean(part && part.trim().length > 0));
|
|
111
|
+
const metadata = {};
|
|
112
|
+
const phoneLabel = t("customers.companies.detail.highlights.primaryPhone");
|
|
113
|
+
const industryLabel = t("customers.companies.detail.fields.industry");
|
|
114
|
+
if (entity.primaryPhone && entity.primaryPhone.trim().length > 0) metadata[phoneLabel] = entity.primaryPhone;
|
|
115
|
+
if (profile?.industry && profile.industry.trim().length > 0) metadata[industryLabel] = profile.industry;
|
|
83
116
|
return {
|
|
84
117
|
title: entity.displayName,
|
|
85
118
|
subtitle: subtitleParts.join(" \u2022 ") || entityId,
|
|
86
119
|
status: entity.status ?? void 0,
|
|
87
|
-
statusColor: statusColor(entity.status)
|
|
120
|
+
statusColor: statusColor(entity.status),
|
|
121
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
88
122
|
};
|
|
89
123
|
}
|
|
90
124
|
async function loadCustomerDealPreview(entityId, ctx) {
|
|
@@ -113,8 +147,10 @@ async function loadCustomerDealPreview(entityId, ctx) {
|
|
|
113
147
|
const probability = typeof deal.probability === "number" ? `${deal.probability}%` : null;
|
|
114
148
|
const subtitle = [amount, probability].filter((part) => Boolean(part && part.length > 0)).join(" \u2022 ");
|
|
115
149
|
const metadata = {};
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
const valueLabel = t("customers.deals.detail.fields.value");
|
|
151
|
+
const probabilityLabel = t("customers.deals.detail.fields.probability");
|
|
152
|
+
if (amount) metadata[valueLabel] = amount;
|
|
153
|
+
if (probability) metadata[probabilityLabel] = probability;
|
|
118
154
|
return {
|
|
119
155
|
title: deal.title,
|
|
120
156
|
subtitle: subtitle || entityId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/messageObjectPreviews.ts"],
|
|
4
|
-
"sourcesContent": ["import { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { ObjectPreviewData } from '@open-mercato/shared/modules/messages/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerDeal, CustomerEntity } from '../data/entities'\n\ntype PreviewContext = {\n tenantId: string\n organizationId?: string | null\n}\n\nfunction formatCurrency(amount: string | null | undefined, currency: string | null | undefined): 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 statusColor(status: string | null | undefined): string | undefined {\n if (!status) return undefined\n const value = status.toLowerCase()\n if (value.includes('won') || value.includes('active') || value.includes('qualified')) return 'green'\n if (value.includes('lost') || value.includes('rejected') || value.includes('inactive')) return 'red'\n if (value.includes('open') || value.includes('new') || value.includes('pending')) return 'amber'\n return 'blue'\n}\n\nasync function resolveEm() {\n const { resolve } = await createRequestContainer()\n return resolve('em') as EntityManager\n}\n\nexport async function loadCustomerPersonPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('customers.messageObjects.person.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const em = await resolveEm()\n const entity = await findOneWithDecryption(\n em,\n CustomerEntity,\n {\n id: entityId,\n kind: 'person',\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!entity) {\n return { title: defaultTitle, subtitle: entityId, status: t('customers.messageObjects.notFound'), statusColor: 'gray' }\n }\n\n const subtitleParts = [entity.primaryEmail, entity.primaryPhone]\n .filter((part): part is string => Boolean(part && part.trim().length > 0))\n return {\n title: entity.displayName,\n subtitle: subtitleParts.join(' \u2022 ') || entityId,\n status: entity.status ?? undefined,\n statusColor: statusColor(entity.status),\n }\n}\n\nexport async function loadCustomerCompanyPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('customers.messageObjects.company.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const em = await resolveEm()\n const entity = await findOneWithDecryption(\n em,\n CustomerEntity,\n {\n id: entityId,\n kind: 'company',\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!entity) {\n return { title: defaultTitle, subtitle: entityId, status: t('customers.messageObjects.notFound'), statusColor: 'gray' }\n }\n\n const subtitleParts = [entity.primaryEmail, entity.primaryPhone]\n .filter((part): part is string => Boolean(part && part.trim().length > 0))\n return {\n title: entity.displayName,\n subtitle: subtitleParts.join(' \u2022 ') || entityId,\n status: entity.status ?? undefined,\n statusColor: statusColor(entity.status),\n }\n}\n\nexport async function loadCustomerDealPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('customers.messageObjects.deal.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const em = await resolveEm()\n const deal = await findOneWithDecryption(\n em,\n CustomerDeal,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!deal) {\n return { title: defaultTitle, subtitle: entityId, status: t('customers.messageObjects.notFound'), statusColor: 'gray' }\n }\n\n const amount = formatCurrency(deal.valueAmount, deal.valueCurrency)\n const probability = typeof deal.probability === 'number' ? `${deal.probability}%` : null\n const subtitle = [amount, probability].filter((part): part is string => Boolean(part && part.length > 0)).join(' \u2022 ')\n const metadata: Record<string, string> = {}\n if (amount) metadata
|
|
5
|
-
"mappings": "AAAA,SAAS,8BAA8B;AACvC,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AAGpC,SAAS,cAAc,
|
|
4
|
+
"sourcesContent": ["import { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { ObjectPreviewData } from '@open-mercato/shared/modules/messages/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerCompanyProfile, CustomerDeal, CustomerEntity, CustomerPersonProfile } from '../data/entities'\n\ntype PreviewContext = {\n tenantId: string\n organizationId?: string | null\n}\n\nfunction formatCurrency(amount: string | null | undefined, currency: string | null | undefined): 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 statusColor(status: string | null | undefined): string | undefined {\n if (!status) return undefined\n const value = status.toLowerCase()\n if (value.includes('won') || value.includes('active') || value.includes('qualified')) return 'green'\n if (value.includes('lost') || value.includes('rejected') || value.includes('inactive')) return 'red'\n if (value.includes('open') || value.includes('new') || value.includes('pending')) return 'amber'\n return 'blue'\n}\n\nasync function resolveEm() {\n const { resolve } = await createRequestContainer()\n return resolve('em') as EntityManager\n}\n\nexport async function loadCustomerPersonPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('customers.messageObjects.person.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const em = await resolveEm()\n const entity = await findOneWithDecryption(\n em,\n CustomerEntity,\n {\n id: entityId,\n kind: 'person',\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!entity) {\n return { title: defaultTitle, subtitle: entityId, status: t('customers.messageObjects.notFound'), statusColor: 'gray' }\n }\n\n const profile = await findOneWithDecryption(\n em,\n CustomerPersonProfile,\n {\n entity,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n const subtitleParts = [entity.primaryEmail, entity.primaryPhone]\n .filter((part): part is string => Boolean(part && part.trim().length > 0))\n const metadata: Record<string, string> = {}\n const phoneLabel = t('customers.people.detail.highlights.primaryPhone')\n const jobTitleLabel = t('customers.people.detail.fields.jobTitle')\n if (entity.primaryPhone && entity.primaryPhone.trim().length > 0) metadata[phoneLabel] = entity.primaryPhone\n if (profile?.jobTitle && profile.jobTitle.trim().length > 0) metadata[jobTitleLabel] = profile.jobTitle\n\n return {\n title: entity.displayName,\n subtitle: subtitleParts.join(' \u2022 ') || entityId,\n status: entity.status ?? undefined,\n statusColor: statusColor(entity.status),\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n }\n}\n\nexport async function loadCustomerCompanyPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('customers.messageObjects.company.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const em = await resolveEm()\n const entity = await findOneWithDecryption(\n em,\n CustomerEntity,\n {\n id: entityId,\n kind: 'company',\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!entity) {\n return { title: defaultTitle, subtitle: entityId, status: t('customers.messageObjects.notFound'), statusColor: 'gray' }\n }\n\n const profile = await findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n entity,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n const subtitleParts = [entity.primaryEmail, entity.primaryPhone]\n .filter((part): part is string => Boolean(part && part.trim().length > 0))\n const metadata: Record<string, string> = {}\n const phoneLabel = t('customers.companies.detail.highlights.primaryPhone')\n const industryLabel = t('customers.companies.detail.fields.industry')\n if (entity.primaryPhone && entity.primaryPhone.trim().length > 0) metadata[phoneLabel] = entity.primaryPhone\n if (profile?.industry && profile.industry.trim().length > 0) metadata[industryLabel] = profile.industry\n\n return {\n title: entity.displayName,\n subtitle: subtitleParts.join(' \u2022 ') || entityId,\n status: entity.status ?? undefined,\n statusColor: statusColor(entity.status),\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n }\n}\n\nexport async function loadCustomerDealPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('customers.messageObjects.deal.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const em = await resolveEm()\n const deal = await findOneWithDecryption(\n em,\n CustomerDeal,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!deal) {\n return { title: defaultTitle, subtitle: entityId, status: t('customers.messageObjects.notFound'), statusColor: 'gray' }\n }\n\n const amount = formatCurrency(deal.valueAmount, deal.valueCurrency)\n const probability = typeof deal.probability === 'number' ? `${deal.probability}%` : null\n const subtitle = [amount, probability].filter((part): part is string => Boolean(part && part.length > 0)).join(' \u2022 ')\n const metadata: Record<string, string> = {}\n const valueLabel = t('customers.deals.detail.fields.value')\n const probabilityLabel = t('customers.deals.detail.fields.probability')\n if (amount) metadata[valueLabel] = amount\n if (probability) metadata[probabilityLabel] = probability\n\n return {\n title: deal.title,\n subtitle: subtitle || entityId,\n status: deal.status ?? undefined,\n statusColor: statusColor(deal.status),\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n }\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CustomerMessageObjectPreview } from "./widgets/messages/CustomerMessageObjectPreview.js";
|
|
1
|
+
import { MessageObjectDetail, MessageObjectPreview } from "@open-mercato/ui";
|
|
3
2
|
const objectMessageTypes = ["default", "messages.defaultWithObjects"];
|
|
4
3
|
const messageObjectTypes = [
|
|
5
4
|
{
|
|
@@ -11,9 +10,16 @@ const messageObjectTypes = [
|
|
|
11
10
|
optionSubtitleField: "email",
|
|
12
11
|
labelKey: "customers.people.list.title",
|
|
13
12
|
icon: "user-round",
|
|
14
|
-
PreviewComponent:
|
|
15
|
-
DetailComponent:
|
|
16
|
-
actions: [
|
|
13
|
+
PreviewComponent: MessageObjectPreview,
|
|
14
|
+
DetailComponent: MessageObjectDetail,
|
|
15
|
+
actions: [
|
|
16
|
+
{
|
|
17
|
+
id: "view",
|
|
18
|
+
labelKey: "common.view",
|
|
19
|
+
variant: "outline",
|
|
20
|
+
href: "/backend/customers/people/{entityId}"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
17
23
|
loadPreview: async (entityId, ctx) => {
|
|
18
24
|
if (typeof window !== "undefined") {
|
|
19
25
|
return { title: "Person", subtitle: entityId };
|
|
@@ -31,9 +37,16 @@ const messageObjectTypes = [
|
|
|
31
37
|
optionSubtitleField: "taxId",
|
|
32
38
|
labelKey: "customers.companies.list.title",
|
|
33
39
|
icon: "building2",
|
|
34
|
-
PreviewComponent:
|
|
35
|
-
DetailComponent:
|
|
36
|
-
actions: [
|
|
40
|
+
PreviewComponent: MessageObjectPreview,
|
|
41
|
+
DetailComponent: MessageObjectDetail,
|
|
42
|
+
actions: [
|
|
43
|
+
{
|
|
44
|
+
id: "view",
|
|
45
|
+
labelKey: "common.view",
|
|
46
|
+
variant: "outline",
|
|
47
|
+
href: "/backend/customers/companies/{entityId}"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
37
50
|
loadPreview: async (entityId, ctx) => {
|
|
38
51
|
if (typeof window !== "undefined") {
|
|
39
52
|
return { title: "Company", subtitle: entityId };
|
|
@@ -51,9 +64,16 @@ const messageObjectTypes = [
|
|
|
51
64
|
optionSubtitleField: "status",
|
|
52
65
|
labelKey: "customers.deals.list.title",
|
|
53
66
|
icon: "briefcase-business",
|
|
54
|
-
PreviewComponent:
|
|
55
|
-
DetailComponent:
|
|
56
|
-
actions: [
|
|
67
|
+
PreviewComponent: MessageObjectPreview,
|
|
68
|
+
DetailComponent: MessageObjectDetail,
|
|
69
|
+
actions: [
|
|
70
|
+
{
|
|
71
|
+
id: "view",
|
|
72
|
+
labelKey: "common.view",
|
|
73
|
+
variant: "outline",
|
|
74
|
+
href: "/backend/customers/deals/{entityId}"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
57
77
|
loadPreview: async (entityId, ctx) => {
|
|
58
78
|
if (typeof window !== "undefined") {
|
|
59
79
|
return { title: "Deal", subtitle: entityId };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/customers/message-objects.ts"],
|
|
4
|
-
"sourcesContent": ["import type { MessageObjectTypeDefinition } from '@open-mercato/shared/modules/messages/types'\nimport {
|
|
5
|
-
"mappings": "AACA,SAAS,
|
|
4
|
+
"sourcesContent": ["import type { MessageObjectTypeDefinition } from '@open-mercato/shared/modules/messages/types'\nimport { MessageObjectDetail, MessageObjectPreview } from '@open-mercato/ui'\n\nconst objectMessageTypes = ['default', 'messages.defaultWithObjects']\n\nexport const messageObjectTypes: MessageObjectTypeDefinition[] = [\n {\n module: 'customers',\n entityType: 'person',\n messageTypes: objectMessageTypes,\n entityId: 'customers:customer_person_profile',\n optionLabelField: 'name',\n optionSubtitleField: 'email',\n labelKey: 'customers.people.list.title',\n icon: 'user-round',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/customers/people/{entityId}',\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return { title: 'Person', subtitle: entityId }\n }\n const { loadCustomerPersonPreview } = await import('./lib/messageObjectPreviews')\n return loadCustomerPersonPreview(entityId, ctx)\n },\n },\n {\n module: 'customers',\n entityType: 'company',\n messageTypes: objectMessageTypes,\n entityId: 'customers:customer_company_profile',\n optionLabelField: 'name',\n optionSubtitleField: 'taxId',\n labelKey: 'customers.companies.list.title',\n icon: 'building2',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/customers/companies/{entityId}',\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return { title: 'Company', subtitle: entityId }\n }\n const { loadCustomerCompanyPreview } = await import('./lib/messageObjectPreviews')\n return loadCustomerCompanyPreview(entityId, ctx)\n },\n },\n {\n module: 'customers',\n entityType: 'deal',\n messageTypes: objectMessageTypes,\n entityId: 'customers:customer_deal',\n optionLabelField: 'title',\n optionSubtitleField: 'status',\n labelKey: 'customers.deals.list.title',\n icon: 'briefcase-business',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/customers/deals/{entityId}',\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return { title: 'Deal', subtitle: entityId }\n }\n const { loadCustomerDealPreview } = await import('./lib/messageObjectPreviews')\n return loadCustomerDealPreview(entityId, ctx)\n },\n },\n]\n\nexport default messageObjectTypes\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,qBAAqB,4BAA4B;AAE1D,MAAM,qBAAqB,CAAC,WAAW,6BAA6B;AAE7D,MAAM,qBAAoD;AAAA,EAC/D;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,aAAa,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO,EAAE,OAAO,UAAU,UAAU,SAAS;AAAA,MAC/C;AACA,YAAM,EAAE,0BAA0B,IAAI,MAAM,OAAO,6BAA6B;AAChF,aAAO,0BAA0B,UAAU,GAAG;AAAA,IAChD;AAAA,EACF;AAAA,EACA;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,aAAa,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO,EAAE,OAAO,WAAW,UAAU,SAAS;AAAA,MAChD;AACA,YAAM,EAAE,2BAA2B,IAAI,MAAM,OAAO,6BAA6B;AACjF,aAAO,2BAA2B,UAAU,GAAG;AAAA,IACjD;AAAA,EACF;AAAA,EACA;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,aAAa,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO,EAAE,OAAO,QAAQ,UAAU,SAAS;AAAA,MAC7C;AACA,YAAM,EAAE,wBAAwB,IAAI,MAAM,OAAO,6BAA6B;AAC9E,aAAO,wBAAwB,UAAU,GAAG;AAAA,IAC9C;AAAA,EACF;AACF;AAEA,IAAO,0BAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -391,6 +391,9 @@ const replyMessageCommand = {
|
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
}
|
|
394
|
+
if (recipientIds.size === 0 && original.senderUserId === input.userId) {
|
|
395
|
+
recipientIds.add(input.userId);
|
|
396
|
+
}
|
|
394
397
|
}
|
|
395
398
|
if (recipientIds.size === 0) throw new Error("No recipients available for reply");
|
|
396
399
|
let messageId = "";
|