diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index c269736b82..0e8cfb2a5c 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -570,6 +570,7 @@ "each_user_will_have_access_to": "", "easily_manage_your_project_files_everywhere": "", "edit": "", + "edit_comment": "", "edit_comment_error_message": "", "edit_comment_error_title": "", "edit_content_directly": "", @@ -577,6 +578,7 @@ "edit_dictionary_empty": "", "edit_dictionary_remove": "", "edit_figure": "", + "edit_message": "", "edit_reference": "", "edit_sso_configuration": "", "edit_tag": "", diff --git a/services/web/frontend/js/features/chat/components/message-content.tsx b/services/web/frontend/js/features/chat/components/message-content.tsx index 4e60ec06dd..4ceaf37b29 100644 --- a/services/web/frontend/js/features/chat/components/message-content.tsx +++ b/services/web/frontend/js/features/chat/components/message-content.tsx @@ -6,7 +6,10 @@ import { debugConsole } from '@/utils/debugging' import { Message, useChatContext } from '@/features/chat/context/chat-context' import OLButton from '@/shared/components/ol/ol-button' import { useTranslation } from 'react-i18next' -import AutoExpandingTextArea from '@/shared/components/auto-expanding-text-area' +import { mentionsFeatureEnabled } from '@/shared/utils/mentions' +import { MentionsInput } from '@/shared/components/mentions-input' +import { parseMentions } from '@/shared/utils/parse-mentions' +import { MentionBadge } from '@/shared/components/mention-badge' const MessageContent: FC<{ content: Message['content'] @@ -47,64 +50,51 @@ const MessageContent: FC<{ } }, [content, mounted]) - const completeEdit = useCallback(() => { - editMessage(messageId, editedContent) - }, [editMessage, editedContent, messageId]) - - const handleKeyDown = useCallback( - (e: React.KeyboardEvent) => { - if (e.key === 'Enter') { - e.preventDefault() - completeEdit() - } else if (e.key === 'Escape') { - e.preventDefault() - cancelMessageEdit() - setEditedContent(content) - } + const completeEdit = useCallback( + (value: string) => { + editMessage(messageId, value) }, - [cancelMessageEdit, completeEdit, content] + [editMessage, messageId] ) - const handleChange = useCallback( - (e: React.ChangeEvent) => { - setEditedContent(e.target.value) - }, - [] - ) + const handleCancel = useCallback(() => { + cancelMessageEdit() + setEditedContent(content) + }, [cancelMessageEdit, content]) - const handleAutoFocus = useCallback( - (textarea: HTMLTextAreaElement) => textarea.select(), - [] - ) + const mentionsEnabled = mentionsFeatureEnabled() return editing ? ( <> -
+ + {t('cancel')} + { - cancelMessageEdit() - setEditedContent(content) - }} + onClick={() => completeEdit(editedContent)} > - {t('cancel')} - - completeEdit()}> {t('save')} ) : (

- {content} + {mentionsEnabled ? ( + renderMentionedContent(content) + ) : ( + {content} + )} {edited ? ( <> {' '} @@ -115,4 +105,14 @@ const MessageContent: FC<{ ) } +function renderMentionedContent(content: string) { + return parseMentions(content).map((segment, index) => + segment.type === 'mention' ? ( + + ) : ( + {segment.value} + ) + ) +} + export default MessageContent diff --git a/services/web/frontend/js/features/chat/components/message-input.tsx b/services/web/frontend/js/features/chat/components/message-input.tsx index e781b72d55..71b74d58df 100644 --- a/services/web/frontend/js/features/chat/components/message-input.tsx +++ b/services/web/frontend/js/features/chat/components/message-input.tsx @@ -1,4 +1,9 @@ import { useTranslation } from 'react-i18next' +import { useCallback, useRef } from 'react' +import { + MentionsInput, + MentionsInputHandle, +} from '@/shared/components/mentions-input' type MessageInputProps = { resetUnreadMessages: () => void @@ -7,33 +12,25 @@ type MessageInputProps = { function MessageInput({ resetUnreadMessages, sendMessage }: MessageInputProps) { const { t } = useTranslation() + const inputRef = useRef(null) - function handleKeyDown(event: React.KeyboardEvent) { - const selectingCharacter = event.nativeEvent.isComposing - if (event.key === 'Enter' && !selectingCharacter) { - event.preventDefault() - const target = event.target as HTMLInputElement - sendMessage(target.value) - // wrap the form reset in setTimeout so input sources have time to finish - // https://github.com/overleaf/internal/pull/9206 - window.setTimeout(() => { - target.blur() - target.closest('form')?.reset() - target.focus() - }, 0) - } - } + const handleSubmit = useCallback( + (message: string) => { + sendMessage(message) + inputRef.current?.clear() + }, + [sendMessage] + ) return (

- -