refactor menu items to react components

This commit is contained in:
Audric Ackermann 2022-01-06 14:16:15 +11:00
parent 3d2158f469
commit 580a59ba3c
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4
8 changed files with 332 additions and 450 deletions

View File

@ -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}
/>
</>
)}
<MemoConversationHeaderMenu
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}
/>
<ConversationHeaderMenu triggerId={triggerId} />
</div>
{isSelectionMode && <SelectionOverlay />}

View File

@ -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';

View File

@ -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 (
<Menu id={triggerId} animation={animation.fade}>
{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)}
</Menu>
<ContextConversationId.Provider value={selectedConversation}>
<Menu id={triggerId} animation={animation.fade}>
<DisappearingMessageMenuItem />
<NotificationForConvoMenuItem />
<PinConversationMenuItem />
<BlockMenuItem />
<CopyMenuItem />
<MarkAllReadMenuItem />
<ChangeNicknameMenuItem />
<ClearNicknameMenuItem />
<DeleteMessagesMenuItem />
<AddModeratorsMenuItem />
<RemoveModeratorsMenuItem />
<BanMenuItem />
<UnbanMenuItem />
<UpdateGroupNameMenuItem />
<LeaveGroupMenuItem />
<InviteContactMenuItem />
<DeleteContactMenuItem />
<ShowUserDetailsMenuItem />
</Menu>
</ContextConversationId.Provider>
);
};
function propsAreEqual(prev: PropsConversationHeaderMenu, next: PropsConversationHeaderMenu) {
return _.isEqual(prev, next);
}
export const MemoConversationHeaderMenu = React.memo(ConversationHeaderMenu, propsAreEqual);

View File

@ -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 (
<Menu id={triggerId} animation={animation.fade}>
{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 || '')}
<NotificationForConvoMenuItem />
<PinConversationMenuItem />
<BlockMenuItem />
<CopyMenuItem />
<MarkAllReadMenuItem />
<ChangeNicknameMenuItem />
<ClearNicknameMenuItem />
<DeleteMessagesMenuItem />
<BanMenuItem />
<UnbanMenuItem />
<InviteContactMenuItem />
<DeleteContactMenuItem />
<LeaveGroupMenuItem />
<ShowUserDetailsMenuItem />
</Menu>
);
};

View File

@ -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 (
<Item
onClick={() => {
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 <Item onClick={showConfirmationModal}>{menuItemText}</Item>;
}
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 (
<Item
onClick={() => {
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 (
<Item
onClick={async () => {
await showUpdateGroupNameByConvoId(conversationId);
await showUpdateGroupNameByConvoId(convoId);
}}
>
{window.i18n('editGroup')}
@ -297,19 +300,19 @@ export function getUpdateGroupNameMenuItem(
);
}
return null;
}
};
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))) {
export const RemoveModeratorsMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const weAreAdmin = useWeAreAdmin(convoId);
if (showRemoveModerators(weAreAdmin, Boolean(isPublic), Boolean(isKickedFromGroup))) {
return (
<Item
onClick={() => {
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 (
<Item
onClick={() => {
showAddModeratorsByConvoId(conversationId);
showAddModeratorsByConvoId(convoId);
}}
>
{window.i18n('addModerators')}
@ -337,40 +340,39 @@ export function getAddModeratorsMenuItem(
);
}
return null;
}
};
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))) {
export const UnbanMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const weAreAdmin = useWeAreAdmin(convoId);
if (showUnbanUser(weAreAdmin, isPublic, isKickedFromGroup)) {
return (
<Item
onClick={() => {
showUnbanUserByConvoId(conversationId);
showUnbanUserByConvoId(convoId);
}}
>
{window.i18n('unbanUser')}
</Item>
);
}
// TODO: translations
return null;
}
};
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))) {
export const BanMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
const isPublic = useIsPublic(convoId);
const isKickedFromGroup = useIsKickedFromGroup(convoId);
const weAreAdmin = useWeAreAdmin(convoId);
if (showBanUser(weAreAdmin, isPublic, isKickedFromGroup)) {
return (
<Item
onClick={() => {
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 <Item onClick={() => copyPublicKeyByConvoId(conversationId)}>{copyIdLabel}</Item>;
return <Item onClick={() => copyPublicKeyByConvoId(convoId)}>{copyIdLabel}</Item>;
}
return null;
}
};
export function getMarkAllReadMenuItem(conversationId: string): JSX.Element | null {
return (
<Item onClick={() => markAllReadByConvoId(conversationId)}>{window.i18n('markAllAsRead')}</Item>
);
}
export const MarkAllReadMenuItem = (): JSX.Element | null => {
const convoId = useContext(ContextConversationId);
return <Item onClick={() => markAllReadByConvoId(convoId)}>{window.i18n('markAllAsRead')}</Item>;
};
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(
<Item
key={item.value}
onClick={async () => {
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({
<Item
key={item.value}
onClick={async () => {
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 <Item onClick={blockHandler}>{blockTitle}</Item>;
}
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 (
<Item onClick={() => clearNickNameByConvoId(conversationId)}>
{window.i18n('clearNickname')}
</Item>
<Item onClick={() => clearNickNameByConvoId(convoId)}>{window.i18n('clearNickname')}</Item>
);
}
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 (
<Item
onClick={() => {
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 (
<Item
onClick={() => {
deleteAllMessagesByConvoIdWithConfirmation(conversationId);
deleteAllMessagesByConvoIdWithConfirmation(convoId);
}}
>
{window.i18n('deleteMessages')}
</Item>
);
return null;
}
};

View File

@ -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);

View File

@ -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;
});

View File

@ -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;
}
);