diff --git a/web/chat/edit-text-message.react.js b/web/chat/edit-text-message.react.js index 875f45190..8fb6ff636 100644 --- a/web/chat/edit-text-message.react.js +++ b/web/chat/edit-text-message.react.js @@ -1,171 +1,184 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import { useCallback } from 'react'; import { XCircle as XCircleIcon } from 'react-feather'; import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; import { useEditMessage } from 'lib/shared/edit-messages-utils.js'; import { trimMessage } from 'lib/shared/message-utils.js'; import { type ThreadInfo } from 'lib/types/thread-types.js'; import cssInputBar from './chat-input-bar.css'; import ChatInputTextArea from './chat-input-text-area.react.js'; import ComposedMessage from './composed-message.react.js'; import { useEditModalContext } from './edit-message-provider.js'; import css from './edit-text-message.css'; import type { ButtonColor } from '../components/button.react.js'; import Button from '../components/button.react.js'; type Props = { +item: ChatMessageInfoItem, +threadInfo: ThreadInfo, +background: boolean, }; const cancelButtonColor: ButtonColor = { backgroundColor: 'transparent', }; function EditTextMessage(props: Props): React.Node { const { background, threadInfo, item } = props; const { editState, clearEditModal, setDraft, setError, updatePosition } = useEditModalContext(); const editMessage = useEditMessage(); const myRef = React.useRef(null); const editedMessageDraft = editState?.editedMessageDraft ?? ''; const threadColor = threadInfo.color; const saveButtonColor: ButtonColor = React.useMemo( () => ({ backgroundColor: `#${threadColor}`, }), [threadColor], ); const isMessageEdited = React.useMemo(() => { const { messageInfo } = item; if (!messageInfo || !messageInfo.text || !editState) { return false; } if (!editedMessageDraft) { return false; } const trimmedDraft = trimMessage(editedMessageDraft); return trimmedDraft !== messageInfo.text; }, [editState, editedMessageDraft, item]); const checkAndEdit = async () => { const { id: messageInfoID } = item.messageInfo; if (!isMessageEdited) { clearEditModal(); return; } if (!messageInfoID || !editState?.editedMessageDraft) { return; } try { await editMessage(messageInfoID, editState.editedMessageDraft); clearEditModal(); } catch (e) { setError(true); } }; const updateDimensions = useCallback(() => { if (!myRef.current || !background) { return; } const { left, top, width, height } = myRef.current.getBoundingClientRect(); updatePosition({ left, top, width, height, }); }, [background, updatePosition]); + const preventCloseTab = React.useCallback( + event => { + if (!isMessageEdited) { + return null; + } + event.preventDefault(); + return (event.returnValue = ''); + }, + [isMessageEdited], + ); + React.useEffect(() => { if (!background) { return undefined; } window.addEventListener('resize', updateDimensions); + window.addEventListener('beforeunload', preventCloseTab); return () => { window.removeEventListener('resize', updateDimensions); + window.removeEventListener('beforeunload', preventCloseTab); }; - }, [background, updateDimensions]); + }, [background, preventCloseTab, updateDimensions]); React.useEffect(() => { updateDimensions(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); let editFailed; if (editState?.isError) { editFailed = (
Edit failed.
Please try again.
); } const containerStyle = classNames(css.editMessage, { [css.backgroundEditMessage]: background, }); return (
{editFailed}
); } const ComposedEditTextMessage: React.ComponentType = React.memo( function ComposedEditTextMessage(props) { const { background, ...restProps } = props; return ( ); }, ); export { EditTextMessage, ComposedEditTextMessage };