@open-mercato/core 0.4.6-develop-18ffe6bc13 → 0.4.6-develop-015a34b6dd

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.
@@ -1,10 +1,8 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
3
3
  import { MessageDetailPageClient } from "../../../components/MessageDetailPageClient.js";
4
- import { resolveCanViewMessagesForCurrentUser } from "../../../lib/access.js";
5
4
  async function MessageDetailPage({ params }) {
6
- const canViewMessages = await resolveCanViewMessagesForCurrentUser();
7
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(MessageDetailPageClient, { id: params.id, canViewMessages }) }) });
5
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(MessageDetailPageClient, { id: params.id }) }) });
8
6
  }
9
7
  export {
10
8
  MessageDetailPage as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/messages/backend/messages/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["import { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { MessageDetailPageClient } from '../../../components/MessageDetailPageClient'\nimport { resolveCanViewMessagesForCurrentUser } from '../../../lib/access'\n\nexport default async function MessageDetailPage({ params }: { params: { id: string } }) {\n const canViewMessages = await resolveCanViewMessagesForCurrentUser()\n return (\n <Page>\n <PageBody>\n <MessageDetailPageClient id={params.id} canViewMessages={canViewMessages} />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "AASQ;AATR,SAAS,MAAM,gBAAgB;AAC/B,SAAS,+BAA+B;AACxC,SAAS,4CAA4C;AAErD,eAAO,kBAAyC,EAAE,OAAO,GAA+B;AACtF,QAAM,kBAAkB,MAAM,qCAAqC;AACnE,SACE,oBAAC,QACC,8BAAC,YACC,8BAAC,2BAAwB,IAAI,OAAO,IAAI,iBAAkC,GAC5E,GACF;AAEJ;",
4
+ "sourcesContent": ["import { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { MessageDetailPageClient } from '../../../components/MessageDetailPageClient'\n\nexport default async function MessageDetailPage({ params }: { params: { id: string } }) {\n return (\n <Page>\n <PageBody>\n <MessageDetailPageClient id={params.id} />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "AAOQ;AAPR,SAAS,MAAM,gBAAgB;AAC/B,SAAS,+BAA+B;AAExC,eAAO,kBAAyC,EAAE,OAAO,GAA+B;AACtF,SACE,oBAAC,QACC,8BAAC,YACC,8BAAC,2BAAwB,IAAI,OAAO,IAAI,GAC1C,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,8 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
3
3
  import { ComposeMessagePageClient } from "../../../components/ComposeMessagePageClient.js";
4
- import { resolveCanViewMessagesForCurrentUser } from "../../../lib/access.js";
5
4
  async function ComposeMessagePage() {
6
- const canViewMessages = await resolveCanViewMessagesForCurrentUser();
7
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ComposeMessagePageClient, { canViewMessages }) }) });
5
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ComposeMessagePageClient, {}) }) });
8
6
  }
9
7
  export {
10
8
  ComposeMessagePage as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/messages/backend/messages/compose/page.tsx"],
4
- "sourcesContent": ["import { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ComposeMessagePageClient } from '../../../components/ComposeMessagePageClient'\nimport { resolveCanViewMessagesForCurrentUser } from '../../../lib/access'\n\nexport default async function ComposeMessagePage() {\n const canViewMessages = await resolveCanViewMessagesForCurrentUser()\n return (\n <Page>\n <PageBody>\n <ComposeMessagePageClient canViewMessages={canViewMessages} />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "AASQ;AATR,SAAS,MAAM,gBAAgB;AAC/B,SAAS,gCAAgC;AACzC,SAAS,4CAA4C;AAErD,eAAO,qBAA4C;AACjD,QAAM,kBAAkB,MAAM,qCAAqC;AACnE,SACE,oBAAC,QACC,8BAAC,YACC,8BAAC,4BAAyB,iBAAkC,GAC9D,GACF;AAEJ;",
4
+ "sourcesContent": ["import { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ComposeMessagePageClient } from '../../../components/ComposeMessagePageClient'\n\nexport default async function ComposeMessagePage() {\n return (\n <Page>\n <PageBody>\n <ComposeMessagePageClient />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "AAOQ;AAPR,SAAS,MAAM,gBAAgB;AAC/B,SAAS,gCAAgC;AAEzC,eAAO,qBAA4C;AACjD,SACE,oBAAC,QACC,8BAAC,YACC,8BAAC,4BAAyB,GAC5B,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,8 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
3
3
  import { MessagesInboxPageClient } from "../components/MessagesInboxPageClient.js";
4
- import { resolveCanViewMessagesForCurrentUser } from "../lib/access.js";
5
4
  async function MessagesInboxPage() {
6
- const canViewMessages = await resolveCanViewMessagesForCurrentUser();
7
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(MessagesInboxPageClient, { canViewMessages }) }) });
5
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(MessagesInboxPageClient, {}) }) });
8
6
  }
9
7
  export {
10
8
  MessagesInboxPage as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/backend/page.tsx"],
4
- "sourcesContent": ["import { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { MessagesInboxPageClient } from '../components/MessagesInboxPageClient'\nimport { resolveCanViewMessagesForCurrentUser } from '../lib/access'\n\nexport default async function MessagesInboxPage() {\n const canViewMessages = await resolveCanViewMessagesForCurrentUser()\n\n return (\n <Page>\n <PageBody>\n <MessagesInboxPageClient canViewMessages={canViewMessages} />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "AAUQ;AAVR,SAAS,MAAM,gBAAgB;AAC/B,SAAS,+BAA+B;AACxC,SAAS,4CAA4C;AAErD,eAAO,oBAA2C;AAChD,QAAM,kBAAkB,MAAM,qCAAqC;AAEnE,SACE,oBAAC,QACC,8BAAC,YACC,8BAAC,2BAAwB,iBAAkC,GAC7D,GACF;AAEJ;",
4
+ "sourcesContent": ["import { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { MessagesInboxPageClient } from '../components/MessagesInboxPageClient'\n\nexport default async function MessagesInboxPage() {\n return (\n <Page>\n <PageBody>\n <MessagesInboxPageClient />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "AAOQ;AAPR,SAAS,MAAM,gBAAgB;AAC/B,SAAS,+BAA+B;AAExC,eAAO,oBAA2C;AAChD,SACE,oBAAC,QACC,8BAAC,YACC,8BAAC,2BAAwB,GAC3B,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -2,23 +2,8 @@
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useRouter } from "next/navigation";
4
4
  import { MessageComposer } from "@open-mercato/ui/backend/messages";
5
- import { ErrorMessage } from "@open-mercato/ui/backend/detail";
6
- import { useT } from "@open-mercato/shared/lib/i18n/context";
7
- function ComposeMessagePageClient({ canViewMessages = true }) {
5
+ function ComposeMessagePageClient() {
8
6
  const router = useRouter();
9
- const t = useT();
10
- if (!canViewMessages) {
11
- return /* @__PURE__ */ jsx(
12
- ErrorMessage,
13
- {
14
- label: t("messages.access.disabled.title", "Messages module is disabled for your role."),
15
- description: t(
16
- "messages.access.disabled.description",
17
- "Ask your administrator to enable the required Messages permissions."
18
- )
19
- }
20
- );
21
- }
22
7
  return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(
23
8
  MessageComposer,
24
9
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/components/ComposeMessagePageClient.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport { useRouter } from 'next/navigation'\nimport { MessageComposer } from '@open-mercato/ui/backend/messages'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport function ComposeMessagePageClient({ canViewMessages = true }: { canViewMessages?: boolean }) {\n const router = useRouter()\n const t = useT()\n\n if (!canViewMessages) {\n return (\n <ErrorMessage\n label={t('messages.access.disabled.title', 'Messages module is disabled for your role.')}\n description={t(\n 'messages.access.disabled.description',\n 'Ask your administrator to enable the required Messages permissions.',\n )}\n />\n )\n }\n\n return (\n <div className=\"space-y-4\">\n <MessageComposer\n inline\n variant=\"compose\"\n onCancel={() => {\n router.push('/backend/messages')\n }}\n onSuccess={(result) => {\n router.push('/backend/messages')\n }}\n />\n </div>\n )\n}\n"],
5
- "mappings": ";AAaM;AAXN,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,YAAY;AAEd,SAAS,yBAAyB,EAAE,kBAAkB,KAAK,GAAkC;AAClG,QAAM,SAAS,UAAU;AACzB,QAAM,IAAI,KAAK;AAEf,MAAI,CAAC,iBAAiB;AACpB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,kCAAkC,4CAA4C;AAAA,QACvF,aAAa;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,aACb;AAAA,IAAC;AAAA;AAAA,MACC,QAAM;AAAA,MACN,SAAQ;AAAA,MACR,UAAU,MAAM;AACd,eAAO,KAAK,mBAAmB;AAAA,MACjC;AAAA,MACA,WAAW,CAAC,WAAW;AACrB,eAAO,KAAK,mBAAmB;AAAA,MACjC;AAAA;AAAA,EACF,GACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport { useRouter } from 'next/navigation'\nimport { MessageComposer } from '@open-mercato/ui/backend/messages'\n\nexport function ComposeMessagePageClient() {\n const router = useRouter()\n\n return (\n <div className=\"space-y-4\">\n <MessageComposer\n inline\n variant=\"compose\"\n onCancel={() => {\n router.push('/backend/messages')\n }}\n onSuccess={(result) => {\n router.push('/backend/messages')\n }}\n />\n </div>\n )\n}\n"],
5
+ "mappings": ";AAUM;AARN,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAEzB,SAAS,2BAA2B;AACzC,QAAM,SAAS,UAAU;AAEzB,SACE,oBAAC,SAAI,WAAU,aACb;AAAA,IAAC;AAAA;AAAA,MACC,QAAM;AAAA,MACN,SAAQ;AAAA,MACR,UAAU,MAAM;AACd,eAAO,KAAK,mBAAmB;AAAA,MACjC;AAAA,MACA,WAAW,CAAC,WAAW;AACrB,eAAO,KAAK,mBAAmB;AAAA,MACjC;AAAA;AAAA,EACF,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,6 @@ import { MessageComposer } from "@open-mercato/ui/backend/messages";
5
5
  import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
6
6
  import { Button } from "@open-mercato/ui/primitives/button";
7
7
  import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
8
- import { useT } from "@open-mercato/shared/lib/i18n/context";
9
8
  import {
10
9
  getMessageUiComponentRegistry
11
10
  } from "./utils/typeUiRegistry.js";
@@ -256,20 +255,7 @@ function MessageDetailPageClientContent({ id }) {
256
255
  ConfirmDialogElement
257
256
  ] });
258
257
  }
259
- function MessageDetailPageClient({ id, canViewMessages = true }) {
260
- const t = useT();
261
- if (!canViewMessages) {
262
- return /* @__PURE__ */ jsx(
263
- ErrorMessage,
264
- {
265
- label: t("messages.access.disabled.title", "Messages module is disabled for your role."),
266
- description: t(
267
- "messages.access.disabled.description",
268
- "Ask your administrator to enable the required Messages permissions."
269
- )
270
- }
271
- );
272
- }
258
+ function MessageDetailPageClient({ id }) {
273
259
  return /* @__PURE__ */ jsx(MessageDetailPageClientContent, { id });
274
260
  }
275
261
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/components/MessageDetailPageClient.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MessageComposer } from '@open-mercato/ui/backend/messages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n getMessageUiComponentRegistry,\n} from './utils/typeUiRegistry'\nimport {\n MessageDetailActionsSection,\n MessageDetailAttachmentsSection,\n MessageDetailBodySection,\n MessageDetailComposerDialogs,\n MessageDetailDialogs,\n MainMessageHeader,\n MessageListComponent,\n MessageHeader,\n MessageDetailMetaSection,\n MessageDetailObjectsSection,\n} from './message-detail/detail-panels'\nimport { useMessageDetails } from './message-detail/hooks/useMessageDetails'\n\nfunction MessageConversationDetailItem({\n messageId,\n isCollapsible,\n isExpanded,\n onToggle,\n onReply,\n onForward,\n}: {\n messageId: string\n isCollapsible: boolean\n isExpanded: boolean\n onToggle: () => void\n onReply: (messageId: string) => void\n onForward: (messageId: string) => void\n}) {\n const state = useMessageDetails(messageId)\n const messageUiRegistry = React.useMemo(() => getMessageUiComponentRegistry(), [])\n\n if (state.isLoadingDetail) {\n return (\n <section className=\"py-3\">\n <LoadingMessage label={state.t('messages.loading.detail', 'Loading message...')} />\n </section>\n )\n }\n\n if (!state.detail) {\n return (\n <section className=\"py-3\">\n <ErrorMessage label={state.loadErrorMessage} />\n </section>\n )\n }\n\n const ContentComponent = state.contentComponentKey\n ? messageUiRegistry.contentComponents[state.contentComponentKey] ?? null\n : null\n const ActionsComponent = state.actionsComponentKey\n ? messageUiRegistry.actionsComponents[state.actionsComponentKey] ?? null\n : null\n\n return (\n <section className=\"py-3\">\n <div className=\"space-y-4\">\n <section className=\"space-y-2 py-2\">\n <MessageHeader\n detail={state.detail}\n updatingState={state.updatingState}\n isArchived={state.isArchived}\n showSubject={false}\n collapseToggle={isCollapsible ? { expanded: isExpanded, onToggle } : undefined}\n onReply={() => onReply(messageId)}\n onForward={() => onForward(messageId)}\n onEdit={() => state.setEditOpen(true)}\n onToggleRead={() => void state.toggleRead()}\n onToggleArchive={() => void state.toggleArchive()}\n onDelete={() => state.setDeleteConfirmationOpen(true)}\n />\n\n <MessageDetailBodySection\n detail={state.detail}\n contentProps={state.contentProps}\n ContentComponent={ContentComponent}\n />\n\n <MessageDetailMetaSection detail={state.detail} />\n </section>\n\n <MessageDetailActionsSection\n detail={state.detail}\n messageActions={state.messageActions}\n executingActionId={state.executingActionId}\n ActionsComponent={ActionsComponent}\n onExecuteActionById={state.handleExecuteActionById}\n onExecuteAction={state.handleExecuteAction}\n />\n\n <MessageDetailObjectsSection\n detail={state.detail}\n objectActionsByObjectId={state.objectActionsByObjectId}\n onExecuteAction={state.handleExecuteAction}\n />\n\n <MessageDetailAttachmentsSection\n attachmentsQuery={state.attachmentsQuery}\n attachments={state.attachments}\n />\n </div>\n\n <MessageDetailComposerDialogs\n id={messageId}\n detail={state.detail}\n attachments={state.attachments}\n editOpen={state.editOpen}\n setEditOpen={state.setEditOpen}\n onRefresh={() => state.detailQuery.refetch()}\n />\n\n <MessageDetailDialogs\n pendingActionConfirmation={state.pendingActionConfirmation}\n setPendingActionConfirmation={state.setPendingActionConfirmation}\n executingActionId={state.executingActionId}\n handleConfirmPendingAction={state.handleConfirmPendingAction}\n handleActionConfirmDialogKeyDown={state.handleActionConfirmDialogKeyDown}\n deleteConfirmationOpen={state.deleteConfirmationOpen}\n setDeleteConfirmationOpen={state.setDeleteConfirmationOpen}\n updatingState={state.updatingState}\n handleDelete={state.handleDelete}\n handleDeleteDialogKeyDown={state.handleDeleteDialogKeyDown}\n />\n </section>\n )\n}\n\nfunction MessageDetailPageClientContent({ id }: { id: string }) {\n const state = useMessageDetails(id)\n const [activeInlineComposer, setActiveInlineComposer] = React.useState<{\n variant: 'reply' | 'forward'\n messageId: string\n } | null>(null)\n const inlineComposerContainerRef = React.useRef<HTMLDivElement | null>(null)\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n React.useEffect(() => {\n if (!activeInlineComposer) return\n\n const composerContainer = inlineComposerContainerRef.current\n if (!composerContainer) return\n\n const firstFocusableElement = composerContainer.querySelector<HTMLElement>(\n 'textarea, input, [contenteditable=\"true\"]',\n )\n firstFocusableElement?.focus()\n }, [activeInlineComposer])\n\n if (state.isLoadingDetail) {\n return <LoadingMessage label={state.t('messages.loading.detail', 'Loading message...')} />\n }\n\n if (!state.detail) {\n return (\n <ErrorMessage\n label={state.loadErrorMessage}\n action={(\n <Button type=\"button\" variant=\"outline\" onClick={state.backToList}>\n {state.t('messages.actions.backToList', 'Back to messages')}\n </Button>\n )}\n />\n )\n }\n\n const detail = state.detail\n const firstConversationMessageId = state.conversationItems[0]?.id ?? null\n const latestConversationMessageId = state.conversationItems[state.conversationItems.length - 1]?.id ?? null\n const canRunConversationActions = Boolean(firstConversationMessageId)\n\n return (\n <div className=\"space-y-3\">\n <MainMessageHeader\n subject={detail.subject}\n priority={(detail.priority as 'low' | 'normal' | 'high' | 'urgent') ?? 'normal'}\n canReply={!detail.isDraft && detail.typeDefinition.allowReply && Boolean(firstConversationMessageId)}\n canForwardAll={!detail.isDraft && detail.typeDefinition.allowForward && Boolean(latestConversationMessageId)}\n actionsDisabled={Boolean(state.activeConversationAction)}\n activeActionId={state.activeConversationAction}\n onReply={() => {\n if (!firstConversationMessageId) return\n setActiveInlineComposer({\n variant: 'reply',\n messageId: firstConversationMessageId,\n })\n }}\n onForwardAll={() => {\n if (!latestConversationMessageId) return\n setActiveInlineComposer({\n variant: 'forward',\n messageId: latestConversationMessageId,\n })\n }}\n onArchiveConversation={() => {\n if (!canRunConversationActions) return\n void state.archiveConversation(firstConversationMessageId ?? undefined)\n }}\n onMarkAllUnread={() => {\n if (!canRunConversationActions) return\n void state.markConversationUnread(firstConversationMessageId ?? undefined)\n }}\n onDeleteConversation={() => {\n if (!canRunConversationActions || state.activeConversationAction) return\n void (async () => {\n const confirmed = await confirm({\n title: state.t('messages.confirm.deleteConversationTitle', 'Delete conversation'),\n text: state.t('messages.confirm.deleteConversation', 'Delete this conversation from your view?'),\n confirmText: state.t('messages.actions.deleteConversation', 'Delete conversation'),\n cancelText: state.t('common.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!confirmed) return\n await state.deleteConversation(firstConversationMessageId ?? undefined)\n })()\n }}\n />\n <div className=\"divide-y border-y\">\n {state.conversationItems.map((item) => {\n const isForcedExpanded = item.id === state.forcedExpandedItemId\n const isExpanded = state.isConversationItemExpanded(item.id)\n if (isExpanded) {\n return (\n <MessageConversationDetailItem\n key={item.id}\n messageId={item.id}\n isCollapsible={!isForcedExpanded}\n isExpanded\n onToggle={() => state.toggleConversationItem(item.id)}\n onReply={(messageId) => {\n setActiveInlineComposer({\n variant: 'reply',\n messageId,\n })\n }}\n onForward={(messageId) => {\n setActiveInlineComposer({\n variant: 'forward',\n messageId,\n })\n }}\n />\n )\n }\n\n return (\n <section key={item.id} className=\"px-1 py-1\">\n <MessageListComponent\n message={state.buildConversationListItemMessage(item)}\n onClick={() => state.toggleConversationItem(item.id)}\n />\n </section>\n )\n })}\n </div>\n\n {activeInlineComposer ? (\n <div ref={inlineComposerContainerRef}>\n <MessageComposer\n inline\n inlineBackHref={null}\n variant={activeInlineComposer.variant}\n messageId={activeInlineComposer.messageId}\n onCancel={() => {\n setActiveInlineComposer(null)\n }}\n onSuccess={() => {\n setActiveInlineComposer(null)\n void state.detailQuery.refetch()\n }}\n />\n </div>\n ) : null}\n {ConfirmDialogElement}\n </div>\n )\n}\n\nexport function MessageDetailPageClient({ id, canViewMessages = true }: { id: string; canViewMessages?: boolean }) {\n const t = useT()\n if (!canViewMessages) {\n return (\n <ErrorMessage\n label={t('messages.access.disabled.title', 'Messages module is disabled for your role.')}\n description={t(\n 'messages.access.disabled.description',\n 'Ask your administrator to enable the required Messages permissions.',\n )}\n />\n )\n }\n return <MessageDetailPageClientContent id={id} />\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MessageComposer } from '@open-mercato/ui/backend/messages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n getMessageUiComponentRegistry,\n} from './utils/typeUiRegistry'\nimport {\n MessageDetailActionsSection,\n MessageDetailAttachmentsSection,\n MessageDetailBodySection,\n MessageDetailComposerDialogs,\n MessageDetailDialogs,\n MainMessageHeader,\n MessageListComponent,\n MessageHeader,\n MessageDetailMetaSection,\n MessageDetailObjectsSection,\n} from './message-detail/detail-panels'\nimport { useMessageDetails } from './message-detail/hooks/useMessageDetails'\n\nfunction MessageConversationDetailItem({\n messageId,\n isCollapsible,\n isExpanded,\n onToggle,\n onReply,\n onForward,\n}: {\n messageId: string\n isCollapsible: boolean\n isExpanded: boolean\n onToggle: () => void\n onReply: (messageId: string) => void\n onForward: (messageId: string) => void\n}) {\n const state = useMessageDetails(messageId)\n const messageUiRegistry = React.useMemo(() => getMessageUiComponentRegistry(), [])\n\n if (state.isLoadingDetail) {\n return (\n <section className=\"py-3\">\n <LoadingMessage label={state.t('messages.loading.detail', 'Loading message...')} />\n </section>\n )\n }\n\n if (!state.detail) {\n return (\n <section className=\"py-3\">\n <ErrorMessage label={state.loadErrorMessage} />\n </section>\n )\n }\n\n const ContentComponent = state.contentComponentKey\n ? messageUiRegistry.contentComponents[state.contentComponentKey] ?? null\n : null\n const ActionsComponent = state.actionsComponentKey\n ? messageUiRegistry.actionsComponents[state.actionsComponentKey] ?? null\n : null\n\n return (\n <section className=\"py-3\">\n <div className=\"space-y-4\">\n <section className=\"space-y-2 py-2\">\n <MessageHeader\n detail={state.detail}\n updatingState={state.updatingState}\n isArchived={state.isArchived}\n showSubject={false}\n collapseToggle={isCollapsible ? { expanded: isExpanded, onToggle } : undefined}\n onReply={() => onReply(messageId)}\n onForward={() => onForward(messageId)}\n onEdit={() => state.setEditOpen(true)}\n onToggleRead={() => void state.toggleRead()}\n onToggleArchive={() => void state.toggleArchive()}\n onDelete={() => state.setDeleteConfirmationOpen(true)}\n />\n\n <MessageDetailBodySection\n detail={state.detail}\n contentProps={state.contentProps}\n ContentComponent={ContentComponent}\n />\n\n <MessageDetailMetaSection detail={state.detail} />\n </section>\n\n <MessageDetailActionsSection\n detail={state.detail}\n messageActions={state.messageActions}\n executingActionId={state.executingActionId}\n ActionsComponent={ActionsComponent}\n onExecuteActionById={state.handleExecuteActionById}\n onExecuteAction={state.handleExecuteAction}\n />\n\n <MessageDetailObjectsSection\n detail={state.detail}\n objectActionsByObjectId={state.objectActionsByObjectId}\n onExecuteAction={state.handleExecuteAction}\n />\n\n <MessageDetailAttachmentsSection\n attachmentsQuery={state.attachmentsQuery}\n attachments={state.attachments}\n />\n </div>\n\n <MessageDetailComposerDialogs\n id={messageId}\n detail={state.detail}\n attachments={state.attachments}\n editOpen={state.editOpen}\n setEditOpen={state.setEditOpen}\n onRefresh={() => state.detailQuery.refetch()}\n />\n\n <MessageDetailDialogs\n pendingActionConfirmation={state.pendingActionConfirmation}\n setPendingActionConfirmation={state.setPendingActionConfirmation}\n executingActionId={state.executingActionId}\n handleConfirmPendingAction={state.handleConfirmPendingAction}\n handleActionConfirmDialogKeyDown={state.handleActionConfirmDialogKeyDown}\n deleteConfirmationOpen={state.deleteConfirmationOpen}\n setDeleteConfirmationOpen={state.setDeleteConfirmationOpen}\n updatingState={state.updatingState}\n handleDelete={state.handleDelete}\n handleDeleteDialogKeyDown={state.handleDeleteDialogKeyDown}\n />\n </section>\n )\n}\n\nfunction MessageDetailPageClientContent({ id }: { id: string }) {\n const state = useMessageDetails(id)\n const [activeInlineComposer, setActiveInlineComposer] = React.useState<{\n variant: 'reply' | 'forward'\n messageId: string\n } | null>(null)\n const inlineComposerContainerRef = React.useRef<HTMLDivElement | null>(null)\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n React.useEffect(() => {\n if (!activeInlineComposer) return\n\n const composerContainer = inlineComposerContainerRef.current\n if (!composerContainer) return\n\n const firstFocusableElement = composerContainer.querySelector<HTMLElement>(\n 'textarea, input, [contenteditable=\"true\"]',\n )\n firstFocusableElement?.focus()\n }, [activeInlineComposer])\n\n if (state.isLoadingDetail) {\n return <LoadingMessage label={state.t('messages.loading.detail', 'Loading message...')} />\n }\n\n if (!state.detail) {\n return (\n <ErrorMessage\n label={state.loadErrorMessage}\n action={(\n <Button type=\"button\" variant=\"outline\" onClick={state.backToList}>\n {state.t('messages.actions.backToList', 'Back to messages')}\n </Button>\n )}\n />\n )\n }\n\n const detail = state.detail\n const firstConversationMessageId = state.conversationItems[0]?.id ?? null\n const latestConversationMessageId = state.conversationItems[state.conversationItems.length - 1]?.id ?? null\n const canRunConversationActions = Boolean(firstConversationMessageId)\n\n return (\n <div className=\"space-y-3\">\n <MainMessageHeader\n subject={detail.subject}\n priority={(detail.priority as 'low' | 'normal' | 'high' | 'urgent') ?? 'normal'}\n canReply={!detail.isDraft && detail.typeDefinition.allowReply && Boolean(firstConversationMessageId)}\n canForwardAll={!detail.isDraft && detail.typeDefinition.allowForward && Boolean(latestConversationMessageId)}\n actionsDisabled={Boolean(state.activeConversationAction)}\n activeActionId={state.activeConversationAction}\n onReply={() => {\n if (!firstConversationMessageId) return\n setActiveInlineComposer({\n variant: 'reply',\n messageId: firstConversationMessageId,\n })\n }}\n onForwardAll={() => {\n if (!latestConversationMessageId) return\n setActiveInlineComposer({\n variant: 'forward',\n messageId: latestConversationMessageId,\n })\n }}\n onArchiveConversation={() => {\n if (!canRunConversationActions) return\n void state.archiveConversation(firstConversationMessageId ?? undefined)\n }}\n onMarkAllUnread={() => {\n if (!canRunConversationActions) return\n void state.markConversationUnread(firstConversationMessageId ?? undefined)\n }}\n onDeleteConversation={() => {\n if (!canRunConversationActions || state.activeConversationAction) return\n void (async () => {\n const confirmed = await confirm({\n title: state.t('messages.confirm.deleteConversationTitle', 'Delete conversation'),\n text: state.t('messages.confirm.deleteConversation', 'Delete this conversation from your view?'),\n confirmText: state.t('messages.actions.deleteConversation', 'Delete conversation'),\n cancelText: state.t('common.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!confirmed) return\n await state.deleteConversation(firstConversationMessageId ?? undefined)\n })()\n }}\n />\n <div className=\"divide-y border-y\">\n {state.conversationItems.map((item) => {\n const isForcedExpanded = item.id === state.forcedExpandedItemId\n const isExpanded = state.isConversationItemExpanded(item.id)\n if (isExpanded) {\n return (\n <MessageConversationDetailItem\n key={item.id}\n messageId={item.id}\n isCollapsible={!isForcedExpanded}\n isExpanded\n onToggle={() => state.toggleConversationItem(item.id)}\n onReply={(messageId) => {\n setActiveInlineComposer({\n variant: 'reply',\n messageId,\n })\n }}\n onForward={(messageId) => {\n setActiveInlineComposer({\n variant: 'forward',\n messageId,\n })\n }}\n />\n )\n }\n\n return (\n <section key={item.id} className=\"px-1 py-1\">\n <MessageListComponent\n message={state.buildConversationListItemMessage(item)}\n onClick={() => state.toggleConversationItem(item.id)}\n />\n </section>\n )\n })}\n </div>\n\n {activeInlineComposer ? (\n <div ref={inlineComposerContainerRef}>\n <MessageComposer\n inline\n inlineBackHref={null}\n variant={activeInlineComposer.variant}\n messageId={activeInlineComposer.messageId}\n onCancel={() => {\n setActiveInlineComposer(null)\n }}\n onSuccess={() => {\n setActiveInlineComposer(null)\n void state.detailQuery.refetch()\n }}\n />\n </div>\n ) : null}\n {ConfirmDialogElement}\n </div>\n )\n}\n\nexport function MessageDetailPageClient({ id }: { id: string }) {\n return <MessageDetailPageClientContent id={id} />\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,7 +7,6 @@ import { useQuery } from "@tanstack/react-query";
7
7
  import { useT } from "@open-mercato/shared/lib/i18n/context";
8
8
  import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
9
9
  import { DataTable } from "@open-mercato/ui/backend/DataTable";
10
- import { ErrorMessage } from "@open-mercato/ui/backend/detail";
11
10
  import { Button } from "@open-mercato/ui/primitives/button";
12
11
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
13
12
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
@@ -30,7 +29,7 @@ function toErrorMessage(payload) {
30
29
  }
31
30
  return null;
32
31
  }
33
- function MessagesInboxPageClient({ canViewMessages = true }) {
32
+ function MessagesInboxPageClient() {
34
33
  const router = useRouter();
35
34
  const t = useT();
36
35
  const scopeVersion = useOrganizationScopeVersion();
@@ -53,7 +52,6 @@ function MessagesInboxPageClient({ canViewMessages = true }) {
53
52
  JSON.stringify(filterValues),
54
53
  scopeVersion
55
54
  ],
56
- enabled: canViewMessages,
57
55
  queryFn: async () => {
58
56
  const params = new URLSearchParams();
59
57
  params.set("folder", folder);
@@ -78,16 +76,6 @@ function MessagesInboxPageClient({ canViewMessages = true }) {
78
76
  if (since) params.set("since", since);
79
77
  const call = await apiCall(`/api/messages?${params.toString()}`);
80
78
  if (!call.ok) {
81
- if (call.status === 403) {
82
- return {
83
- items: [],
84
- total: 0,
85
- page,
86
- pageSize,
87
- totalPages: 1,
88
- accessDenied: true
89
- };
90
- }
91
79
  throw new Error(
92
80
  toErrorMessage(call.result) ?? t("messages.errors.loadListFailed", "Failed to load messages.")
93
81
  );
@@ -97,14 +85,12 @@ function MessagesInboxPageClient({ canViewMessages = true }) {
97
85
  total: Number(call.result?.total ?? 0),
98
86
  page: Number(call.result?.page ?? page),
99
87
  pageSize: Number(call.result?.pageSize ?? pageSize),
100
- totalPages: Number(call.result?.totalPages ?? 1),
101
- accessDenied: false
88
+ totalPages: Number(call.result?.totalPages ?? 1)
102
89
  };
103
90
  }
104
91
  });
105
92
  const messageTypesQuery = useQuery({
106
93
  queryKey: ["messages", "types", scopeVersion],
107
- enabled: canViewMessages,
108
94
  queryFn: async () => {
109
95
  const call = await apiCall("/api/messages/types");
110
96
  if (!call.ok) {
@@ -117,22 +103,19 @@ function MessagesInboxPageClient({ canViewMessages = true }) {
117
103
  }
118
104
  });
119
105
  React.useEffect(() => {
120
- if (!canViewMessages) return;
121
106
  if (!listQuery.error) return;
122
- if (listQuery.data?.accessDenied) return;
123
107
  flash(
124
108
  listQuery.error instanceof Error ? listQuery.error.message : t("messages.errors.loadListFailed", "Failed to load messages."),
125
109
  "error"
126
110
  );
127
- }, [canViewMessages, listQuery.error, t]);
111
+ }, [listQuery.error, t]);
128
112
  React.useEffect(() => {
129
- if (!canViewMessages) return;
130
113
  if (!messageTypesQuery.error) return;
131
114
  flash(
132
115
  messageTypesQuery.error instanceof Error ? messageTypesQuery.error.message : t("messages.errors.loadTypesFailed", "Failed to load message types."),
133
116
  "error"
134
117
  );
135
- }, [canViewMessages, messageTypesQuery.error, t]);
118
+ }, [messageTypesQuery.error, t]);
136
119
  const messageTypeLabelMap = React.useMemo(() => {
137
120
  const map = {};
138
121
  for (const item of messageTypesQuery.data ?? []) {
@@ -305,22 +288,9 @@ function MessagesInboxPageClient({ canViewMessages = true }) {
305
288
  document.removeEventListener("keydown", handleEscape);
306
289
  };
307
290
  }, [folderMenuOpen]);
308
- const accessDenied = !canViewMessages || listQuery.data?.accessDenied === true;
309
291
  const rows = listQuery.data?.items ?? [];
310
292
  const total = listQuery.data?.total ?? 0;
311
293
  const totalPages = listQuery.data?.totalPages ?? 1;
312
- if (accessDenied) {
313
- return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(
314
- ErrorMessage,
315
- {
316
- label: t("messages.access.disabled.title", "Messages module is disabled for your role."),
317
- description: t(
318
- "messages.access.disabled.description",
319
- "Ask your administrator to enable the required Messages permissions."
320
- )
321
- }
322
- ) });
323
- }
324
294
  return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(
325
295
  DataTable,
326
296
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/components/MessagesInboxPageClient.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Archive, ChevronDown, FilePenLine, Inbox, Layers, Send } from 'lucide-react'\nimport { getMessageUiComponentRegistry } from './utils/typeUiRegistry'\nimport { DefaultMessageListItem } from './defaults/DefaultMessageListItem'\n\ntype MessageFolder = 'inbox' | 'sent' | 'drafts' | 'archived' | 'all'\n\ntype MessageListItem = {\n id: string\n type: string\n subject: string\n bodyPreview: string\n senderUserId: string\n senderName?: string | null\n senderEmail?: string | null\n priority: string\n status: string\n hasObjects: boolean\n objectCount: number\n hasAttachments: boolean\n attachmentCount: number\n hasActions: boolean\n actionTaken?: string | null\n sentAt?: string | null\n readAt?: string | null\n threadId?: string | null\n}\n\ntype MessageListResponse = {\n items?: MessageListItem[]\n total?: number\n page?: number\n pageSize?: number\n totalPages?: number\n}\n\ntype MessageListQueryResult = {\n items: MessageListItem[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n accessDenied: boolean\n}\n\ntype MessageTypeItem = {\n type: string\n module: string\n labelKey: string\n ui?: {\n listItemComponent?: string | null\n } | null\n}\n\ntype UserListItem = {\n id: string\n email?: string | null\n name?: string | null\n}\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\nexport function MessagesInboxPageClient({ canViewMessages = true }: { canViewMessages?: boolean }) {\n const router = useRouter()\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n\n const [folder, setFolder] = React.useState<MessageFolder>('inbox')\n const [folderMenuOpen, setFolderMenuOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [page, setPage] = React.useState(1)\n const pageSize = 20\n const folderMenuRef = React.useRef<HTMLDivElement | null>(null)\n const messageUiRegistry = React.useMemo(() => getMessageUiComponentRegistry(), [])\n\n const listQuery = useQuery({\n queryKey: [\n 'messages',\n 'list',\n folder,\n search,\n page,\n pageSize,\n JSON.stringify(filterValues),\n scopeVersion,\n ],\n enabled: canViewMessages,\n queryFn: async () => {\n const params = new URLSearchParams()\n params.set('folder', folder)\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n\n if (search.trim()) {\n params.set('search', search.trim())\n }\n\n const status = typeof filterValues.status === 'string' ? filterValues.status.trim() : ''\n const type = typeof filterValues.type === 'string' ? filterValues.type.trim() : ''\n const hasObjects = typeof filterValues.hasObjects === 'string' ? filterValues.hasObjects.trim() : ''\n const hasAttachments = typeof filterValues.hasAttachments === 'string' ? filterValues.hasAttachments.trim() : ''\n const hasActions = typeof filterValues.hasActions === 'string' ? filterValues.hasActions.trim() : ''\n const senderId = typeof filterValues.senderId === 'string' ? filterValues.senderId.trim() : ''\n const since = typeof filterValues.since === 'string' ? filterValues.since.trim() : ''\n\n if (status) params.set('status', status)\n if (type) params.set('type', type)\n if (hasObjects) params.set('hasObjects', hasObjects)\n if (hasAttachments) params.set('hasAttachments', hasAttachments)\n if (hasActions) params.set('hasActions', hasActions)\n if (senderId) params.set('senderId', senderId)\n if (since) params.set('since', since)\n\n const call = await apiCall<MessageListResponse>(`/api/messages?${params.toString()}`)\n if (!call.ok) {\n if (call.status === 403) {\n return {\n items: [],\n total: 0,\n page,\n pageSize,\n totalPages: 1,\n accessDenied: true,\n } satisfies MessageListQueryResult\n }\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadListFailed', 'Failed to load messages.'),\n )\n }\n\n return {\n items: Array.isArray(call.result?.items) ? call.result?.items ?? [] : [],\n total: Number(call.result?.total ?? 0),\n page: Number(call.result?.page ?? page),\n pageSize: Number(call.result?.pageSize ?? pageSize),\n totalPages: Number(call.result?.totalPages ?? 1),\n accessDenied: false,\n } satisfies MessageListQueryResult\n },\n })\n\n const messageTypesQuery = useQuery({\n queryKey: ['messages', 'types', scopeVersion],\n enabled: canViewMessages,\n queryFn: async () => {\n const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')\n if (!call.ok) {\n if (call.status === 403) return []\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 React.useEffect(() => {\n if (!canViewMessages) return\n if (!listQuery.error) return\n if (listQuery.data?.accessDenied) return\n flash(\n listQuery.error instanceof Error\n ? listQuery.error.message\n : t('messages.errors.loadListFailed', 'Failed to load messages.'),\n 'error',\n )\n }, [canViewMessages, listQuery.error, t])\n\n React.useEffect(() => {\n if (!canViewMessages) return\n if (!messageTypesQuery.error) return\n flash(\n messageTypesQuery.error instanceof Error\n ? messageTypesQuery.error.message\n : t('messages.errors.loadTypesFailed', 'Failed to load message types.'),\n 'error',\n )\n }, [canViewMessages, messageTypesQuery.error, t])\n\n const messageTypeLabelMap = React.useMemo(() => {\n const map: Record<string, string> = {}\n for (const item of messageTypesQuery.data ?? []) {\n map[item.type] = t(item.labelKey, item.type)\n }\n return map\n }, [messageTypesQuery.data, t])\n\n const loadSenderOptions = React.useCallback(async (query?: string) => {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '20')\n if (query && query.trim().length > 0) {\n params.set('search', query.trim())\n }\n\n const call = await apiCall<{ items?: UserListItem[] }>(`/api/auth/users?${params.toString()}`)\n if (!call.ok) return []\n\n const items = Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n return items.flatMap((item) => {\n if (!item || typeof item.id !== 'string' || item.id.trim().length === 0) return []\n const name = typeof item.name === 'string' && item.name.trim().length > 0 ? item.name.trim() : null\n const email = typeof item.email === 'string' && item.email.trim().length > 0 ? item.email.trim() : null\n const label = name ?? email ?? item.id\n return [{\n value: item.id,\n label,\n description: email && email !== label ? email : null,\n }]\n })\n }, [])\n\n const listItemComponentKeyByType = React.useMemo(() => {\n const map: Record<string, string | null> = {}\n for (const item of messageTypesQuery.data ?? []) {\n map[item.type] = item.ui?.listItemComponent ?? null\n }\n return map\n }, [messageTypesQuery.data])\n\n const filters = React.useMemo<FilterDef[]>(() => {\n const typeOptions = (messageTypesQuery.data ?? []).map((item) => ({\n value: item.type,\n label: t(item.labelKey, item.type),\n }))\n\n return [\n {\n id: 'status',\n label: t('messages.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'unread', label: t('messages.status.unread', 'Unread') },\n { value: 'read', label: t('messages.status.read', 'Read') },\n { value: 'archived', label: t('messages.status.archived', 'Archived') },\n ],\n },\n {\n id: 'type',\n label: t('messages.filters.type', 'Type'),\n type: 'select',\n options: [{ value: '', label: t('messages.filters.all', 'All') }, ...typeOptions],\n },\n {\n id: 'hasObjects',\n label: t('messages.filters.hasObjects', 'Objects'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'true', label: t('common.yes', 'Yes') },\n { value: 'false', label: t('common.no', 'No') },\n ],\n },\n {\n id: 'hasAttachments',\n label: t('messages.filters.hasAttachments', 'Attachments'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'true', label: t('common.yes', 'Yes') },\n { value: 'false', label: t('common.no', 'No') },\n ],\n },\n {\n id: 'hasActions',\n label: t('messages.filters.hasActions', 'Actions'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'true', label: t('common.yes', 'Yes') },\n { value: 'false', label: t('common.no', 'No') },\n ],\n },\n {\n id: 'senderId',\n label: t('messages.filters.sender', 'Sender'),\n type: 'select',\n options: [{ value: '', label: t('messages.filters.all', 'All') }],\n loadOptions: loadSenderOptions,\n },\n {\n id: 'since',\n label: t('messages.filters.since', 'Sent after'),\n type: 'text',\n placeholder: t('messages.filters.sincePlaceholder', 'YYYY-MM-DDTHH:mm:ssZ'),\n },\n ]\n }, [loadSenderOptions, messageTypesQuery.data, t])\n\n const columns = React.useMemo<ColumnDef<MessageListItem>[]>(() => [\n {\n accessorKey: 'message',\n header: t('messages.title', 'Messages'),\n meta: {\n truncate: false,\n maxWidth: '100%',\n },\n cell: ({ row }) => {\n const item = row.original\n const listItemComponentKey = listItemComponentKeyByType[item.type]\n const ListItemComponent = listItemComponentKey\n ? messageUiRegistry.listItemComponents[listItemComponentKey] ?? null\n : null\n const ComponentToUse = ListItemComponent || DefaultMessageListItem\n\n return (\n <ComponentToUse\n message={{\n id: item.id,\n type: item.type,\n typeLabel: messageTypeLabelMap[item.type] ?? item.type,\n subject: item.subject,\n body: item.bodyPreview,\n bodyFormat: 'text' as const,\n priority: (item.priority as 'low' | 'normal' | 'high' | 'urgent') ?? 'normal',\n sentAt: item.sentAt ? new Date(item.sentAt) : null,\n senderName: item.senderName || item.senderEmail || item.senderUserId,\n hasObjects: item.hasObjects,\n objectCount: item.objectCount,\n hasAttachments: item.hasAttachments,\n attachmentCount: item.attachmentCount,\n hasActions: item.hasActions,\n actionTaken: item.actionTaken ?? null,\n unread: item.status === 'unread',\n }}\n onClick={() => router.push(`/backend/messages/${item.id}`)}\n />\n )\n },\n },\n ], [listItemComponentKeyByType, messageTypeLabelMap, messageUiRegistry, router, t])\n\n const folderOptions = React.useMemo(() => [\n { id: 'inbox' as const, label: t('messages.folder.inbox', 'Inbox'), icon: Inbox },\n { id: 'sent' as const, label: t('messages.folder.sent', 'Sent'), icon: Send },\n { id: 'drafts' as const, label: t('messages.folder.drafts', 'Drafts'), icon: FilePenLine },\n { id: 'archived' as const, label: t('messages.folder.archived', 'Archived'), icon: Archive },\n { id: 'all' as const, label: t('messages.folder.all', 'All'), icon: Layers },\n ], [t])\n\n const activeFolderOption = folderOptions.find((option) => option.id === folder) ?? folderOptions[0]\n const ActiveFolderIcon = activeFolderOption.icon\n\n React.useEffect(() => {\n if (!folderMenuOpen) return\n const handleClickOutside = (event: MouseEvent) => {\n if (!folderMenuRef.current) return\n const target = event.target\n if (target instanceof Node && !folderMenuRef.current.contains(target)) {\n setFolderMenuOpen(false)\n }\n }\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setFolderMenuOpen(false)\n }\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleEscape)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleEscape)\n }\n }, [folderMenuOpen])\n\n const accessDenied = !canViewMessages || listQuery.data?.accessDenied === true\n const rows = listQuery.data?.items ?? []\n const total = listQuery.data?.total ?? 0\n const totalPages = listQuery.data?.totalPages ?? 1\n\n if (accessDenied) {\n return (\n <div className=\"space-y-4\">\n <ErrorMessage\n label={t('messages.access.disabled.title', 'Messages module is disabled for your role.')}\n description={t(\n 'messages.access.disabled.description',\n 'Ask your administrator to enable the required Messages permissions.',\n )}\n />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n <DataTable\n title={t('messages.title', 'Messages')}\n columns={columns}\n data={rows}\n searchValue={search}\n onSearchChange={(value) => {\n setSearch(value)\n setPage(1)\n }}\n searchPlaceholder={t('messages.searchPlaceholder', 'Search messages')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(value) => {\n setFilterValues(value)\n setPage(1)\n }}\n onFiltersClear={() => {\n setFilterValues({})\n setPage(1)\n }}\n isLoading={listQuery.isLoading || listQuery.isFetching}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative\" ref={folderMenuRef}>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-2\"\n aria-expanded={folderMenuOpen}\n aria-haspopup=\"menu\"\n onClick={() => setFolderMenuOpen((value) => !value)}\n >\n <ActiveFolderIcon className=\"h-4 w-4\" aria-hidden />\n <span>{t('messages.folder.selector', 'Folder')}:</span>\n <span>{activeFolderOption.label}</span>\n <ChevronDown className=\"h-4 w-4 opacity-70\" aria-hidden />\n </Button>\n {folderMenuOpen ? (\n <div\n className=\"absolute right-0 z-20 mt-1 min-w-52 rounded-md border bg-background p-1 shadow\"\n role=\"menu\"\n >\n {folderOptions.map((option) => {\n const Icon = option.icon\n const isActive = option.id === folder\n return (\n <button\n key={option.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={isActive}\n className={`flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-sm hover:bg-accent ${isActive ? 'bg-accent/60' : ''}`}\n onClick={() => {\n setFolder(option.id)\n setPage(1)\n setFolderMenuOpen(false)\n }}\n >\n <Icon className=\"h-4 w-4\" aria-hidden />\n <span>{option.label}</span>\n </button>\n )\n })}\n </div>\n ) : null}\n </div>\n <Button asChild>\n <Link href=\"/backend/messages/compose\">{t('messages.compose', 'Compose message')}</Link>\n </Button>\n </div>\n }\n onRowClick={(row) => {\n router.push(`/backend/messages/${row.id}`)\n }}\n perspective={{ tableId: 'messages.inbox' }}\n embedded\n />\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Archive, ChevronDown, FilePenLine, Inbox, Layers, Send } from 'lucide-react'\nimport { getMessageUiComponentRegistry } from './utils/typeUiRegistry'\nimport { DefaultMessageListItem } from './defaults/DefaultMessageListItem'\n\ntype MessageFolder = 'inbox' | 'sent' | 'drafts' | 'archived' | 'all'\n\ntype MessageListItem = {\n id: string\n type: string\n subject: string\n bodyPreview: string\n senderUserId: string\n senderName?: string | null\n senderEmail?: string | null\n priority: string\n status: string\n hasObjects: boolean\n objectCount: number\n hasAttachments: boolean\n attachmentCount: number\n hasActions: boolean\n actionTaken?: string | null\n sentAt?: string | null\n readAt?: string | null\n threadId?: string | null\n}\n\ntype MessageListResponse = {\n items?: MessageListItem[]\n total?: number\n page?: number\n pageSize?: number\n totalPages?: number\n}\n\ntype MessageTypeItem = {\n type: string\n module: string\n labelKey: string\n ui?: {\n listItemComponent?: string | null\n } | null\n}\n\ntype UserListItem = {\n id: string\n email?: string | null\n name?: string | null\n}\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\nexport function MessagesInboxPageClient() {\n const router = useRouter()\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n\n const [folder, setFolder] = React.useState<MessageFolder>('inbox')\n const [folderMenuOpen, setFolderMenuOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [page, setPage] = React.useState(1)\n const pageSize = 20\n const folderMenuRef = React.useRef<HTMLDivElement | null>(null)\n const messageUiRegistry = React.useMemo(() => getMessageUiComponentRegistry(), [])\n\n const listQuery = useQuery({\n queryKey: [\n 'messages',\n 'list',\n folder,\n search,\n page,\n pageSize,\n JSON.stringify(filterValues),\n scopeVersion,\n ],\n queryFn: async () => {\n const params = new URLSearchParams()\n params.set('folder', folder)\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n\n if (search.trim()) {\n params.set('search', search.trim())\n }\n\n const status = typeof filterValues.status === 'string' ? filterValues.status.trim() : ''\n const type = typeof filterValues.type === 'string' ? filterValues.type.trim() : ''\n const hasObjects = typeof filterValues.hasObjects === 'string' ? filterValues.hasObjects.trim() : ''\n const hasAttachments = typeof filterValues.hasAttachments === 'string' ? filterValues.hasAttachments.trim() : ''\n const hasActions = typeof filterValues.hasActions === 'string' ? filterValues.hasActions.trim() : ''\n const senderId = typeof filterValues.senderId === 'string' ? filterValues.senderId.trim() : ''\n const since = typeof filterValues.since === 'string' ? filterValues.since.trim() : ''\n\n if (status) params.set('status', status)\n if (type) params.set('type', type)\n if (hasObjects) params.set('hasObjects', hasObjects)\n if (hasAttachments) params.set('hasAttachments', hasAttachments)\n if (hasActions) params.set('hasActions', hasActions)\n if (senderId) params.set('senderId', senderId)\n if (since) params.set('since', since)\n\n const call = await apiCall<MessageListResponse>(`/api/messages?${params.toString()}`)\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadListFailed', 'Failed to load messages.'),\n )\n }\n\n return {\n items: Array.isArray(call.result?.items) ? call.result?.items ?? [] : [],\n total: Number(call.result?.total ?? 0),\n page: Number(call.result?.page ?? page),\n pageSize: Number(call.result?.pageSize ?? pageSize),\n totalPages: Number(call.result?.totalPages ?? 1),\n }\n },\n })\n\n const messageTypesQuery = useQuery({\n queryKey: ['messages', 'types', scopeVersion],\n queryFn: async () => {\n const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')\n if (!call.ok) {\n if (call.status === 403) return []\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 React.useEffect(() => {\n if (!listQuery.error) return\n flash(\n listQuery.error instanceof Error\n ? listQuery.error.message\n : t('messages.errors.loadListFailed', 'Failed to load messages.'),\n 'error',\n )\n }, [listQuery.error, t])\n\n React.useEffect(() => {\n if (!messageTypesQuery.error) return\n flash(\n messageTypesQuery.error instanceof Error\n ? messageTypesQuery.error.message\n : t('messages.errors.loadTypesFailed', 'Failed to load message types.'),\n 'error',\n )\n }, [messageTypesQuery.error, t])\n\n const messageTypeLabelMap = React.useMemo(() => {\n const map: Record<string, string> = {}\n for (const item of messageTypesQuery.data ?? []) {\n map[item.type] = t(item.labelKey, item.type)\n }\n return map\n }, [messageTypesQuery.data, t])\n\n const loadSenderOptions = React.useCallback(async (query?: string) => {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '20')\n if (query && query.trim().length > 0) {\n params.set('search', query.trim())\n }\n\n const call = await apiCall<{ items?: UserListItem[] }>(`/api/auth/users?${params.toString()}`)\n if (!call.ok) return []\n\n const items = Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n return items.flatMap((item) => {\n if (!item || typeof item.id !== 'string' || item.id.trim().length === 0) return []\n const name = typeof item.name === 'string' && item.name.trim().length > 0 ? item.name.trim() : null\n const email = typeof item.email === 'string' && item.email.trim().length > 0 ? item.email.trim() : null\n const label = name ?? email ?? item.id\n return [{\n value: item.id,\n label,\n description: email && email !== label ? email : null,\n }]\n })\n }, [])\n\n const listItemComponentKeyByType = React.useMemo(() => {\n const map: Record<string, string | null> = {}\n for (const item of messageTypesQuery.data ?? []) {\n map[item.type] = item.ui?.listItemComponent ?? null\n }\n return map\n }, [messageTypesQuery.data])\n\n const filters = React.useMemo<FilterDef[]>(() => {\n const typeOptions = (messageTypesQuery.data ?? []).map((item) => ({\n value: item.type,\n label: t(item.labelKey, item.type),\n }))\n\n return [\n {\n id: 'status',\n label: t('messages.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'unread', label: t('messages.status.unread', 'Unread') },\n { value: 'read', label: t('messages.status.read', 'Read') },\n { value: 'archived', label: t('messages.status.archived', 'Archived') },\n ],\n },\n {\n id: 'type',\n label: t('messages.filters.type', 'Type'),\n type: 'select',\n options: [{ value: '', label: t('messages.filters.all', 'All') }, ...typeOptions],\n },\n {\n id: 'hasObjects',\n label: t('messages.filters.hasObjects', 'Objects'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'true', label: t('common.yes', 'Yes') },\n { value: 'false', label: t('common.no', 'No') },\n ],\n },\n {\n id: 'hasAttachments',\n label: t('messages.filters.hasAttachments', 'Attachments'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'true', label: t('common.yes', 'Yes') },\n { value: 'false', label: t('common.no', 'No') },\n ],\n },\n {\n id: 'hasActions',\n label: t('messages.filters.hasActions', 'Actions'),\n type: 'select',\n options: [\n { value: '', label: t('messages.filters.all', 'All') },\n { value: 'true', label: t('common.yes', 'Yes') },\n { value: 'false', label: t('common.no', 'No') },\n ],\n },\n {\n id: 'senderId',\n label: t('messages.filters.sender', 'Sender'),\n type: 'select',\n options: [{ value: '', label: t('messages.filters.all', 'All') }],\n loadOptions: loadSenderOptions,\n },\n {\n id: 'since',\n label: t('messages.filters.since', 'Sent after'),\n type: 'text',\n placeholder: t('messages.filters.sincePlaceholder', 'YYYY-MM-DDTHH:mm:ssZ'),\n },\n ]\n }, [loadSenderOptions, messageTypesQuery.data, t])\n\n const columns = React.useMemo<ColumnDef<MessageListItem>[]>(() => [\n {\n accessorKey: 'message',\n header: t('messages.title', 'Messages'),\n meta: {\n truncate: false,\n maxWidth: '100%',\n },\n cell: ({ row }) => {\n const item = row.original\n const listItemComponentKey = listItemComponentKeyByType[item.type]\n const ListItemComponent = listItemComponentKey\n ? messageUiRegistry.listItemComponents[listItemComponentKey] ?? null\n : null\n const ComponentToUse = ListItemComponent || DefaultMessageListItem\n\n return (\n <ComponentToUse\n message={{\n id: item.id,\n type: item.type,\n typeLabel: messageTypeLabelMap[item.type] ?? item.type,\n subject: item.subject,\n body: item.bodyPreview,\n bodyFormat: 'text' as const,\n priority: (item.priority as 'low' | 'normal' | 'high' | 'urgent') ?? 'normal',\n sentAt: item.sentAt ? new Date(item.sentAt) : null,\n senderName: item.senderName || item.senderEmail || item.senderUserId,\n hasObjects: item.hasObjects,\n objectCount: item.objectCount,\n hasAttachments: item.hasAttachments,\n attachmentCount: item.attachmentCount,\n hasActions: item.hasActions,\n actionTaken: item.actionTaken ?? null,\n unread: item.status === 'unread',\n }}\n onClick={() => router.push(`/backend/messages/${item.id}`)}\n />\n )\n },\n },\n ], [listItemComponentKeyByType, messageTypeLabelMap, messageUiRegistry, router, t])\n\n const folderOptions = React.useMemo(() => [\n { id: 'inbox' as const, label: t('messages.folder.inbox', 'Inbox'), icon: Inbox },\n { id: 'sent' as const, label: t('messages.folder.sent', 'Sent'), icon: Send },\n { id: 'drafts' as const, label: t('messages.folder.drafts', 'Drafts'), icon: FilePenLine },\n { id: 'archived' as const, label: t('messages.folder.archived', 'Archived'), icon: Archive },\n { id: 'all' as const, label: t('messages.folder.all', 'All'), icon: Layers },\n ], [t])\n\n const activeFolderOption = folderOptions.find((option) => option.id === folder) ?? folderOptions[0]\n const ActiveFolderIcon = activeFolderOption.icon\n\n React.useEffect(() => {\n if (!folderMenuOpen) return\n const handleClickOutside = (event: MouseEvent) => {\n if (!folderMenuRef.current) return\n const target = event.target\n if (target instanceof Node && !folderMenuRef.current.contains(target)) {\n setFolderMenuOpen(false)\n }\n }\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setFolderMenuOpen(false)\n }\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleEscape)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleEscape)\n }\n }, [folderMenuOpen])\n\n const rows = listQuery.data?.items ?? []\n const total = listQuery.data?.total ?? 0\n const totalPages = listQuery.data?.totalPages ?? 1\n\n return (\n <div className=\"space-y-4\">\n <DataTable\n title={t('messages.title', 'Messages')}\n columns={columns}\n data={rows}\n searchValue={search}\n onSearchChange={(value) => {\n setSearch(value)\n setPage(1)\n }}\n searchPlaceholder={t('messages.searchPlaceholder', 'Search messages')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(value) => {\n setFilterValues(value)\n setPage(1)\n }}\n onFiltersClear={() => {\n setFilterValues({})\n setPage(1)\n }}\n isLoading={listQuery.isLoading || listQuery.isFetching}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative\" ref={folderMenuRef}>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-2\"\n aria-expanded={folderMenuOpen}\n aria-haspopup=\"menu\"\n onClick={() => setFolderMenuOpen((value) => !value)}\n >\n <ActiveFolderIcon className=\"h-4 w-4\" aria-hidden />\n <span>{t('messages.folder.selector', 'Folder')}:</span>\n <span>{activeFolderOption.label}</span>\n <ChevronDown className=\"h-4 w-4 opacity-70\" aria-hidden />\n </Button>\n {folderMenuOpen ? (\n <div\n className=\"absolute right-0 z-20 mt-1 min-w-52 rounded-md border bg-background p-1 shadow\"\n role=\"menu\"\n >\n {folderOptions.map((option) => {\n const Icon = option.icon\n const isActive = option.id === folder\n return (\n <button\n key={option.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={isActive}\n className={`flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-sm hover:bg-accent ${isActive ? 'bg-accent/60' : ''}`}\n onClick={() => {\n setFolder(option.id)\n setPage(1)\n setFolderMenuOpen(false)\n }}\n >\n <Icon className=\"h-4 w-4\" aria-hidden />\n <span>{option.label}</span>\n </button>\n )\n })}\n </div>\n ) : null}\n </div>\n <Button asChild>\n <Link href=\"/backend/messages/compose\">{t('messages.compose', 'Compose message')}</Link>\n </Button>\n </div>\n }\n onRowClick={(row) => {\n router.push(`/backend/messages/${row.id}`)\n }}\n perspective={{ tableId: 'messages.inbox' }}\n embedded\n />\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.4.6-develop-18ffe6bc13",
3
+ "version": "0.4.6-develop-015a34b6dd",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -207,7 +207,7 @@
207
207
  }
208
208
  },
209
209
  "dependencies": {
210
- "@open-mercato/shared": "0.4.6-develop-18ffe6bc13",
210
+ "@open-mercato/shared": "0.4.6-develop-015a34b6dd",
211
211
  "@types/html-to-text": "^9.0.4",
212
212
  "@types/semver": "^7.5.8",
213
213
  "@xyflow/react": "^12.6.0",
@@ -1,13 +1,11 @@
1
1
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
2
2
  import { MessageDetailPageClient } from '../../../components/MessageDetailPageClient'
3
- import { resolveCanViewMessagesForCurrentUser } from '../../../lib/access'
4
3
 
5
4
  export default async function MessageDetailPage({ params }: { params: { id: string } }) {
6
- const canViewMessages = await resolveCanViewMessagesForCurrentUser()
7
5
  return (
8
6
  <Page>
9
7
  <PageBody>
10
- <MessageDetailPageClient id={params.id} canViewMessages={canViewMessages} />
8
+ <MessageDetailPageClient id={params.id} />
11
9
  </PageBody>
12
10
  </Page>
13
11
  )
@@ -1,13 +1,11 @@
1
1
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
2
2
  import { ComposeMessagePageClient } from '../../../components/ComposeMessagePageClient'
3
- import { resolveCanViewMessagesForCurrentUser } from '../../../lib/access'
4
3
 
5
4
  export default async function ComposeMessagePage() {
6
- const canViewMessages = await resolveCanViewMessagesForCurrentUser()
7
5
  return (
8
6
  <Page>
9
7
  <PageBody>
10
- <ComposeMessagePageClient canViewMessages={canViewMessages} />
8
+ <ComposeMessagePageClient />
11
9
  </PageBody>
12
10
  </Page>
13
11
  )
@@ -1,14 +1,11 @@
1
1
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
2
2
  import { MessagesInboxPageClient } from '../components/MessagesInboxPageClient'
3
- import { resolveCanViewMessagesForCurrentUser } from '../lib/access'
4
3
 
5
4
  export default async function MessagesInboxPage() {
6
- const canViewMessages = await resolveCanViewMessagesForCurrentUser()
7
-
8
5
  return (
9
6
  <Page>
10
7
  <PageBody>
11
- <MessagesInboxPageClient canViewMessages={canViewMessages} />
8
+ <MessagesInboxPageClient />
12
9
  </PageBody>
13
10
  </Page>
14
11
  )
@@ -2,24 +2,9 @@
2
2
 
3
3
  import { useRouter } from 'next/navigation'
4
4
  import { MessageComposer } from '@open-mercato/ui/backend/messages'
5
- import { ErrorMessage } from '@open-mercato/ui/backend/detail'
6
- import { useT } from '@open-mercato/shared/lib/i18n/context'
7
5
 
8
- export function ComposeMessagePageClient({ canViewMessages = true }: { canViewMessages?: boolean }) {
6
+ export function ComposeMessagePageClient() {
9
7
  const router = useRouter()
10
- const t = useT()
11
-
12
- if (!canViewMessages) {
13
- return (
14
- <ErrorMessage
15
- label={t('messages.access.disabled.title', 'Messages module is disabled for your role.')}
16
- description={t(
17
- 'messages.access.disabled.description',
18
- 'Ask your administrator to enable the required Messages permissions.',
19
- )}
20
- />
21
- )
22
- }
23
8
 
24
9
  return (
25
10
  <div className="space-y-4">
@@ -287,18 +287,6 @@ function MessageDetailPageClientContent({ id }: { id: string }) {
287
287
  )
288
288
  }
289
289
 
290
- export function MessageDetailPageClient({ id, canViewMessages = true }: { id: string; canViewMessages?: boolean }) {
291
- const t = useT()
292
- if (!canViewMessages) {
293
- return (
294
- <ErrorMessage
295
- label={t('messages.access.disabled.title', 'Messages module is disabled for your role.')}
296
- description={t(
297
- 'messages.access.disabled.description',
298
- 'Ask your administrator to enable the required Messages permissions.',
299
- )}
300
- />
301
- )
302
- }
290
+ export function MessageDetailPageClient({ id }: { id: string }) {
303
291
  return <MessageDetailPageClientContent id={id} />
304
292
  }
@@ -9,7 +9,6 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
9
9
  import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
10
10
  import { DataTable } from '@open-mercato/ui/backend/DataTable'
11
11
  import type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'
12
- import { ErrorMessage } from '@open-mercato/ui/backend/detail'
13
12
  import { Button } from '@open-mercato/ui/primitives/button'
14
13
  import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
15
14
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
@@ -48,15 +47,6 @@ type MessageListResponse = {
48
47
  totalPages?: number
49
48
  }
50
49
 
51
- type MessageListQueryResult = {
52
- items: MessageListItem[]
53
- total: number
54
- page: number
55
- pageSize: number
56
- totalPages: number
57
- accessDenied: boolean
58
- }
59
-
60
50
  type MessageTypeItem = {
61
51
  type: string
62
52
  module: string
@@ -95,7 +85,7 @@ function toErrorMessage(payload: unknown): string | null {
95
85
  return null
96
86
  }
97
87
 
98
- export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMessages?: boolean }) {
88
+ export function MessagesInboxPageClient() {
99
89
  const router = useRouter()
100
90
  const t = useT()
101
91
  const scopeVersion = useOrganizationScopeVersion()
@@ -120,7 +110,6 @@ export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMes
120
110
  JSON.stringify(filterValues),
121
111
  scopeVersion,
122
112
  ],
123
- enabled: canViewMessages,
124
113
  queryFn: async () => {
125
114
  const params = new URLSearchParams()
126
115
  params.set('folder', folder)
@@ -149,16 +138,6 @@ export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMes
149
138
 
150
139
  const call = await apiCall<MessageListResponse>(`/api/messages?${params.toString()}`)
151
140
  if (!call.ok) {
152
- if (call.status === 403) {
153
- return {
154
- items: [],
155
- total: 0,
156
- page,
157
- pageSize,
158
- totalPages: 1,
159
- accessDenied: true,
160
- } satisfies MessageListQueryResult
161
- }
162
141
  throw new Error(
163
142
  toErrorMessage(call.result)
164
143
  ?? t('messages.errors.loadListFailed', 'Failed to load messages.'),
@@ -171,14 +150,12 @@ export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMes
171
150
  page: Number(call.result?.page ?? page),
172
151
  pageSize: Number(call.result?.pageSize ?? pageSize),
173
152
  totalPages: Number(call.result?.totalPages ?? 1),
174
- accessDenied: false,
175
- } satisfies MessageListQueryResult
153
+ }
176
154
  },
177
155
  })
178
156
 
179
157
  const messageTypesQuery = useQuery({
180
158
  queryKey: ['messages', 'types', scopeVersion],
181
- enabled: canViewMessages,
182
159
  queryFn: async () => {
183
160
  const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')
184
161
  if (!call.ok) {
@@ -193,19 +170,16 @@ export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMes
193
170
  })
194
171
 
195
172
  React.useEffect(() => {
196
- if (!canViewMessages) return
197
173
  if (!listQuery.error) return
198
- if (listQuery.data?.accessDenied) return
199
174
  flash(
200
175
  listQuery.error instanceof Error
201
176
  ? listQuery.error.message
202
177
  : t('messages.errors.loadListFailed', 'Failed to load messages.'),
203
178
  'error',
204
179
  )
205
- }, [canViewMessages, listQuery.error, t])
180
+ }, [listQuery.error, t])
206
181
 
207
182
  React.useEffect(() => {
208
- if (!canViewMessages) return
209
183
  if (!messageTypesQuery.error) return
210
184
  flash(
211
185
  messageTypesQuery.error instanceof Error
@@ -213,7 +187,7 @@ export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMes
213
187
  : t('messages.errors.loadTypesFailed', 'Failed to load message types.'),
214
188
  'error',
215
189
  )
216
- }, [canViewMessages, messageTypesQuery.error, t])
190
+ }, [messageTypesQuery.error, t])
217
191
 
218
192
  const messageTypeLabelMap = React.useMemo(() => {
219
193
  const map: Record<string, string> = {}
@@ -400,25 +374,10 @@ export function MessagesInboxPageClient({ canViewMessages = true }: { canViewMes
400
374
  }
401
375
  }, [folderMenuOpen])
402
376
 
403
- const accessDenied = !canViewMessages || listQuery.data?.accessDenied === true
404
377
  const rows = listQuery.data?.items ?? []
405
378
  const total = listQuery.data?.total ?? 0
406
379
  const totalPages = listQuery.data?.totalPages ?? 1
407
380
 
408
- if (accessDenied) {
409
- return (
410
- <div className="space-y-4">
411
- <ErrorMessage
412
- label={t('messages.access.disabled.title', 'Messages module is disabled for your role.')}
413
- description={t(
414
- 'messages.access.disabled.description',
415
- 'Ask your administrator to enable the required Messages permissions.',
416
- )}
417
- />
418
- </div>
419
- )
420
- }
421
-
422
381
  return (
423
382
  <div className="space-y-4">
424
383
  <DataTable
@@ -1,36 +0,0 @@
1
- import { cookies } from "next/headers";
2
- import { getAuthFromCookies } from "@open-mercato/shared/lib/auth/server";
3
- import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
- import { resolveFeatureCheckContext } from "@open-mercato/core/modules/directory/utils/organizationScope";
5
- async function resolveCanViewMessagesForCurrentUser() {
6
- const auth = await getAuthFromCookies();
7
- if (!auth) return false;
8
- try {
9
- const cookieStore = await cookies();
10
- const rawSelectedOrg = cookieStore.get("om_selected_org")?.value;
11
- const rawSelectedTenant = cookieStore.get("om_selected_tenant")?.value;
12
- const selectedOrgForScope = rawSelectedOrg === void 0 ? void 0 : rawSelectedOrg && rawSelectedOrg.trim().length > 0 ? rawSelectedOrg : null;
13
- const selectedTenantForScope = rawSelectedTenant === void 0 ? void 0 : rawSelectedTenant && rawSelectedTenant.trim().length > 0 ? rawSelectedTenant : null;
14
- const container = await createRequestContainer();
15
- const rbac = container.resolve("rbacService");
16
- const { organizationId, scope, allowedOrganizationIds } = await resolveFeatureCheckContext({
17
- container,
18
- auth,
19
- selectedId: selectedOrgForScope,
20
- tenantId: selectedTenantForScope
21
- });
22
- if (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length === 0) {
23
- return false;
24
- }
25
- return await rbac.userHasAllFeatures(auth.sub, ["messages.view"], {
26
- tenantId: scope.tenantId ?? auth.tenantId ?? null,
27
- organizationId: organizationId ?? null
28
- });
29
- } catch {
30
- return false;
31
- }
32
- }
33
- export {
34
- resolveCanViewMessagesForCurrentUser
35
- };
36
- //# sourceMappingURL=access.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/modules/messages/lib/access.ts"],
4
- "sourcesContent": ["import { cookies } from 'next/headers'\nimport { getAuthFromCookies } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\n\nexport async function resolveCanViewMessagesForCurrentUser(): Promise<boolean> {\n const auth = await getAuthFromCookies()\n if (!auth) return false\n\n try {\n const cookieStore = await cookies()\n const rawSelectedOrg = cookieStore.get('om_selected_org')?.value\n const rawSelectedTenant = cookieStore.get('om_selected_tenant')?.value\n const selectedOrgForScope = rawSelectedOrg === undefined\n ? undefined\n : rawSelectedOrg && rawSelectedOrg.trim().length > 0\n ? rawSelectedOrg\n : null\n const selectedTenantForScope = rawSelectedTenant === undefined\n ? undefined\n : rawSelectedTenant && rawSelectedTenant.trim().length > 0\n ? rawSelectedTenant\n : null\n\n const container = await createRequestContainer()\n const rbac = container.resolve<RbacService>('rbacService')\n const { organizationId, scope, allowedOrganizationIds } = await resolveFeatureCheckContext({\n container,\n auth,\n selectedId: selectedOrgForScope,\n tenantId: selectedTenantForScope,\n })\n\n if (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length === 0) {\n return false\n }\n\n return await rbac.userHasAllFeatures(auth.sub, ['messages.view'], {\n tenantId: scope.tenantId ?? auth.tenantId ?? null,\n organizationId: organizationId ?? null,\n })\n } catch {\n return false\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,eAAe;AACxB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,kCAAkC;AAG3C,eAAsB,uCAAyD;AAC7E,QAAM,OAAO,MAAM,mBAAmB;AACtC,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACF,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,iBAAiB,YAAY,IAAI,iBAAiB,GAAG;AAC3D,UAAM,oBAAoB,YAAY,IAAI,oBAAoB,GAAG;AACjE,UAAM,sBAAsB,mBAAmB,SAC3C,SACA,kBAAkB,eAAe,KAAK,EAAE,SAAS,IAC/C,iBACA;AACN,UAAM,yBAAyB,sBAAsB,SACjD,SACA,qBAAqB,kBAAkB,KAAK,EAAE,SAAS,IACrD,oBACA;AAEN,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,OAAO,UAAU,QAAqB,aAAa;AACzD,UAAM,EAAE,gBAAgB,OAAO,uBAAuB,IAAI,MAAM,2BAA2B;AAAA,MACzF;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,UAAU;AAAA,IACZ,CAAC;AAED,QAAI,MAAM,QAAQ,sBAAsB,KAAK,uBAAuB,WAAW,GAAG;AAChF,aAAO;AAAA,IACT;AAEA,WAAO,MAAM,KAAK,mBAAmB,KAAK,KAAK,CAAC,eAAe,GAAG;AAAA,MAChE,UAAU,MAAM,YAAY,KAAK,YAAY;AAAA,MAC7C,gBAAgB,kBAAkB;AAAA,IACpC,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
6
- "names": []
7
- }
@@ -1,46 +0,0 @@
1
- import { cookies } from 'next/headers'
2
- import { getAuthFromCookies } from '@open-mercato/shared/lib/auth/server'
3
- import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
- import { resolveFeatureCheckContext } from '@open-mercato/core/modules/directory/utils/organizationScope'
5
- import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
6
-
7
- export async function resolveCanViewMessagesForCurrentUser(): Promise<boolean> {
8
- const auth = await getAuthFromCookies()
9
- if (!auth) return false
10
-
11
- try {
12
- const cookieStore = await cookies()
13
- const rawSelectedOrg = cookieStore.get('om_selected_org')?.value
14
- const rawSelectedTenant = cookieStore.get('om_selected_tenant')?.value
15
- const selectedOrgForScope = rawSelectedOrg === undefined
16
- ? undefined
17
- : rawSelectedOrg && rawSelectedOrg.trim().length > 0
18
- ? rawSelectedOrg
19
- : null
20
- const selectedTenantForScope = rawSelectedTenant === undefined
21
- ? undefined
22
- : rawSelectedTenant && rawSelectedTenant.trim().length > 0
23
- ? rawSelectedTenant
24
- : null
25
-
26
- const container = await createRequestContainer()
27
- const rbac = container.resolve<RbacService>('rbacService')
28
- const { organizationId, scope, allowedOrganizationIds } = await resolveFeatureCheckContext({
29
- container,
30
- auth,
31
- selectedId: selectedOrgForScope,
32
- tenantId: selectedTenantForScope,
33
- })
34
-
35
- if (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length === 0) {
36
- return false
37
- }
38
-
39
- return await rbac.userHasAllFeatures(auth.sub, ['messages.view'], {
40
- tenantId: scope.tenantId ?? auth.tenantId ?? null,
41
- organizationId: organizationId ?? null,
42
- })
43
- } catch {
44
- return false
45
- }
46
- }