From 50c49b03b0ce6fc06ec3b6eb64835f577caf3fb5 Mon Sep 17 00:00:00 2001 From: Sheldon Guo Date: Thu, 15 May 2025 13:48:55 +0800 Subject: [PATCH] feat(in-app message): support mark message unread and mark all message read (#6835) * feat(MessageList): add 'Mark all as read' functionality and update UI * feat: enhance message and channel handling with improved status filtering and UI updates --- .../src/client/components/InboxContent.tsx | 25 +++++++------ .../src/client/components/MessageList.tsx | 33 +++++++++++++---- .../src/client/observables/channel.ts | 16 +++++++-- .../src/client/observables/message.ts | 36 ++++++++++++------- .../src/client/observables/sse.ts | 8 ++--- .../src/locale/en-US.json | 4 +++ .../src/locale/zh-CN.json | 6 +++- .../src/client/locale/index.ts | 2 +- .../client/manager/channel/schemas/index.ts | 2 +- .../src/locale/en-US.json | 1 + .../src/locale/zh-CN.json | 1 + 11 files changed, 92 insertions(+), 42 deletions(-) diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/InboxContent.tsx b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/InboxContent.tsx index f924b08a3a9..3bc81970698 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/InboxContent.tsx +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/InboxContent.tsx @@ -7,33 +7,32 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import React from 'react'; -import { observer } from '@formily/reactive-react'; -import { Schema } from '@formily/react'; -import { Layout, List, Badge, Button, Flex, Tabs, ConfigProvider, theme } from 'antd'; import { css } from '@emotion/css'; +import { Schema } from '@formily/react'; +import { observer } from '@formily/reactive-react'; +import { useApp } from '@nocobase/client'; import { dayjs } from '@nocobase/utils/client'; +import { Badge, Button, ConfigProvider, Flex, Layout, List, Tabs, theme } from 'antd'; +import React from 'react'; import { useLocalTranslation } from '../../locale'; import { - fetchChannels, - selectedChannelNameObs, channelListObs, - isFetchingChannelsObs, - showChannelLoadingMoreObs, - selectedMessageListObs, - channelStatusFilterObs, ChannelStatus, + channelStatusFilterObs, + fetchChannels, + isFetchingChannelsObs, + selectedChannelNameObs, + selectedMessageListObs, + showChannelLoadingMoreObs, } from '../observables'; -import MessageList from './MessageList'; import FilterTab from './FilterTab'; -import { useApp } from '@nocobase/client'; +import MessageList from './MessageList'; const InnerInboxContent = () => { const app = useApp(); const { token } = theme.useToken(); const { t } = useLocalTranslation(); const channels = channelListObs.value; - const messages = selectedMessageListObs.value; const selectedChannelName = selectedChannelNameObs.value; const onLoadChannelsMore = () => { diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/MessageList.tsx b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/MessageList.tsx index 874c2d51e7b..3f6271b26fd 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/MessageList.tsx +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/components/MessageList.tsx @@ -18,9 +18,11 @@ import { useLocalTranslation } from '../../locale'; import { useApp } from '@nocobase/client'; import { channelMapObs, + channelStatusFilterObs, fetchMessages, inboxVisible, isFecthingMessageObs, + markAllMessagesAsRead, selectedChannelNameObs, selectedMessageListObs, showMsgLoadingMoreObs, @@ -42,13 +44,22 @@ const MessageList = observer(() => { const { token } = theme.useToken(); const [hoveredMessageId, setHoveredMessageId] = useState(null); const selectedChannelName = selectedChannelNameObs.value; + const selectedChannel = selectedChannelName ? channelMapObs.value[selectedChannelName] : null; const isFetchingMessages = isFecthingMessageObs.value; const messages = selectedMessageListObs.value; const msgStatusDict = { read: t('Read'), unread: t('Unread'), }; + + const onMarkAllReadClick = useCallback(() => { + if (selectedChannelName) { + markAllMessagesAsRead({ channelName: selectedChannelName }); + } + }, [selectedChannelName]); + if (!selectedChannelName) return null; + const onItemClicked = (message) => { updateMessage({ filterByTk: message.id, @@ -88,9 +99,19 @@ const MessageList = observer(() => { components: { Badge: { dotSize: 8 } }, }} > - - {title} - +
+ + {title} + + +
{messages.length === 0 && isFecthingMessageObs.value ? ( @@ -150,7 +171,7 @@ const MessageList = observer(() => { {dayjs(message.receiveTimestamp).fromNow()}
- {hoveredMessageId === message.id && message.status === 'unread' ? ( + {hoveredMessageId === message.id ? ( ) : ( {msgStatusDict[message.status]} diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/channel.ts b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/channel.ts index abb982a9339..56ee9609582 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/channel.ts +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/channel.ts @@ -7,10 +7,10 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { observable, autorun, reaction } from '@formily/reactive'; +import { autorun, observable, reaction } from '@formily/reactive'; +import { merge } from '@nocobase/utils/client'; import { Channel } from '../../types'; import { getAPIClient } from '../utils'; -import { merge } from '@nocobase/utils/client'; import { userIdObs } from './user'; export type ChannelStatus = 'all' | 'read' | 'unread'; @@ -60,9 +60,19 @@ export const fetchChannels = async (params: any) => { channelMapObs.value[channel.name] = channel; }); } + await countChannels(); + isFetchingChannelsObs.value = false; +}; + +export const countChannels = async () => { + const apiClient = getAPIClient(); + const res = await apiClient.request({ + url: 'myInAppChannels:list', + method: 'get', + params: { filter: { status: channelStatusFilterObs.value } }, + }); const count = res.data?.meta?.count; if (count >= 0) channelCountObs.value = count; - isFetchingChannelsObs.value = false; }; autorun(() => { diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/message.ts b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/message.ts index 7c84a1413e1..8361c305f5a 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/message.ts +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/message.ts @@ -7,19 +7,12 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { observable, autorun } from '@formily/reactive'; -import { Message } from '../../types'; -import { getAPIClient } from '../utils'; -import { - channelMapObs, - selectedChannelNameObs, - fetchChannels, - InappChannelStatusEnum, - channelStatusFilterObs, -} from './channel'; -import { userIdObs } from './user'; -import { InAppMessagesDefinition } from '../../types'; +import { autorun, observable } from '@formily/reactive'; import { merge } from '@nocobase/utils/client'; +import { InAppMessagesDefinition, Message } from '../../types'; +import { getAPIClient } from '../utils'; +import { channelMapObs, channelStatusFilterObs, fetchChannels, selectedChannelNameObs } from './channel'; +import { userIdObs } from './user'; export const messageMapObs = observable<{ value: Record }>({ value: {} }); export const isFecthingMessageObs = observable<{ value: boolean }>({ value: false }); @@ -76,7 +69,24 @@ export const updateMessage = async (params: { filterByTk: any; values: Record { + const apiClient = getAPIClient(); + await apiClient.request({ + resource: InAppMessagesDefinition.name, + action: 'update', + method: 'post', + params: { filter: { status: 'unread', channelName: channelName }, values: { status: 'read' } }, + }); + Object.values(messageMapObs.value).forEach((message) => { + if (message.channelName === channelName && message.status === 'unread') { + message.status = 'read'; + } + }); + fetchChannels({ filter: { name: channelName, status: 'all' } }); updateUnreadMsgsCount(); }; diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/sse.ts b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/sse.ts index 0b9f6b706b5..4d07949ca7f 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/sse.ts +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/client/observables/sse.ts @@ -8,11 +8,11 @@ */ import { observable, reaction } from '@formily/reactive'; -import { SSEData } from '../../types'; -import { messageMapObs, updateUnreadMsgsCount } from './message'; -import { fetchChannels } from './channel'; -import { getAPIClient } from '../utils'; import { uid } from '@nocobase/utils/client'; +import { SSEData } from '../../types'; +import { getAPIClient } from '../utils'; +import { fetchChannels } from './channel'; +import { messageMapObs, updateUnreadMsgsCount } from './message'; export const liveSSEObs = observable<{ value: SSEData | null }>({ value: null }); reaction( diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/en-US.json b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/en-US.json index 8f98d400b57..2e43327114b 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/en-US.json +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/en-US.json @@ -18,10 +18,14 @@ "Channel name": "Channel name", "Message group name": "Message group name", "Message title": "Message title", + "Content type": "Content type", + "Plain text": "Plain text", "Message content": "Message content", "Details page for desktop": "Details page for desktop", "Support two types of links: internal links and external links. If using an internal link, the link starts with\"/\", for example, \"/admin\". If using an external link, the link starts with \"http\", for example, \"https://example.com\".": "Support two types of links: internal links and external links. If using an internal link, the link starts with \"/\", for example, \"/admin\". If using an external link, the link starts with \"http\", for example, \"https://example.com\".", "Mark as read": "Mark as read", + "Mark as unread": "Mark as unread", + "Mark all as read": "Mark all as read", "Support two types of links: internal links and external links. If using an internal link, the link starts with\"/\", for example, \"/m\". If using an external link, the link starts with \"http\", for example, \"https://example.com\".": "Support two types of links: internal links and external links. If using an internal link, the link starts with \"/\", for example, \"/m\". If using an external link, the link starts with \"http\", for example, \"https://example.com\".", "Details page for mobile": "Details page for mobile", "The message page has already been created.": "The message page has already been created.", diff --git a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/zh-CN.json b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/zh-CN.json index 9bc3d7b1966..890ab341acd 100644 --- a/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/zh-CN.json +++ b/packages/plugins/@nocobase/plugin-notification-in-app-message/src/locale/zh-CN.json @@ -18,10 +18,14 @@ "Message group name": "消息分组名称", "Message title": "消息标题", "Message content": "消息内容", + "Content type": "内容格式", + "Plain text": "纯文本", "detail URL": "详情链接", "Details page for desktop": "桌面端详情页", "Support two types of links: internal links and external links. If using an internal link, the link starts with\"/\", for example, \"/admin\". If using an external link, the link starts with \"http\", for example, \"https://example.com\".": "支持两种链接类型:内部链接和外部链接。如果使用内部链接,链接以“/”开头,例如“/admin”。如果使用外部链接,链接以“http”开头,例如“https://example.com”。", - "Mark as read": "标记为已读", + "Mark as read": "标为已读", + "Mark as unread": "标为未读", + "Mark all as read": "全部标为已读", "Support two types of links: internal links and external links. If using an internal link, the link starts with\"/\", for example, \"/m\". If using an external link, the link starts with \"http\", for example, \"https://example.com\".": "支持两种链接类型:内部链接和外部链接。如果使用内部链接,链接以“/”开头,例如“/m”。如果使用外部链接,链接以“http”开头,例如“https://example.com”。", "Details page for mobile": "移动端详情页", "The message page has already been created.": "站内信页面已创建。", diff --git a/packages/plugins/@nocobase/plugin-notification-manager/src/client/locale/index.ts b/packages/plugins/@nocobase/plugin-notification-manager/src/client/locale/index.ts index 8e74cce2ce6..40fd9e7713d 100644 --- a/packages/plugins/@nocobase/plugin-notification-manager/src/client/locale/index.ts +++ b/packages/plugins/@nocobase/plugin-notification-manager/src/client/locale/index.ts @@ -10,7 +10,7 @@ import { i18n } from '@nocobase/client'; import { useTranslation } from 'react-i18next'; -export const NAMESPACE = '@nocobase/plugin-notification-manager'; +export const NAMESPACE = 'notification-manager'; export function lang(key: string) { return i18n.t(key, { ns: NAMESPACE }); diff --git a/packages/plugins/@nocobase/plugin-notification-manager/src/client/manager/channel/schemas/index.ts b/packages/plugins/@nocobase/plugin-notification-manager/src/client/manager/channel/schemas/index.ts index a031292bb6f..33007352ef5 100644 --- a/packages/plugins/@nocobase/plugin-notification-manager/src/client/manager/channel/schemas/index.ts +++ b/packages/plugins/@nocobase/plugin-notification-manager/src/client/manager/channel/schemas/index.ts @@ -181,7 +181,7 @@ export const channelsSchema: ISchema = { properties: { edit: { type: 'void', - title: 'Edit', + title: '{{t("Edit")}}', 'x-component': 'Action.Link', 'x-component-props': { openMode: 'drawer', diff --git a/packages/plugins/@nocobase/plugin-notification-manager/src/locale/en-US.json b/packages/plugins/@nocobase/plugin-notification-manager/src/locale/en-US.json index 169f35a9a2a..00103fdb46b 100644 --- a/packages/plugins/@nocobase/plugin-notification-manager/src/locale/en-US.json +++ b/packages/plugins/@nocobase/plugin-notification-manager/src/locale/en-US.json @@ -20,6 +20,7 @@ "Add new": "Add new", "Trigger From": "Trigger From", "Status": "Status", + "Edit": "Edit", "Created At": "Created At", "Delete record": "Delete record", "Are you sure you want to delete it?": "Are you sure you want to delete it?", diff --git a/packages/plugins/@nocobase/plugin-notification-manager/src/locale/zh-CN.json b/packages/plugins/@nocobase/plugin-notification-manager/src/locale/zh-CN.json index acca2c46e49..876644c6132 100644 --- a/packages/plugins/@nocobase/plugin-notification-manager/src/locale/zh-CN.json +++ b/packages/plugins/@nocobase/plugin-notification-manager/src/locale/zh-CN.json @@ -25,6 +25,7 @@ "Are you sure you want to delete it?": "确定要删除吗?", "Deleted successfully!": "删除成功!", "Add user": "添加用户", + "Edit": "编辑", "Select users": "选择用户", "Query users": "查询用户", "Receiver type": "接收人类型",