Adding rightclick accept/decline menu options for message requests. Adding hide menu item for message request banner.
This commit is contained in:
parent
600ef86ea7
commit
56c1a06a28
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
);
|
|
@ -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
|
||||
) => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -481,4 +481,5 @@ export type LocalizerKeys =
|
|||
| 'youHaveANewFriendRequest'
|
||||
| 'clearAllConfirmationTitle'
|
||||
| 'clearAllConfirmationBody'
|
||||
| 'hideBanner'
|
||||
| 'reportIssue';
|
||||
|
|
Loading…
Reference in New Issue