refactor: refactor group panel wrapper, extract shared logic

Its make ready for hide navbar in mobile
pull/90/head
moonrailgun 2 years ago
parent 4a842fd161
commit 7a4d55ea61

@ -42,6 +42,7 @@
"k267cc491": "Me", "k267cc491": "Me",
"k2a1422d2": "Configuration", "k2a1422d2": "Configuration",
"k2a8031e": "Homepage", "k2a8031e": "Homepage",
"k2b411a11": "Component can only work in the group panel",
"k2c6ee8d": "Confirm the action", "k2c6ee8d": "Confirm the action",
"k2c7df74f": "Modify Group Panel", "k2c7df74f": "Modify Group Panel",
"k2d6cfb27": "Chat Channel", "k2d6cfb27": "Chat Channel",
@ -313,6 +314,7 @@
"ke071c620": "Allow members to manage users, such as banning, removing users, etc.", "ke071c620": "Allow members to manage users, such as banning, removing users, etc.",
"ke17b2c87": "Do not upload pictures that violate local laws and regulations", "ke17b2c87": "Do not upload pictures that violate local laws and regulations",
"ke187440d": "Panel type cannot be empty", "ke187440d": "Panel type cannot be empty",
"ke2431c67": "Plugin render function does not exist",
"ke3d797fd": "Drop files to send into current converse", "ke3d797fd": "Drop files to send into current converse",
"ke59ffe49": "Muted, there are {{remain}} left", "ke59ffe49": "Muted, there are {{remain}} left",
"kea977d95": "The following users are offline", "kea977d95": "The following users are offline",

@ -42,6 +42,7 @@
"k267cc491": "我", "k267cc491": "我",
"k2a1422d2": "配置", "k2a1422d2": "配置",
"k2a8031e": "个人主页", "k2a8031e": "个人主页",
"k2b411a11": "组件只能在群组面板中才能正常显示",
"k2c6ee8d": "确认操作", "k2c6ee8d": "确认操作",
"k2c7df74f": "编辑群组面板", "k2c7df74f": "编辑群组面板",
"k2d6cfb27": "聊天频道", "k2d6cfb27": "聊天频道",
@ -313,6 +314,7 @@
"ke071c620": "允许成员管理用户,如禁言、移除用户等操作", "ke071c620": "允许成员管理用户,如禁言、移除用户等操作",
"ke17b2c87": "请勿上传违反当地法律法规的图片", "ke17b2c87": "请勿上传违反当地法律法规的图片",
"ke187440d": "面板类型不能为空", "ke187440d": "面板类型不能为空",
"ke2431c67": "插件渲染函数不存在",
"ke3d797fd": "拖放文件以发送到当前会话", "ke3d797fd": "拖放文件以发送到当前会话",
"ke59ffe49": "禁言中, 还剩 {{remain}}", "ke59ffe49": "禁言中, 还剩 {{remain}}",
"kea977d95": "以下用户已离线", "kea977d95": "以下用户已离线",

@ -12,11 +12,11 @@ interface RightPanelType {
/** /**
* *
*/ */
interface CommonPanelWrapperProps extends PropsWithChildren { export interface CommonPanelWrapperProps extends PropsWithChildren {
header: React.ReactNode; header: React.ReactNode;
actions?: ( actions?: (ctx: {
setRightPanel: (info: RightPanelType) => void setRightPanel: (info: RightPanelType) => void;
) => React.ReactElement[]; }) => React.ReactElement[];
} }
export const CommonPanelWrapper: React.FC<CommonPanelWrapperProps> = React.memo( export const CommonPanelWrapper: React.FC<CommonPanelWrapperProps> = React.memo(
(props) => { (props) => {
@ -33,7 +33,7 @@ export const CommonPanelWrapper: React.FC<CommonPanelWrapperProps> = React.memo(
{/* 主面板 */} {/* 主面板 */}
<div className="flex flex-col overflow-hidden flex-1"> <div className="flex flex-col overflow-hidden flex-1">
<PanelCommonHeader <PanelCommonHeader
actions={props.actions && props.actions(setRightPanel)} actions={props.actions && props.actions({ setRightPanel })}
> >
{props.header} {props.header}
</PanelCommonHeader> </PanelCommonHeader>

@ -2,7 +2,6 @@ import { findPluginPanelInfoByName } from '@/utils/plugin-helper';
import { Alert } from 'antd'; import { Alert } from 'antd';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { isValidStr, t, useGroupPanelInfo } from 'tailchat-shared'; import { isValidStr, t, useGroupPanelInfo } from 'tailchat-shared';
import { GroupPanelWrapper } from './Wrapper';
interface GroupPluginPanelProps { interface GroupPluginPanelProps {
groupId: string; groupId: string;
@ -68,15 +67,7 @@ export const GroupPluginPanel: React.FC<GroupPluginPanelProps> = React.memo(
return null; return null;
} }
return ( return <Component panelInfo={panelInfo} />;
<GroupPanelWrapper
groupId={props.groupId}
panelId={props.panelId}
showHeader={false}
>
<Component panelInfo={panelInfo} />
</GroupPanelWrapper>
);
} }
); );
GroupPluginPanel.displayName = 'GroupPluginPanel'; GroupPluginPanel.displayName = 'GroupPluginPanel';

@ -1,5 +1,10 @@
import { ChatBox } from '@/components/ChatBox'; import { ChatBox } from '@/components/ChatBox';
import { ChatInputMentionsContextProvider } from '@/components/ChatBox/ChatInputBox/context'; import { ChatInputMentionsContextProvider } from '@/components/ChatBox/ChatInputBox/context';
import { IconBtn } from '@/components/IconBtn';
import {
GroupPluginPanelActionProps,
pluginPanelActions,
} from '@/plugin/common';
import React, { useCallback, useLayoutEffect, useState } from 'react'; import React, { useCallback, useLayoutEffect, useState } from 'react';
import { import {
useGroupPanelInfo, useGroupPanelInfo,
@ -14,7 +19,8 @@ import {
useGroupInfo, useGroupInfo,
GroupPanelType, GroupPanelType,
} from 'tailchat-shared'; } from 'tailchat-shared';
import { GroupPanelWrapper } from './Wrapper'; import { MembersPanel } from './MembersPanel';
import { GroupPanelContainer } from './shared/GroupPanelContainer';
/** /**
* *
@ -84,7 +90,47 @@ export const TextPanel: React.FC<TextPanelProps> = React.memo(
} }
return ( return (
<GroupPanelWrapper groupId={groupId} panelId={panelId} showHeader={true}> <GroupPanelContainer
groupId={groupId}
panelId={panelId}
prefixActions={() => [
...pluginPanelActions
.filter(
(action): action is GroupPluginPanelActionProps =>
action.position === 'group'
)
.map((action) => (
<IconBtn
key={action.name}
title={action.label}
shape="square"
icon={action.icon}
iconClassName="text-2xl"
onClick={() =>
action.onClick({
groupId,
panelId,
})
}
/>
)),
]}
suffixActions={({ setRightPanel }) => [
<IconBtn
key="members"
title={t('成员列表')}
shape="square"
icon="mdi:account-supervisor-outline"
iconClassName="text-2xl"
onClick={() =>
setRightPanel({
name: t('成员') + ` (${groupMembers.length})`,
panel: <MembersPanel groupId={groupId} />,
})
}
/>,
]}
>
<ChatInputMentionsContextProvider <ChatInputMentionsContextProvider
users={groupMembers.map((m) => ({ users={groupMembers.map((m) => ({
id: m._id, id: m._id,
@ -106,7 +152,7 @@ export const TextPanel: React.FC<TextPanelProps> = React.memo(
groupId={groupId} groupId={groupId}
/> />
</ChatInputMentionsContextProvider> </ChatInputMentionsContextProvider>
</GroupPanelWrapper> </GroupPanelContainer>
); );
} }
); );

@ -1,133 +0,0 @@
import React, { PropsWithChildren, useEffect, useMemo } from 'react';
import { t, useGroupInfo, useGroupPanelInfo } from 'tailchat-shared';
import _isNil from 'lodash/isNil';
import { MembersPanel } from './MembersPanel';
import { CommonPanelWrapper } from '../common/Wrapper';
import { usePanelWindow } from '@/hooks/usePanelWindow';
import { OpenedPanelTip } from '@/components/OpenedPanelTip';
import { IconBtn } from '@/components/IconBtn';
import {
GroupPluginPanelActionProps,
pluginPanelActions,
} from '@/plugin/common';
import { useUserSessionPreference } from '@/hooks/useUserPreference';
import { GroupPanelContext } from '@/context/GroupPanelContext';
/**
* 访id
*/
function useRecordGroupPanel(groupId: string, panelId: string) {
const [lastVisitPanel, setLastVisitPanel] = useUserSessionPreference(
'groupLastVisitPanel'
);
useEffect(() => {
setLastVisitPanel({
...lastVisitPanel,
[groupId]: panelId,
});
}, [groupId, panelId]);
}
/**
*
*/
interface GroupPanelWrapperProps extends PropsWithChildren {
groupId: string;
panelId: string;
/**
*
*/
showHeader: boolean;
}
export const GroupPanelWrapper: React.FC<GroupPanelWrapperProps> = React.memo(
(props) => {
const { groupId, panelId } = props;
const groupInfo = useGroupInfo(groupId);
const panelInfo = useGroupPanelInfo(groupId, panelId);
const groupMemberCount = (groupInfo?.members ?? []).length;
useRecordGroupPanel(groupId, panelId);
const { hasOpenedPanel, openPanelWindow, closePanelWindow } =
usePanelWindow(`/panel/group/${groupId}/${panelId}`);
const groupPanelContextValue = useMemo(
() => ({
groupId,
panelId,
}),
[groupId, panelId]
);
if (_isNil(panelInfo)) {
return null;
}
if (hasOpenedPanel) {
return <OpenedPanelTip onClosePanelWindow={closePanelWindow} />;
}
if (!props.showHeader) {
return (
<GroupPanelContext.Provider value={groupPanelContextValue}>
{props.children}
</GroupPanelContext.Provider>
);
}
return (
<GroupPanelContext.Provider value={groupPanelContextValue}>
<CommonPanelWrapper
header={panelInfo.name}
actions={(setRightPanel) => [
...pluginPanelActions
.filter(
(action): action is GroupPluginPanelActionProps =>
action.position === 'group'
)
.map((action) => (
<IconBtn
key={action.name}
title={action.label}
shape="square"
icon={action.icon}
iconClassName="text-2xl"
onClick={() =>
action.onClick({
groupId: props.groupId,
panelId: props.panelId,
})
}
/>
)),
<IconBtn
key="open"
title={t('在新窗口打开')}
shape="square"
icon="mdi:dock-window"
iconClassName="text-2xl"
onClick={openPanelWindow}
/>,
<IconBtn
key="members"
title={t('成员列表')}
shape="square"
icon="mdi:account-supervisor-outline"
iconClassName="text-2xl"
onClick={() =>
setRightPanel({
name: t('成员') + ` (${groupMemberCount})`,
panel: <MembersPanel groupId={props.groupId} />,
})
}
/>,
]}
>
{props.children}
</CommonPanelWrapper>
</GroupPanelContext.Provider>
);
}
);
GroupPanelWrapper.displayName = 'GroupPanelWrapper';

@ -0,0 +1,55 @@
import { IconBtn } from '@/components/IconBtn';
import React, { PropsWithChildren } from 'react';
import { t, useGroupPanelInfo } from 'tailchat-shared';
import {
CommonPanelWrapper,
CommonPanelWrapperProps,
} from '../../common/Wrapper';
import _isNil from 'lodash/isNil';
import { usePanelWindow } from '@/hooks/usePanelWindow';
import { OpenedPanelTip } from '@/components/OpenedPanelTip';
interface GroupPanelWithHeader extends PropsWithChildren {
groupId: string;
panelId: string;
prefixActions?: CommonPanelWrapperProps['actions'];
suffixActions?: CommonPanelWrapperProps['actions'];
}
export const GroupPanelContainer: React.FC<GroupPanelWithHeader> = React.memo(
(props) => {
const { groupId, panelId } = props;
const panelInfo = useGroupPanelInfo(groupId, panelId);
const { hasOpenedPanel, openPanelWindow, closePanelWindow } =
usePanelWindow(`/panel/group/${groupId}/${panelId}`);
if (_isNil(panelInfo)) {
return null;
}
if (hasOpenedPanel) {
return <OpenedPanelTip onClosePanelWindow={closePanelWindow} />;
}
return (
<CommonPanelWrapper
header={panelInfo.name}
actions={(ctx) => [
...(props.prefixActions?.(ctx) ?? []),
<IconBtn
key="open"
title={t('在新窗口打开')}
shape="square"
icon="mdi:dock-window"
iconClassName="text-2xl"
onClick={openPanelWindow}
/>,
...(props.suffixActions?.(ctx) ?? []),
]}
>
{props.children}
</CommonPanelWrapper>
);
}
);
GroupPanelContainer.displayName = 'GroupPanelWithHeader';

@ -1,8 +1,10 @@
import { GroupPluginPanel } from '@/components/Panel/group/PluginPanel'; import { GroupPluginPanel } from '@/components/Panel/group/PluginPanel';
import { TextPanel } from '@/components/Panel/group/TextPanel'; import { TextPanel } from '@/components/Panel/group/TextPanel';
import { Problem } from '@/components/Problem'; import { Problem } from '@/components/Problem';
import { GroupPanelContext } from '@/context/GroupPanelContext';
import { useUserSessionPreference } from '@/hooks/useUserPreference';
import { Alert } from 'antd'; import { Alert } from 'antd';
import React from 'react'; import React, { useEffect, useMemo } from 'react';
import { import {
GroupInfoContextProvider, GroupInfoContextProvider,
GroupPanelType, GroupPanelType,
@ -12,6 +14,22 @@ import {
} from 'tailchat-shared'; } from 'tailchat-shared';
import { useGroupPanelParams } from './utils'; import { useGroupPanelParams } from './utils';
/**
* 访id
*/
function useRecordGroupPanel(groupId: string, panelId: string) {
const [lastVisitPanel, setLastVisitPanel] = useUserSessionPreference(
'groupLastVisitPanel'
);
useEffect(() => {
setLastVisitPanel({
...lastVisitPanel,
[groupId]: panelId,
});
}, [groupId, panelId]);
}
interface GroupPanelRenderProps { interface GroupPanelRenderProps {
groupId: string; groupId: string;
panelId: string; panelId: string;
@ -21,6 +39,14 @@ export const GroupPanelRender: React.FC<GroupPanelRenderProps> = React.memo(
const { groupId, panelId } = props; const { groupId, panelId } = props;
const groupInfo = useGroupInfo(groupId); const groupInfo = useGroupInfo(groupId);
const panelInfo = useGroupPanelInfo(groupId, panelId); const panelInfo = useGroupPanelInfo(groupId, panelId);
const groupPanelContextValue = useMemo(
() => ({
groupId,
panelId,
}),
[groupId, panelId]
);
useRecordGroupPanel(groupId, panelId);
if (groupInfo === null) { if (groupInfo === null) {
return ( return (
@ -39,11 +65,18 @@ export const GroupPanelRender: React.FC<GroupPanelRenderProps> = React.memo(
if (panelInfo.type === GroupPanelType.TEXT) { if (panelInfo.type === GroupPanelType.TEXT) {
return ( return (
<GroupInfoContextProvider groupInfo={groupInfo}> <GroupInfoContextProvider groupInfo={groupInfo}>
<GroupPanelContext.Provider value={groupPanelContextValue}>
<TextPanel groupId={groupId} panelId={panelInfo.id} /> <TextPanel groupId={groupId} panelId={panelInfo.id} />
</GroupPanelContext.Provider>
</GroupInfoContextProvider> </GroupInfoContextProvider>
); );
} else if (panelInfo.type === GroupPanelType.PLUGIN) { }
return <GroupPluginPanel groupId={groupId} panelId={panelInfo.id} />; if (panelInfo.type === GroupPanelType.PLUGIN) {
return (
<GroupPanelContext.Provider value={groupPanelContextValue}>
<GroupPluginPanel groupId={groupId} panelId={panelInfo.id} />;
</GroupPanelContext.Provider>
);
} }
return ( return (

Loading…
Cancel
Save