@open-mercato/ui 0.8.1-develop.7296.1.2111d779db → 0.8.1-develop.7441.1.b42958b98c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/backend/CrudForm.js +19 -6
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/DataTable.js +61 -9
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/RowActions.js +54 -5
- package/dist/backend/RowActions.js.map +2 -2
- package/dist/backend/charts/KpiCard.js +2 -1
- package/dist/backend/charts/KpiCard.js.map +2 -2
- package/dist/backend/detail/AttachmentsSection.js +17 -5
- package/dist/backend/detail/AttachmentsSection.js.map +2 -2
- package/dist/backend/detail/NotesSection.js +38 -20
- package/dist/backend/detail/NotesSection.js.map +2 -2
- package/dist/backend/dev/DevRuntimeDiagnosticsBanner.js +11 -1
- package/dist/backend/dev/DevRuntimeDiagnosticsBanner.js.map +2 -2
- package/dist/backend/icons/lucideRegistry.generated.js +26 -0
- package/dist/backend/icons/lucideRegistry.generated.js.map +2 -2
- package/dist/backend/injection/eventBridge.js +33 -0
- package/dist/backend/injection/eventBridge.js.map +2 -2
- package/dist/backend/inputs/LookupSelect.js +20 -3
- package/dist/backend/inputs/LookupSelect.js.map +2 -2
- package/dist/backend/inputs/PhoneNumberField.js +1 -1
- package/dist/backend/inputs/PhoneNumberField.js.map +2 -2
- package/dist/backend/inputs/TagsInput.js +20 -2
- package/dist/backend/inputs/TagsInput.js.map +2 -2
- package/dist/backend/messages/EmailThreadsPanel.js +2 -1
- package/dist/backend/messages/EmailThreadsPanel.js.map +2 -2
- package/dist/backend/messages/MessageComposer.js.map +2 -2
- package/dist/backend/messages/index.js.map +2 -2
- package/dist/backend/messages/message-compose-form-groups.js +24 -0
- package/dist/backend/messages/message-compose-form-groups.js.map +2 -2
- package/dist/backend/messages/useMessageCompose.js +27 -0
- package/dist/backend/messages/useMessageCompose.js.map +2 -2
- package/dist/backend/messages/useMessageComposeOperations.js +1 -0
- package/dist/backend/messages/useMessageComposeOperations.js.map +2 -2
- package/dist/backend/notifications/NotificationItem.js +8 -1
- package/dist/backend/notifications/NotificationItem.js.map +2 -2
- package/dist/portal/PortalShell.js +2 -2
- package/dist/portal/PortalShell.js.map +2 -2
- package/dist/primitives/calendar.js +69 -14
- package/dist/primitives/calendar.js.map +2 -2
- package/package.json +3 -3
- package/src/backend/CrudForm.tsx +30 -8
- package/src/backend/DataTable.tsx +92 -19
- package/src/backend/RowActions.tsx +114 -6
- package/src/backend/__tests__/AttachmentsSection.upload.test.tsx +183 -0
- package/src/backend/__tests__/CrudForm.fieldInjection.test.tsx +139 -2
- package/src/backend/__tests__/CrudForm.hiddenGroups.test.tsx +1 -1
- package/src/backend/__tests__/DataTable.extensions.test.tsx +30 -0
- package/src/backend/__tests__/DataTable.perspectiveReconcile.test.tsx +320 -2
- package/src/backend/__tests__/DevRuntimeDiagnosticsBanner.test.tsx +117 -0
- package/src/backend/__tests__/NotesSection.test.tsx +138 -0
- package/src/backend/__tests__/RowActions.test.tsx +202 -0
- package/src/backend/charts/KpiCard.tsx +1 -0
- package/src/backend/charts/__tests__/KpiCard.test.tsx +20 -0
- package/src/backend/detail/AttachmentsSection.tsx +17 -5
- package/src/backend/detail/NotesSection.tsx +122 -66
- package/src/backend/dev/DevRuntimeDiagnosticsBanner.tsx +24 -1
- package/src/backend/icons/lucideRegistry.generated.tsx +26 -0
- package/src/backend/injection/__tests__/eventBridge.test.tsx +47 -1
- package/src/backend/injection/eventBridge.ts +35 -0
- package/src/backend/inputs/LookupSelect.tsx +32 -3
- package/src/backend/inputs/PhoneNumberField.tsx +1 -1
- package/src/backend/inputs/TagsInput.tsx +24 -3
- package/src/backend/inputs/__tests__/LookupSelect.test.tsx +166 -1
- package/src/backend/inputs/__tests__/PhoneNumberField.typeahead.test.tsx +43 -0
- package/src/backend/inputs/__tests__/TagsInput.test.tsx +81 -0
- package/src/backend/messages/EmailThreadsPanel.tsx +21 -1
- package/src/backend/messages/MessageComposer.tsx +1 -0
- package/src/backend/messages/__tests__/EmailThreadsPanel.senderLabel.test.tsx +99 -0
- package/src/backend/messages/__tests__/MessageComposer.test.tsx +44 -0
- package/src/backend/messages/__tests__/useMessageCompose.test.tsx +69 -0
- package/src/backend/messages/__tests__/useMessageComposeSender.test.tsx +208 -0
- package/src/backend/messages/index.ts +1 -0
- package/src/backend/messages/message-compose-form-groups.tsx +41 -0
- package/src/backend/messages/message-composer.types.ts +26 -0
- package/src/backend/messages/useMessageCompose.ts +46 -0
- package/src/backend/messages/useMessageComposeOperations.ts +8 -0
- package/src/backend/notifications/NotificationItem.tsx +7 -0
- package/src/backend/notifications/__tests__/NotificationItem.customRenderer.test.tsx +139 -0
- package/src/portal/PortalShell.tsx +7 -4
- package/src/portal/__tests__/PortalShell.test.tsx +29 -1
- package/src/primitives/__tests__/calendar.test.tsx +174 -1
- package/src/primitives/calendar.tsx +168 -96
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/messages/MessageComposer.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Forward, Reply, Send } from 'lucide-react'\nimport { CrudForm } from '../CrudForm'\nimport { Button } from '../../primitives/button'\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../primitives/dialog'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { getMessageUiComponentRegistry } from '@open-mercato/core/modules/messages/components/utils/typeUiRegistry'\nimport { getMessageObjectType } from '@open-mercato/core/modules/messages/lib/message-objects-registry'\nimport { createMessageComposeFormGroups } from './message-compose-form-groups'\nimport { useMessageCompose } from './useMessageCompose'\nimport type { MessageComposerContextObject, MessageComposerProps } from './message-composer.types'\n\nexport type {\n MessageComposerContextObject,\n MessageComposerProps,\n MessageComposerRequiredActionConfig,\n MessageComposerRequiredActionOption,\n MessageComposerVariant,\n MessageTypeItem,\n} from './message-composer.types'\n\nfunction ContextObjectPreview({ contextObject }: { contextObject: MessageComposerContextObject }) {\n const t = useT()\n const registry = getMessageUiComponentRegistry()\n const previewComponentKey = `${contextObject.entityModule}:${contextObject.entityType}`\n const PreviewComponent = registry.objectPreviewComponents[previewComponentKey]\n ?? registry.objectPreviewComponents['messages:default']\n const objectType = getMessageObjectType(contextObject.entityModule, contextObject.entityType)\n\n if (PreviewComponent) {\n return (\n <PreviewComponent\n entityId={contextObject.entityId}\n entityModule={contextObject.entityModule}\n entityType={contextObject.entityType}\n actionRequired={contextObject.actionRequired}\n actionType={contextObject.actionType}\n actionLabel={contextObject.actionLabel}\n previewData={contextObject.previewData ?? undefined}\n icon={objectType?.icon}\n />\n )\n }\n\n return (\n <div className=\"space-y-1\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('messages.composer.contextPreview.title', 'Context object')}\n </p>\n <p className=\"text-sm font-medium\">\n {contextObject.entityModule}:{contextObject.entityType}\n </p>\n <p className=\"text-xs font-mono text-muted-foreground\">\n {contextObject.entityId}\n </p>\n </div>\n )\n}\n\nexport function MessageComposer(props: MessageComposerProps) {\n const compose = useMessageCompose(props)\n const inlineBackHref = props.inlineBackHref\n const SubmitIcon = compose.variant === 'reply'\n ? Reply\n : compose.variant === 'forward'\n ? Forward\n : Send\n\n const inlineExtraActions = compose.inline\n ? (\n <>\n {compose.variant === 'compose' ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleSaveDraft}\n disabled={compose.submitting}\n >\n {compose.t('messages.saveDraft', 'Save draft')}\n </Button>\n ) : null}\n {compose.variant !== 'compose' ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleBack}\n disabled={compose.submitting}\n >\n {compose.t('ui.forms.actions.cancel', 'Cancel')}\n </Button>\n ) : null}\n </>\n )\n : null\n\n const dialogExtraActions = !compose.inline\n ? (\n <>\n {compose.variant === 'compose' ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleSaveDraft}\n disabled={compose.submitting}\n >\n {compose.t('messages.saveDraft', 'Save draft')}\n </Button>\n ) : null}\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleBack}\n disabled={compose.submitting}\n >\n {compose.t('ui.forms.actions.cancel', 'Cancel')}\n </Button>\n </>\n )\n : null\n\n const backHref = compose.inline\n ? inlineBackHref === undefined\n ? '/backend/messages'\n : inlineBackHref ?? undefined\n : undefined\n\n const fallbackContextPreview = React.useMemo(() => {\n if (compose.contextPreview) return compose.contextPreview\n if (!props.contextObject) return null\n return <ContextObjectPreview contextObject={props.contextObject} />\n }, [compose.contextPreview, props.contextObject])\n\n const composeWithContextPreview = React.useMemo(\n () => ({ ...compose, contextPreview: fallbackContextPreview }),\n [compose, fallbackContextPreview],\n )\n\n const composePanel = (\n <CrudForm<Record<string, unknown>>\n backHref={backHref}\n title={composeWithContextPreview.composerTitle}\n titleHeadingLevel={2}\n fields={createMessageComposeFormGroups(composeWithContextPreview)}\n initialValues={{}}\n submitLabel={composeWithContextPreview.submitLabel}\n submitIcon={SubmitIcon}\n extraActions={composeWithContextPreview.inline ? inlineExtraActions : dialogExtraActions}\n hideFooterActions\n onSubmit={async () => {\n await composeWithContextPreview.handleSubmit()\n }}\n />\n )\n\n if (compose.inline) {\n return (\n <div className=\"space-y-4\">\n {composePanel}\n </div>\n )\n }\n\n return (\n <Dialog open={Boolean(compose.open)} onOpenChange={compose.handleDialogOpenChange}>\n <DialogContent className=\"sm:max-w-3xl [&>button]:hidden\">\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{compose.composerTitle}</DialogTitle>\n <DialogDescription>\n {compose.t('messages.composer.dialogDescription', 'Compose and send a message.')}\n </DialogDescription>\n </DialogHeader>\n {composePanel}\n <div className=\"flex items-center justify-end gap-2 border-t pt-4\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleBack}\n disabled={compose.submitting}\n >\n {compose.t('ui.forms.actions.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n void compose.handleSubmit()\n }}\n disabled={compose.submitting}\n >\n <SubmitIcon className=\"mr-2 size-4\" />\n {compose.submitLabel}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Forward, Reply, Send } from 'lucide-react'\nimport { CrudForm } from '../CrudForm'\nimport { Button } from '../../primitives/button'\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../primitives/dialog'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { getMessageUiComponentRegistry } from '@open-mercato/core/modules/messages/components/utils/typeUiRegistry'\nimport { getMessageObjectType } from '@open-mercato/core/modules/messages/lib/message-objects-registry'\nimport { createMessageComposeFormGroups } from './message-compose-form-groups'\nimport { useMessageCompose } from './useMessageCompose'\nimport type { MessageComposerContextObject, MessageComposerProps } from './message-composer.types'\n\nexport type {\n MessageComposerContextObject,\n MessageComposerProps,\n MessageComposerRequiredActionConfig,\n MessageComposerRequiredActionOption,\n MessageComposerVariant,\n MessageSenderOption,\n MessageTypeItem,\n} from './message-composer.types'\n\nfunction ContextObjectPreview({ contextObject }: { contextObject: MessageComposerContextObject }) {\n const t = useT()\n const registry = getMessageUiComponentRegistry()\n const previewComponentKey = `${contextObject.entityModule}:${contextObject.entityType}`\n const PreviewComponent = registry.objectPreviewComponents[previewComponentKey]\n ?? registry.objectPreviewComponents['messages:default']\n const objectType = getMessageObjectType(contextObject.entityModule, contextObject.entityType)\n\n if (PreviewComponent) {\n return (\n <PreviewComponent\n entityId={contextObject.entityId}\n entityModule={contextObject.entityModule}\n entityType={contextObject.entityType}\n actionRequired={contextObject.actionRequired}\n actionType={contextObject.actionType}\n actionLabel={contextObject.actionLabel}\n previewData={contextObject.previewData ?? undefined}\n icon={objectType?.icon}\n />\n )\n }\n\n return (\n <div className=\"space-y-1\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('messages.composer.contextPreview.title', 'Context object')}\n </p>\n <p className=\"text-sm font-medium\">\n {contextObject.entityModule}:{contextObject.entityType}\n </p>\n <p className=\"text-xs font-mono text-muted-foreground\">\n {contextObject.entityId}\n </p>\n </div>\n )\n}\n\nexport function MessageComposer(props: MessageComposerProps) {\n const compose = useMessageCompose(props)\n const inlineBackHref = props.inlineBackHref\n const SubmitIcon = compose.variant === 'reply'\n ? Reply\n : compose.variant === 'forward'\n ? Forward\n : Send\n\n const inlineExtraActions = compose.inline\n ? (\n <>\n {compose.variant === 'compose' ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleSaveDraft}\n disabled={compose.submitting}\n >\n {compose.t('messages.saveDraft', 'Save draft')}\n </Button>\n ) : null}\n {compose.variant !== 'compose' ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleBack}\n disabled={compose.submitting}\n >\n {compose.t('ui.forms.actions.cancel', 'Cancel')}\n </Button>\n ) : null}\n </>\n )\n : null\n\n const dialogExtraActions = !compose.inline\n ? (\n <>\n {compose.variant === 'compose' ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleSaveDraft}\n disabled={compose.submitting}\n >\n {compose.t('messages.saveDraft', 'Save draft')}\n </Button>\n ) : null}\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleBack}\n disabled={compose.submitting}\n >\n {compose.t('ui.forms.actions.cancel', 'Cancel')}\n </Button>\n </>\n )\n : null\n\n const backHref = compose.inline\n ? inlineBackHref === undefined\n ? '/backend/messages'\n : inlineBackHref ?? undefined\n : undefined\n\n const fallbackContextPreview = React.useMemo(() => {\n if (compose.contextPreview) return compose.contextPreview\n if (!props.contextObject) return null\n return <ContextObjectPreview contextObject={props.contextObject} />\n }, [compose.contextPreview, props.contextObject])\n\n const composeWithContextPreview = React.useMemo(\n () => ({ ...compose, contextPreview: fallbackContextPreview }),\n [compose, fallbackContextPreview],\n )\n\n const composePanel = (\n <CrudForm<Record<string, unknown>>\n backHref={backHref}\n title={composeWithContextPreview.composerTitle}\n titleHeadingLevel={2}\n fields={createMessageComposeFormGroups(composeWithContextPreview)}\n initialValues={{}}\n submitLabel={composeWithContextPreview.submitLabel}\n submitIcon={SubmitIcon}\n extraActions={composeWithContextPreview.inline ? inlineExtraActions : dialogExtraActions}\n hideFooterActions\n onSubmit={async () => {\n await composeWithContextPreview.handleSubmit()\n }}\n />\n )\n\n if (compose.inline) {\n return (\n <div className=\"space-y-4\">\n {composePanel}\n </div>\n )\n }\n\n return (\n <Dialog open={Boolean(compose.open)} onOpenChange={compose.handleDialogOpenChange}>\n <DialogContent className=\"sm:max-w-3xl [&>button]:hidden\">\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{compose.composerTitle}</DialogTitle>\n <DialogDescription>\n {compose.t('messages.composer.dialogDescription', 'Compose and send a message.')}\n </DialogDescription>\n </DialogHeader>\n {composePanel}\n <div className=\"flex items-center justify-end gap-2 border-t pt-4\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={compose.handleBack}\n disabled={compose.submitting}\n >\n {compose.t('ui.forms.actions.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n void compose.handleSubmit()\n }}\n disabled={compose.submitting}\n >\n <SubmitIcon className=\"mr-2 size-4\" />\n {compose.submitLabel}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/messages/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { MessageComposer } from './MessageComposer'\nexport type {\n MessageComposerContextObject,\n MessageComposerProps,\n MessageComposerVariant,\n MessageTypeItem,\n} from './MessageComposer'\n\nexport { SendObjectMessageDialog } from './SendObjectMessageDialog'\nexport type { SendObjectMessageDialogProps } from './SendObjectMessageDialog'\n\nexport { MessageObjectRecordPicker } from './MessageObjectRecordPicker'\nexport type { MessageObjectRecordPickerProps } from './MessageObjectRecordPicker'\n\nexport { MessagesIcon } from './MessagesIcon'\nexport type { MessagesIconProps } from './MessagesIcon'\n\nexport { useMessages } from './useMessages'\nexport { useMessagesPoll } from './useMessagesPoll'\nexport { useMessagesSse } from './useMessagesSse'\nexport type { MessagePollItem, UseMessagesPollResult } from './useMessagesPoll'\n\nexport { MessageObjectPreview } from './MessageObjectPreview'\nexport { MessageObjectDetail } from './MessageObjectDetail'\n\nexport { EmailThreadsPanel } from './EmailThreadsPanel'\nexport type {\n EmailThread,\n EmailThreadMessage,\n EmailThreadMessageStatus,\n EmailThreadDirection,\n EmailThreadsPanelProps,\n} from './EmailThreadsPanel'\n\nexport { mergeOptimisticEmailThreads } from './mergeOptimisticEmailThreads'\nexport type { OptimisticEmailMessage } from './mergeOptimisticEmailThreads'\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,uBAAuB;
|
|
4
|
+
"sourcesContent": ["export { MessageComposer } from './MessageComposer'\nexport type {\n MessageComposerContextObject,\n MessageComposerProps,\n MessageComposerVariant,\n MessageSenderOption,\n MessageTypeItem,\n} from './MessageComposer'\n\nexport { SendObjectMessageDialog } from './SendObjectMessageDialog'\nexport type { SendObjectMessageDialogProps } from './SendObjectMessageDialog'\n\nexport { MessageObjectRecordPicker } from './MessageObjectRecordPicker'\nexport type { MessageObjectRecordPickerProps } from './MessageObjectRecordPicker'\n\nexport { MessagesIcon } from './MessagesIcon'\nexport type { MessagesIconProps } from './MessagesIcon'\n\nexport { useMessages } from './useMessages'\nexport { useMessagesPoll } from './useMessagesPoll'\nexport { useMessagesSse } from './useMessagesSse'\nexport type { MessagePollItem, UseMessagesPollResult } from './useMessagesPoll'\n\nexport { MessageObjectPreview } from './MessageObjectPreview'\nexport { MessageObjectDetail } from './MessageObjectDetail'\n\nexport { EmailThreadsPanel } from './EmailThreadsPanel'\nexport type {\n EmailThread,\n EmailThreadMessage,\n EmailThreadMessageStatus,\n EmailThreadDirection,\n EmailThreadsPanelProps,\n} from './EmailThreadsPanel'\n\nexport { mergeOptimisticEmailThreads } from './mergeOptimisticEmailThreads'\nexport type { OptimisticEmailMessage } from './mergeOptimisticEmailThreads'\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,uBAAuB;AAShC,SAAS,+BAA+B;AAGxC,SAAS,iCAAiC;AAG1C,SAAS,oBAAoB;AAG7B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAG/B,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AAEpC,SAAS,yBAAyB;AASlC,SAAS,mCAAmC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -154,6 +154,29 @@ function MarkdownBodySection({
|
|
|
154
154
|
) })
|
|
155
155
|
] });
|
|
156
156
|
}
|
|
157
|
+
const PLATFORM_SENDER_VALUE = "__platform__";
|
|
158
|
+
function SenderSelector({ compose }) {
|
|
159
|
+
if (compose.senderOptions.length === 0) return null;
|
|
160
|
+
const fieldError = compose.submitFieldErrors?.senderChannelId ?? null;
|
|
161
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
162
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "messages-compose-sender", children: compose.t("messages.sendFrom", "Send from") }),
|
|
163
|
+
/* @__PURE__ */ jsxs(
|
|
164
|
+
Select,
|
|
165
|
+
{
|
|
166
|
+
value: compose.senderChannelId || PLATFORM_SENDER_VALUE,
|
|
167
|
+
onValueChange: (value) => compose.setSenderChannelId(value === PLATFORM_SENDER_VALUE ? "" : value),
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id: "messages-compose-sender", "aria-invalid": fieldError ? true : void 0, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
170
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
171
|
+
/* @__PURE__ */ jsx(SelectItem, { value: PLATFORM_SENDER_VALUE, children: compose.t("messages.sendFromPlatform", "Platform sender (default)") }),
|
|
172
|
+
compose.senderOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.id, children: option.description ? `${option.label} (${option.description})` : option.label }, option.id))
|
|
173
|
+
] })
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
fieldError ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", role: "alert", children: fieldError }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: compose.t("messages.sendFromHint", "Replies to a message sent from your own mailbox come back into this thread.") })
|
|
178
|
+
] });
|
|
179
|
+
}
|
|
157
180
|
function ComposeModeFields({ compose }) {
|
|
158
181
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
159
182
|
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
@@ -175,6 +198,7 @@ function ComposeModeFields({ compose }) {
|
|
|
175
198
|
] }) }),
|
|
176
199
|
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsx(VisibilitySelector, { compose }) })
|
|
177
200
|
] }),
|
|
201
|
+
/* @__PURE__ */ jsx(SenderSelector, { compose }),
|
|
178
202
|
/* @__PURE__ */ jsx(ContextActionsSection, { compose })
|
|
179
203
|
] }),
|
|
180
204
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/messages/message-compose-form-groups.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport { FileCode, Globe, Lock } from 'lucide-react'\nimport { type CrudField } from '../CrudForm'\nimport { IconButton } from '../../primitives/icon-button'\nimport { Input } from '../../primitives/input'\nimport { EmailInput } from '../../primitives/email-input'\nimport { Label } from '../../primitives/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../../primitives/select'\nimport { Switch } from '../../primitives/switch'\nimport { SwitchField } from '../../primitives/switch-field'\nimport { AttachmentsSection } from '../detail/AttachmentsSection'\nimport { SwitchableMarkdownInput } from '../inputs/SwitchableMarkdownInput'\nimport { TagsInput } from '../inputs/TagsInput'\nimport { MessagePrioritySelector } from './MessagePrioritySelector'\nimport type { UseMessageComposeResult } from './useMessageCompose'\n\ntype ComposeProps = {\n compose: UseMessageComposeResult\n}\n\nfunction RecipientTagsInput({ compose }: ComposeProps) {\n return (\n <TagsInput\n value={compose.recipientIds}\n onChange={compose.setRecipientIds}\n selectedOptions={compose.selectedRecipientOptions}\n resolveLabel={compose.resolveRecipientLabel}\n loadSuggestions={compose.loadRecipientSuggestions}\n placeholder={compose.t('messages.placeholders.recipients', 'Search recipients...')}\n allowCustomValues={false}\n showSuggestionsOnFocus={false}\n />\n )\n}\n\nfunction VisibilitySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.visibility', 'Visibility')}</Label>\n <div\n className=\"inline-flex items-center gap-1 rounded-md border bg-background p-1\"\n role=\"radiogroup\"\n aria-label={compose.t('messages.visibility', 'Visibility')}\n >\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'internal' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'internal'}\n aria-label={compose.t('messages.visibilityInternal', 'Internal')}\n title={compose.t('messages.visibilityInternal', 'Internal')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('internal')}\n >\n <Lock className=\"h-3.5 w-3.5\" />\n </IconButton>\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'public' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'public'}\n aria-label={compose.t('messages.visibilityPublic', 'Public')}\n title={compose.t('messages.visibilityPublic', 'Public')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('public')}\n >\n <Globe className=\"h-3.5 w-3.5\" />\n </IconButton>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {compose.visibility === 'public'\n ? compose.t('messages.visibilityPublicHint', 'Public messages are sent to external email only.')\n : compose.t('messages.visibilityInternalHint', 'Internal messages are sent to selected system users.')}\n </p>\n </>\n )\n}\n\nfunction ContextActionsSection({ compose }: ComposeProps) {\n if (!compose.shouldShowContextActions) return null\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.normalizedRequiredActionMode === 'optional' ? (\n <div className=\"flex items-center justify-between rounded border px-3 py-2 sm:col-span-2\">\n <div>\n <p className=\"text-sm font-medium\">\n {compose.t('messages.composer.objectPicker.actionRequiredLabel', 'Action required')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {compose.t('messages.composer.objectPicker.actionRequiredHint', 'Mark this object as requiring recipient action.')}\n </p>\n </div>\n <Switch checked={compose.contextActionRequired} onCheckedChange={compose.setContextActionRequired} />\n </div>\n ) : null}\n {compose.normalizedRequiredActionMode === 'required' || compose.contextActionRequired ? (\n <div className=\"space-y-2 sm:col-span-2\">\n <Label htmlFor=\"messages-compose-context-action-type\">\n {compose.t('messages.composer.objectPicker.actionTypeLabel', 'Action type')}\n </Label>\n <Select\n value={compose.contextActionType || undefined}\n onValueChange={(value) => compose.setContextActionType(value || '')}\n >\n <SelectTrigger id=\"messages-compose-context-action-type\">\n <SelectValue placeholder={compose.t('messages.composer.objectPicker.actionTypePlaceholder', 'Select action')} />\n </SelectTrigger>\n <SelectContent>\n {compose.contextActionOptions.map((option) => (\n <SelectItem key={option.id} value={option.id}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction PrioritySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.priority', 'Priority')}</Label>\n <MessagePrioritySelector\n value={compose.priority}\n onChange={compose.setPriority}\n t={compose.t}\n />\n </>\n )\n}\n\nfunction MarkdownBodySection({\n compose,\n label,\n placeholder,\n inputId,\n rows,\n textareaClassName,\n}: ComposeProps & {\n label: string\n placeholder: string\n inputId: string\n rows: number\n textareaClassName: string\n}) {\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label htmlFor={inputId}>{label}</Label>\n <IconButton\n type=\"button\"\n size=\"sm\"\n variant={compose.bodyFormat === 'markdown' ? 'outline' : 'ghost'}\n aria-pressed={compose.bodyFormat === 'markdown'}\n onClick={() => compose.setBodyFormat((previousValue) => (previousValue === 'markdown' ? 'text' : 'markdown'))}\n title={compose.t('messages.bodyFormat.toggle', 'Toggle markdown')}\n >\n <FileCode className=\"h-4 w-4\" />\n </IconButton>\n </div>\n <div id={inputId}>\n <SwitchableMarkdownInput\n value={compose.body}\n onChange={compose.setBody}\n isMarkdownEnabled={compose.bodyFormat === 'markdown'}\n rows={rows}\n placeholder={placeholder}\n textareaClassName={textareaClassName}\n />\n </div>\n </div>\n )\n}\n\nfunction ComposeModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-3\">\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n {compose.visibility === 'public' ? (\n <>\n <Label htmlFor=\"messages-compose-external-email\">{compose.t('messages.externalEmail', 'External email')}</Label>\n <EmailInput\n id=\"messages-compose-external-email\"\n value={compose.externalEmail}\n onChange={(event) => compose.setExternalEmail(event.target.value)}\n placeholder={compose.t('messages.placeholders.externalEmail', 'name@example.com')}\n />\n </>\n ) : (\n <>\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <VisibilitySelector compose={compose} />\n </div>\n </div>\n\n <ContextActionsSection compose={compose} />\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-subject\">{compose.t('messages.subject', 'Subject')}</Label>\n <Input\n id=\"messages-compose-subject\"\n value={compose.subject}\n onChange={(event) => compose.setSubject(event.target.value)}\n placeholder={compose.t('messages.placeholders.subject', 'Enter subject...')}\n />\n </div>\n\n <div className=\"space-y-2\">\n <PrioritySelector compose={compose} />\n </div>\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.body', 'Message')}\n placeholder={compose.t('messages.placeholders.body', 'Write your message...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ReplyModeFields({ compose }: ComposeProps) {\n return (\n <>\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.replyBody', 'Reply')}\n placeholder={compose.t('messages.placeholders.replyBody', 'Write your reply...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ForwardModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.forwardContent', 'Forwarded content')}\n placeholder={compose.t('messages.placeholders.forwardContent', 'Review and edit forwarded content...')}\n inputId=\"messages-forward-note\"\n rows={6}\n textareaClassName=\"min-h-[140px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n </>\n )\n}\n\nfunction EmailDeliverySection({ compose }: ComposeProps) {\n if (compose.variant === 'reply' || compose.variant === 'forward') {\n return null\n }\n\n if (compose.isComposePublicVisibility) {\n return (\n <div className=\"rounded border px-3 py-2\">\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailForcedPublic', 'For public visibility, email delivery is always enabled.')}</p>\n </div>\n )\n }\n\n return (\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.sendViaEmail', 'Also send via email')}\n description={compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}\n checked={compose.sendViaEmail}\n onCheckedChange={compose.setSendViaEmail}\n />\n )\n}\n\nfunction ReplyForwardOptionsRow({ compose }: ComposeProps) {\n if (compose.variant !== 'reply' && compose.variant !== 'forward') {\n return null\n }\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.variant === 'forward' ? (\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.includeAttachments', 'Include attachments')}\n description={compose.t('messages.includeAttachmentsHint', 'Carry over attachments from the original message.')}\n checked={compose.includeAttachments}\n onCheckedChange={compose.setIncludeAttachments}\n />\n ) : (\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.replyAll', 'Reply all')}\n description={compose.t('messages.replyAllHint', 'Include all original recipients.')}\n checked={compose.replyAll}\n onCheckedChange={compose.setReplyAll}\n />\n )}\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.sendViaEmail', 'Also send via email')}\n description={compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}\n checked={compose.sendViaEmail}\n onCheckedChange={compose.setSendViaEmail}\n />\n </div>\n )\n}\n\nfunction MessageComposeFormBody({ compose }: ComposeProps) {\n return (\n <div className=\"space-y-4\" onKeyDown={compose.handleKeyDown}>\n {compose.contextPreview ? (\n <div className=\"rounded border bg-muted/30 p-3 text-sm\">\n {compose.contextPreview}\n </div>\n ) : null}\n {compose.variant === 'compose' ? <ComposeModeFields compose={compose} /> : null}\n {compose.variant === 'reply' ? <ReplyModeFields compose={compose} /> : null}\n {compose.variant === 'forward' ? <ForwardModeFields compose={compose} /> : null}\n <ReplyForwardOptionsRow compose={compose} />\n <EmailDeliverySection compose={compose} />\n {compose.submitError ? <p className=\"text-sm text-destructive\">{compose.submitError}</p> : null}\n </div>\n )\n}\n\nexport function createMessageComposeFormGroups(compose: UseMessageComposeResult): CrudField[] {\n return [{\n id: 'composer',\n label: '',\n type: 'custom',\n component: () => <MessageComposeFormBody compose={compose} />,\n }]\n}\n"],
|
|
5
|
-
"mappings": "AA4BI,SAeA,UAfA,KAiBE,YAjBF;AA3BJ,SAAS,UAAU,OAAO,YAAY;AAEtC,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AACxC,SAAS,iBAAiB;AAC1B,SAAS,+BAA+B;AAOxC,SAAS,mBAAmB,EAAE,QAAQ,GAAiB;AACrD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,QAAQ;AAAA,MACf,UAAU,QAAQ;AAAA,MAClB,iBAAiB,QAAQ;AAAA,MACzB,cAAc,QAAQ;AAAA,MACtB,iBAAiB,QAAQ;AAAA,MACzB,aAAa,QAAQ,EAAE,oCAAoC,sBAAsB;AAAA,MACjF,mBAAmB;AAAA,MACnB,wBAAwB;AAAA;AAAA,EAC1B;AAEJ;AAEA,SAAS,mBAAmB,EAAE,QAAQ,GAAiB;AACrD,SACE,iCACE;AAAA,wBAAC,SAAO,kBAAQ,EAAE,uBAAuB,YAAY,GAAE;AAAA,IACvD;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,cAAY,QAAQ,EAAE,uBAAuB,YAAY;AAAA,QAEzD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,MAAK;AAAA,cACL,SAAS,QAAQ,eAAe,aAAa,YAAY;AAAA,cACzD,MAAK;AAAA,cACL,gBAAc,QAAQ,eAAe;AAAA,cACrC,cAAY,QAAQ,EAAE,+BAA+B,UAAU;AAAA,cAC/D,OAAO,QAAQ,EAAE,+BAA+B,UAAU;AAAA,cAC1D,WAAU;AAAA,cACV,SAAS,MAAM,QAAQ,cAAc,UAAU;AAAA,cAE/C,8BAAC,QAAK,WAAU,eAAc;AAAA;AAAA,UAChC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,MAAK;AAAA,cACL,SAAS,QAAQ,eAAe,WAAW,YAAY;AAAA,cACvD,MAAK;AAAA,cACL,gBAAc,QAAQ,eAAe;AAAA,cACrC,cAAY,QAAQ,EAAE,6BAA6B,QAAQ;AAAA,cAC3D,OAAO,QAAQ,EAAE,6BAA6B,QAAQ;AAAA,cACtD,WAAU;AAAA,cACV,SAAS,MAAM,QAAQ,cAAc,QAAQ;AAAA,cAE7C,8BAAC,SAAM,WAAU,eAAc;AAAA;AAAA,UACjC;AAAA;AAAA;AAAA,IACF;AAAA,IACA,oBAAC,OAAE,WAAU,iCACV,kBAAQ,eAAe,WACpB,QAAQ,EAAE,iCAAiC,kDAAkD,IAC7F,QAAQ,EAAE,mCAAmC,sDAAsD,GACzG;AAAA,KACF;AAEJ;AAEA,SAAS,sBAAsB,EAAE,QAAQ,GAAiB;AACxD,MAAI,CAAC,QAAQ,yBAA0B,QAAO;AAE9C,SACE,qBAAC,SAAI,WAAU,6BACZ;AAAA,YAAQ,iCAAiC,aACxC,qBAAC,SAAI,WAAU,4EACb;AAAA,2BAAC,SACC;AAAA,4BAAC,OAAE,WAAU,uBACV,kBAAQ,EAAE,sDAAsD,iBAAiB,GACpF;AAAA,QACA,oBAAC,OAAE,WAAU,iCACV,kBAAQ,EAAE,qDAAqD,iDAAiD,GACnH;AAAA,SACF;AAAA,MACA,oBAAC,UAAO,SAAS,QAAQ,uBAAuB,iBAAiB,QAAQ,0BAA0B;AAAA,OACrG,IACE;AAAA,IACH,QAAQ,iCAAiC,cAAc,QAAQ,wBAC9D,qBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,SAAM,SAAQ,wCACZ,kBAAQ,EAAE,kDAAkD,aAAa,GAC5E;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,QAAQ,qBAAqB;AAAA,UACpC,eAAe,CAAC,UAAU,QAAQ,qBAAqB,SAAS,EAAE;AAAA,UAElE;AAAA,gCAAC,iBAAc,IAAG,wCAChB,8BAAC,eAAY,aAAa,QAAQ,EAAE,wDAAwD,eAAe,GAAG,GAChH;AAAA,YACA,oBAAC,iBACE,kBAAQ,qBAAqB,IAAI,CAAC,WACjC,oBAAC,cAA2B,OAAO,OAAO,IACvC,iBAAO,SADO,OAAO,EAExB,CACD,GACH;AAAA;AAAA;AAAA,MACF;AAAA,OACF,IACE;AAAA,KACN;AAEJ;AAEA,SAAS,iBAAiB,EAAE,QAAQ,GAAiB;AACnD,SACE,iCACE;AAAA,wBAAC,SAAO,kBAAQ,EAAE,qBAAqB,UAAU,GAAE;AAAA,IACnD;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,QAAQ;AAAA,QACf,UAAU,QAAQ;AAAA,QAClB,GAAG,QAAQ;AAAA;AAAA,IACb;AAAA,KACF;AAEJ;AAEA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,2CACb;AAAA,0BAAC,SAAM,SAAS,SAAU,iBAAM;AAAA,MAChC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,QAAQ,eAAe,aAAa,YAAY;AAAA,UACzD,gBAAc,QAAQ,eAAe;AAAA,UACrC,SAAS,MAAM,QAAQ,cAAc,CAAC,kBAAmB,kBAAkB,aAAa,SAAS,UAAW;AAAA,UAC5G,OAAO,QAAQ,EAAE,8BAA8B,iBAAiB;AAAA,UAEhE,8BAAC,YAAS,WAAU,WAAU;AAAA;AAAA,MAChC;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,IAAI,SACP;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,QAAQ;AAAA,QACf,UAAU,QAAQ;AAAA,QAClB,mBAAmB,QAAQ,eAAe;AAAA,QAC1C;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;AAEA,SAAS,kBAAkB,EAAE,QAAQ,GAAiB;AACpD,SACE,iCACE;AAAA,yBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,6BACb;AAAA,4BAAC,SAAI,WAAU,aACZ,kBAAQ,eAAe,WACtB,iCACE;AAAA,8BAAC,SAAM,SAAQ,mCAAmC,kBAAQ,EAAE,0BAA0B,gBAAgB,GAAE;AAAA,UACxG;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO,QAAQ;AAAA,cACf,UAAU,CAAC,UAAU,QAAQ,iBAAiB,MAAM,OAAO,KAAK;AAAA,cAChE,aAAa,QAAQ,EAAE,uCAAuC,kBAAkB;AAAA;AAAA,UAClF;AAAA,WACF,IAEA,iCACE;AAAA,8BAAC,SAAM,SAAQ,+BAA+B,kBAAQ,EAAE,eAAe,IAAI,GAAE;AAAA,UAC7E,oBAAC,sBAAmB,SAAkB;AAAA,WACxC,GAEJ;AAAA,QAEA,oBAAC,SAAI,WAAU,aACb,8BAAC,sBAAmB,SAAkB,GACxC;AAAA,SACF;AAAA,MAEA,oBAAC,yBAAsB,SAAkB;AAAA,OAC3C;AAAA,IAEA,qBAAC,SAAI,WAAU,6BACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,SAAM,SAAQ,4BAA4B,kBAAQ,EAAE,oBAAoB,SAAS,GAAE;AAAA,QACpF;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAO,QAAQ;AAAA,YACf,UAAU,CAAC,UAAU,QAAQ,WAAW,MAAM,OAAO,KAAK;AAAA,YAC1D,aAAa,QAAQ,EAAE,iCAAiC,kBAAkB;AAAA;AAAA,QAC5E;AAAA,SACF;AAAA,MAEA,oBAAC,SAAI,WAAU,aACb,8BAAC,oBAAiB,SAAkB,GACtC;AAAA,OACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO,QAAQ,EAAE,iBAAiB,SAAS;AAAA,QAC3C,aAAa,QAAQ,EAAE,8BAA8B,uBAAuB;AAAA,QAC5E,SAAQ;AAAA,QACR,MAAM;AAAA,QACN,mBAAkB;AAAA;AAAA,IACpB;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,SAAO,kBAAQ,EAAE,0BAA0B,aAAa,GAAE;AAAA,MAC3D;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,QAAQ;AAAA,UAClB,UAAU,QAAQ;AAAA,UAClB,YAAY;AAAA,UACZ,SAAO;AAAA,UACP,WAAW,MAAM;AACf,iBAAK,QAAQ,kBAAkB,EAAE,MAAM,MAAM,IAAI;AAAA,UACnD;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,gBAAgB,EAAE,QAAQ,GAAiB;AAClD,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO,QAAQ,EAAE,sBAAsB,OAAO;AAAA,QAC9C,aAAa,QAAQ,EAAE,mCAAmC,qBAAqB;AAAA,QAC/E,SAAQ;AAAA,QACR,MAAM;AAAA,QACN,mBAAkB;AAAA;AAAA,IACpB;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,SAAO,kBAAQ,EAAE,0BAA0B,aAAa,GAAE;AAAA,MAC3D;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,QAAQ;AAAA,UAClB,UAAU,QAAQ;AAAA,UAClB,YAAY;AAAA,UACZ,SAAO;AAAA,UACP,WAAW,MAAM;AACf,iBAAK,QAAQ,kBAAkB,EAAE,MAAM,MAAM,IAAI;AAAA,UACnD;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,kBAAkB,EAAE,QAAQ,GAAiB;AACpD,SACE,iCACE;AAAA,yBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,SAAM,SAAQ,+BAA+B,kBAAQ,EAAE,eAAe,IAAI,GAAE;AAAA,MAC7E,oBAAC,sBAAmB,SAAkB;AAAA,OACxC;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO,QAAQ,EAAE,2BAA2B,mBAAmB;AAAA,QAC/D,aAAa,QAAQ,EAAE,wCAAwC,sCAAsC;AAAA,QACrG,SAAQ;AAAA,QACR,MAAM;AAAA,QACN,mBAAkB;AAAA;AAAA,IACpB;AAAA,KACF;AAEJ;AAEA,SAAS,qBAAqB,EAAE,QAAQ,GAAiB;AACvD,MAAI,QAAQ,YAAY,WAAW,QAAQ,YAAY,WAAW;AAChE,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,2BAA2B;AACrC,WACE,qBAAC,SAAI,WAAU,4BACb;AAAA,0BAAC,OAAE,WAAU,uBAAuB,kBAAQ,EAAE,yBAAyB,qBAAqB,GAAE;AAAA,MAC9F,oBAAC,OAAE,WAAU,iCAAiC,kBAAQ,EAAE,qCAAqC,0DAA0D,GAAE;AAAA,OAC3J;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,oBAAmB;AAAA,MACnB,OAAO,QAAQ,EAAE,yBAAyB,qBAAqB;AAAA,MAC/D,aAAa,QAAQ,EAAE,6BAA6B,2DAA2D;AAAA,MAC/G,SAAS,QAAQ;AAAA,MACjB,iBAAiB,QAAQ;AAAA;AAAA,EAC3B;AAEJ;AAEA,SAAS,uBAAuB,EAAE,QAAQ,GAAiB;AACzD,MAAI,QAAQ,YAAY,WAAW,QAAQ,YAAY,WAAW;AAChE,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,SAAI,WAAU,6BACZ;AAAA,YAAQ,YAAY,YACnB;AAAA,MAAC;AAAA;AAAA,QACC,oBAAmB;AAAA,QACnB,OAAO,QAAQ,EAAE,+BAA+B,qBAAqB;AAAA,QACrE,aAAa,QAAQ,EAAE,mCAAmC,mDAAmD;AAAA,QAC7G,SAAS,QAAQ;AAAA,QACjB,iBAAiB,QAAQ;AAAA;AAAA,IAC3B,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,oBAAmB;AAAA,QACnB,OAAO,QAAQ,EAAE,qBAAqB,WAAW;AAAA,QACjD,aAAa,QAAQ,EAAE,yBAAyB,kCAAkC;AAAA,QAClF,SAAS,QAAQ;AAAA,QACjB,iBAAiB,QAAQ;AAAA;AAAA,IAC3B;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,oBAAmB;AAAA,QACnB,OAAO,QAAQ,EAAE,yBAAyB,qBAAqB;AAAA,QAC/D,aAAa,QAAQ,EAAE,6BAA6B,2DAA2D;AAAA,QAC/G,SAAS,QAAQ;AAAA,QACjB,iBAAiB,QAAQ;AAAA;AAAA,IAC3B;AAAA,KACF;AAEJ;AAEA,SAAS,uBAAuB,EAAE,QAAQ,GAAiB;AACzD,SACE,qBAAC,SAAI,WAAU,aAAY,WAAW,QAAQ,eAC3C;AAAA,YAAQ,iBACP,oBAAC,SAAI,WAAU,0CACZ,kBAAQ,gBACX,IACE;AAAA,IACH,QAAQ,YAAY,YAAY,oBAAC,qBAAkB,SAAkB,IAAK;AAAA,IAC1E,QAAQ,YAAY,UAAU,oBAAC,mBAAgB,SAAkB,IAAK;AAAA,IACtE,QAAQ,YAAY,YAAY,oBAAC,qBAAkB,SAAkB,IAAK;AAAA,IAC3E,oBAAC,0BAAuB,SAAkB;AAAA,IAC1C,oBAAC,wBAAqB,SAAkB;AAAA,IACvC,QAAQ,cAAc,oBAAC,OAAE,WAAU,4BAA4B,kBAAQ,aAAY,IAAO;AAAA,KAC7F;AAEJ;AAEO,SAAS,+BAA+B,SAA+C;AAC5F,SAAO,CAAC;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,IACN,WAAW,MAAM,oBAAC,0BAAuB,SAAkB;AAAA,EAC7D,CAAC;AACH;",
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport { FileCode, Globe, Lock } from 'lucide-react'\nimport { type CrudField } from '../CrudForm'\nimport { IconButton } from '../../primitives/icon-button'\nimport { Input } from '../../primitives/input'\nimport { EmailInput } from '../../primitives/email-input'\nimport { Label } from '../../primitives/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../../primitives/select'\nimport { Switch } from '../../primitives/switch'\nimport { SwitchField } from '../../primitives/switch-field'\nimport { AttachmentsSection } from '../detail/AttachmentsSection'\nimport { SwitchableMarkdownInput } from '../inputs/SwitchableMarkdownInput'\nimport { TagsInput } from '../inputs/TagsInput'\nimport { MessagePrioritySelector } from './MessagePrioritySelector'\nimport type { UseMessageComposeResult } from './useMessageCompose'\n\ntype ComposeProps = {\n compose: UseMessageComposeResult\n}\n\nfunction RecipientTagsInput({ compose }: ComposeProps) {\n return (\n <TagsInput\n value={compose.recipientIds}\n onChange={compose.setRecipientIds}\n selectedOptions={compose.selectedRecipientOptions}\n resolveLabel={compose.resolveRecipientLabel}\n loadSuggestions={compose.loadRecipientSuggestions}\n placeholder={compose.t('messages.placeholders.recipients', 'Search recipients...')}\n allowCustomValues={false}\n showSuggestionsOnFocus={false}\n />\n )\n}\n\nfunction VisibilitySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.visibility', 'Visibility')}</Label>\n <div\n className=\"inline-flex items-center gap-1 rounded-md border bg-background p-1\"\n role=\"radiogroup\"\n aria-label={compose.t('messages.visibility', 'Visibility')}\n >\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'internal' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'internal'}\n aria-label={compose.t('messages.visibilityInternal', 'Internal')}\n title={compose.t('messages.visibilityInternal', 'Internal')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('internal')}\n >\n <Lock className=\"h-3.5 w-3.5\" />\n </IconButton>\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'public' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'public'}\n aria-label={compose.t('messages.visibilityPublic', 'Public')}\n title={compose.t('messages.visibilityPublic', 'Public')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('public')}\n >\n <Globe className=\"h-3.5 w-3.5\" />\n </IconButton>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {compose.visibility === 'public'\n ? compose.t('messages.visibilityPublicHint', 'Public messages are sent to external email only.')\n : compose.t('messages.visibilityInternalHint', 'Internal messages are sent to selected system users.')}\n </p>\n </>\n )\n}\n\nfunction ContextActionsSection({ compose }: ComposeProps) {\n if (!compose.shouldShowContextActions) return null\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.normalizedRequiredActionMode === 'optional' ? (\n <div className=\"flex items-center justify-between rounded border px-3 py-2 sm:col-span-2\">\n <div>\n <p className=\"text-sm font-medium\">\n {compose.t('messages.composer.objectPicker.actionRequiredLabel', 'Action required')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {compose.t('messages.composer.objectPicker.actionRequiredHint', 'Mark this object as requiring recipient action.')}\n </p>\n </div>\n <Switch checked={compose.contextActionRequired} onCheckedChange={compose.setContextActionRequired} />\n </div>\n ) : null}\n {compose.normalizedRequiredActionMode === 'required' || compose.contextActionRequired ? (\n <div className=\"space-y-2 sm:col-span-2\">\n <Label htmlFor=\"messages-compose-context-action-type\">\n {compose.t('messages.composer.objectPicker.actionTypeLabel', 'Action type')}\n </Label>\n <Select\n value={compose.contextActionType || undefined}\n onValueChange={(value) => compose.setContextActionType(value || '')}\n >\n <SelectTrigger id=\"messages-compose-context-action-type\">\n <SelectValue placeholder={compose.t('messages.composer.objectPicker.actionTypePlaceholder', 'Select action')} />\n </SelectTrigger>\n <SelectContent>\n {compose.contextActionOptions.map((option) => (\n <SelectItem key={option.id} value={option.id}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction PrioritySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.priority', 'Priority')}</Label>\n <MessagePrioritySelector\n value={compose.priority}\n onChange={compose.setPriority}\n t={compose.t}\n />\n </>\n )\n}\n\nfunction MarkdownBodySection({\n compose,\n label,\n placeholder,\n inputId,\n rows,\n textareaClassName,\n}: ComposeProps & {\n label: string\n placeholder: string\n inputId: string\n rows: number\n textareaClassName: string\n}) {\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label htmlFor={inputId}>{label}</Label>\n <IconButton\n type=\"button\"\n size=\"sm\"\n variant={compose.bodyFormat === 'markdown' ? 'outline' : 'ghost'}\n aria-pressed={compose.bodyFormat === 'markdown'}\n onClick={() => compose.setBodyFormat((previousValue) => (previousValue === 'markdown' ? 'text' : 'markdown'))}\n title={compose.t('messages.bodyFormat.toggle', 'Toggle markdown')}\n >\n <FileCode className=\"h-4 w-4\" />\n </IconButton>\n </div>\n <div id={inputId}>\n <SwitchableMarkdownInput\n value={compose.body}\n onChange={compose.setBody}\n isMarkdownEnabled={compose.bodyFormat === 'markdown'}\n rows={rows}\n placeholder={placeholder}\n textareaClassName={textareaClassName}\n />\n </div>\n </div>\n )\n}\n\nconst PLATFORM_SENDER_VALUE = '__platform__'\n\nfunction SenderSelector({ compose }: ComposeProps) {\n if (compose.senderOptions.length === 0) return null\n\n const fieldError = compose.submitFieldErrors?.senderChannelId ?? null\n\n return (\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-sender\">{compose.t('messages.sendFrom', 'Send from')}</Label>\n <Select\n value={compose.senderChannelId || PLATFORM_SENDER_VALUE}\n onValueChange={(value) => compose.setSenderChannelId(value === PLATFORM_SENDER_VALUE ? '' : value)}\n >\n <SelectTrigger id=\"messages-compose-sender\" aria-invalid={fieldError ? true : undefined}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={PLATFORM_SENDER_VALUE}>\n {compose.t('messages.sendFromPlatform', 'Platform sender (default)')}\n </SelectItem>\n {compose.senderOptions.map((option) => (\n <SelectItem key={option.id} value={option.id}>\n {option.description ? `${option.label} (${option.description})` : option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {fieldError ? (\n <p className=\"text-sm text-destructive\" role=\"alert\">{fieldError}</p>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n {compose.t('messages.sendFromHint', 'Replies to a message sent from your own mailbox come back into this thread.')}\n </p>\n )}\n </div>\n )\n}\n\nfunction ComposeModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-3\">\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n {compose.visibility === 'public' ? (\n <>\n <Label htmlFor=\"messages-compose-external-email\">{compose.t('messages.externalEmail', 'External email')}</Label>\n <EmailInput\n id=\"messages-compose-external-email\"\n value={compose.externalEmail}\n onChange={(event) => compose.setExternalEmail(event.target.value)}\n placeholder={compose.t('messages.placeholders.externalEmail', 'name@example.com')}\n />\n </>\n ) : (\n <>\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <VisibilitySelector compose={compose} />\n </div>\n </div>\n\n <SenderSelector compose={compose} />\n\n <ContextActionsSection compose={compose} />\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-subject\">{compose.t('messages.subject', 'Subject')}</Label>\n <Input\n id=\"messages-compose-subject\"\n value={compose.subject}\n onChange={(event) => compose.setSubject(event.target.value)}\n placeholder={compose.t('messages.placeholders.subject', 'Enter subject...')}\n />\n </div>\n\n <div className=\"space-y-2\">\n <PrioritySelector compose={compose} />\n </div>\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.body', 'Message')}\n placeholder={compose.t('messages.placeholders.body', 'Write your message...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ReplyModeFields({ compose }: ComposeProps) {\n return (\n <>\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.replyBody', 'Reply')}\n placeholder={compose.t('messages.placeholders.replyBody', 'Write your reply...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ForwardModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.forwardContent', 'Forwarded content')}\n placeholder={compose.t('messages.placeholders.forwardContent', 'Review and edit forwarded content...')}\n inputId=\"messages-forward-note\"\n rows={6}\n textareaClassName=\"min-h-[140px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n </>\n )\n}\n\nfunction EmailDeliverySection({ compose }: ComposeProps) {\n if (compose.variant === 'reply' || compose.variant === 'forward') {\n return null\n }\n\n if (compose.isComposePublicVisibility) {\n return (\n <div className=\"rounded border px-3 py-2\">\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailForcedPublic', 'For public visibility, email delivery is always enabled.')}</p>\n </div>\n )\n }\n\n return (\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.sendViaEmail', 'Also send via email')}\n description={compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}\n checked={compose.sendViaEmail}\n onCheckedChange={compose.setSendViaEmail}\n />\n )\n}\n\nfunction ReplyForwardOptionsRow({ compose }: ComposeProps) {\n if (compose.variant !== 'reply' && compose.variant !== 'forward') {\n return null\n }\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.variant === 'forward' ? (\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.includeAttachments', 'Include attachments')}\n description={compose.t('messages.includeAttachmentsHint', 'Carry over attachments from the original message.')}\n checked={compose.includeAttachments}\n onCheckedChange={compose.setIncludeAttachments}\n />\n ) : (\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.replyAll', 'Reply all')}\n description={compose.t('messages.replyAllHint', 'Include all original recipients.')}\n checked={compose.replyAll}\n onCheckedChange={compose.setReplyAll}\n />\n )}\n <SwitchField\n containerClassName=\"rounded border px-3 py-2\"\n label={compose.t('messages.sendViaEmail', 'Also send via email')}\n description={compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}\n checked={compose.sendViaEmail}\n onCheckedChange={compose.setSendViaEmail}\n />\n </div>\n )\n}\n\nfunction MessageComposeFormBody({ compose }: ComposeProps) {\n return (\n <div className=\"space-y-4\" onKeyDown={compose.handleKeyDown}>\n {compose.contextPreview ? (\n <div className=\"rounded border bg-muted/30 p-3 text-sm\">\n {compose.contextPreview}\n </div>\n ) : null}\n {compose.variant === 'compose' ? <ComposeModeFields compose={compose} /> : null}\n {compose.variant === 'reply' ? <ReplyModeFields compose={compose} /> : null}\n {compose.variant === 'forward' ? <ForwardModeFields compose={compose} /> : null}\n <ReplyForwardOptionsRow compose={compose} />\n <EmailDeliverySection compose={compose} />\n {compose.submitError ? <p className=\"text-sm text-destructive\">{compose.submitError}</p> : null}\n </div>\n )\n}\n\nexport function createMessageComposeFormGroups(compose: UseMessageComposeResult): CrudField[] {\n return [{\n id: 'composer',\n label: '',\n type: 'custom',\n component: () => <MessageComposeFormBody compose={compose} />,\n }]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -29,6 +29,13 @@ function toErrorMessage(payload) {
|
|
|
29
29
|
}
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
|
+
function readFieldErrors(payload) {
|
|
33
|
+
if (!payload || typeof payload !== "object") return null;
|
|
34
|
+
const raw = payload.fieldErrors;
|
|
35
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
36
|
+
const entries = Object.entries(raw).filter((entry) => typeof entry[1] === "string");
|
|
37
|
+
return entries.length ? Object.fromEntries(entries) : null;
|
|
38
|
+
}
|
|
32
39
|
function createTemporaryAttachmentRecordId() {
|
|
33
40
|
const randomPart = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
34
41
|
return `messages-composer:${randomPart}`;
|
|
@@ -43,6 +50,7 @@ function useMessageCompose({
|
|
|
43
50
|
contextObject = null,
|
|
44
51
|
requiredActionConfig = null,
|
|
45
52
|
contextPreview = null,
|
|
53
|
+
senderOptions,
|
|
46
54
|
defaultValues,
|
|
47
55
|
expectedUpdatedAt = null,
|
|
48
56
|
onSuccess,
|
|
@@ -73,6 +81,8 @@ function useMessageCompose({
|
|
|
73
81
|
const [submitting, setSubmitting] = React.useState(false);
|
|
74
82
|
const [submitMode, setSubmitMode] = React.useState("send");
|
|
75
83
|
const [submitError, setSubmitError] = React.useState(null);
|
|
84
|
+
const [submitFieldErrors, setSubmitFieldErrors] = React.useState(null);
|
|
85
|
+
const [senderChannelId, setSenderChannelId] = React.useState("");
|
|
76
86
|
const isOpenRef = React.useRef(false);
|
|
77
87
|
const wasOpenRef = React.useRef(false);
|
|
78
88
|
const submitLockReleaseRef = React.useRef(null);
|
|
@@ -317,7 +327,13 @@ function useMessageCompose({
|
|
|
317
327
|
}
|
|
318
328
|
onCancel?.();
|
|
319
329
|
}, [inline, onCancel, onOpenChange, submitting]);
|
|
330
|
+
const resolvedSenderOptions = React.useMemo(
|
|
331
|
+
() => isComposePublicVisibility ? senderOptions ?? [] : [],
|
|
332
|
+
[isComposePublicVisibility, senderOptions]
|
|
333
|
+
);
|
|
334
|
+
const effectiveSenderChannelId = resolvedSenderOptions.some((option) => option.id === senderChannelId) ? senderChannelId : "";
|
|
320
335
|
const composeSendOperation = useComposeSendOperation({
|
|
336
|
+
senderChannelId: effectiveSenderChannelId,
|
|
321
337
|
t,
|
|
322
338
|
messageType,
|
|
323
339
|
createableMessageTypes,
|
|
@@ -339,6 +355,7 @@ function useMessageCompose({
|
|
|
339
355
|
});
|
|
340
356
|
const composeDraftOperation = useComposeDraftOperation({
|
|
341
357
|
t,
|
|
358
|
+
senderChannelId: effectiveSenderChannelId,
|
|
342
359
|
messageId,
|
|
343
360
|
messageType,
|
|
344
361
|
priority,
|
|
@@ -376,6 +393,7 @@ function useMessageCompose({
|
|
|
376
393
|
});
|
|
377
394
|
const sendDraftOperation = useSendDraftOperation({
|
|
378
395
|
t,
|
|
396
|
+
senderChannelId: effectiveSenderChannelId,
|
|
379
397
|
messageId: messageId ?? "",
|
|
380
398
|
messageType,
|
|
381
399
|
priority,
|
|
@@ -396,6 +414,7 @@ function useMessageCompose({
|
|
|
396
414
|
});
|
|
397
415
|
const updateDraftOperation = useUpdateDraftOperation({
|
|
398
416
|
t,
|
|
417
|
+
senderChannelId: effectiveSenderChannelId,
|
|
399
418
|
messageId: messageId ?? "",
|
|
400
419
|
messageType,
|
|
401
420
|
priority,
|
|
@@ -417,6 +436,7 @@ function useMessageCompose({
|
|
|
417
436
|
const handleSubmit = React.useCallback(async ({ saveAsDraft = false } = {}) => {
|
|
418
437
|
if (submitting) return false;
|
|
419
438
|
setSubmitError(null);
|
|
439
|
+
setSubmitFieldErrors(null);
|
|
420
440
|
const isEditingExistingDraft = variant === "compose" && Boolean(messageId);
|
|
421
441
|
const isComposeDraftSubmit = saveAsDraft && variant === "compose";
|
|
422
442
|
const operation = isComposeDraftSubmit ? isEditingExistingDraft ? updateDraftOperation : composeDraftOperation : variant === "compose" ? isEditingExistingDraft ? sendDraftOperation : composeSendOperation : variant === "reply" ? replyOperation : forwardOperation;
|
|
@@ -464,6 +484,7 @@ function useMessageCompose({
|
|
|
464
484
|
} else {
|
|
465
485
|
const message = toErrorMessage(call.result) ?? t("messages.errors.sendFailed", "Failed to send message.");
|
|
466
486
|
setSubmitError(message);
|
|
487
|
+
setSubmitFieldErrors(readFieldErrors(call.result));
|
|
467
488
|
flash(message, "error");
|
|
468
489
|
}
|
|
469
490
|
shouldReturnFalse = true;
|
|
@@ -536,6 +557,8 @@ function useMessageCompose({
|
|
|
536
557
|
return;
|
|
537
558
|
}
|
|
538
559
|
if (event.key === "Escape") {
|
|
560
|
+
if (event.defaultPrevented) return;
|
|
561
|
+
if (event.target instanceof Node && !event.currentTarget.contains(event.target)) return;
|
|
539
562
|
event.preventDefault();
|
|
540
563
|
handleCancel();
|
|
541
564
|
}
|
|
@@ -574,6 +597,9 @@ function useMessageCompose({
|
|
|
574
597
|
setVisibility,
|
|
575
598
|
externalEmail,
|
|
576
599
|
setExternalEmail,
|
|
600
|
+
senderOptions: resolvedSenderOptions,
|
|
601
|
+
senderChannelId: effectiveSenderChannelId,
|
|
602
|
+
setSenderChannelId,
|
|
577
603
|
sendViaEmail,
|
|
578
604
|
setSendViaEmail,
|
|
579
605
|
contextActionRequired,
|
|
@@ -587,6 +613,7 @@ function useMessageCompose({
|
|
|
587
613
|
submitting,
|
|
588
614
|
submitMode,
|
|
589
615
|
submitError,
|
|
616
|
+
submitFieldErrors,
|
|
590
617
|
composerTitle,
|
|
591
618
|
submitLabel,
|
|
592
619
|
selectedRecipientOptions,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/messages/useMessageCompose.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { flash } from '../FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '../utils/apiCall'\nimport { buildOptimisticLockHeader } from '../utils/optimisticLock'\nimport { surfaceRecordConflict } from '../conflicts'\nimport type {\n AttachmentListResponse,\n MessageComposerProps,\n MessageTypeItem,\n UserListItem,\n} from './message-composer.types'\nimport type { MessagePriority } from './message-priority'\nimport type { TagsInputOption } from '../inputs/TagsInput'\nimport {\n useComposeDraftOperation,\n useComposeSendOperation,\n useForwardSubmitOperation,\n useReplySubmitOperation,\n useSendDraftOperation,\n useUpdateDraftOperation,\n} from './useMessageComposeOperations'\n\nfunction toErrorMessage(payload: unknown): string | null {\n if (!payload) return null\n if (typeof payload === 'string') return payload\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const nested = toErrorMessage(item)\n if (nested) return nested\n }\n return null\n }\n if (typeof payload === 'object') {\n const record = payload as Record<string, unknown>\n return (\n toErrorMessage(record.error)\n ?? toErrorMessage(record.message)\n ?? toErrorMessage(record.detail)\n ?? toErrorMessage(record.details)\n ?? null\n )\n }\n return null\n}\n\nfunction createTemporaryAttachmentRecordId(): string {\n const randomPart =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`\n return `messages-composer:${randomPart}`\n}\n\nexport type UseMessageComposeParams = MessageComposerProps\n\nexport type UseMessageComposeResult = {\n t: ReturnType<typeof useT>\n variant: NonNullable<MessageComposerProps['variant']>\n messageId?: string\n open?: boolean\n inline: boolean\n contextPreview: React.ReactNode\n isOpen: boolean\n messageTypes: MessageTypeItem[]\n createableMessageTypes: MessageTypeItem[]\n normalizedRequiredActionMode: 'none' | 'optional' | 'required'\n contextActionOptions: Array<{ id: string; label: string }>\n shouldShowContextActions: boolean\n isComposePublicVisibility: boolean\n attachmentEntityId: string\n attachmentRecordId: string\n recipientIds: string[]\n setRecipientIds: React.Dispatch<React.SetStateAction<string[]>>\n messageType: string\n setMessageType: React.Dispatch<React.SetStateAction<string>>\n subject: string\n setSubject: React.Dispatch<React.SetStateAction<string>>\n body: string\n setBody: React.Dispatch<React.SetStateAction<string>>\n bodyFormat: 'text' | 'markdown'\n setBodyFormat: React.Dispatch<React.SetStateAction<'text' | 'markdown'>>\n priority: MessagePriority\n setPriority: React.Dispatch<React.SetStateAction<MessagePriority>>\n visibility: 'public' | 'internal'\n setVisibility: React.Dispatch<React.SetStateAction<'public' | 'internal'>>\n externalEmail: string\n setExternalEmail: React.Dispatch<React.SetStateAction<string>>\n sendViaEmail: boolean\n setSendViaEmail: React.Dispatch<React.SetStateAction<boolean>>\n contextActionRequired: boolean\n setContextActionRequired: React.Dispatch<React.SetStateAction<boolean>>\n contextActionType: string\n setContextActionType: React.Dispatch<React.SetStateAction<string>>\n replyAll: boolean\n setReplyAll: React.Dispatch<React.SetStateAction<boolean>>\n includeAttachments: boolean\n setIncludeAttachments: React.Dispatch<React.SetStateAction<boolean>>\n submitting: boolean\n submitMode: 'send' | 'draft'\n submitError: string | null\n composerTitle: string\n submitLabel: string\n selectedRecipientOptions: TagsInputOption[]\n resolveRecipientLabel: (id: string) => string\n loadRecipientSuggestions: (query?: string) => Promise<TagsInputOption[]>\n loadAttachmentIds: () => Promise<string[]>\n handleSaveDraft: () => void\n handleBack: () => void\n handleSubmit: ({ saveAsDraft }?: { saveAsDraft?: boolean }) => Promise<boolean>\n handleDialogOpenChange: (nextOpen: boolean) => void\n handleKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void\n}\n\ntype ForwardPreviewResponse = {\n subject?: string\n body?: string\n}\n\nexport function useMessageCompose({\n variant: variantProp = 'compose',\n messageId,\n open,\n onOpenChange,\n inline = false,\n lockedType = null,\n contextObject = null,\n requiredActionConfig = null,\n contextPreview = null,\n defaultValues,\n expectedUpdatedAt = null,\n onSuccess,\n onCancel,\n}: UseMessageComposeParams): UseMessageComposeResult {\n const t = useT()\n const variant = variantProp\n const isOpen = inline ? true : Boolean(open)\n const recipientSuggestionsCacheRef = React.useRef<TagsInputOption[] | null>(null)\n\n const [recipientIds, setRecipientIds] = React.useState<string[]>([])\n const [recipientMap, setRecipientMap] = React.useState<Record<string, TagsInputOption>>({})\n const [messageType, setMessageType] = React.useState(lockedType ?? 'default')\n const [subject, setSubject] = React.useState('')\n const [body, setBody] = React.useState('')\n const [bodyFormat, setBodyFormat] = React.useState<'text' | 'markdown'>('text')\n const [priority, setPriority] = React.useState<MessagePriority>('normal')\n const [visibility, setVisibility] = React.useState<'public' | 'internal'>('internal')\n const [externalEmail, setExternalEmail] = React.useState('')\n const [attachmentIds, setAttachmentIds] = React.useState<string[]>([])\n const [sendViaEmail, setSendViaEmail] = React.useState(false)\n const [contextActionRequired, setContextActionRequired] = React.useState(false)\n const [contextActionType, setContextActionType] = React.useState('')\n const [replyAll, setReplyAll] = React.useState(false)\n const [includeAttachments, setIncludeAttachments] = React.useState(true)\n const [temporaryAttachmentRecordId, setTemporaryAttachmentRecordId] = React.useState<string>(() =>\n createTemporaryAttachmentRecordId(),\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [submitMode, setSubmitMode] = React.useState<'send' | 'draft'>('send')\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n // Tracks whether the composer is currently in the \"open\" lifecycle so the init\n // effect below only runs on the closed \u2192 open transition, not on every parent\n // re-render that produces a new `defaultValues` / `contextObject` reference\n // while the user is typing. Without this guard, an inline literal\n // `defaultValues={{...}}` in a re-rendering parent (e.g. message detail page\n // with live notification badges or queue progress) would clear the body /\n // subject mid-keystroke. CI shard 9 surfaced this as TC-MSG-009 timing out\n // because `keyboard.type` characters appeared to \"type nowhere\" \u2014 they were\n // typed correctly, then immediately wiped by the next effect run.\n const isOpenRef = React.useRef(false)\n const wasOpenRef = React.useRef(false)\n const submitLockReleaseRef = React.useRef<(() => void) | null>(null)\n\n const messageTypesQuery = useQuery({\n queryKey: ['messages', 'types'],\n enabled: variant === 'compose' && isOpen,\n staleTime: 5 * 60 * 1000,\n queryFn: async () => {\n const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadTypesFailed', 'Failed to load message types.'),\n )\n }\n return Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n },\n })\n\n const messageTypes = React.useMemo(\n () => messageTypesQuery.data ?? [],\n [messageTypesQuery.data],\n )\n const createableMessageTypes = React.useMemo(\n () => messageTypes.filter((item) => item.isCreateableByUser !== false),\n [messageTypes],\n )\n const normalizedRequiredActionMode = requiredActionConfig?.mode ?? 'none'\n const contextActionOptions = React.useMemo(\n () => (requiredActionConfig?.options ?? []).filter((option) => option.id.trim().length > 0),\n [requiredActionConfig?.options],\n )\n const shouldShowContextActions = (\n variant === 'compose'\n && Boolean(contextObject)\n && normalizedRequiredActionMode !== 'none'\n && contextActionOptions.length > 0\n )\n\n const isComposePublicVisibility = variant === 'compose' && visibility === 'public'\n\n const attachmentEntityId = variant === 'compose' && messageId ? 'messages:message' : 'attachments:library'\n const attachmentRecordId = variant === 'compose' && messageId ? messageId : temporaryAttachmentRecordId\n\n const loadAttachmentIds = React.useCallback(async (): Promise<string[]> => {\n const params = new URLSearchParams()\n params.set('entityId', attachmentEntityId)\n params.set('recordId', attachmentRecordId)\n\n const call = await apiCall<AttachmentListResponse>(`/api/attachments?${params.toString()}`)\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.'),\n )\n }\n\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const nextIds = items\n .map((item) => (typeof item?.id === 'string' ? item.id : ''))\n .filter((id) => id.length > 0)\n\n setAttachmentIds(nextIds)\n return nextIds\n }, [attachmentEntityId, attachmentRecordId, t])\n\n React.useEffect(() => {\n if (!isOpen) {\n isOpenRef.current = false\n return\n }\n // Only initialize on the closed \u2192 open transition. Subsequent parent\n // re-renders that change `defaultValues` / `contextObject` references\n // (inline object literals are a new reference on every render) MUST NOT\n // overwrite state the user has typed in.\n if (isOpenRef.current) return\n isOpenRef.current = true\n\n const nextRecipients = defaultValues?.recipients?.filter((value) => typeof value === 'string' && value.trim().length > 0) ?? []\n const dedupedRecipients = Array.from(new Set(nextRecipients))\n\n setRecipientIds(dedupedRecipients)\n setMessageType(lockedType ?? defaultValues?.type ?? 'default')\n setSubject(defaultValues?.subject ?? '')\n setBody(defaultValues?.body ?? '')\n setBodyFormat(defaultValues?.bodyFormat ?? 'text')\n setPriority(defaultValues?.priority ?? 'normal')\n setVisibility(defaultValues?.visibility ?? 'internal')\n setExternalEmail(defaultValues?.externalEmail ?? '')\n setAttachmentIds(\n Array.isArray(defaultValues?.attachmentIds)\n ? defaultValues.attachmentIds.filter((id): id is string => typeof id === 'string' && id.trim().length > 0)\n : [],\n )\n setSendViaEmail(Boolean(defaultValues?.sendViaEmail))\n if (contextObject) {\n const defaultContextActionType = requiredActionConfig?.defaultActionType?.trim() ?? ''\n const fallbackContextActionType = contextObject.actionType?.trim() ?? ''\n const selectedActionType = defaultContextActionType || fallbackContextActionType\n const selectedActionAllowed = contextActionOptions.some((option) => option.id === selectedActionType)\n const nextActionType = selectedActionAllowed ? selectedActionType : ''\n setContextActionType(nextActionType)\n if (normalizedRequiredActionMode === 'required') {\n setContextActionRequired(true)\n } else if (normalizedRequiredActionMode === 'optional') {\n setContextActionRequired(Boolean(nextActionType) || Boolean(contextObject.actionRequired))\n } else {\n setContextActionRequired(Boolean(contextObject.actionRequired))\n }\n } else {\n setContextActionType('')\n setContextActionRequired(false)\n }\n setReplyAll(Boolean(defaultValues?.replyAll))\n setIncludeAttachments(defaultValues?.includeAttachments !== false)\n setTemporaryAttachmentRecordId(createTemporaryAttachmentRecordId())\n setSubmitError(null)\n }, [\n contextActionOptions,\n contextObject,\n defaultValues,\n isOpen,\n lockedType,\n normalizedRequiredActionMode,\n requiredActionConfig?.defaultActionType,\n ])\n\n React.useEffect(() => {\n if (!isOpen) {\n submitLockReleaseRef.current?.()\n submitLockReleaseRef.current = null\n wasOpenRef.current = false\n return\n }\n\n const justOpened = isOpen && !wasOpenRef.current\n wasOpenRef.current = isOpen\n if (!justOpened) return\n submitLockReleaseRef.current?.()\n submitLockReleaseRef.current = null\n setSubmitting(false)\n setSubmitMode('send')\n }, [isOpen])\n\n React.useEffect(() => () => {\n submitLockReleaseRef.current?.()\n submitLockReleaseRef.current = null\n }, [])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'forward') return\n if (!messageId) return\n\n let isActive = true\n\n void (async () => {\n const call = await apiCall<ForwardPreviewResponse>(`/api/messages/${encodeURIComponent(messageId)}/forward-preview`)\n if (!isActive) return\n\n if (!call.ok) {\n const message = toErrorMessage(call.result)\n ?? t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n return\n }\n\n if (typeof call.result?.subject === 'string') {\n setSubject((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.subject ?? ''))\n }\n if (typeof call.result?.body === 'string') {\n setBody((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.body ?? ''))\n }\n setBodyFormat('text')\n })().catch((error) => {\n if (!isActive) return\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n })\n\n return () => {\n isActive = false\n }\n }, [isOpen, messageId, t, variant])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'compose' && variant !== 'reply') return\n void loadAttachmentIds().catch(() => null)\n }, [isOpen, loadAttachmentIds, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (!createableMessageTypes.length) return\n\n if (lockedType) {\n if (createableMessageTypes.some((item) => item.type === lockedType)) {\n setMessageType(lockedType)\n return\n }\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n return\n }\n\n if (createableMessageTypes.some((item) => item.type === messageType)) return\n\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n }, [createableMessageTypes, lockedType, messageType, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (visibility !== 'public') return\n setSendViaEmail(true)\n setRecipientIds([])\n }, [variant, visibility])\n\n React.useEffect(() => {\n if (isOpen) return\n recipientSuggestionsCacheRef.current = null\n }, [isOpen])\n\n const resolveRecipientLabel = React.useCallback((id: string) => {\n return recipientMap[id]?.label ?? id\n }, [recipientMap])\n\n const selectedRecipientOptions = React.useMemo(() => {\n return recipientIds.map((id) => recipientMap[id] ?? { value: id, label: id })\n }, [recipientIds, recipientMap])\n\n const loadRecipientSuggestions = React.useCallback(async (_query?: string) => {\n const cachedOptions = recipientSuggestionsCacheRef.current\n if (cachedOptions) {\n return cachedOptions\n }\n\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '100')\n // Scope suggestions to the composer's active organization: a message is stamped with\n // that org and its detail endpoint denies cross-org recipients, so a recipient from\n // another org could never open what they were sent.\n params.set('scopeToActiveOrganization', '1')\n // Recipient lookup is filtered in TagsInput because incremental auth user search is unreliable.\n\n const call = await apiCall<{ items?: UserListItem[] }>(\n `/api/auth/users?${params.toString()}`,\n {\n headers: {\n 'x-om-forbidden-redirect': '0',\n },\n },\n ).catch(() => null)\n if (!call) {\n return []\n }\n if (!call.ok) {\n return []\n }\n\n const rawItems = Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n const options: TagsInputOption[] = []\n for (const item of rawItems) {\n if (!item || typeof item !== 'object') continue\n const id = typeof item.id === 'string' ? item.id : ''\n if (!id) continue\n\n const email = typeof item.email === 'string' && item.email.trim().length ? item.email.trim() : id\n const name = typeof item.name === 'string' && item.name.trim().length ? item.name.trim() : undefined\n\n options.push({\n value: id,\n label: email,\n description: name,\n })\n }\n\n if (options.length) {\n setRecipientMap((prev) => {\n const next = { ...prev }\n for (const option of options) {\n next[option.value] = option\n }\n return next\n })\n }\n\n recipientSuggestionsCacheRef.current = options\n return options\n }, [])\n\n const handleCancel = React.useCallback(() => {\n if (submitting) return\n if (!inline) {\n onOpenChange?.(false)\n }\n onCancel?.()\n }, [inline, onCancel, onOpenChange, submitting])\n\n const composeSendOperation = useComposeSendOperation({\n t,\n messageType,\n createableMessageTypes,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const composeDraftOperation = useComposeDraftOperation({\n t,\n messageId,\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const replyOperation = useReplySubmitOperation({\n t,\n messageId,\n body,\n bodyFormat,\n replyAll,\n recipientIds,\n sendViaEmail,\n })\n\n const forwardOperation = useForwardSubmitOperation({\n t,\n messageId,\n recipientIds,\n body,\n includeAttachments,\n sendViaEmail,\n })\n\n const sendDraftOperation = useSendDraftOperation({\n t,\n messageId: messageId ?? '',\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const updateDraftOperation = useUpdateDraftOperation({\n t,\n messageId: messageId ?? '',\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const handleSubmit = React.useCallback(async ({ saveAsDraft = false }: { saveAsDraft?: boolean } = {}) => {\n if (submitting) return false\n\n setSubmitError(null)\n\n const isEditingExistingDraft = variant === 'compose' && Boolean(messageId)\n const isComposeDraftSubmit = saveAsDraft && variant === 'compose'\n const operation = isComposeDraftSubmit\n ? (isEditingExistingDraft ? updateDraftOperation : composeDraftOperation)\n : variant === 'compose'\n ? (isEditingExistingDraft ? sendDraftOperation : composeSendOperation)\n : variant === 'reply'\n ? replyOperation\n : forwardOperation\n\n const validationMessage = operation.validate()\n if (validationMessage) {\n setSubmitError(validationMessage)\n flash(validationMessage, 'error')\n return false\n }\n\n setSubmitMode(isComposeDraftSubmit ? 'draft' : 'send')\n setSubmitting(true)\n let keepSubmitLock = false\n let shouldReturnFalse = false\n\n try {\n let nextAttachmentIds = attachmentIds\n if (operation.requiresAttachmentRefresh) {\n try {\n nextAttachmentIds = await loadAttachmentIds()\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.')\n setSubmitError(message)\n flash(message, 'error')\n shouldReturnFalse = true\n }\n }\n\n if (!shouldReturnFalse) {\n const { endpoint, method, payload } = operation.buildRequest({ attachmentIds: nextAttachmentIds })\n\n // Editing an existing draft is a PATCH on the message aggregate, so carry\n // the OSS optimistic-lock header to reject a stale overwrite. New\n // compose/reply/forward writes create fresh records and never lock.\n const lockHeaders = isEditingExistingDraft\n ? buildOptimisticLockHeader(expectedUpdatedAt)\n : {}\n\n const call = await withScopedApiRequestHeaders(lockHeaders, () =>\n apiCall<{ id?: string }>(endpoint, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n )\n\n if (!call.ok) {\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) {\n setSubmitError(\n t('ui.forms.flash.recordModified', 'This record was modified by someone else. Refresh and try again.'),\n )\n // The shared conflict banner renders at page level, so it is hidden\n // behind the compose modal. Close the dialog to reveal it (with its\n // Refresh action); the stale draft must be reloaded anyway (#3260 QA).\n if (!inline) {\n onOpenChange?.(false)\n }\n } else {\n const message = toErrorMessage(call.result) ?? t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n }\n shouldReturnFalse = true\n } else {\n flash(operation.successMessage, 'success')\n keepSubmitLock = true\n\n onSuccess?.({ id: call.result?.id })\n\n if (!inline) {\n onOpenChange?.(false)\n }\n }\n }\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n shouldReturnFalse = true\n } finally {\n if (!keepSubmitLock) {\n setSubmitting(false)\n }\n setSubmitMode('send')\n }\n\n if (shouldReturnFalse) {\n return false\n }\n\n if (keepSubmitLock) {\n return await new Promise<boolean>((resolve) => {\n submitLockReleaseRef.current = () => resolve(true)\n })\n }\n\n return true\n }, [\n attachmentIds,\n composeDraftOperation,\n composeSendOperation,\n expectedUpdatedAt,\n forwardOperation,\n inline,\n loadAttachmentIds,\n messageId,\n onOpenChange,\n onSuccess,\n replyOperation,\n sendDraftOperation,\n submitting,\n t,\n updateDraftOperation,\n variant,\n ])\n\n const handleSaveDraft = React.useCallback(() => {\n if (variant !== 'compose') return\n void handleSubmit({ saveAsDraft: true })\n }, [handleSubmit, variant])\n\n const handleBack = React.useCallback(() => {\n if (submitting) return\n handleCancel()\n }, [handleCancel, submitting])\n\n const handleDialogOpenChange = React.useCallback((nextOpen: boolean) => {\n if (nextOpen) {\n onOpenChange?.(true)\n return\n }\n void handleBack()\n }, [handleBack, onOpenChange])\n\n const handleKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n handleCancel()\n }\n }, [handleCancel, handleSubmit])\n\n const composerTitle = variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.compose', 'Compose message')\n\n const submitLabel = submitting\n ? submitMode === 'draft'\n ? t('messages.savingDraft', 'Saving draft...')\n : t('messages.sending', 'Sending...')\n : variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.send', 'Send')\n\n return {\n t,\n variant,\n messageId,\n open,\n inline,\n contextPreview,\n isOpen,\n messageTypes,\n createableMessageTypes,\n normalizedRequiredActionMode,\n contextActionOptions,\n shouldShowContextActions,\n isComposePublicVisibility,\n attachmentEntityId,\n attachmentRecordId,\n recipientIds,\n setRecipientIds,\n messageType,\n setMessageType,\n subject,\n setSubject,\n body,\n setBody,\n bodyFormat,\n setBodyFormat,\n priority,\n setPriority,\n visibility,\n setVisibility,\n externalEmail,\n setExternalEmail,\n sendViaEmail,\n setSendViaEmail,\n contextActionRequired,\n setContextActionRequired,\n contextActionType,\n setContextActionType,\n replyAll,\n setReplyAll,\n includeAttachments,\n setIncludeAttachments,\n submitting,\n submitMode,\n submitError,\n composerTitle,\n submitLabel,\n selectedRecipientOptions,\n resolveRecipientLabel,\n loadRecipientSuggestions,\n loadAttachmentIds,\n handleSaveDraft,\n handleBack,\n handleSubmit,\n handleDialogOpenChange,\n handleKeyDown,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { flash } from '../FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '../utils/apiCall'\nimport { buildOptimisticLockHeader } from '../utils/optimisticLock'\nimport { surfaceRecordConflict } from '../conflicts'\nimport type {\n AttachmentListResponse,\n MessageComposerProps,\n MessageSenderOption,\n MessageTypeItem,\n UserListItem,\n} from './message-composer.types'\nimport type { MessagePriority } from './message-priority'\nimport type { TagsInputOption } from '../inputs/TagsInput'\nimport {\n useComposeDraftOperation,\n useComposeSendOperation,\n useForwardSubmitOperation,\n useReplySubmitOperation,\n useSendDraftOperation,\n useUpdateDraftOperation,\n} from './useMessageComposeOperations'\n\nfunction toErrorMessage(payload: unknown): string | null {\n if (!payload) return null\n if (typeof payload === 'string') return payload\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const nested = toErrorMessage(item)\n if (nested) return nested\n }\n return null\n }\n if (typeof payload === 'object') {\n const record = payload as Record<string, unknown>\n return (\n toErrorMessage(record.error)\n ?? toErrorMessage(record.message)\n ?? toErrorMessage(record.detail)\n ?? toErrorMessage(record.details)\n ?? null\n )\n }\n return null\n}\n\n/**\n * Field-level errors a route returns alongside `error`, e.g. the send-as-user\n * facade's 422 for a mailbox that needs reconnecting. Read defensively: the\n * key is optional and any non-string value is dropped rather than rendered.\n */\nfunction readFieldErrors(payload: unknown): Record<string, string> | null {\n if (!payload || typeof payload !== 'object') return null\n const raw = (payload as Record<string, unknown>).fieldErrors\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null\n const entries = Object.entries(raw as Record<string, unknown>)\n .filter((entry): entry is [string, string] => typeof entry[1] === 'string')\n return entries.length ? Object.fromEntries(entries) : null\n}\n\nfunction createTemporaryAttachmentRecordId(): string {\n const randomPart =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`\n return `messages-composer:${randomPart}`\n}\n\nexport type UseMessageComposeParams = MessageComposerProps\n\nexport type UseMessageComposeResult = {\n t: ReturnType<typeof useT>\n variant: NonNullable<MessageComposerProps['variant']>\n messageId?: string\n open?: boolean\n inline: boolean\n contextPreview: React.ReactNode\n isOpen: boolean\n messageTypes: MessageTypeItem[]\n createableMessageTypes: MessageTypeItem[]\n normalizedRequiredActionMode: 'none' | 'optional' | 'required'\n contextActionOptions: Array<{ id: string; label: string }>\n shouldShowContextActions: boolean\n isComposePublicVisibility: boolean\n attachmentEntityId: string\n attachmentRecordId: string\n recipientIds: string[]\n setRecipientIds: React.Dispatch<React.SetStateAction<string[]>>\n messageType: string\n setMessageType: React.Dispatch<React.SetStateAction<string>>\n subject: string\n setSubject: React.Dispatch<React.SetStateAction<string>>\n body: string\n setBody: React.Dispatch<React.SetStateAction<string>>\n bodyFormat: 'text' | 'markdown'\n setBodyFormat: React.Dispatch<React.SetStateAction<'text' | 'markdown'>>\n priority: MessagePriority\n setPriority: React.Dispatch<React.SetStateAction<MessagePriority>>\n visibility: 'public' | 'internal'\n setVisibility: React.Dispatch<React.SetStateAction<'public' | 'internal'>>\n externalEmail: string\n setExternalEmail: React.Dispatch<React.SetStateAction<string>>\n senderOptions: MessageSenderOption[]\n senderChannelId: string\n setSenderChannelId: React.Dispatch<React.SetStateAction<string>>\n sendViaEmail: boolean\n setSendViaEmail: React.Dispatch<React.SetStateAction<boolean>>\n contextActionRequired: boolean\n setContextActionRequired: React.Dispatch<React.SetStateAction<boolean>>\n contextActionType: string\n setContextActionType: React.Dispatch<React.SetStateAction<string>>\n replyAll: boolean\n setReplyAll: React.Dispatch<React.SetStateAction<boolean>>\n includeAttachments: boolean\n setIncludeAttachments: React.Dispatch<React.SetStateAction<boolean>>\n submitting: boolean\n submitMode: 'send' | 'draft'\n submitError: string | null\n submitFieldErrors: Record<string, string> | null\n composerTitle: string\n submitLabel: string\n selectedRecipientOptions: TagsInputOption[]\n resolveRecipientLabel: (id: string) => string\n loadRecipientSuggestions: (query?: string) => Promise<TagsInputOption[]>\n loadAttachmentIds: () => Promise<string[]>\n handleSaveDraft: () => void\n handleBack: () => void\n handleSubmit: ({ saveAsDraft }?: { saveAsDraft?: boolean }) => Promise<boolean>\n handleDialogOpenChange: (nextOpen: boolean) => void\n handleKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void\n}\n\ntype ForwardPreviewResponse = {\n subject?: string\n body?: string\n}\n\nexport function useMessageCompose({\n variant: variantProp = 'compose',\n messageId,\n open,\n onOpenChange,\n inline = false,\n lockedType = null,\n contextObject = null,\n requiredActionConfig = null,\n contextPreview = null,\n senderOptions,\n defaultValues,\n expectedUpdatedAt = null,\n onSuccess,\n onCancel,\n}: UseMessageComposeParams): UseMessageComposeResult {\n const t = useT()\n const variant = variantProp\n const isOpen = inline ? true : Boolean(open)\n const recipientSuggestionsCacheRef = React.useRef<TagsInputOption[] | null>(null)\n\n const [recipientIds, setRecipientIds] = React.useState<string[]>([])\n const [recipientMap, setRecipientMap] = React.useState<Record<string, TagsInputOption>>({})\n const [messageType, setMessageType] = React.useState(lockedType ?? 'default')\n const [subject, setSubject] = React.useState('')\n const [body, setBody] = React.useState('')\n const [bodyFormat, setBodyFormat] = React.useState<'text' | 'markdown'>('text')\n const [priority, setPriority] = React.useState<MessagePriority>('normal')\n const [visibility, setVisibility] = React.useState<'public' | 'internal'>('internal')\n const [externalEmail, setExternalEmail] = React.useState('')\n const [attachmentIds, setAttachmentIds] = React.useState<string[]>([])\n const [sendViaEmail, setSendViaEmail] = React.useState(false)\n const [contextActionRequired, setContextActionRequired] = React.useState(false)\n const [contextActionType, setContextActionType] = React.useState('')\n const [replyAll, setReplyAll] = React.useState(false)\n const [includeAttachments, setIncludeAttachments] = React.useState(true)\n const [temporaryAttachmentRecordId, setTemporaryAttachmentRecordId] = React.useState<string>(() =>\n createTemporaryAttachmentRecordId(),\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [submitMode, setSubmitMode] = React.useState<'send' | 'draft'>('send')\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n const [submitFieldErrors, setSubmitFieldErrors] = React.useState<Record<string, string> | null>(null)\n // Empty means the platform sender: the default the composer has always used.\n const [senderChannelId, setSenderChannelId] = React.useState('')\n // Tracks whether the composer is currently in the \"open\" lifecycle so the init\n // effect below only runs on the closed \u2192 open transition, not on every parent\n // re-render that produces a new `defaultValues` / `contextObject` reference\n // while the user is typing. Without this guard, an inline literal\n // `defaultValues={{...}}` in a re-rendering parent (e.g. message detail page\n // with live notification badges or queue progress) would clear the body /\n // subject mid-keystroke. CI shard 9 surfaced this as TC-MSG-009 timing out\n // because `keyboard.type` characters appeared to \"type nowhere\" \u2014 they were\n // typed correctly, then immediately wiped by the next effect run.\n const isOpenRef = React.useRef(false)\n const wasOpenRef = React.useRef(false)\n const submitLockReleaseRef = React.useRef<(() => void) | null>(null)\n\n const messageTypesQuery = useQuery({\n queryKey: ['messages', 'types'],\n enabled: variant === 'compose' && isOpen,\n staleTime: 5 * 60 * 1000,\n queryFn: async () => {\n const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadTypesFailed', 'Failed to load message types.'),\n )\n }\n return Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n },\n })\n\n const messageTypes = React.useMemo(\n () => messageTypesQuery.data ?? [],\n [messageTypesQuery.data],\n )\n const createableMessageTypes = React.useMemo(\n () => messageTypes.filter((item) => item.isCreateableByUser !== false),\n [messageTypes],\n )\n const normalizedRequiredActionMode = requiredActionConfig?.mode ?? 'none'\n const contextActionOptions = React.useMemo(\n () => (requiredActionConfig?.options ?? []).filter((option) => option.id.trim().length > 0),\n [requiredActionConfig?.options],\n )\n const shouldShowContextActions = (\n variant === 'compose'\n && Boolean(contextObject)\n && normalizedRequiredActionMode !== 'none'\n && contextActionOptions.length > 0\n )\n\n const isComposePublicVisibility = variant === 'compose' && visibility === 'public'\n\n const attachmentEntityId = variant === 'compose' && messageId ? 'messages:message' : 'attachments:library'\n const attachmentRecordId = variant === 'compose' && messageId ? messageId : temporaryAttachmentRecordId\n\n const loadAttachmentIds = React.useCallback(async (): Promise<string[]> => {\n const params = new URLSearchParams()\n params.set('entityId', attachmentEntityId)\n params.set('recordId', attachmentRecordId)\n\n const call = await apiCall<AttachmentListResponse>(`/api/attachments?${params.toString()}`)\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.'),\n )\n }\n\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const nextIds = items\n .map((item) => (typeof item?.id === 'string' ? item.id : ''))\n .filter((id) => id.length > 0)\n\n setAttachmentIds(nextIds)\n return nextIds\n }, [attachmentEntityId, attachmentRecordId, t])\n\n React.useEffect(() => {\n if (!isOpen) {\n isOpenRef.current = false\n return\n }\n // Only initialize on the closed \u2192 open transition. Subsequent parent\n // re-renders that change `defaultValues` / `contextObject` references\n // (inline object literals are a new reference on every render) MUST NOT\n // overwrite state the user has typed in.\n if (isOpenRef.current) return\n isOpenRef.current = true\n\n const nextRecipients = defaultValues?.recipients?.filter((value) => typeof value === 'string' && value.trim().length > 0) ?? []\n const dedupedRecipients = Array.from(new Set(nextRecipients))\n\n setRecipientIds(dedupedRecipients)\n setMessageType(lockedType ?? defaultValues?.type ?? 'default')\n setSubject(defaultValues?.subject ?? '')\n setBody(defaultValues?.body ?? '')\n setBodyFormat(defaultValues?.bodyFormat ?? 'text')\n setPriority(defaultValues?.priority ?? 'normal')\n setVisibility(defaultValues?.visibility ?? 'internal')\n setExternalEmail(defaultValues?.externalEmail ?? '')\n setAttachmentIds(\n Array.isArray(defaultValues?.attachmentIds)\n ? defaultValues.attachmentIds.filter((id): id is string => typeof id === 'string' && id.trim().length > 0)\n : [],\n )\n setSendViaEmail(Boolean(defaultValues?.sendViaEmail))\n if (contextObject) {\n const defaultContextActionType = requiredActionConfig?.defaultActionType?.trim() ?? ''\n const fallbackContextActionType = contextObject.actionType?.trim() ?? ''\n const selectedActionType = defaultContextActionType || fallbackContextActionType\n const selectedActionAllowed = contextActionOptions.some((option) => option.id === selectedActionType)\n const nextActionType = selectedActionAllowed ? selectedActionType : ''\n setContextActionType(nextActionType)\n if (normalizedRequiredActionMode === 'required') {\n setContextActionRequired(true)\n } else if (normalizedRequiredActionMode === 'optional') {\n setContextActionRequired(Boolean(nextActionType) || Boolean(contextObject.actionRequired))\n } else {\n setContextActionRequired(Boolean(contextObject.actionRequired))\n }\n } else {\n setContextActionType('')\n setContextActionRequired(false)\n }\n setReplyAll(Boolean(defaultValues?.replyAll))\n setIncludeAttachments(defaultValues?.includeAttachments !== false)\n setTemporaryAttachmentRecordId(createTemporaryAttachmentRecordId())\n setSubmitError(null)\n }, [\n contextActionOptions,\n contextObject,\n defaultValues,\n isOpen,\n lockedType,\n normalizedRequiredActionMode,\n requiredActionConfig?.defaultActionType,\n ])\n\n React.useEffect(() => {\n if (!isOpen) {\n submitLockReleaseRef.current?.()\n submitLockReleaseRef.current = null\n wasOpenRef.current = false\n return\n }\n\n const justOpened = isOpen && !wasOpenRef.current\n wasOpenRef.current = isOpen\n if (!justOpened) return\n submitLockReleaseRef.current?.()\n submitLockReleaseRef.current = null\n setSubmitting(false)\n setSubmitMode('send')\n }, [isOpen])\n\n React.useEffect(() => () => {\n submitLockReleaseRef.current?.()\n submitLockReleaseRef.current = null\n }, [])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'forward') return\n if (!messageId) return\n\n let isActive = true\n\n void (async () => {\n const call = await apiCall<ForwardPreviewResponse>(`/api/messages/${encodeURIComponent(messageId)}/forward-preview`)\n if (!isActive) return\n\n if (!call.ok) {\n const message = toErrorMessage(call.result)\n ?? t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n return\n }\n\n if (typeof call.result?.subject === 'string') {\n setSubject((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.subject ?? ''))\n }\n if (typeof call.result?.body === 'string') {\n setBody((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.body ?? ''))\n }\n setBodyFormat('text')\n })().catch((error) => {\n if (!isActive) return\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n })\n\n return () => {\n isActive = false\n }\n }, [isOpen, messageId, t, variant])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'compose' && variant !== 'reply') return\n void loadAttachmentIds().catch(() => null)\n }, [isOpen, loadAttachmentIds, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (!createableMessageTypes.length) return\n\n if (lockedType) {\n if (createableMessageTypes.some((item) => item.type === lockedType)) {\n setMessageType(lockedType)\n return\n }\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n return\n }\n\n if (createableMessageTypes.some((item) => item.type === messageType)) return\n\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n }, [createableMessageTypes, lockedType, messageType, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (visibility !== 'public') return\n setSendViaEmail(true)\n setRecipientIds([])\n }, [variant, visibility])\n\n React.useEffect(() => {\n if (isOpen) return\n recipientSuggestionsCacheRef.current = null\n }, [isOpen])\n\n const resolveRecipientLabel = React.useCallback((id: string) => {\n return recipientMap[id]?.label ?? id\n }, [recipientMap])\n\n const selectedRecipientOptions = React.useMemo(() => {\n return recipientIds.map((id) => recipientMap[id] ?? { value: id, label: id })\n }, [recipientIds, recipientMap])\n\n const loadRecipientSuggestions = React.useCallback(async (_query?: string) => {\n const cachedOptions = recipientSuggestionsCacheRef.current\n if (cachedOptions) {\n return cachedOptions\n }\n\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '100')\n // Scope suggestions to the composer's active organization: a message is stamped with\n // that org and its detail endpoint denies cross-org recipients, so a recipient from\n // another org could never open what they were sent.\n params.set('scopeToActiveOrganization', '1')\n // Recipient lookup is filtered in TagsInput because incremental auth user search is unreliable.\n\n const call = await apiCall<{ items?: UserListItem[] }>(\n `/api/auth/users?${params.toString()}`,\n {\n headers: {\n 'x-om-forbidden-redirect': '0',\n },\n },\n ).catch(() => null)\n if (!call) {\n return []\n }\n if (!call.ok) {\n return []\n }\n\n const rawItems = Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n const options: TagsInputOption[] = []\n for (const item of rawItems) {\n if (!item || typeof item !== 'object') continue\n const id = typeof item.id === 'string' ? item.id : ''\n if (!id) continue\n\n const email = typeof item.email === 'string' && item.email.trim().length ? item.email.trim() : id\n const name = typeof item.name === 'string' && item.name.trim().length ? item.name.trim() : undefined\n\n options.push({\n value: id,\n label: email,\n description: name,\n })\n }\n\n if (options.length) {\n setRecipientMap((prev) => {\n const next = { ...prev }\n for (const option of options) {\n next[option.value] = option\n }\n return next\n })\n }\n\n recipientSuggestionsCacheRef.current = options\n return options\n }, [])\n\n const handleCancel = React.useCallback(() => {\n if (submitting) return\n if (!inline) {\n onOpenChange?.(false)\n }\n onCancel?.()\n }, [inline, onCancel, onOpenChange, submitting])\n\n // The \"Send from\" control only exists for a compose addressing an external\n // recipient, so a selection made before the mode changed must not survive into\n // a payload the control is no longer shown for.\n const resolvedSenderOptions = React.useMemo(\n () => (isComposePublicVisibility ? senderOptions ?? [] : []),\n [isComposePublicVisibility, senderOptions],\n )\n const effectiveSenderChannelId = resolvedSenderOptions.some((option) => option.id === senderChannelId)\n ? senderChannelId\n : ''\n\n const composeSendOperation = useComposeSendOperation({\n senderChannelId: effectiveSenderChannelId,\n t,\n messageType,\n createableMessageTypes,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const composeDraftOperation = useComposeDraftOperation({\n t,\n senderChannelId: effectiveSenderChannelId,\n messageId,\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const replyOperation = useReplySubmitOperation({\n t,\n messageId,\n body,\n bodyFormat,\n replyAll,\n recipientIds,\n sendViaEmail,\n })\n\n const forwardOperation = useForwardSubmitOperation({\n t,\n messageId,\n recipientIds,\n body,\n includeAttachments,\n sendViaEmail,\n })\n\n const sendDraftOperation = useSendDraftOperation({\n t,\n senderChannelId: effectiveSenderChannelId,\n messageId: messageId ?? '',\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const updateDraftOperation = useUpdateDraftOperation({\n t,\n senderChannelId: effectiveSenderChannelId,\n messageId: messageId ?? '',\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const handleSubmit = React.useCallback(async ({ saveAsDraft = false }: { saveAsDraft?: boolean } = {}) => {\n if (submitting) return false\n\n setSubmitError(null)\n setSubmitFieldErrors(null)\n\n const isEditingExistingDraft = variant === 'compose' && Boolean(messageId)\n const isComposeDraftSubmit = saveAsDraft && variant === 'compose'\n const operation = isComposeDraftSubmit\n ? (isEditingExistingDraft ? updateDraftOperation : composeDraftOperation)\n : variant === 'compose'\n ? (isEditingExistingDraft ? sendDraftOperation : composeSendOperation)\n : variant === 'reply'\n ? replyOperation\n : forwardOperation\n\n const validationMessage = operation.validate()\n if (validationMessage) {\n setSubmitError(validationMessage)\n flash(validationMessage, 'error')\n return false\n }\n\n setSubmitMode(isComposeDraftSubmit ? 'draft' : 'send')\n setSubmitting(true)\n let keepSubmitLock = false\n let shouldReturnFalse = false\n\n try {\n let nextAttachmentIds = attachmentIds\n if (operation.requiresAttachmentRefresh) {\n try {\n nextAttachmentIds = await loadAttachmentIds()\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.')\n setSubmitError(message)\n flash(message, 'error')\n shouldReturnFalse = true\n }\n }\n\n if (!shouldReturnFalse) {\n const { endpoint, method, payload } = operation.buildRequest({ attachmentIds: nextAttachmentIds })\n\n // Editing an existing draft is a PATCH on the message aggregate, so carry\n // the OSS optimistic-lock header to reject a stale overwrite. New\n // compose/reply/forward writes create fresh records and never lock.\n const lockHeaders = isEditingExistingDraft\n ? buildOptimisticLockHeader(expectedUpdatedAt)\n : {}\n\n const call = await withScopedApiRequestHeaders(lockHeaders, () =>\n apiCall<{ id?: string }>(endpoint, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n )\n\n if (!call.ok) {\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) {\n setSubmitError(\n t('ui.forms.flash.recordModified', 'This record was modified by someone else. Refresh and try again.'),\n )\n // The shared conflict banner renders at page level, so it is hidden\n // behind the compose modal. Close the dialog to reveal it (with its\n // Refresh action); the stale draft must be reloaded anyway (#3260 QA).\n if (!inline) {\n onOpenChange?.(false)\n }\n } else {\n const message = toErrorMessage(call.result) ?? t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n setSubmitFieldErrors(readFieldErrors(call.result))\n flash(message, 'error')\n }\n shouldReturnFalse = true\n } else {\n flash(operation.successMessage, 'success')\n keepSubmitLock = true\n\n onSuccess?.({ id: call.result?.id })\n\n if (!inline) {\n onOpenChange?.(false)\n }\n }\n }\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n shouldReturnFalse = true\n } finally {\n if (!keepSubmitLock) {\n setSubmitting(false)\n }\n setSubmitMode('send')\n }\n\n if (shouldReturnFalse) {\n return false\n }\n\n if (keepSubmitLock) {\n return await new Promise<boolean>((resolve) => {\n submitLockReleaseRef.current = () => resolve(true)\n })\n }\n\n return true\n }, [\n attachmentIds,\n composeDraftOperation,\n composeSendOperation,\n expectedUpdatedAt,\n forwardOperation,\n inline,\n loadAttachmentIds,\n messageId,\n onOpenChange,\n onSuccess,\n replyOperation,\n sendDraftOperation,\n submitting,\n t,\n updateDraftOperation,\n variant,\n ])\n\n const handleSaveDraft = React.useCallback(() => {\n if (variant !== 'compose') return\n void handleSubmit({ saveAsDraft: true })\n }, [handleSubmit, variant])\n\n const handleBack = React.useCallback(() => {\n if (submitting) return\n handleCancel()\n }, [handleCancel, submitting])\n\n const handleDialogOpenChange = React.useCallback((nextOpen: boolean) => {\n if (nextOpen) {\n onOpenChange?.(true)\n return\n }\n void handleBack()\n }, [handleBack, onOpenChange])\n\n const handleKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n return\n }\n\n if (event.key === 'Escape') {\n if (event.defaultPrevented) return\n if (event.target instanceof Node && !event.currentTarget.contains(event.target)) return\n event.preventDefault()\n handleCancel()\n }\n }, [handleCancel, handleSubmit])\n\n const composerTitle = variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.compose', 'Compose message')\n\n const submitLabel = submitting\n ? submitMode === 'draft'\n ? t('messages.savingDraft', 'Saving draft...')\n : t('messages.sending', 'Sending...')\n : variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.send', 'Send')\n\n return {\n t,\n variant,\n messageId,\n open,\n inline,\n contextPreview,\n isOpen,\n messageTypes,\n createableMessageTypes,\n normalizedRequiredActionMode,\n contextActionOptions,\n shouldShowContextActions,\n isComposePublicVisibility,\n attachmentEntityId,\n attachmentRecordId,\n recipientIds,\n setRecipientIds,\n messageType,\n setMessageType,\n subject,\n setSubject,\n body,\n setBody,\n bodyFormat,\n setBodyFormat,\n priority,\n setPriority,\n visibility,\n setVisibility,\n externalEmail,\n setExternalEmail,\n senderOptions: resolvedSenderOptions,\n senderChannelId: effectiveSenderChannelId,\n setSenderChannelId,\n sendViaEmail,\n setSendViaEmail,\n contextActionRequired,\n setContextActionRequired,\n contextActionType,\n setContextActionType,\n replyAll,\n setReplyAll,\n includeAttachments,\n setIncludeAttachments,\n submitting,\n submitMode,\n submitError,\n submitFieldErrors,\n composerTitle,\n submitLabel,\n selectedRecipientOptions,\n resolveRecipientLabel,\n loadRecipientSuggestions,\n loadAttachmentIds,\n handleSaveDraft,\n handleBack,\n handleSubmit,\n handleDialogOpenChange,\n handleKeyDown,\n }\n}\n"],
|
|
5
|
+
"mappings": "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YACV,EAAE,oBAAoB,SAAS,IAC/B,EAAE,iBAAiB,MAAM;AAEjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["defaultType"]
|
|
7
7
|
}
|
|
@@ -53,6 +53,7 @@ function buildComposePayload(params, input) {
|
|
|
53
53
|
objects: contextObjects,
|
|
54
54
|
attachmentIds: input.attachmentIds.length > 0 ? input.attachmentIds : void 0,
|
|
55
55
|
sendViaEmail: params.sendViaEmail,
|
|
56
|
+
senderChannelId: !input.isDraft && publicMessage && params.senderChannelId ? params.senderChannelId : void 0,
|
|
56
57
|
isDraft: input.isDraft
|
|
57
58
|
};
|
|
58
59
|
}
|