feat: 增加收件箱操作: 全部已读和清空收件箱

pull/64/head
moonrailgun 2 years ago
parent b74b956e45
commit 677cf7689b

@ -18,8 +18,18 @@ export interface InboxItem {
updatedAt: string;
}
export async function setInboxAck(inboxItemId: string) {
/**
*
*/
export async function setInboxAck(inboxItemIds: string[]) {
await request.post('/api/chat/inbox/ack', {
inboxItemId,
inboxItemIds,
});
}
/**
*
*/
export async function clearInbox() {
await request.post('/api/chat/inbox/clear');
}

@ -269,6 +269,10 @@ function listenNotify(socket: AppSocket, store: AppStore) {
store.dispatch(groupActions.removeGroup(groupId));
});
socket.listen<InboxItem>('chat.inbox.append', (item) => {
store.dispatch(chatActions.appendInboxItem(item));
});
socket.listen('chat.inbox.updated', () => {
// 检测到收件箱列表被更新,需要重新获取
socket.request<InboxItem[]>('chat.inbox.all').then((list) => {

@ -314,7 +314,6 @@ const chatSlice = createSlice({
);
message.reactions.splice(reactionIndex, 1);
},
/**
*
*/
@ -322,6 +321,13 @@ const chatSlice = createSlice({
const list = action.payload;
state.inbox = list;
},
/**
*
*/
appendInboxItem(state, action: PayloadAction<InboxItem>) {
state.inbox.push(action.payload);
},
/**
*
*/

@ -11,6 +11,9 @@ import {
import { chatActions } from 'tailchat-shared';
import { InboxMessageContent } from './Message';
/**
*
*/
export const InboxContent: React.FC = React.memo((props) => {
const { inboxItemId } = useParams();
const inboxItem = useInboxItem(inboxItemId ?? '');
@ -40,7 +43,7 @@ function useInboxAck(inboxItemId: string) {
if (item.readed === false) {
dispatch(chatActions.setInboxItemAck(inboxItemId));
model.inbox.setInboxAck(inboxItemId);
model.inbox.setInboxAck([inboxItemId]);
}
});
}

@ -1,6 +1,15 @@
import React, { useMemo } from 'react';
import { CommonSidebarWrapper } from '@/components/CommonSidebarWrapper';
import { InboxItem, isValidStr, model, t, useInboxList } from 'tailchat-shared';
import {
chatActions,
InboxItem,
isValidStr,
model,
t,
useAppDispatch,
useAsyncRequest,
useInboxList,
} from 'tailchat-shared';
import clsx from 'clsx';
import _orderBy from 'lodash/orderBy';
import { GroupName } from '@/components/GroupName';
@ -10,6 +19,7 @@ import { useLocation } from 'react-router';
import { Link } from 'react-router-dom';
import { PillTabPane, PillTabs } from '@/components/PillTabs';
import { SectionHeader } from '@/components/SectionHeader';
import { openReconfirmModalP } from '@/components/Modal';
const buildLink = (itemId: string) => `/main/inbox/${itemId}`;
@ -19,6 +29,7 @@ const buildLink = (itemId: string) => `/main/inbox/${itemId}`;
export const InboxSidebar: React.FC = React.memo(() => {
const inbox = useInboxList();
const list = useMemo(() => _orderBy(inbox, 'createdAt', 'desc'), [inbox]);
const dispatch = useAppDispatch();
const renderInbox = (item: InboxItem) => {
if (item.type === 'message') {
@ -49,9 +60,44 @@ export const InboxSidebar: React.FC = React.memo(() => {
const fullList = list;
const unreadList = list.filter((item) => item.readed === false);
const [, handleAllAck] = useAsyncRequest(async () => {
unreadList.forEach((item) => {
dispatch(chatActions.setInboxItemAck(item._id));
});
await model.inbox.setInboxAck(unreadList.map((item) => item._id));
}, [unreadList]);
const [, handleClear] = useAsyncRequest(async () => {
const res = await openReconfirmModalP({
title: t('确认清空收件箱么?'),
});
if (res) {
await model.inbox.clearInbox();
}
}, [unreadList]);
return (
<CommonSidebarWrapper data-tc-role="sidebar-inbox">
<SectionHeader>{t('收件箱')}</SectionHeader>
<SectionHeader
menu={{
items: [
{
key: 'readAll',
label: t('所有已读'),
onClick: handleAllAck,
},
{
key: 'clear',
label: t('清空收件箱'),
danger: true,
onClick: handleClear,
},
],
}}
>
{t('收件箱')}
</SectionHeader>
<div>
<PillTabs>

@ -21,7 +21,7 @@ Inbox.displayName = 'Inbox';
const InboxNoSelect: React.FC = React.memo(() => {
return (
<div className="mt-11 w-full">
<Problem text={t('空空的,什么都没有选中')} />
<Problem text={t('提及(@)您的消息会在这里出现哦')} />
</div>
);
});

@ -52,8 +52,6 @@ class InboxService extends TcService {
})
);
}
this.notifyUsersInboxUpdate(ctx, mentions);
}
}
);
@ -80,9 +78,10 @@ class InboxService extends TcService {
this.registerAction('all', this.all);
this.registerAction('ack', this.ack, {
params: {
inboxItemId: 'string',
inboxItemIds: { type: 'array', items: 'string' },
},
});
this.registerAction('clear', this.clear);
}
async appendMessage(
@ -102,7 +101,7 @@ class InboxService extends TcService {
messageSnippet,
} = ctx.params;
await this.adapter.model.create({
const doc = await this.adapter.model.create({
userId,
type: 'message',
message: {
@ -113,6 +112,10 @@ class InboxService extends TcService {
},
});
const inboxItem = await this.transformDocuments(ctx, {}, doc);
await this.notifyUsersInboxAppend(ctx, [userId], inboxItem);
return true;
}
@ -141,6 +144,8 @@ class InboxService extends TcService {
},
});
await this.notifyUsersInboxUpdate(ctx, [userId]); // not good, 后面最好修改为发送删除的项而不是所有
return true;
}
@ -160,13 +165,15 @@ class InboxService extends TcService {
/**
*
*/
async ack(ctx: TcContext<{ inboxItemId: string }>) {
const inboxItemId = ctx.params.inboxItemId;
async ack(ctx: TcContext<{ inboxItemIds: string[] }>) {
const inboxItemIds = ctx.params.inboxItemIds;
const userId = ctx.meta.userId;
await this.adapter.model.updateOne(
await this.adapter.model.updateMany(
{
_id: inboxItemId,
_id: {
$in: [...inboxItemIds],
},
userId,
},
{
@ -177,6 +184,34 @@ class InboxService extends TcService {
return true;
}
/**
*
*/
async clear(ctx: TcContext) {
const userId = ctx.meta.userId;
await this.adapter.model.deleteMany({
userId,
});
await this.notifyUsersInboxUpdate(ctx, [userId]);
return true;
}
/**
*
*
*
*/
private async notifyUsersInboxAppend(
ctx: TcPureContext,
userIds: string[],
data: any
): Promise<void> {
await this.listcastNotify(ctx, userIds, 'append', { ...data });
}
/**
*
*

Loading…
Cancel
Save