mirror of https://github.com/msgbyte/tailchat
refactor(shared): 群组列表获取与展示
parent
229a037275
commit
fc3d9ae06f
@ -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[];
|
||||||
|
}
|
@ -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 { combineReducers } from '@reduxjs/toolkit';
|
||||||
import { userReducer } from './user';
|
import { userReducer } from './user';
|
||||||
import { chatReducer } from './chat';
|
import { chatReducer } from './chat';
|
||||||
|
import { groupReducer } from './group';
|
||||||
|
|
||||||
export const appReducer = combineReducers({
|
export const appReducer = combineReducers({
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
chat: chatReducer,
|
chat: chatReducer,
|
||||||
|
group: groupReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AppState = ReturnType<typeof appReducer>;
|
export type AppState = ReturnType<typeof appReducer>;
|
||||||
|
|
||||||
export { userActions } from './user';
|
export { userActions } from './user';
|
||||||
export { chatActions } from './chat';
|
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';
|
Loading…
Reference in New Issue