feat: 收件箱增加message类型的消息内容渲染

pull/64/head
moonrailgun 2 years ago
parent 170a243a66
commit a9f2d00d9e

@ -140,6 +140,7 @@ export type {
GroupInvite,
GroupMember,
} from './model/group';
export type { InboxItem } from './model/inbox';
export {
sendMessage,
recallMessage,
@ -195,7 +196,7 @@ export {
useHasGroupPermission,
} from './redux/hooks/useGroupPermission';
export { useUserInfo, useUserId } from './redux/hooks/useUserInfo';
export { useInboxList } from './redux/hooks/useInboxList';
export { useInboxList, useInboxItem } from './redux/hooks/useInbox';
export { useUnread } from './redux/hooks/useUnread';
export {
userActions,

@ -108,6 +108,23 @@ export async function fetchConverseLastMessages(
return data;
}
/**
* @param converseId ID
* @param messageId ID
* @returns
*/
export async function fetchNearbyMessage(
converseId: string,
messageId: string
): Promise<ChatMessage[]> {
const { data } = await request.post('/api/chat/message/fetchNearbyMessage', {
converseId,
messageId,
});
return data;
}
/**
*
*/

@ -7,3 +7,12 @@ import { useAppSelector } from './useAppSelector';
export function useInboxList(): InboxItem[] {
return useAppSelector((state) => state.chat.inbox ?? []);
}
/**
*
*/
export function useInboxItem(inboxItemId: string): InboxItem | null {
const list = useInboxList();
return list.find((item) => item._id === inboxItemId) ?? null;
}

@ -1,5 +1,6 @@
import React from 'react';
import problemSvg from '@assets/images/problem.svg';
import { t } from 'tailchat-shared';
interface ProblemProps {
text?: React.ReactNode;
@ -13,7 +14,7 @@ export const Problem: React.FC<ProblemProps> = React.memo((props) => {
<div className="text-center w-full">
<img className="w-32 h-32 m-auto mb-2" src={problemSvg} />
<div>{props.text}</div>
<div>{props.text ?? t('出现了一些问题')}</div>
</div>
);
});

@ -0,0 +1,84 @@
import { NormalMessageList } from '@/components/ChatBox/ChatMessageList/NormalList';
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';
interface Props {
info: InboxItem;
}
export const InboxMessageContent: React.FC<Props> = React.memo((props) => {
const info = props.info;
const navigate = useNavigate();
const message = info.message;
if (!message) {
return <Problem />;
}
const { groupId, converseId, messageId } = message;
return (
<div className="w-full relative">
<NearbyMessages converseId={converseId} messageId={messageId} />
<div className="absolute bottom-4 left-0 right-0 text-center">
<div
className="shadow-lg px-6 py-2 rounded-full inline-block bg-indigo-600 hover:bg-indigo-700 text-white cursor-pointer"
onClick={() => {
if (groupId) {
// 跳转到群组
navigate(`/main/group/${groupId}/${converseId}`);
} else {
navigate(`/main/personal/converse/${converseId}`);
}
}}
>
{t('跳转到会话')}
</div>
</div>
</div>
);
});
InboxMessageContent.displayName = 'InboxMessageContent';
export const NearbyMessages: React.FC<{
converseId: string;
messageId: string;
}> = React.memo((props) => {
const { value = [], loading } = useAsync(async () => {
try {
const list = await model.message.fetchNearbyMessage(
props.converseId,
props.messageId
);
return list;
} catch (err) {
showErrorToasts(err);
console.error(err);
}
}, [props.converseId, props.messageId]);
if (loading) {
return <LoadingSpinner />;
}
return (
<div>
<NormalMessageList
messages={value}
isLoadingMore={false}
hasMoreMessage={false}
onLoadMore={async () => {}}
/>
</div>
);
});
NearbyMessages.displayName = 'NearbyMessages';

@ -0,0 +1,21 @@
import { NotFound } from '@/components/NotFound';
import React from 'react';
import { useParams } from 'react-router';
import { t, useInboxItem } from 'tailchat-shared';
import { InboxMessageContent } from './Message';
export const InboxContent: React.FC = React.memo((props) => {
const { inboxItemId } = useParams();
const inboxItem = useInboxItem(inboxItemId ?? '');
if (!inboxItem) {
return <NotFound message={t('没有找到该记录')} />;
}
if (inboxItem.type === 'message') {
return <InboxMessageContent info={inboxItem} />;
}
return <NotFound message={t('没有找到该类型的渲染方式')} />;
});
InboxContent.displayName = 'InboxContent';

@ -6,16 +6,13 @@ import _orderBy from 'lodash/orderBy';
import { GroupName } from '@/components/GroupName';
import { ConverseName } from '@/components/ConverseName';
import { getMessageRender } from '@/plugin/common';
interface InboxSidebarProps {
selectedItem: string;
onSelect: (itemId: string) => void;
}
import { useLocation } from 'react-router';
import { Link } from 'react-router-dom';
/**
*
*/
export const InboxSidebar: React.FC<InboxSidebarProps> = React.memo((props) => {
export const InboxSidebar: React.FC = React.memo(() => {
const inbox = useInboxList();
const list = useMemo(() => _orderBy(inbox, 'createdAt', 'desc'), [inbox]);
@ -41,8 +38,7 @@ export const InboxSidebar: React.FC<InboxSidebarProps> = React.memo((props) => {
title={title}
desc={getMessageRender(message.messageSnippet ?? '')}
source={'Tailchat'}
selected={props.selectedItem === item._id}
onSelect={() => props.onSelect(item._id)}
to={`/main/inbox/${item._id}`}
/>
);
}
@ -57,30 +53,32 @@ const InboxSidebarItem: React.FC<{
title: React.ReactNode;
desc: React.ReactNode;
source: string;
selected: boolean;
onSelect: () => void;
to: string;
}> = React.memo((props) => {
const location = useLocation();
const isActive = location.pathname.startsWith(props.to);
return (
<div
className={clsx(
'p-2 overflow-auto cursor-pointer hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10',
{
'bg-black bg-opacity-10 dark:bg-white dark:bg-opacity-10':
props.selected,
}
)}
onClick={props.onSelect}
>
<div className="text-lg overflow-ellipsis overflow-hidden">
{props.title || <span>&nbsp;</span>}
</div>
<div className="break-all text-opacity-80 text-black dark:text-opacity-80 dark:text-white text-sm p-1 border-l-2 border-gray-500 border-opacity-50">
{props.desc}
</div>
<div className="text-xs text-opacity-50 text-black dark:text-opacity-50 dark:text-white">
{t('来自')}: {props.source}
<Link to={props.to}>
<div
className={clsx(
'p-2 overflow-auto cursor-pointer hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10',
{
'bg-black bg-opacity-10 dark:bg-white dark:bg-opacity-10': isActive,
}
)}
>
<div className="text-lg overflow-ellipsis overflow-hidden text-gray-700 dark:text-white">
{props.title || <span>&nbsp;</span>}
</div>
<div className="break-all text-opacity-80 text-black dark:text-opacity-80 dark:text-white text-sm p-1 border-l-2 border-gray-500 border-opacity-50">
{props.desc}
</div>
<div className="text-xs text-opacity-50 text-black dark:text-opacity-50 dark:text-white">
{t('来自')}: {props.source}
</div>
</div>
</div>
</Link>
);
});
InboxSidebarItem.displayName = 'InboxSidebarItem';

@ -1,17 +1,15 @@
import React, { useState } from 'react';
import React from 'react';
import { Route, Routes } from 'react-router';
import { PageContent } from '../PageContent';
import { InboxContent } from './Content';
import { InboxSidebar } from './Sidebar';
export const Inbox: React.FC = React.memo(() => {
const [selectedItem, setSelectedItem] = useState('');
return (
<PageContent
data-tc-role="content-inbox"
sidebar={
<InboxSidebar selectedItem={selectedItem} onSelect={setSelectedItem} />
}
>
<div>Inbox {selectedItem}</div>
<PageContent data-tc-role="content-inbox" sidebar={<InboxSidebar />}>
<Routes>
<Route path="/:inboxItemId" element={<InboxContent />} />
</Routes>
</PageContent>
);
});

Loading…
Cancel
Save