Adding rightclick accept/decline menu options for message requests. Adding hide menu item for message request banner.

This commit is contained in:
warrickct 2022-02-25 14:17:34 +11:00
parent 600ef86ea7
commit 56c1a06a28
9 changed files with 162 additions and 31 deletions

View File

@ -478,5 +478,6 @@
"youHaveANewFriendRequest": "You have a new friend request",
"clearAllConfirmationTitle": "Clear All Message Requests",
"clearAllConfirmationBody": "Are you sure you want to clear all message requests?",
"hideBanner": "Hide",
"openMessageRequestInboxDescription": "View your Message Request inbox"
}

View File

@ -1,22 +1,17 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { getMessageCountByType } from '../../data/data';
import {
approveConvoAndSendResponse,
blockConvoById,
declineConversation,
declineConversationWithConfirm,
} from '../../interactions/conversationInteractions';
import { MessageDirection } from '../../models/messageType';
import { getConversationController } from '../../session/conversations';
import { forceSyncConfigurationNowIfNeeded } from '../../session/utils/syncUtils';
import { clearConversationFocus } from '../../state/ducks/conversations';
import { updateConfirmModal } from '../../state/ducks/modalDialog';
import { getSelectedConversation } from '../../state/selectors/conversations';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
export const ConversationMessageRequestButtons = () => {
const dispatch = useDispatch();
const selectedConversation = useSelector(getSelectedConversation);
const [hasIncoming, setHasIncomingMsgs] = useState(false);
const [incomingChecked, setIncomingChecked] = useState(false);
@ -50,26 +45,7 @@ export const ConversationMessageRequestButtons = () => {
.isRequest();
const handleDeclineConversationRequest = () => {
dispatch(
updateConfirmModal({
okText: window.i18n('decline'),
cancelText: window.i18n('cancel'),
message: window.i18n('declineRequestMessage'),
onClickOk: async () => {
const { id } = selectedConversation;
await declineConversation(id, false);
await blockConvoById(id);
await forceSyncConfigurationNowIfNeeded();
clearConversationFocus();
},
onClickCancel: () => {
dispatch(updateConfirmModal(null));
},
onClickClose: () => {
dispatch(updateConfirmModal(null));
},
})
);
declineConversationWithConfirm(selectedConversation.id, true);
};
const handleAcceptConversationRequest = async () => {

View File

@ -1,9 +1,12 @@
import React from 'react';
import React, { useState } from 'react';
import { contextMenu } from 'react-contexify';
import { createPortal } from 'react-dom';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { getConversationRequests } from '../../state/selectors/conversations';
import { getHideMessageRequestBanner } from '../../state/selectors/userConfig';
import { SessionIcon, SessionIconSize, SessionIconType } from '../icon';
import { MemoMessageRequestBannerContextMenu } from '../menu/MessageRequestBannerContextMenu';
const StyledMessageRequestBanner = styled.div`
height: 64px;
@ -86,13 +89,38 @@ export const MessageRequestsBanner = (props: { handleOnClick: () => any }) => {
const { handleOnClick } = props;
const conversationRequests = useSelector(getConversationRequests);
const hideRequestBanner = useSelector(getHideMessageRequestBanner);
const [isMenuOpen, setIsMenuOpen] = useState(false);
if (!conversationRequests.length || hideRequestBanner) {
return null;
}
const triggerId = 'msg-req-banner';
const handleOnContextMenu = (e: any) => {
contextMenu.show({
id: triggerId,
event: e,
});
setIsMenuOpen(true);
};
const handleOnClickBanner = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.button === 0 && !isMenuOpen) {
handleOnClick();
}
};
return (
<StyledMessageRequestBanner onClick={handleOnClick}>
<StyledMessageRequestBanner
onContextMenu={handleOnContextMenu}
onClick={handleOnClickBanner}
onMouseUp={e => {
e.stopPropagation();
e.preventDefault();
}}
>
<CirclularIcon iconType="messageRequest" iconSize="medium" />
<StyledMessageRequestBannerHeader>
{window.i18n('messageRequests')}
@ -100,6 +128,13 @@ export const MessageRequestsBanner = (props: { handleOnClick: () => any }) => {
<StyledUnreadCounter>
<div>{conversationRequests.length || 0}</div>
</StyledUnreadCounter>
<Portal>
<MemoMessageRequestBannerContextMenu triggerId={triggerId} />
</Portal>
</StyledMessageRequestBanner>
);
};
const Portal = ({ children }: { children: any }) => {
return createPortal(children, document.querySelector('.inbox.index') as Element);
};

View File

@ -3,11 +3,13 @@ import { animation, Menu } from 'react-contexify';
import _ from 'lodash';
import {
AcceptMenuItem,
BanMenuItem,
BlockMenuItem,
ChangeNicknameMenuItem,
ClearNicknameMenuItem,
CopyMenuItem,
DeclineMenuItem,
DeleteContactMenuItem,
DeleteMessagesMenuItem,
InviteContactMenuItem,
@ -28,6 +30,8 @@ const ConversationListItemContextMenu = (props: PropsContextConversationItem) =>
return (
<Menu id={triggerId} animation={animation.fade}>
<AcceptMenuItem />
<DeclineMenuItem />
<NotificationForConvoMenuItem />
<PinConversationMenuItem />
<BlockMenuItem />

View File

@ -16,9 +16,11 @@ import {
useWeAreAdmin,
} from '../../hooks/useParamSelector';
import {
approveConvoAndSendResponse,
blockConvoById,
clearNickNameByConvoId,
copyPublicKeyByConvoId,
declineConversationWithConfirm,
deleteAllMessagesByConvoIdWithConfirmation,
markAllReadByConvoId,
setDisappearingMessagesByConvoId,
@ -44,6 +46,7 @@ import {
updateUserDetailsModal,
} from '../../state/ducks/modalDialog';
import { SectionType } from '../../state/ducks/section';
import { hideMessageRequestBanner } from '../../state/ducks/userConfig';
import { getNumberOfPinnedConversations } from '../../state/selectors/conversations';
import { getFocusedSection } from '../../state/selectors/section';
import { getTimerOptions } from '../../state/selectors/timerOptions';
@ -558,3 +561,57 @@ export const DeleteMessagesMenuItem = () => {
</Item>
);
};
export const HideBannerMenuItem = (): JSX.Element => {
const dispatch = useDispatch();
return (
<Item
onClick={() => {
dispatch(hideMessageRequestBanner());
}}
>
{window.i18n('hideBanner')}
</Item>
);
};
export const AcceptMenuItem = () => {
const convoId = useContext(ContextConversationId);
const convo = getConversationController().get(convoId);
const showMenuItem = convo.isRequest();
if (showMenuItem) {
return (
<Item
onClick={async () => {
await convo.setDidApproveMe(true);
await convo.addOutgoingApprovalMessage(Date.now());
await approveConvoAndSendResponse(convoId, true);
}}
>
{window.i18n('accept')}
</Item>
);
}
return null;
};
export const DeclineMenuItem = () => {
const convoId = useContext(ContextConversationId);
const showMenuItem = getConversationController()
.get(convoId)
.isRequest();
if (showMenuItem) {
return (
<Item
onClick={() => {
declineConversationWithConfirm(convoId, true);
}}
>
{window.i18n('decline')}
</Item>
);
}
return null;
};

View File

@ -0,0 +1,27 @@
import React from 'react';
import { animation, Menu } from 'react-contexify';
import _ from 'lodash';
import { HideBannerMenuItem } from './Menu';
export type PropsContextConversationItem = {
triggerId: string;
};
const MessageRequestBannerContextMenu = (props: PropsContextConversationItem) => {
const { triggerId } = props;
return (
<Menu id={triggerId} animation={animation.fade}>
<HideBannerMenuItem />
</Menu>
);
};
function propsAreEqual(prev: PropsContextConversationItem, next: PropsContextConversationItem) {
return _.isEqual(prev, next);
}
export const MemoMessageRequestBannerContextMenu = React.memo(
MessageRequestBannerContextMenu,
propsAreEqual
);

View File

@ -29,7 +29,11 @@ import {
lastAvatarUploadTimestamp,
removeAllMessagesInConversation,
} from '../data/data';
import { conversationReset, quoteMessage } from '../state/ducks/conversations';
import {
clearConversationFocus,
conversationReset,
quoteMessage,
} from '../state/ducks/conversations';
import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager';
import { IMAGE_JPEG } from '../types/MIME';
import { FSv2 } from '../session/apis/file_server_api';
@ -145,10 +149,32 @@ export const approveConvoAndSendResponse = async (
}
};
export const declineConversationWithConfirm = (convoId: string, syncToDevices: boolean = true) => {
window?.inboxStore?.dispatch(
updateConfirmModal({
okText: window.i18n('decline'),
cancelText: window.i18n('cancel'),
message: window.i18n('declineRequestMessage'),
onClickOk: async () => {
await declineConversationWithoutConfirm(convoId, syncToDevices);
await blockConvoById(convoId);
await forceSyncConfigurationNowIfNeeded();
clearConversationFocus();
},
onClickCancel: () => {
window?.inboxStore?.dispatch(updateConfirmModal(null));
},
onClickClose: () => {
window?.inboxStore?.dispatch(updateConfirmModal(null));
},
})
);
};
/**
* Sets the approval fields to false for conversation. Sends decline message.
*/
export const declineConversation = async (
export const declineConversationWithoutConfirm = async (
conversationId: string,
syncToDevices: boolean = true
) => {

View File

@ -32,6 +32,9 @@ const userConfigSlice = createSlice({
showMessageRequestBanner: state => {
state.hideMessageRequests = false;
},
hideMessageRequestBanner: state => {
state.hideMessageRequests = true;
},
},
});
@ -41,5 +44,6 @@ export const {
disableRecoveryPhrasePrompt,
toggleMessageRequests,
showMessageRequestBanner,
hideMessageRequestBanner,
} = actions;
export const userConfigReducer = reducer;

View File

@ -481,4 +481,5 @@ export type LocalizerKeys =
| 'youHaveANewFriendRequest'
| 'clearAllConfirmationTitle'
| 'clearAllConfirmationBody'
| 'hideBanner'
| 'reportIssue';