diff --git a/shared/index.tsx b/shared/index.tsx index ba8103c9..21ea7e73 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -68,6 +68,7 @@ export { export { useAppSelector, useAppDispatch } from './redux/hooks/useAppSelector'; export { useDMConverseList } from './redux/hooks/useConverse'; export { useConverseMessage } from './redux/hooks/useConverseMessage'; +export { useGroupInfo } from './redux/hooks/useGroup'; export { useUserId } from './redux/hooks/useUserInfo'; export { userActions } from './redux/slices'; export type { ChatConverseState } from './redux/slices/chat'; diff --git a/shared/redux/hooks/useGroup.ts b/shared/redux/hooks/useGroup.ts new file mode 100644 index 00000000..3ed119cc --- /dev/null +++ b/shared/redux/hooks/useGroup.ts @@ -0,0 +1,9 @@ +import type { GroupInfo } from '../../model/group'; +import { useAppSelector } from './useAppSelector'; + +/** + * 获取群组信息 + */ +export function useGroupInfo(groupId: string): GroupInfo | undefined { + return useAppSelector((state) => state.group.groups[groupId]); +} diff --git a/web/src/App.tsx b/web/src/App.tsx index ba357c33..5f364aa3 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -26,7 +26,7 @@ export const App: React.FC = React.memo(() => { return (
diff --git a/web/src/components/ChatBox/index.tsx b/web/src/components/ChatBox/index.tsx index 8c9dc98c..d39812dd 100644 --- a/web/src/components/ChatBox/index.tsx +++ b/web/src/components/ChatBox/index.tsx @@ -39,7 +39,7 @@ export const ChatBox: React.FC<{ } return ( -
+
= React.memo((props) => { + const [isShow, switchShow] = useReducer((v) => !v, true); + + return ( +
+
+ +
{props.header}
+
+
+ ref?.style.setProperty('--max-height', `${ref.scrollHeight}px`) + } + > + {props.children} +
+
+ ); +}); +GroupSection.displayName = 'GroupSection'; + +const GroupPanelItem: React.FC<{ + name: string; + icon: React.ReactNode; + to: string; + badge?: boolean; +}> = React.memo((props) => { + const { icon, name, to, badge } = props; + const location = useLocation(); + const isActive = location.pathname.startsWith(to); + + return ( + +
+
{icon}
+ + + {name} + + + {badge === true ? ( + + ) : ( + + )} +
+ + ); +}); +GroupPanelItem.displayName = 'GroupPanelItem'; + +/** + * 个人面板侧边栏组件 + */ +export const Sidebar: React.FC = React.memo(() => { + const { groupId } = useParams(); + const groupInfo = useGroupInfo(groupId); + const groupPanels = groupInfo?.panels ?? []; + + return ( +
+ {groupPanels + .filter((panel) => panel.type === GroupPanelType.GROUP) + .map((group) => ( + + {groupPanels + .filter((panel) => panel.parentId === group.id) + .map((panel) => ( + #
} + to={`/main/group/${groupId}/${panel.id}`} + /> + ))} + + ))} +
+ ); +}); +Sidebar.displayName = 'Sidebar'; diff --git a/web/src/routes/Main/Content/Group/index.tsx b/web/src/routes/Main/Content/Group/index.tsx new file mode 100644 index 00000000..433b1958 --- /dev/null +++ b/web/src/routes/Main/Content/Group/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { PageContent } from '../PageContent'; +import { Sidebar } from './Sidebar'; + +export const Group: React.FC = React.memo(() => { + return ( + }> +
TODO
+
+ ); +}); +Group.displayName = 'Group'; diff --git a/web/src/routes/Main/Content/index.tsx b/web/src/routes/Main/Content/index.tsx index 84233b55..efe6a8e6 100644 --- a/web/src/routes/Main/Content/index.tsx +++ b/web/src/routes/Main/Content/index.tsx @@ -1,17 +1,13 @@ import React from 'react'; import { Personal } from './Personal'; import { Route, Switch, Redirect } from 'react-router-dom'; +import { Group } from './Group'; export const MainContent: React.FC = React.memo(() => { return ( - {/* - - - - - */} + ); diff --git a/web/src/routes/Main/Navbar/GroupNav.tsx b/web/src/routes/Main/Navbar/GroupNav.tsx index 9c3bbd36..c3d31ab5 100644 --- a/web/src/routes/Main/Navbar/GroupNav.tsx +++ b/web/src/routes/Main/Navbar/GroupNav.tsx @@ -3,6 +3,7 @@ import { openModal } from '@/components/Modal'; import { ModalCreateGroup } from '@/components/modals/CreateGroup'; import { Icon } from '@iconify/react'; import React, { useCallback, useMemo } from 'react'; +import { useHistory } from 'react-router'; import { GroupInfo, useAppSelector } from 'tailchat-shared'; import { NavbarNavItem } from './NavItem'; @@ -16,6 +17,11 @@ function useGroups(): GroupInfo[] { export const GroupNav: React.FC = React.memo(() => { const groups = useGroups(); + const history = useHistory(); + + const handleToGroup = useCallback((groupId: string) => { + history.push(`/main/group/${groupId}`); + }, []); const handleCreateGroup = useCallback(() => { openModal(); @@ -25,7 +31,10 @@ export const GroupNav: React.FC = React.memo(() => {
{Array.isArray(groups) && groups.map((group) => ( - + handleToGroup(group._id)} + > { const userInfo = useAppSelector((state) => state.user.info); + const history = useHistory(); return (
{/* Navbar */}
- + history.push('/main/personal')}>