diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index e1d7db689..93d0118d1 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -6,7 +6,6 @@ import { contextMenu } from 'react-contexify'; import styled from 'styled-components'; import { ConversationNotificationSettingType } from '../../models/conversation'; import { - getConversationHeaderProps, getConversationHeaderTitleProps, getCurrentNotificationSettingText, getIsSelectedBlocked, @@ -33,10 +32,14 @@ import { } from '../../state/ducks/conversations'; import { callRecipient } from '../../interactions/conversationInteractions'; 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 { SessionIconButton } from '../icon'; -import { MemoConversationHeaderMenu } from '../menu/ConversationHeaderMenu'; +import { ConversationHeaderMenu } from '../menu/ConversationHeaderMenu'; export interface TimerOption { name: string; @@ -328,33 +331,20 @@ export const ConversationHeaderSubtitle = (props: { text?: string | null }): JSX }; export const ConversationHeaderWithDetails = () => { - const headerProps = useSelector(getConversationHeaderProps); - const isSelectionMode = useSelector(isMessageSelectionMode); const isMessageDetailOpened = useSelector(isMessageDetailView); - + const selectedConvoKey = useSelector(getSelectedConversationKey); const dispatch = useDispatch(); - if (!headerProps) { + if (!selectedConvoKey) { return null; } - const { - isKickedFromGroup, - expirationSettingName, - avatarPath, - name, - profileName, - isMe, - isPublic, - currentNotificationSetting, - hasNickname, - weAreAdmin, - isBlocked, - left, - conversationKey, - isPrivate, - isGroup, - } = headerProps; + + const isKickedFromGroup = useIsKickedFromGroup(selectedConvoKey); + const expireTimerSetting = useExpireTimer(selectedConvoKey); + const expirationSettingName = expireTimerSetting + ? window.Whisper.ExpirationTimerOptions.getName(expireTimerSetting || 0) + : null; const triggerId = 'conversation-header'; @@ -383,29 +373,13 @@ export const ConversationHeaderWithDetails = () => { onAvatarClick={() => { dispatch(openRightPanel()); }} - pubkey={conversationKey} + pubkey={selectedConvoKey} showBackButton={isMessageDetailOpened} /> )} - + {isSelectionMode && } diff --git a/ts/components/dialog/UpdateGroupMembersDialog.tsx b/ts/components/dialog/UpdateGroupMembersDialog.tsx index bb3919cbf..32fe0a7c0 100644 --- a/ts/components/dialog/UpdateGroupMembersDialog.tsx +++ b/ts/components/dialog/UpdateGroupMembersDialog.tsx @@ -9,10 +9,9 @@ import { SessionButton, SessionButtonColor } from '../basic/SessionButton'; import { MemberListItem } from '../MemberListItem'; import { SessionWrapperModal } from '../SessionWrapperModal'; import { useDispatch } from 'react-redux'; -import { useConversationPropsById } from '../../hooks/useParamSelector'; +import { useConversationPropsById, useWeAreAdmin } from '../../hooks/useParamSelector'; // tslint:disable-next-line: no-submodule-imports import useKey from 'react-use/lib/useKey'; -import { useWeAreAdmin } from '../../hooks/useWeAreAdmin'; import { useSet } from '../../hooks/useSet'; import { ClosedGroup } from '../../session'; import { getConversationController } from '../../session/conversations'; diff --git a/ts/components/menu/ConversationHeaderMenu.tsx b/ts/components/menu/ConversationHeaderMenu.tsx index 05348ae85..4ea167c7f 100644 --- a/ts/components/menu/ConversationHeaderMenu.tsx +++ b/ts/components/menu/ConversationHeaderMenu.tsx @@ -1,98 +1,64 @@ import React from 'react'; import { animation, Menu } from 'react-contexify'; import { - getAddModeratorsMenuItem, - getBanMenuItem, - getBlockMenuItem, - getChangeNicknameMenuItem, - getClearNicknameMenuItem, - getCopyMenuItem, - getDeleteContactMenuItem, - getDeleteMessagesMenuItem, - getDisappearingMenuItem, - getInviteContactMenuItem, - getLeaveGroupMenuItem, - getMarkAllReadMenuItem, - getNotificationForConvoMenuItem, - getPinConversationMenuItem, - getRemoveModeratorsMenuItem, - getShowUserDetailsMenuItem, - getUnbanMenuItem, - getUpdateGroupNameMenuItem, + AddModeratorsMenuItem, + BanMenuItem, + BlockMenuItem, + ChangeNicknameMenuItem, + ClearNicknameMenuItem, + CopyMenuItem, + DeleteContactMenuItem, + DeleteMessagesMenuItem, + DisappearingMessageMenuItem, + InviteContactMenuItem, + LeaveGroupMenuItem, + MarkAllReadMenuItem, + NotificationForConvoMenuItem, + PinConversationMenuItem, + RemoveModeratorsMenuItem, + ShowUserDetailsMenuItem, + UnbanMenuItem, + UpdateGroupNameMenuItem, } from './Menu'; 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 = { - conversationId: 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) => { - const { - conversationId, - triggerId, - isMe, - isPublic, - isGroup, - isKickedFromGroup, - weAreAdmin, - isBlocked, - isPrivate, - left, - hasNickname, - currentNotificationSetting, - name, - profileName, - avatarPath, - } = props; - const userName = name || profileName || conversationId; +export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { + const { triggerId } = props; + const selectedConversation = useSelector(getSelectedConversationKey); + + if (!selectedConversation) { + throw new Error('selectedConversation must be set for a header to be visible!'); + } return ( - - {getDisappearingMenuItem(isPublic, isKickedFromGroup, left, isBlocked, conversationId)} - {getNotificationForConvoMenuItem({ - isKickedFromGroup, - left, - isBlocked, - isPrivate, - currentNotificationSetting, - conversationId, - })} - {getPinConversationMenuItem(conversationId)} - {getBlockMenuItem(isMe, isPrivate, isBlocked, conversationId)} - {getCopyMenuItem(isPublic, isGroup, conversationId)} - {getMarkAllReadMenuItem(conversationId)} - {getChangeNicknameMenuItem(isMe, isGroup, conversationId)} - {getClearNicknameMenuItem(isMe, hasNickname, isGroup, conversationId)} - {getDeleteMessagesMenuItem(conversationId)} - {getAddModeratorsMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} - {getRemoveModeratorsMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} - {getBanMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} - {getUnbanMenuItem(weAreAdmin, isPublic, isKickedFromGroup, conversationId)} - {getUpdateGroupNameMenuItem(weAreAdmin, isKickedFromGroup, left, conversationId)} - {getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)} - {getInviteContactMenuItem(isGroup, isPublic, conversationId)} - {getDeleteContactMenuItem(isGroup, isPublic, left, isKickedFromGroup, conversationId)} - {getShowUserDetailsMenuItem(isPrivate, conversationId, avatarPath, userName)} - + + + + + + + + + + + + + + + + + + + + + + ); }; - -function propsAreEqual(prev: PropsConversationHeaderMenu, next: PropsConversationHeaderMenu) { - return _.isEqual(prev, next); -} -export const MemoConversationHeaderMenu = React.memo(ConversationHeaderMenu, propsAreEqual); diff --git a/ts/components/menu/ConversationListItemContextMenu.tsx b/ts/components/menu/ConversationListItemContextMenu.tsx index cdc45d396..866b31ccf 100644 --- a/ts/components/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/menu/ConversationListItemContextMenu.tsx @@ -1,29 +1,22 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { animation, Menu } from 'react-contexify'; import _ from 'underscore'; -import { - useAvatarPath, - useConversationPropsById, - useConversationUsername, -} from '../../hooks/useParamSelector'; -import { ConversationTypeEnum } from '../../models/conversation'; -import { ContextConversationId } from '../leftpane/conversation-list-item/ConversationListItem'; import { - getBanMenuItem, - getBlockMenuItem, - getChangeNicknameMenuItem, - getClearNicknameMenuItem, - getCopyMenuItem, - getDeleteContactMenuItem, - getDeleteMessagesMenuItem, - getInviteContactMenuItem, - getLeaveGroupMenuItem, - getMarkAllReadMenuItem, - getNotificationForConvoMenuItem, - getPinConversationMenuItem, - getShowUserDetailsMenuItem, - getUnbanMenuItem, + BanMenuItem, + BlockMenuItem, + ChangeNicknameMenuItem, + ClearNicknameMenuItem, + CopyMenuItem, + DeleteContactMenuItem, + DeleteMessagesMenuItem, + InviteContactMenuItem, + LeaveGroupMenuItem, + MarkAllReadMenuItem, + NotificationForConvoMenuItem, + PinConversationMenuItem, + ShowUserDetailsMenuItem, + UnbanMenuItem, } from './Menu'; export type PropsContextConversationItem = { @@ -31,54 +24,24 @@ export type PropsContextConversationItem = { }; const ConversationListItemContextMenu = (props: PropsContextConversationItem) => { - const conversationId = useContext(ContextConversationId); - - const itemMenuProps = useConversationPropsById(conversationId); 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 ( - {getNotificationForConvoMenuItem({ - isPrivate, - isKickedFromGroup, - left, - isBlocked, - currentNotificationSetting, - conversationId, - })} - {getPinConversationMenuItem(conversationId)} - {getBlockMenuItem(isMe, type === ConversationTypeEnum.PRIVATE, isBlocked, conversationId)} - {getCopyMenuItem(isPublic, isGroup, conversationId)} - {getMarkAllReadMenuItem(conversationId)} - {getChangeNicknameMenuItem(isMe, isGroup, conversationId)} - {getClearNicknameMenuItem(isMe, hasNickname, isGroup, conversationId)} - {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 || '')} + + + + + + + + + + + + + + ); }; diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index 5dafc5445..b80335b50 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -1,7 +1,20 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { Item, Submenu } from 'react-contexify'; import { useDispatch, useSelector } from 'react-redux'; +import { + useAvatarPath, + useConversationUsername, + useHasNickname, + useIsBlocked, + useIsKickedFromGroup, + useIsLeft, + useIsMe, + useIsPrivate, + useIsPublic, + useNotificationSetting, + useWeAreAdmin, +} from '../../hooks/useParamSelector'; import { blockConvoById, clearNickNameByConvoId, @@ -36,6 +49,7 @@ import { getFocusedSection } from '../../state/selectors/section'; import { getTimerOptions } from '../../state/selectors/timerOptions'; import { LocalizerKeys } from '../../types/LocalizerKeys'; import { SessionButtonColor } from '../basic/SessionButton'; +import { ContextConversationId } from '../leftpane/conversation-list-item/ConversationListItem'; const maxNumberOfPinnedConversations = 5; @@ -60,17 +74,17 @@ function showBlock(isMe: boolean, isPrivate: boolean): boolean { return !isMe && isPrivate; } -function showClearNickname(isMe: boolean, hasNickname: boolean, isGroup: boolean): boolean { - return !isMe && hasNickname && !isGroup; +function showClearNickname(isMe: boolean, hasNickname: boolean, isPrivate: boolean): boolean { + return !isMe && hasNickname && isPrivate; } -function showChangeNickname(isMe: boolean, isGroup: boolean) { - return !isMe && !isGroup; +function showChangeNickname(isMe: boolean, isPrivate: boolean) { + return !isMe && isPrivate; } // we want to show the copyId for open groups and private chats only -function showCopyId(isPublic: boolean, isGroup: boolean): boolean { - return !isGroup || isPublic; +function showCopyId(isPublic: boolean, isPrivate: boolean): boolean { + return isPrivate || isPublic; } function showDeleteContact( @@ -83,32 +97,36 @@ function showDeleteContact( return !isGroup || (isGroup && (isGroupLeft || isKickedFromGroup || isPublic)); } -const showUnbanUser = (isAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => { - return !isKickedFromGroup && isAdmin && isPublic; +const showUnbanUser = (weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => { + return !isKickedFromGroup && weAreAdmin && isPublic; }; -const showBanUser = (isAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => { - return !isKickedFromGroup && isAdmin && isPublic; +const showBanUser = (weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean) => { + return !isKickedFromGroup && weAreAdmin && isPublic; }; function showAddModerators( - isAdmin: boolean, + weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean ): boolean { - return !isKickedFromGroup && isAdmin && isPublic; + return !isKickedFromGroup && weAreAdmin && isPublic; } function showRemoveModerators( - isAdmin: boolean, + weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: boolean ): boolean { - return !isKickedFromGroup && isAdmin && isPublic; + return !isKickedFromGroup && weAreAdmin && isPublic; } -function showUpdateGroupName(isAdmin: boolean, isKickedFromGroup: boolean, left: boolean): boolean { - return !isKickedFromGroup && !left && isAdmin; +function showUpdateGroupName( + weAreAdmin: boolean, + isKickedFromGroup: boolean, + left: boolean +): boolean { + return !isKickedFromGroup && !left && weAreAdmin; } function showLeaveGroup( @@ -120,22 +138,21 @@ function showLeaveGroup( return !isKickedFromGroup && !left && isGroup && !isPublic; } -function showInviteContact(isGroup: boolean, isPublic: boolean): boolean { - return isGroup && isPublic; +function showInviteContact(isPublic: boolean): boolean { + return isPublic; } /** Menu items standardized */ -export function getInviteContactMenuItem( - isGroup: boolean | undefined, - isPublic: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showInviteContact(Boolean(isGroup), Boolean(isPublic))) { +export const InviteContactMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + + if (showInviteContact(isPublic)) { return ( { - showInviteContactByConvoId(conversationId); + showInviteContactByConvoId(convoId); }} > {window.i18n('inviteContacts')} @@ -143,13 +160,10 @@ export function getInviteContactMenuItem( ); } 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 nbOfAlreadyPinnedConvos = useSelector(getNumberOfPinnedConversations); @@ -175,30 +189,22 @@ export const getPinConversationMenuItem = (conversationId: string): JSX.Element return null; }; -export function getDeleteContactMenuItem( - isGroup: boolean | undefined, - isPublic: boolean | undefined, - isLeft: boolean | undefined, - isKickedFromGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { +export const DeleteContactMenuItem = () => { const dispatch = useDispatch(); + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + const isLeft = useIsLeft(convoId); + const isKickedFromGroup = useIsKickedFromGroup(convoId); + const isPrivate = useIsPrivate(convoId); - if ( - showDeleteContact( - Boolean(isGroup), - Boolean(isPublic), - Boolean(isLeft), - Boolean(isKickedFromGroup) - ) - ) { + if (showDeleteContact(!isPrivate, isPublic, isLeft, isKickedFromGroup)) { let menuItemText: string; if (isPublic) { menuItemText = window.i18n('leaveGroup'); } else { - menuItemText = isGroup - ? window.i18n('editMenuDeleteGroup') - : window.i18n('editMenuDeleteContact'); + menuItemText = isPrivate + ? window.i18n('editMenuDeleteContact') + : window.i18n('editMenuDeleteGroup'); } const onClickClose = () => { @@ -209,13 +215,13 @@ export function getDeleteContactMenuItem( dispatch( updateConfirmModal({ title: menuItemText, - message: isGroup - ? window.i18n('leaveGroupConfirmation') - : window.i18n('deleteContactConfirmation'), + message: isPrivate + ? window.i18n('deleteContactConfirmation') + : window.i18n('leaveGroupConfirmation'), onClickClose, okTheme: SessionButtonColor.Danger, onClickOk: async () => { - await getConversationController().deleteContact(conversationId); + await getConversationController().deleteContact(convoId); }, }) ); @@ -224,22 +230,20 @@ export function getDeleteContactMenuItem( return {menuItemText}; } return null; -} +}; -export function getLeaveGroupMenuItem( - isKickedFromGroup: boolean | undefined, - left: boolean | undefined, - isGroup: boolean | undefined, - isPublic: boolean | undefined, - conversationId: string -): JSX.Element | null { - if ( - showLeaveGroup(Boolean(isKickedFromGroup), Boolean(left), Boolean(isGroup), Boolean(isPublic)) - ) { +export const LeaveGroupMenuItem = () => { + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + const isLeft = useIsLeft(convoId); + const isKickedFromGroup = useIsKickedFromGroup(convoId); + const isPrivate = useIsPrivate(convoId); + + if (showLeaveGroup(isKickedFromGroup, isLeft, !isPrivate, isPublic)) { return ( { - showLeaveGroupByConvoId(conversationId); + showLeaveGroupByConvoId(convoId); }} > {window.i18n('leaveGroup')} @@ -248,15 +252,14 @@ export function getLeaveGroupMenuItem( } return null; -} +}; -export function getShowUserDetailsMenuItem( - isPrivate: boolean | undefined, - conversationId: string, - avatarPath: string | null, - userName: string -): JSX.Element | null { +export const ShowUserDetailsMenuItem = () => { const dispatch = useDispatch(); + const convoId = useContext(ContextConversationId); + const isPrivate = useIsPrivate(convoId); + const avatarPath = useAvatarPath(convoId); + const userName = useConversationUsername(convoId) || convoId; if (isPrivate) { return ( @@ -264,7 +267,7 @@ export function getShowUserDetailsMenuItem( onClick={() => { dispatch( updateUserDetailsModal({ - conversationId: conversationId, + conversationId: convoId, userName, authorAvatarPath: avatarPath, }) @@ -277,19 +280,19 @@ export function getShowUserDetailsMenuItem( } return null; -} +}; -export function getUpdateGroupNameMenuItem( - isAdmin: boolean | undefined, - isKickedFromGroup: boolean | undefined, - left: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showUpdateGroupName(Boolean(isAdmin), Boolean(isKickedFromGroup), Boolean(left))) { +export const UpdateGroupNameMenuItem = () => { + const convoId = useContext(ContextConversationId); + const left = useIsLeft(convoId); + const isKickedFromGroup = useIsKickedFromGroup(convoId); + const weAreAdmin = useWeAreAdmin(convoId); + + if (showUpdateGroupName(weAreAdmin, isKickedFromGroup, left)) { return ( { - await showUpdateGroupNameByConvoId(conversationId); + await showUpdateGroupNameByConvoId(convoId); }} > {window.i18n('editGroup')} @@ -297,19 +300,19 @@ export function getUpdateGroupNameMenuItem( ); } 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( - isAdmin: boolean | undefined, - isPublic: boolean | undefined, - isKickedFromGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showRemoveModerators(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) { + if (showRemoveModerators(weAreAdmin, Boolean(isPublic), Boolean(isKickedFromGroup))) { return ( { - showRemoveModeratorsByConvoId(conversationId); + showRemoveModeratorsByConvoId(convoId); }} > {window.i18n('removeModerators')} @@ -317,19 +320,19 @@ export function getRemoveModeratorsMenuItem( ); } return null; -} +}; -export function getAddModeratorsMenuItem( - isAdmin: boolean | undefined, - isPublic: boolean | undefined, - isKickedFromGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showAddModerators(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) { +export const AddModeratorsMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + const isKickedFromGroup = useIsKickedFromGroup(convoId); + const weAreAdmin = useWeAreAdmin(convoId); + + if (showAddModerators(weAreAdmin, isPublic, isKickedFromGroup)) { return ( { - showAddModeratorsByConvoId(conversationId); + showAddModeratorsByConvoId(convoId); }} > {window.i18n('addModerators')} @@ -337,40 +340,39 @@ export function getAddModeratorsMenuItem( ); } 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( - isAdmin: boolean | undefined, - isPublic: boolean | undefined, - isKickedFromGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showUnbanUser(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) { + if (showUnbanUser(weAreAdmin, isPublic, isKickedFromGroup)) { return ( { - showUnbanUserByConvoId(conversationId); + showUnbanUserByConvoId(convoId); }} > {window.i18n('unbanUser')} ); } - // TODO: translations 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( - isAdmin: boolean | undefined, - isPublic: boolean | undefined, - isKickedFromGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showBanUser(Boolean(isAdmin), Boolean(isPublic), Boolean(isKickedFromGroup))) { + if (showBanUser(weAreAdmin, isPublic, isKickedFromGroup)) { return ( { - showBanUserByConvoId(conversationId); + showBanUserByConvoId(convoId); }} > {window.i18n('banUser')} @@ -378,40 +380,38 @@ export function getBanMenuItem( ); } return null; -} +}; -export function getCopyMenuItem( - isPublic: boolean | undefined, - isGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showCopyId(Boolean(isPublic), Boolean(isGroup))) { +export const CopyMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + const isPrivate = useIsPrivate(convoId); + + if (showCopyId(isPublic, isPrivate)) { const copyIdLabel = isPublic ? window.i18n('copyOpenGroupURL') : window.i18n('copySessionID'); - return copyPublicKeyByConvoId(conversationId)}>{copyIdLabel}; + return copyPublicKeyByConvoId(convoId)}>{copyIdLabel}; } return null; -} +}; -export function getMarkAllReadMenuItem(conversationId: string): JSX.Element | null { - return ( - markAllReadByConvoId(conversationId)}>{window.i18n('markAllAsRead')} - ); -} +export const MarkAllReadMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + return markAllReadByConvoId(convoId)}>{window.i18n('markAllAsRead')}; +}; -export function getDisappearingMenuItem( - isPublic: boolean | undefined, - isKickedFromGroup: boolean | undefined, - left: boolean | undefined, - isBlocked: boolean | undefined, - conversationId: string -): JSX.Element | null { +export const DisappearingMessageMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isBlocked = useIsBlocked(convoId); + const isPublic = useIsPublic(convoId); + const isLeft = useIsLeft(convoId); + const isKickedFromGroup = useIsKickedFromGroup(convoId); const timerOptions = useSelector(getTimerOptions).timerOptions; if ( showTimerOptions( Boolean(isPublic), Boolean(isKickedFromGroup), - Boolean(left), + Boolean(isLeft), Boolean(isBlocked) ) ) { @@ -427,7 +427,7 @@ export function getDisappearingMenuItem( { - await setDisappearingMessagesByConvoId(conversationId, item.value); + await setDisappearingMessagesByConvoId(convoId, item.value); }} > {item.name} @@ -437,23 +437,16 @@ export function getDisappearingMenuItem( ); } 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))) { // const isRtlMode = isRtlBody();' @@ -484,7 +477,7 @@ export function getNotificationForConvoMenuItem({ { - await setNotificationForConvoId(conversationId, item.value); + await setNotificationForConvoId(convoId, item.value); }} disabled={disabled} > @@ -496,55 +489,53 @@ export function getNotificationForConvoMenuItem({ ); } return null; -} +}; export function isRtlBody(): boolean { return ($('body') as any).hasClass('rtl'); } -export function getBlockMenuItem( - isMe: boolean | undefined, - isPrivate: boolean | undefined, - isBlocked: boolean | undefined, - conversationId: string -): JSX.Element | null { +export const BlockMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isMe = useIsMe(convoId); + const isBlocked = useIsBlocked(convoId); + const isPrivate = useIsPrivate(convoId); + if (showBlock(Boolean(isMe), Boolean(isPrivate))) { const blockTitle = isBlocked ? window.i18n('unblockUser') : window.i18n('blockUser'); const blockHandler = isBlocked - ? () => unblockConvoById(conversationId) - : () => blockConvoById(conversationId); + ? () => unblockConvoById(convoId) + : () => blockConvoById(convoId); return {blockTitle}; } return null; -} +}; -export function getClearNicknameMenuItem( - isMe: boolean | undefined, - hasNickname: boolean | undefined, - isGroup: boolean | undefined, - conversationId: string -): JSX.Element | null { - if (showClearNickname(Boolean(isMe), Boolean(hasNickname), Boolean(isGroup))) { +export const ClearNicknameMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isMe = useIsMe(convoId); + const hasNickname = useHasNickname(convoId); + const isPrivate = useIsPrivate(convoId); + + if (showClearNickname(Boolean(isMe), Boolean(hasNickname), Boolean(isPrivate))) { return ( - clearNickNameByConvoId(conversationId)}> - {window.i18n('clearNickname')} - + clearNickNameByConvoId(convoId)}>{window.i18n('clearNickname')} ); } 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(); - if (showChangeNickname(Boolean(isMe), Boolean(isGroup))) { + if (showChangeNickname(isMe, isPrivate)) { return ( { - dispatch(changeNickNameModal({ conversationId })); + dispatch(changeNickNameModal({ conversationId: convoId })); }} > {window.i18n('changeNickname')} @@ -552,18 +543,18 @@ export function getChangeNicknameMenuItem( ); } return null; -} +}; + +export const DeleteMessagesMenuItem = () => { + const convoId = useContext(ContextConversationId); -export function getDeleteMessagesMenuItem(conversationId: string): JSX.Element | null { return ( { - deleteAllMessagesByConvoIdWithConfirmation(conversationId); + deleteAllMessagesByConvoIdWithConfirmation(convoId); }} > {window.i18n('deleteMessages')} ); - - return null; -} +}; diff --git a/ts/hooks/useParamSelector.ts b/ts/hooks/useParamSelector.ts index 141c2315c..0ea86226d 100644 --- a/ts/hooks/useParamSelector.ts +++ b/ts/hooks/useParamSelector.ts @@ -52,7 +52,7 @@ export function useOurConversationUsername() { } export function useIsMe(pubkey?: string) { - return pubkey && pubkey === UserUtils.getOurPubKeyStrFromCache(); + return Boolean(pubkey && pubkey === UserUtils.getOurPubKeyStrFromCache()); } export function useIsClosedGroup(convoId?: string) { @@ -65,6 +65,45 @@ export function useIsPrivate(convoId?: string) { 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) { const convoProps = useConversationPropsById(convoId); return Boolean(convoProps && convoProps.isPinned); diff --git a/ts/hooks/useWeAreAdmin.ts b/ts/hooks/useWeAreAdmin.ts deleted file mode 100644 index da7d6eddd..000000000 --- a/ts/hooks/useWeAreAdmin.ts +++ /dev/null @@ -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; - }); diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index a7e94b936..c74b554f2 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -14,12 +14,9 @@ import { import { getIntl, getOurNumber } from './user'; import { BlockedNumberController } from '../../util'; -import { ConversationNotificationSetting, ConversationTypeEnum } from '../../models/conversation'; +import { ConversationTypeEnum } from '../../models/conversation'; import { LocalizerType } from '../../types/Util'; -import { - ConversationHeaderProps, - ConversationHeaderTitleProps, -} from '../../components/conversation/ConversationHeader'; +import { ConversationHeaderTitleProps } from '../../components/conversation/ConversationHeader'; import _ from 'lodash'; import { getIsMessageRequestsEnabled } from './userConfig'; 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( - getConversationHeaderProps, - (headerProps): boolean => { - return headerProps?.isPrivate || false; + getSelectedConversation, + (selectedProps): boolean => { + return selectedProps?.isPrivate || false; } ); export const getIsSelectedBlocked = createSelector( - getConversationHeaderProps, - (headerProps): boolean => { - return headerProps?.isBlocked || false; + getSelectedConversation, + (selectedProps): boolean => { + return selectedProps?.isBlocked || false; } ); export const getIsSelectedNoteToSelf = createSelector( - getConversationHeaderProps, - (headerProps): boolean => { - return headerProps?.isMe || false; + getSelectedConversation, + (selectedProps): boolean => { + return selectedProps?.isMe || false; } );