refactor menu items to react components

pull/2131/head
Audric Ackermann 3 years ago
parent 3d2158f469
commit 580a59ba3c
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -6,7 +6,6 @@ import { contextMenu } from 'react-contexify';
import styled from 'styled-components'; import styled from 'styled-components';
import { ConversationNotificationSettingType } from '../../models/conversation'; import { ConversationNotificationSettingType } from '../../models/conversation';
import { import {
getConversationHeaderProps,
getConversationHeaderTitleProps, getConversationHeaderTitleProps,
getCurrentNotificationSettingText, getCurrentNotificationSettingText,
getIsSelectedBlocked, getIsSelectedBlocked,
@ -33,10 +32,14 @@ import {
} from '../../state/ducks/conversations'; } from '../../state/ducks/conversations';
import { callRecipient } from '../../interactions/conversationInteractions'; import { callRecipient } from '../../interactions/conversationInteractions';
import { getHasIncomingCall, getHasOngoingCall } from '../../state/selectors/call'; import { getHasIncomingCall, getHasOngoingCall } from '../../state/selectors/call';
import { useConversationUsername } from '../../hooks/useParamSelector'; import {
useConversationUsername,
useExpireTimer,
useIsKickedFromGroup,
} from '../../hooks/useParamSelector';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SessionIconButton } from '../icon'; import { SessionIconButton } from '../icon';
import { MemoConversationHeaderMenu } from '../menu/ConversationHeaderMenu'; import { ConversationHeaderMenu } from '../menu/ConversationHeaderMenu';
export interface TimerOption { export interface TimerOption {
name: string; name: string;
@ -328,33 +331,20 @@ export const ConversationHeaderSubtitle = (props: { text?: string | null }): JSX
}; };
export const ConversationHeaderWithDetails = () => { export const ConversationHeaderWithDetails = () => {
const headerProps = useSelector(getConversationHeaderProps);
const isSelectionMode = useSelector(isMessageSelectionMode); const isSelectionMode = useSelector(isMessageSelectionMode);
const isMessageDetailOpened = useSelector(isMessageDetailView); const isMessageDetailOpened = useSelector(isMessageDetailView);
const selectedConvoKey = useSelector(getSelectedConversationKey);
const dispatch = useDispatch(); const dispatch = useDispatch();
if (!headerProps) { if (!selectedConvoKey) {
return null; return null;
} }
const {
isKickedFromGroup, const isKickedFromGroup = useIsKickedFromGroup(selectedConvoKey);
expirationSettingName, const expireTimerSetting = useExpireTimer(selectedConvoKey);
avatarPath, const expirationSettingName = expireTimerSetting
name, ? window.Whisper.ExpirationTimerOptions.getName(expireTimerSetting || 0)
profileName, : null;
isMe,
isPublic,
currentNotificationSetting,
hasNickname,
weAreAdmin,
isBlocked,
left,
conversationKey,
isPrivate,
isGroup,
} = headerProps;
const triggerId = 'conversation-header'; const triggerId = 'conversation-header';
@ -383,29 +373,13 @@ export const ConversationHeaderWithDetails = () => {
onAvatarClick={() => { onAvatarClick={() => {
dispatch(openRightPanel()); dispatch(openRightPanel());
}} }}
pubkey={conversationKey} pubkey={selectedConvoKey}
showBackButton={isMessageDetailOpened} showBackButton={isMessageDetailOpened}
/> />
</> </>
)} )}
<MemoConversationHeaderMenu <ConversationHeaderMenu triggerId={triggerId} />
conversationId={conversationKey}
triggerId={triggerId}
isMe={isMe}
isPublic={isPublic}
isGroup={isGroup}
isKickedFromGroup={isKickedFromGroup}
weAreAdmin={weAreAdmin}
isBlocked={isBlocked}
isPrivate={isPrivate}
left={left}
hasNickname={hasNickname}
currentNotificationSetting={currentNotificationSetting}
avatarPath={avatarPath}
name={name}
profileName={profileName}
/>
</div> </div>
{isSelectionMode && <SelectionOverlay />} {isSelectionMode && <SelectionOverlay />}

@ -9,10 +9,9 @@ import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
import { MemberListItem } from '../MemberListItem'; import { MemberListItem } from '../MemberListItem';
import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionWrapperModal } from '../SessionWrapperModal';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { useConversationPropsById } from '../../hooks/useParamSelector'; import { useConversationPropsById, useWeAreAdmin } from '../../hooks/useParamSelector';
// tslint:disable-next-line: no-submodule-imports // tslint:disable-next-line: no-submodule-imports
import useKey from 'react-use/lib/useKey'; import useKey from 'react-use/lib/useKey';
import { useWeAreAdmin } from '../../hooks/useWeAreAdmin';
import { useSet } from '../../hooks/useSet'; import { useSet } from '../../hooks/useSet';
import { ClosedGroup } from '../../session'; import { ClosedGroup } from '../../session';
import { getConversationController } from '../../session/conversations'; import { getConversationController } from '../../session/conversations';

@ -1,98 +1,64 @@
import React from 'react'; import React from 'react';
import { animation, Menu } from 'react-contexify'; import { animation, Menu } from 'react-contexify';
import { import {
getAddModeratorsMenuItem, AddModeratorsMenuItem,
getBanMenuItem, BanMenuItem,
getBlockMenuItem, BlockMenuItem,
getChangeNicknameMenuItem, ChangeNicknameMenuItem,
getClearNicknameMenuItem, ClearNicknameMenuItem,
getCopyMenuItem, CopyMenuItem,
getDeleteContactMenuItem, DeleteContactMenuItem,
getDeleteMessagesMenuItem, DeleteMessagesMenuItem,
getDisappearingMenuItem, DisappearingMessageMenuItem,
getInviteContactMenuItem, InviteContactMenuItem,
getLeaveGroupMenuItem, LeaveGroupMenuItem,
getMarkAllReadMenuItem, MarkAllReadMenuItem,
getNotificationForConvoMenuItem, NotificationForConvoMenuItem,
getPinConversationMenuItem, PinConversationMenuItem,
getRemoveModeratorsMenuItem, RemoveModeratorsMenuItem,
getShowUserDetailsMenuItem, ShowUserDetailsMenuItem,
getUnbanMenuItem, UnbanMenuItem,
getUpdateGroupNameMenuItem, UpdateGroupNameMenuItem,
} from './Menu'; } from './Menu';
import _ from 'lodash'; import _ from 'lodash';
import { ConversationNotificationSettingType } from '../../models/conversation'; import { ContextConversationId } from '../leftpane/conversation-list-item/ConversationListItem';
import { getSelectedConversationKey } from '../../state/selectors/conversations';
import { useSelector } from 'react-redux';
export type PropsConversationHeaderMenu = { export type PropsConversationHeaderMenu = {
conversationId: string;
triggerId: string; triggerId: string;
isMe: boolean;
isPublic: boolean;
isKickedFromGroup: boolean;
left: boolean;
isGroup: boolean;
weAreAdmin: boolean;
currentNotificationSetting: ConversationNotificationSettingType;
isPrivate: boolean;
isBlocked: boolean;
hasNickname: boolean;
name: string | undefined;
profileName: string | undefined;
avatarPath: string | null;
}; };
const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
const { const { triggerId } = props;
conversationId,
triggerId,
isMe,
isPublic,
isGroup,
isKickedFromGroup,
weAreAdmin,
isBlocked,
isPrivate,
left,
hasNickname,
currentNotificationSetting,
name,
profileName,
avatarPath,
} = props;
const userName = name || profileName || conversationId;
const selectedConversation = useSelector(getSelectedConversationKey);
if (!selectedConversation) {
throw new Error('selectedConversation must be set for a header to be visible!');
}
return ( return (
<Menu id={triggerId} animation={animation.fade}> <ContextConversationId.Provider value={selectedConversation}>
{getDisappearingMenuItem(isPublic, isKickedFromGroup, left, isBlocked, conversationId)} <Menu id={triggerId} animation={animation.fade}>
{getNotificationForConvoMenuItem({ <DisappearingMessageMenuItem />
isKickedFromGroup, <NotificationForConvoMenuItem />
left, <PinConversationMenuItem />
isBlocked, <BlockMenuItem />
isPrivate, <CopyMenuItem />
currentNotificationSetting, <MarkAllReadMenuItem />
conversationId, <ChangeNicknameMenuItem />
})} <ClearNicknameMenuItem />
{getPinConversationMenuItem(conversationId)} <DeleteMessagesMenuItem />
{getBlockMenuItem(isMe, isPrivate, isBlocked, conversationId)} <AddModeratorsMenuItem />
{getCopyMenuItem(isPublic, isGroup, conversationId)} <RemoveModeratorsMenuItem />
{getMarkAllReadMenuItem(conversationId)} <BanMenuItem />
{getChangeNicknameMenuItem(isMe, isGroup, conversationId)} <UnbanMenuItem />
{getClearNicknameMenuItem(isMe, hasNickname, isGroup, conversationId)} <UpdateGroupNameMenuItem />
{getDeleteMessagesMenuItem(conversationId)} <LeaveGroupMenuItem />
{getAddModeratorsMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} <InviteContactMenuItem />
{getRemoveModeratorsMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} <DeleteContactMenuItem />
{getBanMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} <ShowUserDetailsMenuItem />
{getUnbanMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} </Menu>
{getUpdateGroupNameMenuItem(weAreAdmin, isKickedFromGroup, left, conversationId)} </ContextConversationId.Provider>
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)}
{getInviteContactMenuItem(isGroup, isPublic, conversationId)}
{getDeleteContactMenuItem(isGroup, isPublic, left, isKickedFromGroup, conversationId)}
{getShowUserDetailsMenuItem(isPrivate, conversationId, avatarPath, userName)}
</Menu>
); );
}; };
function propsAreEqual(prev: PropsConversationHeaderMenu, next: PropsConversationHeaderMenu) {
return _.isEqual(prev, next);
}
export const MemoConversationHeaderMenu = React.memo(ConversationHeaderMenu, propsAreEqual);

@ -1,29 +1,22 @@
import React, { useContext } from 'react'; import React from 'react';
import { animation, Menu } from 'react-contexify'; import { animation, Menu } from 'react-contexify';
import _ from 'underscore'; import _ from 'underscore';
import {
useAvatarPath,
useConversationPropsById,
useConversationUsername,
} from '../../hooks/useParamSelector';
import { ConversationTypeEnum } from '../../models/conversation';
import { ContextConversationId } from '../leftpane/conversation-list-item/ConversationListItem';
import { import {
getBanMenuItem, BanMenuItem,
getBlockMenuItem, BlockMenuItem,
getChangeNicknameMenuItem, ChangeNicknameMenuItem,
getClearNicknameMenuItem, ClearNicknameMenuItem,
getCopyMenuItem, CopyMenuItem,
getDeleteContactMenuItem, DeleteContactMenuItem,
getDeleteMessagesMenuItem, DeleteMessagesMenuItem,
getInviteContactMenuItem, InviteContactMenuItem,
getLeaveGroupMenuItem, LeaveGroupMenuItem,
getMarkAllReadMenuItem, MarkAllReadMenuItem,
getNotificationForConvoMenuItem, NotificationForConvoMenuItem,
getPinConversationMenuItem, PinConversationMenuItem,
getShowUserDetailsMenuItem, ShowUserDetailsMenuItem,
getUnbanMenuItem, UnbanMenuItem,
} from './Menu'; } from './Menu';
export type PropsContextConversationItem = { export type PropsContextConversationItem = {
@ -31,54 +24,24 @@ export type PropsContextConversationItem = {
}; };
const ConversationListItemContextMenu = (props: PropsContextConversationItem) => { const ConversationListItemContextMenu = (props: PropsContextConversationItem) => {
const conversationId = useContext(ContextConversationId);
const itemMenuProps = useConversationPropsById(conversationId);
const { triggerId } = props; const { triggerId } = props;
if (!itemMenuProps) {
return null;
}
const {
isBlocked,
isMe,
isPublic,
hasNickname,
type,
left,
isKickedFromGroup,
currentNotificationSetting,
isPrivate,
weAreAdmin,
} = itemMenuProps;
const isGroup = type === 'group';
const userName = useConversationUsername(conversationId);
const avatarPath = useAvatarPath(conversationId);
return ( return (
<Menu id={triggerId} animation={animation.fade}> <Menu id={triggerId} animation={animation.fade}>
{getNotificationForConvoMenuItem({ <NotificationForConvoMenuItem />
isPrivate, <PinConversationMenuItem />
isKickedFromGroup, <BlockMenuItem />
left, <CopyMenuItem />
isBlocked, <MarkAllReadMenuItem />
currentNotificationSetting, <ChangeNicknameMenuItem />
conversationId, <ClearNicknameMenuItem />
})} <DeleteMessagesMenuItem />
{getPinConversationMenuItem(conversationId)} <BanMenuItem />
{getBlockMenuItem(isMe, type === ConversationTypeEnum.PRIVATE, isBlocked, conversationId)} <UnbanMenuItem />
{getCopyMenuItem(isPublic, isGroup, conversationId)} <InviteContactMenuItem />
{getMarkAllReadMenuItem(conversationId)} <DeleteContactMenuItem />
{getChangeNicknameMenuItem(isMe, isGroup, conversationId)} <LeaveGroupMenuItem />
{getClearNicknameMenuItem(isMe, hasNickname, isGroup, conversationId)} <ShowUserDetailsMenuItem />
{getDeleteMessagesMenuItem(conversationId)}
{getBanMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)}
{getUnbanMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)}
{getInviteContactMenuItem(isGroup, isPublic, conversationId)}
{getDeleteContactMenuItem(isGroup, isPublic, left, isKickedFromGroup, conversationId)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)}
{getShowUserDetailsMenuItem(isPrivate, conversationId, avatarPath, userName || '')}
</Menu> </Menu>
); );
}; };

@ -1,7 +1,20 @@
import React from 'react'; import React, { useContext } from 'react';
import { Item, Submenu } from 'react-contexify'; import { Item, Submenu } from 'react-contexify';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import {
useAvatarPath,
useConversationUsername,
useHasNickname,
useIsBlocked,
useIsKickedFromGroup,
useIsLeft,
useIsMe,
useIsPrivate,
useIsPublic,
useNotificationSetting,
useWeAreAdmin,
} from '../../hooks/useParamSelector';
import { import {
blockConvoById, blockConvoById,
clearNickNameByConvoId, clearNickNameByConvoId,
@ -36,6 +49,7 @@ import { getFocusedSection } from '../../state/selectors/section';
import { getTimerOptions } from '../../state/selectors/timerOptions'; import { getTimerOptions } from '../../state/selectors/timerOptions';
import { LocalizerKeys } from '../../types/LocalizerKeys'; import { LocalizerKeys } from '../../types/LocalizerKeys';
import { SessionButtonColor } from '../basic/SessionButton'; import { SessionButtonColor } from '../basic/SessionButton';
import { ContextConversationId } from '../leftpane/conversation-list-item/ConversationListItem';
const maxNumberOfPinnedConversations = 5; const maxNumberOfPinnedConversations = 5;
@ -60,17 +74,17 @@ function showBlock(isMe: boolean, isPrivate: boolean): boolean {
return !isMe && isPrivate; return !isMe && isPrivate;
} }
function showClearNickname(isMe: boolean, hasNickname: boolean, isGroup: boolean): boolean { function showClearNickname(isMe: boolean, hasNickname: boolean, isPrivate: boolean): boolean {
return !isMe && hasNickname && !isGroup; return !isMe && hasNickname && isPrivate;
} }
function showChangeNickname(isMe: boolean, isGroup: boolean) { function showChangeNickname(isMe: boolean, isPrivate: boolean) {
return !isMe && !isGroup; return !isMe && isPrivate;
} }
// we want to show the copyId for open groups and private chats only // we want to show the copyId for open groups and private chats only
function showCopyId(isPublic: boolean, isGroup: boolean): boolean { function showCopyId(isPublic: boolean, isPrivate: boolean): boolean {
return !isGroup || isPublic; return isPrivate || isPublic;
} }
function showDeleteContact( function showDeleteContact(
@ -83,32 +97,36 @@ function showDeleteContact(
return !isGroup || (isGroup && (isGroupLeft || isKickedFromGroup || isPublic)); return !isGroup || (isGroup && (isGroupLeft || isKickedFromGroup || isPublic));
} }
const showUnbanUser = (isAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => { const showUnbanUser = (weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => {
return !isKickedFromGroup && isAdmin && isPublic; return !isKickedFromGroup && weAreAdmin && isPublic;
}; };
const showBanUser = (isAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => { const showBanUser = (weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => {
return !isKickedFromGroup && isAdmin && isPublic; return !isKickedFromGroup && weAreAdmin && isPublic;
}; };
function showAddModerators( function showAddModerators(
isAdmin: boolean, weAreAdmin: boolean,
isPublic: boolean, isPublic: boolean,
isKickedFromGroup: boolean isKickedFromGroup: boolean
): boolean { ): boolean {
return !isKickedFromGroup && isAdmin && isPublic; return !isKickedFromGroup && weAreAdmin && isPublic;
} }
function showRemoveModerators( function showRemoveModerators(
isAdmin: boolean, weAreAdmin: boolean,
isPublic: boolean, isPublic: boolean,
isKickedFromGroup: boolean isKickedFromGroup: boolean
): boolean { ): boolean {
return !isKickedFromGroup && isAdmin && isPublic; return !isKickedFromGroup && weAreAdmin && isPublic;
} }
function showUpdateGroupName(isAdmin: boolean, isKickedFromGroup: boolean, left: boolean): boolean { function showUpdateGroupName(
return !isKickedFromGroup && !left && isAdmin; weAreAdmin: boolean,
isKickedFromGroup: boolean,
left: boolean
): boolean {
return !isKickedFromGroup && !left && weAreAdmin;
} }
function showLeaveGroup( function showLeaveGroup(
@ -120,22 +138,21 @@ function showLeaveGroup(
return !isKickedFromGroup && !left && isGroup && !isPublic; return !isKickedFromGroup && !left && isGroup && !isPublic;
} }
function showInviteContact(isGroup: boolean, isPublic: boolean): boolean { function showInviteContact(isPublic: boolean): boolean {
return isGroup && isPublic; return isPublic;
} }
/** Menu items standardized */ /** Menu items standardized */
export function getInviteContactMenuItem( export const InviteContactMenuItem = (): JSX.Element | null => {
isGroup: boolean | undefined, const convoId = useContext(ContextConversationId);
isPublic: boolean | undefined, const isPublic = useIsPublic(convoId);
conversationId: string
): JSX.Element | null { if (showInviteContact(isPublic)) {
if (showInviteContact(Boolean(isGroup), Boolean(isPublic))) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
showInviteContactByConvoId(conversationId); showInviteContactByConvoId(convoId);
}} }}
> >
{window.i18n('inviteContacts')} {window.i18n('inviteContacts')}
@ -143,13 +160,10 @@ export function getInviteContactMenuItem(
); );
} }
return null; return null;
} };
export interface PinConversationMenuItemProps {
conversationId: string;
}
export const getPinConversationMenuItem = (conversationId: string): JSX.Element | null => { export const PinConversationMenuItem = (): JSX.Element | null => {
const conversationId = useContext(ContextConversationId);
const isMessagesSection = useSelector(getFocusedSection) === SectionType.Message; const isMessagesSection = useSelector(getFocusedSection) === SectionType.Message;
const nbOfAlreadyPinnedConvos = useSelector(getNumberOfPinnedConversations); const nbOfAlreadyPinnedConvos = useSelector(getNumberOfPinnedConversations);
@ -175,30 +189,22 @@ export const getPinConversationMenuItem = (conversationId: string): JSX.Element
return null; return null;
}; };
export function getDeleteContactMenuItem( export const DeleteContactMenuItem = () => {
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isLeft: boolean | undefined,
isKickedFromGroup: boolean | undefined,
conversationId: string
): JSX.Element | null {
const dispatch = useDispatch(); const dispatch = useDispatch();
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isLeft = useIsLeft(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const isPrivate = useIsPrivate(convoId);
if ( if (showDeleteContact(!isPrivate, isPublic, isLeft, isKickedFromGroup)) {
showDeleteContact(
Boolean(isGroup),
Boolean(isPublic),
Boolean(isLeft),
Boolean(isKickedFromGroup)
)
) {
let menuItemText: string; let menuItemText: string;
if (isPublic) { if (isPublic) {
menuItemText = window.i18n('leaveGroup'); menuItemText = window.i18n('leaveGroup');
} else { } else {
menuItemText = isGroup menuItemText = isPrivate
? window.i18n('editMenuDeleteGroup') ? window.i18n('editMenuDeleteContact')
: window.i18n('editMenuDeleteContact'); : window.i18n('editMenuDeleteGroup');
} }
const onClickClose = () => { const onClickClose = () => {
@ -209,13 +215,13 @@ export function getDeleteContactMenuItem(
dispatch( dispatch(
updateConfirmModal({ updateConfirmModal({
title: menuItemText, title: menuItemText,
message: isGroup message: isPrivate
? window.i18n('leaveGroupConfirmation') ? window.i18n('deleteContactConfirmation')
: window.i18n('deleteContactConfirmation'), : window.i18n('leaveGroupConfirmation'),
onClickClose, onClickClose,
okTheme: SessionButtonColor.Danger, okTheme: SessionButtonColor.Danger,
onClickOk: async () => { onClickOk: async () => {
await getConversationController().deleteContact(conversationId); await getConversationController().deleteContact(convoId);
}, },
}) })
); );
@ -224,22 +230,20 @@ export function getDeleteContactMenuItem(
return <Item onClick={showConfirmationModal}>{menuItemText}</Item>; return <Item onClick={showConfirmationModal}>{menuItemText}</Item>;
} }
return null; return null;
} };
export function getLeaveGroupMenuItem( export const LeaveGroupMenuItem = () => {
isKickedFromGroup: boolean | undefined, const convoId = useContext(ContextConversationId);
left: boolean | undefined, const isPublic = useIsPublic(convoId);
isGroup: boolean | undefined, const isLeft = useIsLeft(convoId);
isPublic: boolean | undefined, const isKickedFromGroup = useIsKickedFromGroup(convoId);
conversationId: string const isPrivate = useIsPrivate(convoId);
): JSX.Element | null {
if ( if (showLeaveGroup(isKickedFromGroup, isLeft, !isPrivate, isPublic)) {
showLeaveGroup(Boolean(isKickedFromGroup), Boolean(left), Boolean(isGroup), Boolean(isPublic))
) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
showLeaveGroupByConvoId(conversationId); showLeaveGroupByConvoId(convoId);
}} }}
> >
{window.i18n('leaveGroup')} {window.i18n('leaveGroup')}
@ -248,15 +252,14 @@ export function getLeaveGroupMenuItem(
} }
return null; return null;
} };
export function getShowUserDetailsMenuItem( export const ShowUserDetailsMenuItem = () => {
isPrivate: boolean | undefined,
conversationId: string,
avatarPath: string | null,
userName: string
): JSX.Element | null {
const dispatch = useDispatch(); const dispatch = useDispatch();
const convoId = useContext(ContextConversationId);
const isPrivate = useIsPrivate(convoId);
const avatarPath = useAvatarPath(convoId);
const userName = useConversationUsername(convoId) || convoId;
if (isPrivate) { if (isPrivate) {
return ( return (
@ -264,7 +267,7 @@ export function getShowUserDetailsMenuItem(
onClick={() => { onClick={() => {
dispatch( dispatch(
updateUserDetailsModal({ updateUserDetailsModal({
conversationId: conversationId, conversationId: convoId,
userName, userName,
authorAvatarPath: avatarPath, authorAvatarPath: avatarPath,
}) })
@ -277,19 +280,19 @@ export function getShowUserDetailsMenuItem(
} }
return null; return null;
} };
export function getUpdateGroupNameMenuItem( export const UpdateGroupNameMenuItem = () => {
isAdmin: boolean | undefined, const convoId = useContext(ContextConversationId);
isKickedFromGroup: boolean | undefined, const left = useIsLeft(convoId);
left: boolean | undefined, const isKickedFromGroup = useIsKickedFromGroup(convoId);
conversationId: string const weAreAdmin = useWeAreAdmin(convoId);
): JSX.Element | null {
if (showUpdateGroupName(Boolean(isAdmin), Boolean(isKickedFromGroup), Boolean(left))) { if (showUpdateGroupName(weAreAdmin, isKickedFromGroup, left)) {
return ( return (
<Item <Item
onClick={async () => { onClick={async () => {
await showUpdateGroupNameByConvoId(conversationId); await showUpdateGroupNameByConvoId(convoId);
}} }}
> >
{window.i18n('editGroup')} {window.i18n('editGroup')}
@ -297,19 +300,19 @@ export function getUpdateGroupNameMenuItem(
); );
} }
return null; return null;
} };
export const RemoveModeratorsMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const weAreAdmin = useWeAreAdmin(convoId);
export function getRemoveModeratorsMenuItem( if (showRemoveModerators(weAreAdmin, Boolean(isPublic), Boolean(isKickedFromGroup))) {
isAdmin: boolean | undefined,
isPublic: boolean | undefined,
isKickedFromGroup: boolean | undefined,
conversationId: string
): JSX.Element | null {
if (showRemoveModerators(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
showRemoveModeratorsByConvoId(conversationId); showRemoveModeratorsByConvoId(convoId);
}} }}
> >
{window.i18n('removeModerators')} {window.i18n('removeModerators')}
@ -317,19 +320,19 @@ export function getRemoveModeratorsMenuItem(
); );
} }
return null; return null;
} };
export function getAddModeratorsMenuItem( export const AddModeratorsMenuItem = (): JSX.Element | null => {
isAdmin: boolean | undefined, const convoId = useContext(ContextConversationId);
isPublic: boolean | undefined, const isPublic = useIsPublic(convoId);
isKickedFromGroup: boolean | undefined, const isKickedFromGroup = useIsKickedFromGroup(convoId);
conversationId: string const weAreAdmin = useWeAreAdmin(convoId);
): JSX.Element | null {
if (showAddModerators(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) { if (showAddModerators(weAreAdmin, isPublic, isKickedFromGroup)) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
showAddModeratorsByConvoId(conversationId); showAddModeratorsByConvoId(convoId);
}} }}
> >
{window.i18n('addModerators')} {window.i18n('addModerators')}
@ -337,40 +340,39 @@ export function getAddModeratorsMenuItem(
); );
} }
return null; return null;
} };
export const UnbanMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const weAreAdmin = useWeAreAdmin(convoId);
export function getUnbanMenuItem( if (showUnbanUser(weAreAdmin, isPublic, isKickedFromGroup)) {
isAdmin: boolean | undefined,
isPublic: boolean | undefined,
isKickedFromGroup: boolean | undefined,
conversationId: string
): JSX.Element | null {
if (showUnbanUser(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
showUnbanUserByConvoId(conversationId); showUnbanUserByConvoId(convoId);
}} }}
> >
{window.i18n('unbanUser')} {window.i18n('unbanUser')}
</Item> </Item>
); );
} }
// TODO: translations
return null; return null;
} };
export const BanMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const weAreAdmin = useWeAreAdmin(convoId);
export function getBanMenuItem( if (showBanUser(weAreAdmin, isPublic, isKickedFromGroup)) {
isAdmin: boolean | undefined,
isPublic: boolean | undefined,
isKickedFromGroup: boolean | undefined,
conversationId: string
): JSX.Element | null {
if (showBanUser(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
showBanUserByConvoId(conversationId); showBanUserByConvoId(convoId);
}} }}
> >
{window.i18n('banUser')} {window.i18n('banUser')}
@ -378,40 +380,38 @@ export function getBanMenuItem(
); );
} }
return null; return null;
} };
export function getCopyMenuItem( export const CopyMenuItem = (): JSX.Element | null => {
isPublic: boolean | undefined, const convoId = useContext(ContextConversationId);
isGroup: boolean | undefined, const isPublic = useIsPublic(convoId);
conversationId: string const isPrivate = useIsPrivate(convoId);
): JSX.Element | null {
if (showCopyId(Boolean(isPublic), Boolean(isGroup))) { if (showCopyId(isPublic, isPrivate)) {
const copyIdLabel = isPublic ? window.i18n('copyOpenGroupURL') : window.i18n('copySessionID'); const copyIdLabel = isPublic ? window.i18n('copyOpenGroupURL') : window.i18n('copySessionID');
return <Item onClick={() => copyPublicKeyByConvoId(conversationId)}>{copyIdLabel}</Item>; return <Item onClick={() => copyPublicKeyByConvoId(convoId)}>{copyIdLabel}</Item>;
} }
return null; return null;
} };
export function getMarkAllReadMenuItem(conversationId: string): JSX.Element | null { export const MarkAllReadMenuItem = (): JSX.Element | null => {
return ( const convoId = useContext(ContextConversationId);
<Item onClick={() => markAllReadByConvoId(conversationId)}>{window.i18n('markAllAsRead')}</Item> return <Item onClick={() => markAllReadByConvoId(convoId)}>{window.i18n('markAllAsRead')}</Item>;
); };
}
export function getDisappearingMenuItem( export const DisappearingMessageMenuItem = (): JSX.Element | null => {
isPublic: boolean | undefined, const convoId = useContext(ContextConversationId);
isKickedFromGroup: boolean | undefined, const isBlocked = useIsBlocked(convoId);
left: boolean | undefined, const isPublic = useIsPublic(convoId);
isBlocked: boolean | undefined, const isLeft = useIsLeft(convoId);
conversationId: string const isKickedFromGroup = useIsKickedFromGroup(convoId);
): JSX.Element | null {
const timerOptions = useSelector(getTimerOptions).timerOptions; const timerOptions = useSelector(getTimerOptions).timerOptions;
if ( if (
showTimerOptions( showTimerOptions(
Boolean(isPublic), Boolean(isPublic),
Boolean(isKickedFromGroup), Boolean(isKickedFromGroup),
Boolean(left), Boolean(isLeft),
Boolean(isBlocked) Boolean(isBlocked)
) )
) { ) {
@ -427,7 +427,7 @@ export function getDisappearingMenuItem(
<Item <Item
key={item.value} key={item.value}
onClick={async () => { onClick={async () => {
await setDisappearingMessagesByConvoId(conversationId, item.value); await setDisappearingMessagesByConvoId(convoId, item.value);
}} }}
> >
{item.name} {item.name}
@ -437,23 +437,16 @@ export function getDisappearingMenuItem(
); );
} }
return null; return null;
} };
export const NotificationForConvoMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const left = useIsLeft(convoId);
const isBlocked = useIsBlocked(convoId);
const isPrivate = useIsPrivate(convoId);
const currentNotificationSetting = useNotificationSetting(convoId);
export function getNotificationForConvoMenuItem({
conversationId,
currentNotificationSetting,
isBlocked,
isKickedFromGroup,
left,
isPrivate,
}: {
isKickedFromGroup: boolean | undefined;
left: boolean | undefined;
isBlocked: boolean | undefined;
isPrivate: boolean | undefined;
currentNotificationSetting: ConversationNotificationSettingType | undefined;
conversationId: string;
}): JSX.Element | null {
if (showNotificationConvo(Boolean(isKickedFromGroup), Boolean(left), Boolean(isBlocked))) { if (showNotificationConvo(Boolean(isKickedFromGroup), Boolean(left), Boolean(isBlocked))) {
// const isRtlMode = isRtlBody();' // const isRtlMode = isRtlBody();'
@ -484,7 +477,7 @@ export function getNotificationForConvoMenuItem({
<Item <Item
key={item.value} key={item.value}
onClick={async () => { onClick={async () => {
await setNotificationForConvoId(conversationId, item.value); await setNotificationForConvoId(convoId, item.value);
}} }}
disabled={disabled} disabled={disabled}
> >
@ -496,55 +489,53 @@ export function getNotificationForConvoMenuItem({
); );
} }
return null; return null;
} };
export function isRtlBody(): boolean { export function isRtlBody(): boolean {
return ($('body') as any).hasClass('rtl'); return ($('body') as any).hasClass('rtl');
} }
export function getBlockMenuItem( export const BlockMenuItem = (): JSX.Element | null => {
isMe: boolean | undefined, const convoId = useContext(ContextConversationId);
isPrivate: boolean | undefined, const isMe = useIsMe(convoId);
isBlocked: boolean | undefined, const isBlocked = useIsBlocked(convoId);
conversationId: string const isPrivate = useIsPrivate(convoId);
): JSX.Element | null {
if (showBlock(Boolean(isMe), Boolean(isPrivate))) { if (showBlock(Boolean(isMe), Boolean(isPrivate))) {
const blockTitle = isBlocked ? window.i18n('unblockUser') : window.i18n('blockUser'); const blockTitle = isBlocked ? window.i18n('unblockUser') : window.i18n('blockUser');
const blockHandler = isBlocked const blockHandler = isBlocked
? () => unblockConvoById(conversationId) ? () => unblockConvoById(convoId)
: () => blockConvoById(conversationId); : () => blockConvoById(convoId);
return <Item onClick={blockHandler}>{blockTitle}</Item>; return <Item onClick={blockHandler}>{blockTitle}</Item>;
} }
return null; return null;
} };
export function getClearNicknameMenuItem( export const ClearNicknameMenuItem = (): JSX.Element | null => {
isMe: boolean | undefined, const convoId = useContext(ContextConversationId);
hasNickname: boolean | undefined, const isMe = useIsMe(convoId);
isGroup: boolean | undefined, const hasNickname = useHasNickname(convoId);
conversationId: string const isPrivate = useIsPrivate(convoId);
): JSX.Element | null {
if (showClearNickname(Boolean(isMe), Boolean(hasNickname), Boolean(isGroup))) { if (showClearNickname(Boolean(isMe), Boolean(hasNickname), Boolean(isPrivate))) {
return ( return (
<Item onClick={() => clearNickNameByConvoId(conversationId)}> <Item onClick={() => clearNickNameByConvoId(convoId)}>{window.i18n('clearNickname')}</Item>
{window.i18n('clearNickname')}
</Item>
); );
} }
return null; return null;
} };
export const ChangeNicknameMenuItem = () => {
const convoId = useContext(ContextConversationId);
const isMe = useIsMe(convoId);
const isPrivate = useIsPrivate(convoId);
export function getChangeNicknameMenuItem(
isMe: boolean | undefined,
isGroup: boolean | undefined,
conversationId: string
): JSX.Element | null {
const dispatch = useDispatch(); const dispatch = useDispatch();
if (showChangeNickname(Boolean(isMe), Boolean(isGroup))) { if (showChangeNickname(isMe, isPrivate)) {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
dispatch(changeNickNameModal({ conversationId })); dispatch(changeNickNameModal({ conversationId: convoId }));
}} }}
> >
{window.i18n('changeNickname')} {window.i18n('changeNickname')}
@ -552,18 +543,18 @@ export function getChangeNicknameMenuItem(
); );
} }
return null; return null;
} };
export const DeleteMessagesMenuItem = () => {
const convoId = useContext(ContextConversationId);
export function getDeleteMessagesMenuItem(conversationId: string): JSX.Element | null {
return ( return (
<Item <Item
onClick={() => { onClick={() => {
deleteAllMessagesByConvoIdWithConfirmation(conversationId); deleteAllMessagesByConvoIdWithConfirmation(convoId);
}} }}
> >
{window.i18n('deleteMessages')} {window.i18n('deleteMessages')}
</Item> </Item>
); );
};
return null;
}

@ -52,7 +52,7 @@ export function useOurConversationUsername() {
} }
export function useIsMe(pubkey?: string) { export function useIsMe(pubkey?: string) {
return pubkey && pubkey === UserUtils.getOurPubKeyStrFromCache(); return Boolean(pubkey && pubkey === UserUtils.getOurPubKeyStrFromCache());
} }
export function useIsClosedGroup(convoId?: string) { export function useIsClosedGroup(convoId?: string) {
@ -65,6 +65,45 @@ export function useIsPrivate(convoId?: string) {
return Boolean(convoProps && convoProps.isPrivate); return Boolean(convoProps && convoProps.isPrivate);
} }
export function useHasNickname(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.hasNickname);
}
export function useNotificationSetting(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return convoProps?.currentNotificationSetting || 'all';
}
export function useIsPublic(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.isPublic);
}
export function useIsBlocked(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.isBlocked);
}
export function useIsLeft(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.left);
}
export function useIsKickedFromGroup(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.isKickedFromGroup);
}
export function useWeAreAdmin(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.weAreAdmin);
}
export function useExpireTimer(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.expireTimer);
}
export function useIsPinned(convoId?: string) { export function useIsPinned(convoId?: string) {
const convoProps = useConversationPropsById(convoId); const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.isPinned); return Boolean(convoProps && convoProps.isPinned);

@ -1,14 +0,0 @@
import { useSelector } from 'react-redux';
import { StateType } from '../state/reducer';
export const useWeAreAdmin = (convoId?: string) =>
useSelector((state: StateType) => {
if (!convoId) {
return false;
}
const convo = state.conversations.conversationLookup[convoId];
if (!convo) {
return false;
}
return convo.weAreAdmin;
});

@ -14,12 +14,9 @@ import {
import { getIntl, getOurNumber } from './user'; import { getIntl, getOurNumber } from './user';
import { BlockedNumberController } from '../../util'; import { BlockedNumberController } from '../../util';
import { ConversationNotificationSetting, ConversationTypeEnum } from '../../models/conversation'; import { ConversationTypeEnum } from '../../models/conversation';
import { LocalizerType } from '../../types/Util'; import { LocalizerType } from '../../types/Util';
import { import { ConversationHeaderTitleProps } from '../../components/conversation/ConversationHeader';
ConversationHeaderProps,
ConversationHeaderTitleProps,
} from '../../components/conversation/ConversationHeader';
import _ from 'lodash'; import _ from 'lodash';
import { getIsMessageRequestsEnabled } from './userConfig'; import { getIsMessageRequestsEnabled } from './userConfig';
import { ReplyingToMessageProps } from '../../components/conversation/composition/CompositionBox'; import { ReplyingToMessageProps } from '../../components/conversation/composition/CompositionBox';
@ -532,57 +529,24 @@ export const getCurrentNotificationSettingText = createSelector(getSelectedConve
} }
}); });
export const getConversationHeaderProps = createSelector(getSelectedConversation, (state):
| ConversationHeaderProps
| undefined => {
if (!state) {
return undefined;
}
const expirationSettingName = state.expireTimer
? window.Whisper.ExpirationTimerOptions.getName(state.expireTimer || 0)
: null;
return {
conversationKey: state.id,
isPrivate: !!state.isPrivate,
currentNotificationSetting:
state.currentNotificationSetting || ConversationNotificationSetting[0], // if undefined, it is 'all'
isBlocked: !!state.isBlocked,
left: !!state.left,
avatarPath: state.avatarPath || null,
expirationSettingName: expirationSettingName,
hasNickname: !!state.hasNickname,
weAreAdmin: !!state.weAreAdmin,
isKickedFromGroup: !!state.isKickedFromGroup,
isMe: !!state.isMe,
members: state.members || [],
isPublic: !!state.isPublic,
profileName: state.profileName,
name: state.name,
subscriberCount: state.subscriberCount,
isGroup: !!state.isGroup,
};
});
export const getIsSelectedPrivate = createSelector( export const getIsSelectedPrivate = createSelector(
getConversationHeaderProps, getSelectedConversation,
(headerProps): boolean => { (selectedProps): boolean => {
return headerProps?.isPrivate || false; return selectedProps?.isPrivate || false;
} }
); );
export const getIsSelectedBlocked = createSelector( export const getIsSelectedBlocked = createSelector(
getConversationHeaderProps, getSelectedConversation,
(headerProps): boolean => { (selectedProps): boolean => {
return headerProps?.isBlocked || false; return selectedProps?.isBlocked || false;
} }
); );
export const getIsSelectedNoteToSelf = createSelector( export const getIsSelectedNoteToSelf = createSelector(
getConversationHeaderProps, getSelectedConversation,
(headerProps): boolean => { (selectedProps): boolean => {
return headerProps?.isMe || false; return selectedProps?.isMe || false;
} }
); );

Loading…
Cancel
Save