Changeset View
Changeset View
Standalone View
Standalone View
web/chat/edit-text-message.react.js
// @flow | // @flow | ||||
import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { XCircle as XCircleIcon } from 'react-feather'; | import { XCircle as XCircleIcon } from 'react-feather'; | ||||
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; | 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 { type ThreadInfo } from 'lib/types/thread-types.js'; | ||||
import cssInputBar from './chat-input-bar.css'; | import cssInputBar from './chat-input-bar.css'; | ||||
import ChatInputTextArea from './chat-input-text-area.react.js'; | import ChatInputTextArea from './chat-input-text-area.react.js'; | ||||
import ComposedMessage from './composed-message.react.js'; | import ComposedMessage from './composed-message.react.js'; | ||||
import { useEditModalContext } from './edit-message-provider.js'; | import { useEditModalContext } from './edit-message-provider.js'; | ||||
import css from './edit-text-message.css'; | import css from './edit-text-message.css'; | ||||
import type { ButtonColor } from '../components/button.react.js'; | import type { ButtonColor } from '../components/button.react.js'; | ||||
import Button from '../components/button.react.js'; | import Button from '../components/button.react.js'; | ||||
type Props = { | type Props = { | ||||
+item: ChatMessageInfoItem, | +item: ChatMessageInfoItem, | ||||
+threadInfo: ThreadInfo, | +threadInfo: ThreadInfo, | ||||
+background: boolean, | +background: boolean, | ||||
}; | }; | ||||
const cancelButtonColor: ButtonColor = { | const cancelButtonColor: ButtonColor = { | ||||
backgroundColor: 'transparent', | backgroundColor: 'transparent', | ||||
}; | }; | ||||
function EditTextMessage(props: Props): React.Node { | function EditTextMessage(props: Props): React.Node { | ||||
const { background, threadInfo } = props; | const { background, threadInfo, item } = props; | ||||
const { editState, clearEditModal, setDraft } = useEditModalContext(); | const { editState, clearEditModal, setDraft, setError } = | ||||
useEditModalContext(); | |||||
const editMessage = useEditMessage(); | |||||
const editedMessageDraft = editState?.editedMessageDraft ?? ''; | const editedMessageDraft = editState?.editedMessageDraft ?? ''; | ||||
const threadColor = threadInfo.color; | const threadColor = threadInfo.color; | ||||
const saveButtonColor: ButtonColor = React.useMemo( | const saveButtonColor: ButtonColor = React.useMemo( | ||||
() => ({ | () => ({ | ||||
backgroundColor: `#${threadColor}`, | backgroundColor: `#${threadColor}`, | ||||
}), | }), | ||||
[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); | |||||
} | |||||
}; | |||||
let editFailed; | let editFailed; | ||||
if (editState?.isError) { | if (editState?.isError) { | ||||
editFailed = ( | editFailed = ( | ||||
<div className={css.failedText}> | <div className={css.failedText}> | ||||
<XCircleIcon className={css.icon} /> | <XCircleIcon className={css.icon} /> | ||||
<div className={css.errorColor}>Edit failed.</div> | <div className={css.errorColor}>Edit failed.</div> | ||||
<div className={css.whiteColor}>Please try again.</div> | <div className={css.whiteColor}>Please try again.</div> | ||||
</div> | </div> | ||||
); | ); | ||||
} | } | ||||
const containerStyle = classNames(css.editMessage, { | const containerStyle = classNames(css.editMessage, { | ||||
[css.backgroundEditMessage]: background, | [css.backgroundEditMessage]: background, | ||||
}); | }); | ||||
return ( | return ( | ||||
<div className={containerStyle}> | <div className={containerStyle}> | ||||
<div className={cssInputBar.inputBarTextInput}> | <div className={cssInputBar.inputBarTextInput}> | ||||
<ChatInputTextArea | <ChatInputTextArea | ||||
focus={!background} | focus={!background} | ||||
currentText={editedMessageDraft} | currentText={editedMessageDraft} | ||||
setCurrentText={setDraft} | setCurrentText={setDraft} | ||||
send={checkAndEdit} | |||||
/> | /> | ||||
</div> | </div> | ||||
<div className={css.bottomRow}> | <div className={css.bottomRow}> | ||||
{editFailed} | {editFailed} | ||||
<div className={css.buttons}> | <div className={css.buttons}> | ||||
<Button | <Button | ||||
className={[css.saveButton, css.smallButton]} | className={[css.saveButton, css.smallButton]} | ||||
variant="filled" | variant="filled" | ||||
buttonColor={saveButtonColor} | buttonColor={saveButtonColor} | ||||
onClick={checkAndEdit} | |||||
> | > | ||||
Save (enter) | Save (enter) | ||||
</Button> | </Button> | ||||
<Button | <Button | ||||
className={css.smallButton} | className={css.smallButton} | ||||
variant="filled" | variant="filled" | ||||
buttonColor={cancelButtonColor} | buttonColor={cancelButtonColor} | ||||
onClick={clearEditModal} | onClick={clearEditModal} | ||||
Show All 25 Lines |