Add contextMenu for deleting call events on right-click
This commit is contained in:
parent
7fb01f102d
commit
88fd42a46b
12 changed files with 394 additions and 269 deletions
244
ts/components/conversation/MessageContextMenu.tsx
Normal file
244
ts/components/conversation/MessageContextMenu.tsx
Normal file
|
@ -0,0 +1,244 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { type RefObject } from 'react';
|
||||
import { ContextMenu, MenuItem } from 'react-contextmenu';
|
||||
import ReactDOM from 'react-dom';
|
||||
import type { LocalizerType } from '../../types/I18N';
|
||||
|
||||
export type ContextMenuTriggerType = {
|
||||
handleContextClick: (
|
||||
event: React.MouseEvent<HTMLDivElement> | MouseEvent
|
||||
) => void;
|
||||
};
|
||||
|
||||
type MessageContextProps = {
|
||||
i18n: LocalizerType;
|
||||
triggerId: string;
|
||||
shouldShowAdditional: boolean;
|
||||
|
||||
onDownload: (() => void) | undefined;
|
||||
onEdit: (() => void) | undefined;
|
||||
onReplyToMessage: (() => void) | undefined;
|
||||
onReact: (() => void) | undefined;
|
||||
onRetryMessageSend: (() => void) | undefined;
|
||||
onRetryDeleteForEveryone: (() => void) | undefined;
|
||||
onCopy: (() => void) | undefined;
|
||||
onForward: (() => void) | undefined;
|
||||
onDeleteMessage: () => void;
|
||||
onMoreInfo: (() => void) | undefined;
|
||||
onSelect: (() => void) | undefined;
|
||||
};
|
||||
export const MessageContextMenu = ({
|
||||
i18n,
|
||||
triggerId,
|
||||
shouldShowAdditional,
|
||||
onDownload,
|
||||
onEdit,
|
||||
onReplyToMessage,
|
||||
onReact,
|
||||
onMoreInfo,
|
||||
onCopy,
|
||||
onSelect,
|
||||
onRetryMessageSend,
|
||||
onRetryDeleteForEveryone,
|
||||
onForward,
|
||||
onDeleteMessage,
|
||||
}: MessageContextProps): JSX.Element => {
|
||||
const menu = (
|
||||
<ContextMenu id={triggerId}>
|
||||
{shouldShowAdditional && (
|
||||
<>
|
||||
{onDownload && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__download',
|
||||
}}
|
||||
onClick={onDownload}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__download')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onReplyToMessage && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__reply',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onReplyToMessage();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__reply')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onReact && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__react',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onReact();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__react')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{onForward && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__forward-message',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onForward();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__forward')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onEdit && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__edit-message',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onEdit();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:edit')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onSelect && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__select',
|
||||
}}
|
||||
onClick={() => {
|
||||
onSelect();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__select')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onCopy && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__copy-timestamp',
|
||||
}}
|
||||
onClick={() => {
|
||||
onCopy();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:copy')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onMoreInfo && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__more-info',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onMoreInfo();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__info')}
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__delete-message',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onDeleteMessage();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:MessageContextMenu__deleteMessage')}
|
||||
</MenuItem>
|
||||
{onRetryMessageSend && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__retry-send',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onRetryMessageSend();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:retrySend')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onRetryDeleteForEveryone && (
|
||||
<MenuItem
|
||||
attributes={{
|
||||
className:
|
||||
'module-message__context--icon module-message__context__delete-message-for-everyone',
|
||||
}}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
onRetryDeleteForEveryone();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:retryDeleteForEveryone')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</ContextMenu>
|
||||
);
|
||||
|
||||
return ReactDOM.createPortal(menu, document.body);
|
||||
};
|
||||
|
||||
export function useHandleMessageContextMenu(
|
||||
menuTriggerRef: RefObject<ContextMenuTriggerType>
|
||||
): ContextMenuTriggerType['handleContextClick'] {
|
||||
return React.useCallback(
|
||||
(event: React.MouseEvent<HTMLDivElement> | MouseEvent): void => {
|
||||
const selection = window.getSelection();
|
||||
|
||||
if (selection && !selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
if (event && event.target instanceof HTMLAnchorElement) {
|
||||
return;
|
||||
}
|
||||
if (menuTriggerRef.current) {
|
||||
menuTriggerRef.current.handleContextClick(
|
||||
event ?? new MouseEvent('click')
|
||||
);
|
||||
}
|
||||
},
|
||||
[menuTriggerRef]
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue