diff --git a/app/soapbox/features/chats/components/chat-composer.tsx b/app/soapbox/features/chats/components/chat-composer.tsx index d419186b4..60f4cafa0 100644 --- a/app/soapbox/features/chats/components/chat-composer.tsx +++ b/app/soapbox/features/chats/components/chat-composer.tsx @@ -1,10 +1,11 @@ import React, { useState } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; +import { defineMessages, IntlShape, useIntl } from 'react-intl'; import { unblockAccount } from 'soapbox/actions/accounts'; import { openModal } from 'soapbox/actions/modals'; import { Button, Combobox, ComboboxInput, ComboboxList, ComboboxOption, ComboboxPopover, HStack, IconButton, Stack, Text, Textarea } from 'soapbox/components/ui'; import { useChatContext } from 'soapbox/contexts/chat-context'; +import UploadButton from 'soapbox/features/compose/components/upload-button'; import { search as emojiSearch } from 'soapbox/features/emoji/emoji-mart-search-light'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { textAtCursorMatchesToken } from 'soapbox/utils/suggestions'; @@ -32,10 +33,12 @@ interface Suggestion { token: string, } -interface IChatComposer extends Pick, 'onKeyDown' | 'onChange' | 'disabled'> { +interface IChatComposer extends Pick, 'onKeyDown' | 'onChange' | 'onPaste' | 'disabled'> { value: string onSubmit: () => void errorMessage: string | undefined + onSelectFile: (files: FileList, intl: IntlShape) => void + resetFileKey: number | null } /** Textarea input for chats. */ @@ -46,6 +49,9 @@ const ChatComposer = React.forwardRef onSubmit, errorMessage = false, disabled = false, + onSelectFile, + resetFileKey, + onPaste, }, ref) => { const dispatch = useAppDispatch(); const intl = useIntl(); @@ -143,6 +149,10 @@ const ChatComposer = React.forwardRef return (
+ + + + onKeyDown={handleKeyDown} value={value} onChange={handleChange} + onPaste={onPaste} isResizeable={false} autoGrow maxRows={5} diff --git a/app/soapbox/features/chats/components/chat.tsx b/app/soapbox/features/chats/components/chat.tsx index ab0b81abf..9eab2b118 100644 --- a/app/soapbox/features/chats/components/chat.tsx +++ b/app/soapbox/features/chats/components/chat.tsx @@ -3,16 +3,17 @@ import classNames from 'clsx'; import React, { MutableRefObject, useEffect, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { Stack } from 'soapbox/components/ui'; -// import UploadProgress from 'soapbox/components/upload-progress'; -// import UploadButton from 'soapbox/features/compose/components/upload_button'; +import { uploadMedia } from 'soapbox/actions/media'; +import { IconButton, Stack } from 'soapbox/components/ui'; +import UploadProgress from 'soapbox/components/upload-progress'; +import { useAppDispatch } from 'soapbox/hooks'; import { IChat, useChatActions } from 'soapbox/queries/chats'; -// import { truncateFilename } from 'soapbox/utils/media'; +import { truncateFilename } from 'soapbox/utils/media'; import ChatComposer from './chat-composer'; import ChatMessageList from './chat-message-list'; -// const fileKeyGen = (): number => Math.floor((Math.random() * 0x10000)); +const fileKeyGen = (): number => Math.floor((Math.random() * 0x10000)); const messages = defineMessages({ failedToSend: { id: 'chat.failed_to_send', defaultMessage: 'Message failed to send.' }, @@ -46,14 +47,15 @@ const clearNativeInputValue = (element: HTMLTextAreaElement) => { */ const Chat: React.FC = ({ chat, inputRef, className }) => { const intl = useIntl(); + const dispatch = useAppDispatch(); const { createChatMessage, acceptChat } = useChatActions(chat.id); const [content, setContent] = useState(''); const [attachment, setAttachment] = useState(undefined); - // const [isUploading, setIsUploading] = useState(false); - // const [uploadProgress, setUploadProgress] = useState(0); - // const [resetFileKey, setResetFileKey] = useState(fileKeyGen()); + const [isUploading, setIsUploading] = useState(false); + const [uploadProgress, setUploadProgress] = useState(0); + const [resetFileKey, setResetFileKey] = useState(fileKeyGen()); const [errorMessage, setErrorMessage] = useState(); const isSubmitDisabled = content.length === 0 && !attachment; @@ -79,10 +81,9 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { } setContent(''); setAttachment(undefined); - // setIsUploading(false); - // setUploadProgress(0); - // setResetFileKey(fileKeyGen()); - // setErrorSubmittingMessage(false); + setIsUploading(false); + setUploadProgress(0); + setResetFileKey(fileKeyGen()); }; const sendMessage = () => { @@ -113,11 +114,11 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { setContent(event.target.value); }; - // const handlePaste: React.ClipboardEventHandler = (e) => { - // if (isSubmitDisabled && e.clipboardData && e.clipboardData.files.length === 1) { - // handleFiles(e.clipboardData.files); - // } - // }; + const handlePaste: React.ClipboardEventHandler = (e) => { + if (isSubmitDisabled && e.clipboardData && e.clipboardData.files.length === 1) { + handleFiles(e.clipboardData.files); + } + }; const markRead = () => { // markAsRead.mutate(); @@ -126,59 +127,47 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { const handleMouseOver = () => markRead(); - // const handleRemoveFile = () => { - // setAttachment(undefined); - // setResetFileKey(fileKeyGen()); - // }; + const handleRemoveFile = () => { + setAttachment(undefined); + setResetFileKey(fileKeyGen()); + }; - // const onUploadProgress = (e: ProgressEvent) => { - // const { loaded, total } = e; - // setUploadProgress(loaded / total); - // }; + const onUploadProgress = (e: ProgressEvent) => { + const { loaded, total } = e; + setUploadProgress(loaded / total); + }; - // const handleFiles = (files: FileList) => { - // setIsUploading(true); + const handleFiles = (files: FileList) => { + setIsUploading(true); - // const data = new FormData(); - // data.append('file', files[0]); + const data = new FormData(); + data.append('file', files[0]); - // dispatch(uploadMedia(data, onUploadProgress)).then((response: any) => { - // setAttachment(response.data); - // setIsUploading(false); - // }).catch(() => { - // setIsUploading(false); - // }); - // }; + dispatch(uploadMedia(data, onUploadProgress)).then((response: any) => { + setAttachment(response.data); + setIsUploading(false); + }).catch(() => { + setIsUploading(false); + }); + }; - // const renderAttachment = () => { - // if (!attachment) return null; + const renderAttachment = () => { + if (!attachment) return null; - // return ( - //
- //
- // {truncateFilename(attachment.preview_url, 20)} - //
- //
- // - //
- //
- // ); - // }; - - // const renderActionButton = () => { - // return canSubmit() ? ( - // - // ) : ( - // - // ); - // }; + return ( +
+
+ {truncateFilename(attachment.preview_url, 20)} +
+
+ +
+
+ ); + }; useEffect(() => { if (inputRef?.current) { @@ -192,6 +181,12 @@ const Chat: React.FC = ({ chat, inputRef, className }) => {
+ {renderAttachment()} + + {isUploading && ( + + )} + = ({ chat, inputRef, className }) => { onChange={handleContentChange} onSubmit={sendMessage} errorMessage={errorMessage} + onSelectFile={handleFiles} + resetFileKey={resetFileKey} + onPaste={handlePaste} /> - // {renderAttachment()} - // {isUploading && ( - // - // )} - //
- //
- // {renderActionButton()} - //
- //