Middle Header: Add edit button (#3449)

This commit is contained in:
Alexander Zinchuk 2023-07-05 13:15:04 +02:00
parent efc36cb517
commit af973d6f20
7 changed files with 74 additions and 17 deletions

View File

@ -21,6 +21,7 @@ import {
selectTabState, selectTabState,
selectUser, selectUser,
selectUserFullInfo, selectUserFullInfo,
selectCanManage, selectIsRightColumnShown,
} from '../../global/selectors'; } from '../../global/selectors';
import { import {
getCanAddContact, getCanAddContact,
@ -108,6 +109,8 @@ type StateProps = {
canEditTopic?: boolean; canEditTopic?: boolean;
hasLinkedChat?: boolean; hasLinkedChat?: boolean;
isChatInfoShown?: boolean; isChatInfoShown?: boolean;
isRightColumnShown?: boolean;
canManage?: boolean;
}; };
const CLOSE_MENU_ANIMATION_DURATION = 200; const CLOSE_MENU_ANIMATION_DURATION = 200;
@ -145,6 +148,8 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
canAddContact, canAddContact,
canCreateTopic, canCreateTopic,
canEditTopic, canEditTopic,
canManage,
isRightColumnShown,
onJoinRequestsClick, onJoinRequestsClick,
onSubscribeChannel, onSubscribeChannel,
onSearchClick, onSearchClick,
@ -168,10 +173,12 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
openCreateTopicPanel, openCreateTopicPanel,
openEditTopicPanel, openEditTopicPanel,
openChat, openChat,
toggleManagement,
} = getActions(); } = getActions();
const { isMobile } = useAppLayout(); const { isMobile } = useAppLayout();
const [isMenuOpen, setIsMenuOpen] = useState(true); const [isMenuOpen, setIsMenuOpen] = useState(true);
const [shouldCloseFast, setShouldCloseFast] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isReportModalOpen, setIsReportModalOpen] = useState(false); const [isReportModalOpen, setIsReportModalOpen] = useState(false);
const [isMuteModalOpen, setIsMuteModalOpen] = useState(false); const [isMuteModalOpen, setIsMuteModalOpen] = useState(false);
@ -210,6 +217,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
const handleViewGroupInfo = useLastCallback(() => { const handleViewGroupInfo = useLastCallback(() => {
openChatWithInfo({ id: chatId, threadId }); openChatWithInfo({ id: chatId, threadId });
setShouldCloseFast(!isRightColumnShown);
closeMenu(); closeMenu();
}); });
@ -239,11 +247,19 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
const handleCreateTopicClick = useLastCallback(() => { const handleCreateTopicClick = useLastCallback(() => {
openCreateTopicPanel({ chatId }); openCreateTopicPanel({ chatId });
setShouldCloseFast(!isRightColumnShown);
closeMenu();
});
const handleEditClick = useLastCallback(() => {
toggleManagement({ force: true });
setShouldCloseFast(!isRightColumnShown);
closeMenu(); closeMenu();
}); });
const handleEditTopicClick = useLastCallback(() => { const handleEditTopicClick = useLastCallback(() => {
openEditTopicPanel({ chatId, topicId: threadId }); openEditTopicPanel({ chatId, topicId: threadId });
setShouldCloseFast(!isRightColumnShown);
closeMenu(); closeMenu();
}); });
@ -303,6 +319,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
const handleStatisticsClick = useLastCallback(() => { const handleStatisticsClick = useLastCallback(() => {
toggleStatistics(); toggleStatistics();
setShouldCloseFast(!isRightColumnShown);
closeMenu(); closeMenu();
}); });
@ -354,6 +371,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
positionX="right" positionX="right"
style={`left: ${x}px;top: ${y}px;`} style={`left: ${x}px;top: ${y}px;`}
onClose={closeMenu} onClose={closeMenu}
shouldCloseFast={shouldCloseFast}
> >
{isMobile && canSearch && ( {isMobile && canSearch && (
<MenuItem <MenuItem
@ -382,6 +400,14 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
{isTopic ? lang('lng_context_view_topic') : lang('lng_context_view_group')} {isTopic ? lang('lng_context_view_topic') : lang('lng_context_view_group')}
</MenuItem> </MenuItem>
)} )}
{canManage && !canEditTopic && (
<MenuItem
icon="edit"
onClick={handleEditClick}
>
{lang('Edit')}
</MenuItem>
)}
{canEditTopic && ( {canEditTopic && (
<MenuItem <MenuItem
icon="edit" icon="edit"
@ -598,6 +624,7 @@ export default memo(withGlobal<OwnProps>(
chat.isCreator || !isUserRightBanned(chat, 'manageTopics') || getHasAdminRight(chat, 'manageTopics') chat.isCreator || !isUserRightBanned(chat, 'manageTopics') || getHasAdminRight(chat, 'manageTopics')
); );
const canEditTopic = topic && getCanManageTopic(chat, topic); const canEditTopic = topic && getCanManageTopic(chat, topic);
const canManage = selectCanManage(global, chatId);
return { return {
chat, chat,
@ -615,6 +642,8 @@ export default memo(withGlobal<OwnProps>(
&& currentChatId === chatId && currentThreadId === threadId, && currentChatId === chatId && currentThreadId === threadId,
canCreateTopic, canCreateTopic,
canEditTopic, canEditTopic,
canManage,
isRightColumnShown: selectIsRightColumnShown(global),
}; };
}, },
)(HeaderMenuContainer)); )(HeaderMenuContainer));

View File

@ -12,17 +12,17 @@ import { ANIMATION_END_DELAY } from '../../config';
import { debounce } from '../../util/schedulers'; import { debounce } from '../../util/schedulers';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { import {
selectCanManage,
selectChat, selectChat,
selectChatFullInfo, selectChatFullInfo,
selectCurrentGifSearch, selectCurrentGifSearch,
selectCurrentStickerSearch, selectCurrentStickerSearch,
selectCurrentTextSearch, selectCurrentTextSearch,
selectIsChatWithSelf,
selectTabState, selectTabState,
selectUser, selectUser,
} from '../../global/selectors'; } from '../../global/selectors';
import { import {
getCanAddContact, getCanManageTopic, isChatAdmin, isChatChannel, isUserBot, isUserId, getCanAddContact, getCanManageTopic, isChatChannel, isUserBot, isUserId,
} from '../../global/helpers'; } from '../../global/helpers';
import { getDayStartAt } from '../../util/dateFormat'; import { getDayStartAt } from '../../util/dateFormat';
@ -464,7 +464,7 @@ const RightHeader: FC<OwnProps & StateProps> = ({
<i className="icon icon-add-user" /> <i className="icon icon-add-user" />
</Button> </Button>
)} )}
{canManage && !isInsideTopic && !isBot && ( {canManage && !isInsideTopic && (
<Button <Button
round round
color="translucent" color="translucent"
@ -561,15 +561,8 @@ export default memo(withGlobal<OwnProps>(
const isBot = user && isUserBot(user); const isBot = user && isUserBot(user);
const canAddContact = user && getCanAddContact(user); const canAddContact = user && getCanAddContact(user);
const canManage = Boolean( const canManage = Boolean(!isManagement && isProfile && chatId && selectCanManage(global, chatId));
!isManagement
&& isProfile
&& !canAddContact
&& chat
&& !selectIsChatWithSelf(global, chat.id)
// chat.isCreator is for Basic Groups
&& (isUserId(chat.id) || ((isChatAdmin(chat) || chat.isCreator) && !chat.isNotJoined)),
);
const isEditingInvite = Boolean(chatId && tabState.management.byChatId[chatId]?.editingInvite); const isEditingInvite = Boolean(chatId && tabState.management.byChatId[chatId]?.editingInvite);
const canViewStatistics = !isInsideTopic && chatId const canViewStatistics = !isInsideTopic && chatId
? selectChatFullInfo(global, chatId)?.canViewStatistics ? selectChatFullInfo(global, chatId)?.canViewStatistics

View File

@ -38,6 +38,10 @@
transition: opacity 0.2s ease-in, transform 0.2s ease-in !important; transition: opacity 0.2s ease-in, transform 0.2s ease-in !important;
} }
&.close-fast {
transition-duration: 70ms !important;
}
body.no-context-menu-animations & { body.no-context-menu-animations & {
transform: none !important; transform: none !important;
transition: opacity 0.15s !important; transition: opacity 0.15s !important;

View File

@ -23,6 +23,7 @@ type OwnProps = {
ref?: RefObject<HTMLDivElement>; ref?: RefObject<HTMLDivElement>;
containerRef?: RefObject<HTMLElement>; containerRef?: RefObject<HTMLElement>;
isOpen: boolean; isOpen: boolean;
shouldCloseFast?: boolean;
id?: string; id?: string;
className?: string; className?: string;
bubbleClassName?: string; bubbleClassName?: string;
@ -54,6 +55,7 @@ const ANIMATION_DURATION = 200;
const Menu: FC<OwnProps> = ({ const Menu: FC<OwnProps> = ({
ref, ref,
containerRef, containerRef,
shouldCloseFast,
isOpen, isOpen,
id, id,
className, className,
@ -131,6 +133,7 @@ const Menu: FC<OwnProps> = ({
footer && 'with-footer', footer && 'with-footer',
transitionClassNames, transitionClassNames,
bubbleClassName, bubbleClassName,
shouldCloseFast && 'close-fast',
); );
const transformOriginYStyle = transformOriginY !== undefined ? `${transformOriginY}px` : undefined; const transformOriginYStyle = transformOriginY !== undefined ? `${transformOriginY}px` : undefined;

View File

@ -61,7 +61,7 @@ addActionHandler('resetLeftColumnWidth', (global): ActionReturnType => {
}); });
addActionHandler('toggleManagement', (global, actions, payload): ActionReturnType => { addActionHandler('toggleManagement', (global, actions, payload): ActionReturnType => {
const { tabId = getCurrentTabId() } = payload || {}; const { force, tabId = getCurrentTabId() } = payload || {};
const { chatId } = selectCurrentMessageList(global, tabId) || {}; const { chatId } = selectCurrentMessageList(global, tabId) || {};
if (!chatId) { if (!chatId) {
@ -76,7 +76,7 @@ addActionHandler('toggleManagement', (global, actions, payload): ActionReturnTyp
...tabState.management.byChatId, ...tabState.management.byChatId,
[chatId]: { [chatId]: {
...tabState.management.byChatId[chatId], ...tabState.management.byChatId[chatId],
isActive: !(tabState.management.byChatId[chatId] || {}).isActive, isActive: force !== undefined ? force : !(tabState.management.byChatId[chatId] || {}).isActive,
}, },
}, },
}, },

View File

@ -1,10 +1,14 @@
import type { GlobalState, TabArgs } from '../types'; import type { GlobalState, TabArgs } from '../types';
import { selectCurrentMessageList } from './messages'; import { selectCurrentMessageList } from './messages';
import { selectChat } from './chats'; import { selectChat, selectIsChatWithSelf } from './chats';
import { isChatGroup, isUserId } from '../helpers'; import {
getCanAddContact,
isChatAdmin, isChatGroup, isUserBot, isUserId,
} from '../helpers';
import { selectTabState } from './tabs'; import { selectTabState } from './tabs';
import { getCurrentTabId } from '../../util/establishMultitabRole'; import { getCurrentTabId } from '../../util/establishMultitabRole';
import { selectUser } from './users';
export function selectManagement<T extends GlobalState>( export function selectManagement<T extends GlobalState>(
global: T, chatId: string, global: T, chatId: string,
@ -54,3 +58,25 @@ export function selectCurrentManagementType<T extends GlobalState>(
return 'channel'; return 'channel';
} }
export function selectCanManage<T extends GlobalState>(
global: T,
chatId: string,
) {
const chat = selectChat(global, chatId);
if (!chat || chat.isRestricted) return false;
const isPrivate = isUserId(chat.id);
const user = isPrivate ? selectUser(global, chatId) : undefined;
const canAddContact = user && getCanAddContact(user);
const isBot = user && isUserBot(user);
return Boolean(
!canAddContact
&& chat
&& !selectIsChatWithSelf(global, chat.id)
// chat.isCreator is for Basic Groups
&& (isUserId(chat.id) || ((isChatAdmin(chat) || chat.isCreator) && !chat.isNotJoined))
&& !isBot,
);
}

View File

@ -1526,7 +1526,9 @@ export interface ActionPayloads {
hideChatReportPanel: { hideChatReportPanel: {
chatId: string; chatId: string;
}; };
toggleManagement: WithTabId | undefined; toggleManagement: ({
force?: boolean;
} & WithTabId) | undefined;
requestNextManagementScreen: ({ requestNextManagementScreen: ({
screen?: ManagementScreens; screen?: ManagementScreens;
} & WithTabId) | undefined; } & WithTabId) | undefined;