diff --git a/client/web/src/components/JumpToButton.tsx b/client/web/src/components/JumpToButton.tsx new file mode 100644 index 00000000..ebe666ae --- /dev/null +++ b/client/web/src/components/JumpToButton.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { useNavigate } from 'react-router'; +import { t } from 'tailchat-shared'; + +interface Props { + link: string; + text: string; +} +/** + * 跳转到会话面板 + */ +export const JumpToButton: React.FC = React.memo((props) => { + const navigate = useNavigate(); + + return ( +
+
{ + navigate(props.link); + }} + > + {props.text} +
+
+ ); +}); +JumpToButton.displayName = 'JumpToButton'; + +export const JumpToGroupPanelButton: React.FC<{ + groupId: string; + panelId: string; +}> = React.memo((props) => { + const link = `/main/group/${props.groupId}/${props.panelId}`; + + return ; +}); +JumpToGroupPanelButton.displayName = 'JumpToGroupPanelButton'; + +export const JumpToConverseButton: React.FC<{ + groupId?: string; + converseId: string; +}> = React.memo((props) => { + const link = props.groupId + ? `/main/group/${props.groupId}/${props.converseId}` + : `/main/personal/converse/${props.converseId}`; + + return ; +}); +JumpToConverseButton.displayName = 'JumpToConverseButton'; diff --git a/client/web/src/components/PillTabs.less b/client/web/src/components/PillTabs.less index 79d4805e..996def1e 100644 --- a/client/web/src/components/PillTabs.less +++ b/client/web/src/components/PillTabs.less @@ -1,5 +1,5 @@ .pill-tabs.ant-tabs.ant-tabs-card { - @apply text-gray-700 dark:text-gray-100; + @apply text-gray-700 dark:text-gray-100 max-h-full; .ant-tabs-nav { @apply px-2 py-3 m-0 text-base; diff --git a/client/web/src/plugin/common/reg.ts b/client/web/src/plugin/common/reg.ts index 3818fee5..a72b90e6 100644 --- a/client/web/src/plugin/common/reg.ts +++ b/client/web/src/plugin/common/reg.ts @@ -7,6 +7,8 @@ import { regSocketEventListener, PermissionItemType, GroupPanelFeature, + InboxItem, + buildRegMap, } from 'tailchat-shared'; import type { MetaFormFieldMeta } from 'tailchat-design'; import type { FullModalFactoryConfig } from '@/components/FullModal/Factory'; @@ -278,3 +280,18 @@ type PluginSettings = FullModalFactoryConfig & { */ export const [pluginSettings, regPluginSettings] = buildRegList(); + +interface PluginInboxItem { + /** + * 来源 + */ + source: string; + getPreview: (inboxItem: InboxItem) => { title: string; desc: string }; + render: React.ComponentType<{ inboxItem: InboxItem }>; +} + +/** + * 注册收件箱内容 + */ +export const [pluginInboxItemMap, regPluginInboxItemMap] = + buildRegMap(); diff --git a/client/web/src/plugin/component/index.tsx b/client/web/src/plugin/component/index.tsx index 9fa69bfa..90ad1356 100644 --- a/client/web/src/plugin/component/index.tsx +++ b/client/web/src/plugin/component/index.tsx @@ -60,3 +60,9 @@ export { UserName } from '@/components/UserName'; export { Markdown } from '@/components/Markdown'; export { Webview, WebviewKeepAlive } from '@/components/Webview'; export { Card } from '@/components/Card'; +export { Problem } from '@/components/Problem'; +export { + JumpToButton, + JumpToGroupPanelButton, + JumpToConverseButton, +} from '@/components/JumpToButton'; diff --git a/client/web/src/routes/Main/Content/Inbox/Content/Message.tsx b/client/web/src/routes/Main/Content/Inbox/Content/Message.tsx index bc104ed8..dba0418f 100644 --- a/client/web/src/routes/Main/Content/Inbox/Content/Message.tsx +++ b/client/web/src/routes/Main/Content/Inbox/Content/Message.tsx @@ -1,23 +1,16 @@ import { MessageHighlightContainer } from '@/components/ChatBox/ChatMessageList/MessageHighlightContainer'; import { NormalMessageList } from '@/components/ChatBox/ChatMessageList/NormalList'; +import { JumpToConverseButton } from '@/components/JumpToButton'; import { LoadingSpinner } from '@/components/LoadingSpinner'; import { Problem } from '@/components/Problem'; import React from 'react'; -import { useNavigate } from 'react-router'; -import { - InboxItem, - model, - showErrorToasts, - t, - useAsync, -} from 'tailchat-shared'; +import { InboxItem, model, showErrorToasts, useAsync } from 'tailchat-shared'; interface Props { info: InboxItem; } export const InboxMessageContent: React.FC = React.memo((props) => { const info = props.info; - const navigate = useNavigate(); const message = info.message; if (!message) { @@ -31,21 +24,7 @@ export const InboxMessageContent: React.FC = React.memo((props) => { -
-
{ - if (groupId) { - // 跳转到群组 - navigate(`/main/group/${groupId}/${converseId}`); - } else { - navigate(`/main/personal/converse/${converseId}`); - } - }} - > - {t('跳转到会话')} -
-
+ ); }); diff --git a/client/web/src/routes/Main/Content/Inbox/Content/index.tsx b/client/web/src/routes/Main/Content/Inbox/Content/index.tsx index e464fd56..d762d109 100644 --- a/client/web/src/routes/Main/Content/Inbox/Content/index.tsx +++ b/client/web/src/routes/Main/Content/Inbox/Content/index.tsx @@ -1,4 +1,5 @@ import { NotFound } from '@/components/NotFound'; +import { pluginInboxItemMap } from '@/plugin/common'; import React from 'react'; import { useParams } from 'react-router'; import { @@ -30,6 +31,11 @@ export const InboxContent: React.FC = React.memo((props) => { if (inboxItem.type === 'message') { return ; + } else if (pluginInboxItemMap[inboxItem.type]) { + const info = pluginInboxItemMap[inboxItem.type]; + const Component = info.render; + + return ; } return ; diff --git a/client/web/src/routes/Main/Content/Inbox/Sidebar.tsx b/client/web/src/routes/Main/Content/Inbox/Sidebar.tsx index 63f01b4b..3cb92644 100644 --- a/client/web/src/routes/Main/Content/Inbox/Sidebar.tsx +++ b/client/web/src/routes/Main/Content/Inbox/Sidebar.tsx @@ -14,7 +14,7 @@ import clsx from 'clsx'; import _orderBy from 'lodash/orderBy'; import { GroupName } from '@/components/GroupName'; import { ConverseName } from '@/components/ConverseName'; -import { getMessageRender } from '@/plugin/common'; +import { getMessageRender, pluginInboxItemMap } from '@/plugin/common'; import { useLocation } from 'react-router'; import { Link } from 'react-router-dom'; import { PillTabPane, PillTabs } from '@/components/PillTabs'; @@ -52,6 +52,20 @@ export const InboxSidebar: React.FC = React.memo(() => { to={buildLink(item._id)} /> ); + } else if (pluginInboxItemMap[item.type]) { + const info = pluginInboxItemMap[item.type]; + const preview = info.getPreview(item); + + return ( + + ); } return null; @@ -99,7 +113,7 @@ export const InboxSidebar: React.FC = React.memo(() => { {t('收件箱')} -
+
{fullList.map((item) => renderInbox(item))} diff --git a/client/web/tailchat.d.ts b/client/web/tailchat.d.ts index ceefa1fe..cae4281d 100644 --- a/client/web/tailchat.d.ts +++ b/client/web/tailchat.d.ts @@ -312,6 +312,10 @@ declare module '@capital/common' { export const regPluginSettings: any; + export const pluginInboxItemMap: any; + + export const regPluginInboxItemMap: any; + export const useGroupIdContext: () => string; export const useGroupPanelContext: () => { @@ -499,4 +503,14 @@ declare module '@capital/component' { export const Webview: any; export const WebviewKeepAlive: any; + + export const Card: any; + + export const Problem: any; + + export const JumpToButton: any; + + export const JumpToGroupPanelButton: any; + + export const JumpToConverseButton: any; } diff --git a/server/models/chat/inbox.ts b/server/models/chat/inbox.ts index ed3f8043..9e82a5fb 100644 --- a/server/models/chat/inbox.ts +++ b/server/models/chat/inbox.ts @@ -10,7 +10,6 @@ import { import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'; import type { Types } from 'mongoose'; import { User } from '../user/user'; -import { Message } from './message'; interface InboxMessage { /** diff --git a/server/plugins/com.msgbyte.topic/services/topic.service.ts b/server/plugins/com.msgbyte.topic/services/topic.service.ts index b0ad81a4..ab6cf6d5 100644 --- a/server/plugins/com.msgbyte.topic/services/topic.service.ts +++ b/server/plugins/com.msgbyte.topic/services/topic.service.ts @@ -179,10 +179,24 @@ class GroupTopicService extends TcService { const json = await this.transformDocuments(ctx, {}, topic); - // TODO: 回复需要添加到收件箱 - this.roomcastNotify(ctx, panelId, 'createComment', json); + // 向所有参与者都添加收件箱消息 + const memberIds = _.uniq([ + topic.author, + ...topic.comments.map((c) => c.author), + ]); + + await Promise.all( + memberIds.map((memberId) => + call(ctx).appendInbox( + 'plugin:com.msgbyte.topic.comment', + json, + String(memberId) + ) + ) + ); + return true; } } diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/inbox/TopicInboxItem.tsx b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/inbox/TopicInboxItem.tsx new file mode 100644 index 00000000..3c3fc328 --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/inbox/TopicInboxItem.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { TopicCard } from '../components/TopicCard'; +import { Problem, JumpToGroupPanelButton } from '@capital/component'; +import { Translate } from '../translate'; + +export const TopicInboxItem: React.FC<{ inboxItem: any }> = React.memo( + (props) => { + const payload = props.inboxItem.payload; + if (!payload) { + return ; + } + + return ( +
+
+ +
+ + +
+ ); + } +); +TopicInboxItem.displayName = 'TopicInboxItem'; diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx index 0f3990b9..997e2cd0 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/index.tsx @@ -1,4 +1,8 @@ -import { regGroupPanel } from '@capital/common'; +import { + getMessageRender, + regGroupPanel, + regPluginInboxItemMap, +} from '@capital/common'; import { Loadable } from '@capital/component'; import { Translate } from './translate'; @@ -11,3 +15,16 @@ regGroupPanel({ render: Loadable(() => import('./group/GroupTopicPanelRender')), feature: ['subscribe', 'ack'], }); + +regPluginInboxItemMap('plugin:com.msgbyte.topic.comment', { + source: Translate.topicpanel, + getPreview: (item) => { + return { + title: Translate.topicpanel, + desc: getMessageRender(item?.payload?.content ?? ''), + }; + }, + render: Loadable(() => + import('./inbox/TopicInboxItem').then((module) => module.TopicInboxItem) + ), +}); diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts index 6585b49b..ea973c6b 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/translate.ts @@ -21,4 +21,8 @@ export const Translate = { 'zh-CN': '加载中...', 'en-US': 'Loading...', }), + topicDataError: localTrans({ + 'zh-CN': '话题信息异常', + 'en-US': 'Topic Data Error', + }), }; diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts index ceefa1fe..cae4281d 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts @@ -312,6 +312,10 @@ declare module '@capital/common' { export const regPluginSettings: any; + export const pluginInboxItemMap: any; + + export const regPluginInboxItemMap: any; + export const useGroupIdContext: () => string; export const useGroupPanelContext: () => { @@ -499,4 +503,14 @@ declare module '@capital/component' { export const Webview: any; export const WebviewKeepAlive: any; + + export const Card: any; + + export const Problem: any; + + export const JumpToButton: any; + + export const JumpToGroupPanelButton: any; + + export const JumpToConverseButton: any; }