feat: group preview component

feat/group-preview
moonrailgun 2 years ago
parent 0d21980e40
commit 030adfa4b3

@ -55,13 +55,13 @@ export class AppSocket {
if (resp.result === true) {
resolve(resp.data);
} else if (resp.result === false) {
reject(
new SocketEventError(
`[${eventName}]: ${resp.message}: \ndata: ${JSON.stringify(
eventData
)}`
)
const error = new SocketEventError(
`[${eventName}]: ${resp.message}: \ndata: ${JSON.stringify(
eventData
)}`
);
console.error(error);
reject(error);
}
});
});

@ -59,6 +59,14 @@ const InviteRoute = Loadable(
)
);
const PreviewRoute = Loadable(
() =>
import(
/* webpackChunkName: 'preview' */ /* webpackPreload: true */
'./routes/Preview'
)
);
export const TcAntdProvider: React.FC<PropsWithChildren> = React.memo(
(props) => {
const { value: locale } = useAsync(async (): Promise<Locale> => {
@ -168,6 +176,7 @@ export const App: React.FC = React.memo(() => {
<Route path="/main/*" element={<MainRoute />} />
<Route path="/panel/*" element={<PanelRoute />} />
<Route path="/invite/:inviteCode" element={<InviteRoute />} />
<Route path="/preview/*" element={<PreviewRoute />} />
<Route
path="/plugin/*"
element={

@ -0,0 +1,14 @@
import React from 'react';
import { useSocket } from './useSocket';
/**
* A Component for Group Preview Entry
*/
export const GroupPreview: React.FC<{
groupId: string;
}> = React.memo((props) => {
useSocket(props.groupId);
return null;
});
GroupPreview.displayName = 'GroupPreview';

@ -0,0 +1,19 @@
import React from 'react';
import { ChatMessageList } from '../ChatBox/ChatMessageList';
interface GroupPreviewMessageListProps {
groupId: string;
converseId: string;
}
export const GroupPreviewMessageList: React.FC<GroupPreviewMessageListProps> =
React.memo(() => {
return (
<ChatMessageList
messages={[]}
isLoadingMore={false}
hasMoreMessage={false}
onLoadMore={async () => {}}
/>
);
});
GroupPreviewMessageList.displayName = 'GroupPreviewMessageList';

@ -0,0 +1,3 @@
Preview Group Message like Discord.
NOTICE: GroupPreview should has independent context because its should can run in non-main page.

@ -0,0 +1 @@
export { GroupPreview } from './GroupPreview';

@ -0,0 +1,29 @@
import { create } from 'zustand';
import type { model } from 'tailchat-shared';
interface ChatConverseState extends model.converse.ChatConverseInfo {
messages: model.message.LocalChatMessage[];
}
interface GroupPreviewState {
groupInfo: model.group.GroupInfo | null;
converses: Record<string, ChatConverseState>;
}
function getDefaultState() {
return {
groupInfo: null,
converses: {},
};
}
export const useGroupPreviewStore = create<GroupPreviewState>((get) => ({
...getDefaultState(),
}));
/**
*
*/
export function resetGroupPreviewState() {
useGroupPreviewStore.setState(getDefaultState());
}

@ -0,0 +1,41 @@
import { useSocketContext } from '@/context/SocketContext';
import { useEffect } from 'react';
import { GroupInfo, GroupPanelType } from 'tailchat-shared';
import { resetGroupPreviewState, useGroupPreviewStore } from './store';
export function useSocket(groupId: string) {
const socket = useSocketContext();
useEffect(() => {
socket.request('group.preview.joinGroupRooms', {
groupId,
});
socket
.request<GroupInfo>('group.preview.getGroupInfo', {
groupId,
})
.then((groupInfo) => {
console.log('groupInfo', groupInfo);
useGroupPreviewStore.setState({
groupInfo,
});
if (Array.isArray(groupInfo.panels)) {
const textPanels = groupInfo.panels.map(
(p) => p.type === GroupPanelType.TEXT
);
// TODO
}
});
return () => {
socket.request('group.preview.leaveGroupRooms', {
groupId,
});
resetGroupPreviewState();
};
}, [groupId]);
}

@ -0,0 +1,34 @@
import { GroupPreview } from '@/components/GroupPreview';
import { NotFound } from '@/components/NotFound';
import React from 'react';
import { Route, Routes, useParams } from 'react-router';
import { t } from 'tailchat-shared';
import { MainProvider } from '../Main/Provider';
const PreviewRoute: React.FC = React.memo(() => {
return (
<MainProvider>
<Routes>
<Route path="/:groupId" element={<GroupPreviewRoute />} />
<Route path="/*" element={t('未知的页面')} />
</Routes>
</MainProvider>
);
});
PreviewRoute.displayName = 'PreviewRoute';
const GroupPreviewRoute: React.FC = React.memo(() => {
const { groupId } = useParams<{
groupId: string;
}>();
if (!groupId) {
return <NotFound />;
}
return <GroupPreview groupId={groupId} />;
});
GroupPreviewRoute.displayName = 'GroupPreviewRoute';
export default PreviewRoute;

@ -25,6 +25,7 @@ import {
db,
} from 'tailchat-server-sdk';
import moment from 'moment';
import type { GroupStruct } from 'tailchat-server-sdk';
interface GroupService
extends TcService,
@ -48,6 +49,7 @@ class GroupService extends TcService {
'getJoinedGroupAndPanelIds',
this.getJoinedGroupAndPanelIds
);
this.registerAction('getGroupSocketRooms', this.getGroupSocketRooms);
this.registerAction('getGroupBasicInfo', this.getGroupBasicInfo, {
params: {
groupId: 'string',
@ -234,7 +236,7 @@ class GroupService extends TcService {
*
* socket
*/
private getSubscribedGroupPanelIds(group: Group): {
private getSubscribedGroupPanelIds(group: GroupStruct): {
textPanelIds: string[];
subscribeFeaturePanelIds: string[];
} {
@ -254,7 +256,7 @@ class GroupService extends TcService {
* id
*
*/
private getGroupTextPanelIds(group: Group): string[] {
private getGroupTextPanelIds(group: GroupStruct): string[] {
// TODO: 先无视权限, 把所有的信息全部显示
const textPanelIds = group.panels
.filter((p) => p.type === GroupPanelType.TEXT)
@ -268,7 +270,7 @@ class GroupService extends TcService {
* @param group
*/
private getGroupPanelIdsWithFeature(
group: Group,
group: GroupStruct,
feature: PanelFeature
): string[] {
const featureAllPanelNames = this.getPanelNamesWithFeature(feature);
@ -301,12 +303,14 @@ class GroupService extends TcService {
throw new NoPermissionError(t('创建群组功能已被管理员禁用'));
}
const group = await this.adapter.model.createGroup({
const doc = await this.adapter.model.createGroup({
name,
panels,
owner: userId,
});
const group = await this.transformDocuments(ctx, {}, doc);
const { textPanelIds, subscribeFeaturePanelIds } =
this.getSubscribedGroupPanelIds(group);
@ -315,10 +319,10 @@ class GroupService extends TcService {
userId
);
return this.transformDocuments(ctx, {}, group);
return group;
}
async getUserGroups(ctx: TcContext): Promise<Group[]> {
async getUserGroups(ctx: TcContext): Promise<GroupStruct[]> {
const userId = ctx.meta.userId;
const groups = await this.adapter.model.getUserGroups(userId);
@ -351,6 +355,20 @@ class GroupService extends TcService {
};
}
/**
*
*/
async getGroupSocketRooms(ctx: TcContext<{ groupId: string }>): Promise<{
textPanelIds: string[];
subscribeFeaturePanelIds: string[];
}> {
const groupId = ctx.params.groupId;
const group = await call(ctx).getGroupInfo(groupId);
return this.getSubscribedGroupPanelIds(group);
}
/**
*
*/
@ -550,7 +568,7 @@ class GroupService extends TcService {
)
.exec();
const group: Group = await this.transformDocuments(ctx, {}, doc);
const group: GroupStruct = await this.transformDocuments(ctx, {}, doc);
this.notifyGroupInfoUpdate(ctx, group); // 推送变更
this.unicastNotify(ctx, userId, 'add', group);
@ -1241,13 +1259,15 @@ class GroupService extends TcService {
*/
private async notifyGroupInfoUpdate(
ctx: TcContext,
group: Group
): Promise<Group> {
group: Group | GroupStruct
): Promise<GroupStruct> {
const groupId = String(group._id);
let json = group;
let json: GroupStruct;
if (_.isPlainObject(group) === false) {
// 当传入的数据为group doc时
json = await this.transformDocuments(ctx, {}, group);
} else {
json = group as any;
}
this.cleanGroupInfoCache(groupId);

@ -0,0 +1,78 @@
import { TcService, TcContext, call } from 'tailchat-server-sdk';
class GroupPreviewService extends TcService {
get serviceName(): string {
return 'group.preview';
}
onInit(): void {
/**
* TODO: action
*/
this.registerAction('joinGroupRooms', this.joinGroupRooms, {
params: {
groupId: 'string',
},
});
this.registerAction('leaveGroupRooms', this.leaveGroupRooms, {
params: {
groupId: 'string',
},
});
this.registerAction('getGroupInfo', this.getGroupInfo, {
params: {
groupId: 'string',
},
});
}
async joinGroupRooms(ctx: TcContext<{ groupId: string }>) {
const groupId = ctx.params.groupId;
const { textPanelIds, subscribeFeaturePanelIds } = await ctx.call<
{
textPanelIds: string[];
subscribeFeaturePanelIds: string[];
},
{ groupId: string }
>('group.getGroupSocketRooms', {
groupId,
});
await call(ctx).joinSocketIORoom([
groupId,
...textPanelIds,
...subscribeFeaturePanelIds,
]);
}
async leaveGroupRooms(ctx: TcContext<{ groupId: string }>) {
const groupId = ctx.params.groupId;
const { textPanelIds, subscribeFeaturePanelIds } = await ctx.call<
{
textPanelIds: string[];
subscribeFeaturePanelIds: string[];
},
{ groupId: string }
>('group.getGroupSocketRooms', {
groupId,
});
await call(ctx).leaveSocketIORoom([
groupId,
...textPanelIds,
...subscribeFeaturePanelIds,
]);
}
async getGroupInfo(ctx: TcContext<{ groupId: string }>) {
const groupId = ctx.params.groupId;
const groupInfo = await call(ctx).getGroupInfo(groupId);
return groupInfo;
}
}
export default GroupPreviewService;
Loading…
Cancel
Save