feat: 收件箱增加已读未读标识

pull/64/head
moonrailgun 2 years ago
parent db64ed45d4
commit af03bec1a9

@ -202,6 +202,7 @@ export {
userActions, userActions,
groupActions, groupActions,
uiActions, uiActions,
chatActions,
globalActions, globalActions,
} from './redux/slices'; } from './redux/slices';
export type { ChatConverseState } from './redux/slices/chat'; export type { ChatConverseState } from './redux/slices/chat';

@ -1,3 +1,5 @@
import { request } from '../api/request';
/** /**
* *
*/ */
@ -15,3 +17,9 @@ export interface InboxItem {
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
export async function setInboxAck(inboxItemId: string) {
await request.post('/api/chat/inbox/ack', {
inboxItemId,
});
}

@ -322,6 +322,17 @@ const chatSlice = createSlice({
const list = action.payload; const list = action.payload;
state.inbox = list; state.inbox = list;
}, },
/**
*
*/
setInboxItemAck(state, action: PayloadAction<string>) {
const inboxItemId = action.payload;
const item = state.inbox.find((item) => item._id === inboxItemId);
if (item) {
item.readed = true;
}
},
}, },
}); });

@ -1,13 +1,22 @@
import { NotFound } from '@/components/NotFound'; import { NotFound } from '@/components/NotFound';
import React from 'react'; import React from 'react';
import { useParams } from 'react-router'; import { useParams } from 'react-router';
import { t, useInboxItem } from 'tailchat-shared'; import {
model,
t,
useAppDispatch,
useInboxItem,
useWatch,
} from 'tailchat-shared';
import { chatActions } from 'tailchat-shared';
import { InboxMessageContent } from './Message'; import { InboxMessageContent } from './Message';
export const InboxContent: React.FC = React.memo((props) => { export const InboxContent: React.FC = React.memo((props) => {
const { inboxItemId } = useParams(); const { inboxItemId } = useParams();
const inboxItem = useInboxItem(inboxItemId ?? ''); const inboxItem = useInboxItem(inboxItemId ?? '');
useInboxAck(inboxItemId ?? '');
if (!inboxItem) { if (!inboxItem) {
return <NotFound message={t('没有找到该记录')} />; return <NotFound message={t('没有找到该记录')} />;
} }
@ -19,3 +28,19 @@ export const InboxContent: React.FC = React.memo((props) => {
return <NotFound message={t('没有找到该类型的渲染方式')} />; return <NotFound message={t('没有找到该类型的渲染方式')} />;
}); });
InboxContent.displayName = 'InboxContent'; InboxContent.displayName = 'InboxContent';
function useInboxAck(inboxItemId: string) {
const dispatch = useAppDispatch();
const item = useInboxItem(inboxItemId);
useWatch([inboxItemId], () => {
if (!item) {
return;
}
if (item.readed === false) {
dispatch(chatActions.setInboxItemAck(inboxItemId));
model.inbox.setInboxAck(inboxItemId);
}
});
}

@ -1,6 +1,6 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { CommonSidebarWrapper } from '@/components/CommonSidebarWrapper'; import { CommonSidebarWrapper } from '@/components/CommonSidebarWrapper';
import { isValidStr, model, t, useInboxList } from 'tailchat-shared'; import { InboxItem, isValidStr, model, t, useInboxList } from 'tailchat-shared';
import clsx from 'clsx'; import clsx from 'clsx';
import _orderBy from 'lodash/orderBy'; import _orderBy from 'lodash/orderBy';
import { GroupName } from '@/components/GroupName'; import { GroupName } from '@/components/GroupName';
@ -8,6 +8,7 @@ import { ConverseName } from '@/components/ConverseName';
import { getMessageRender } from '@/plugin/common'; import { getMessageRender } from '@/plugin/common';
import { useLocation } from 'react-router'; import { useLocation } from 'react-router';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { PillTabPane, PillTabs } from '@/components/PillTabs';
/** /**
* *
@ -16,10 +17,7 @@ export const InboxSidebar: React.FC = React.memo(() => {
const inbox = useInboxList(); const inbox = useInboxList();
const list = useMemo(() => _orderBy(inbox, 'createdAt', 'desc'), [inbox]); const list = useMemo(() => _orderBy(inbox, 'createdAt', 'desc'), [inbox]);
return ( const renderInbox = (item: InboxItem) => {
<CommonSidebarWrapper data-tc-role="sidebar-inbox">
<div className="overflow-auto">
{list.map((item) => {
const { type } = item; const { type } = item;
if (type === 'message') { if (type === 'message') {
@ -38,11 +36,29 @@ export const InboxSidebar: React.FC = React.memo(() => {
title={title} title={title}
desc={getMessageRender(message.messageSnippet ?? '')} desc={getMessageRender(message.messageSnippet ?? '')}
source={'Tailchat'} source={'Tailchat'}
readed={item.readed}
to={`/main/inbox/${item._id}`} to={`/main/inbox/${item._id}`}
/> />
); );
} }
})}
return null;
};
const fullList = list;
const unreadList = list.filter((item) => item.readed === false);
return (
<CommonSidebarWrapper data-tc-role="sidebar-inbox">
<div>
<PillTabs>
<PillTabPane key="1" tab={`${t('全部')} (${fullList.length})`}>
{fullList.map((item) => renderInbox(item))}
</PillTabPane>
<PillTabPane key="2" tab={`${t('未读')} (${unreadList.length})`}>
{unreadList.map((item) => renderInbox(item))}
</PillTabPane>
</PillTabs>
</div> </div>
</CommonSidebarWrapper> </CommonSidebarWrapper>
); );
@ -53,6 +69,7 @@ const InboxSidebarItem: React.FC<{
title: React.ReactNode; title: React.ReactNode;
desc: React.ReactNode; desc: React.ReactNode;
source: string; source: string;
readed: boolean;
to: string; to: string;
}> = React.memo((props) => { }> = React.memo((props) => {
const location = useLocation(); const location = useLocation();
@ -62,10 +79,11 @@ const InboxSidebarItem: React.FC<{
<Link to={props.to}> <Link to={props.to}>
<div <div
className={clsx( className={clsx(
'p-2 overflow-auto cursor-pointer hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10', 'p-2 overflow-auto cursor-pointer hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10 border-r-4 rounded',
{ {
'bg-black bg-opacity-10 dark:bg-white dark:bg-opacity-10': isActive, 'bg-black bg-opacity-10 dark:bg-white dark:bg-opacity-10': isActive,
} },
props.readed ? 'border-transparent' : 'border-green-500'
)} )}
> >
<div className="text-lg overflow-ellipsis overflow-hidden text-gray-700 dark:text-white"> <div className="text-lg overflow-ellipsis overflow-hidden text-gray-700 dark:text-white">

Loading…
Cancel
Save