refactor(shared): 群组列表获取与展示

pull/13/head
moonrailgun 4 years ago
parent 229a037275
commit fc3d9ae06f

@ -51,6 +51,7 @@ export {
denyFriendRequest,
} from './model/friend';
export type { FriendRequest } from './model/friend';
export type { GroupInfo } from './model/group';
export type { ChatMessage } from './model/message';
export type { UserBaseInfo, UserLoginInfo } from './model/user';
export {

@ -0,0 +1,25 @@
export enum GroupPanelType {
TEXT = 0,
GROUP = 1,
}
export interface GroupMember {
role: string; // 角色
userId: string;
}
export interface GroupPanel {
id: string; // 在群组中唯一
name: string;
parentId?: string;
type: GroupPanelType;
}
export interface GroupInfo {
_id: string;
name: string;
avatar?: string;
creator: string;
members: GroupMember[];
panels: GroupPanel[];
}

@ -1,12 +1,14 @@
import type { AppStore } from './store';
import type { AppSocket } from '../api/socket';
import { chatActions, userActions } from './slices';
import { chatActions, groupActions, userActions } from './slices';
import type { FriendRequest } from '../model/friend';
import type { UserDMList } from '../model/user';
import { getCachedConverseInfo } from '../cache/cache';
import type { GroupInfo } from '../model/group';
/**
* Redux
* Redux
* Redux
*/
export function setupRedux(socket: AppSocket, store: AppStore) {
initial(socket, store);
@ -37,6 +39,10 @@ function initial(socket: AppSocket, store: AppStore) {
store.dispatch(chatActions.setConverseInfo(converse));
});
});
socket.request<GroupInfo[]>('group.getUserGroups').then((groups) => {
store.dispatch(groupActions.appendGroups(groups));
});
}
/**

@ -0,0 +1,30 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import type { GroupInfo } from '../../model/group';
interface GroupState {
groups: Record<string, GroupInfo>;
}
const initialState: GroupState = {
groups: {},
};
const groupSlice = createSlice({
name: 'group',
initialState,
reducers: {
appendGroups(state, action: PayloadAction<GroupInfo[]>) {
const groups = action.payload;
for (const group of groups) {
state.groups[group._id] = {
...state.groups[group._id],
...group,
};
}
},
},
});
export const groupActions = groupSlice.actions;
export const groupReducer = groupSlice.reducer;

@ -1,13 +1,16 @@
import { combineReducers } from '@reduxjs/toolkit';
import { userReducer } from './user';
import { chatReducer } from './chat';
import { groupReducer } from './group';
export const appReducer = combineReducers({
user: userReducer,
chat: chatReducer,
group: groupReducer,
});
export type AppState = ReturnType<typeof appReducer>;
export { userActions } from './user';
export { chatActions } from './chat';
export { groupActions } from './group';

@ -0,0 +1,39 @@
import { Avatar } from '@/components/Avatar';
import { Icon } from '@iconify/react';
import React, { useMemo } from 'react';
import { GroupInfo, useAppSelector } from 'tailchat-shared';
import { NavbarNavItem } from './NavItem';
function useGroups(): GroupInfo[] {
const groups = useAppSelector((state) => state.group.groups);
return useMemo(
() => Object.entries(groups).map(([_, group]) => group),
[groups]
);
}
export const GroupNav: React.FC = React.memo(() => {
const groups = useGroups();
return (
<div className="space-y-2">
{Array.isArray(groups) &&
groups.map((group) => (
<NavbarNavItem key={group._id}>
<Avatar
shape="square"
size={48}
name={group.name}
src={group.avatar}
/>
</NavbarNavItem>
))}
{/* 创建群组 */}
<NavbarNavItem className="bg-green-500">
<Icon className="text-3xl text-white" icon="mdi-plus" />
</NavbarNavItem>
</div>
);
});
GroupNav.displayName = 'GroupNav';

@ -0,0 +1,19 @@
import type { ClassValue } from 'clsx';
import clsx from 'clsx';
import React from 'react';
export const NavbarNavItem: React.FC<{
className?: ClassValue;
}> = React.memo((props) => {
return (
<div
className={clsx(
'w-12 h-12 hover:rounded-lg bg-gray-300 transition-all rounded-1/2 cursor-pointer flex items-center justify-center overflow-hidden',
props.className
)}
>
{props.children}
</div>
);
});
NavbarNavItem.displayName = 'NavbarNavItem';

@ -1,24 +1,9 @@
import React from 'react';
import { useAppSelector } from 'tailchat-shared';
import { Icon } from '@iconify/react';
import clsx, { ClassValue } from 'clsx';
import { Avatar } from '../../components/Avatar';
const NavbarNavItem: React.FC<{
className?: ClassValue;
}> = React.memo((props) => {
return (
<div
className={clsx(
'w-12 h-12 hover:rounded-lg bg-gray-300 transition-all rounded-1/2 cursor-pointer flex items-center justify-center overflow-hidden',
props.className
)}
>
{props.children}
</div>
);
});
NavbarNavItem.displayName = 'NavbarNavItem';
import { Avatar } from '@/components/Avatar';
import { NavbarNavItem } from './NavItem';
import { GroupNav } from './GroupNav';
/**
*
@ -39,15 +24,8 @@ export const Navbar: React.FC = React.memo(() => {
/>
</NavbarNavItem>
<div className="h-px w-full bg-white mt-4 mb-4"></div>
<div className="space-y-2">
<NavbarNavItem />
<NavbarNavItem />
<NavbarNavItem />
<NavbarNavItem />
<NavbarNavItem className="bg-green-500">
<Icon className="text-3xl text-white" icon="mdi-plus" />
</NavbarNavItem>
</div>
<GroupNav />
</div>
<div>
<Icon
Loading…
Cancel
Save