From 83dab223713b2a37db518e5af014d2c9a1268ef1 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 27 Feb 2023 09:59:00 -0600 Subject: [PATCH] Chats: allow uploading multiple attachments at once (if the backend supports it) --- .../chats/components/chat-composer.tsx | 7 +++-- .../chats/components/chat-textarea.tsx | 10 ++++--- .../features/chats/components/chat.tsx | 28 +++++++++++-------- app/soapbox/utils/features.ts | 2 +- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/app/soapbox/features/chats/components/chat-composer.tsx b/app/soapbox/features/chats/components/chat-composer.tsx index c56eb1efe..481e3799d 100644 --- a/app/soapbox/features/chats/components/chat-composer.tsx +++ b/app/soapbox/features/chats/components/chat-composer.tsx @@ -45,7 +45,7 @@ interface IChatComposer extends Pick void - isUploading?: boolean + uploadCount?: number uploadProgress?: number } @@ -63,7 +63,7 @@ const ChatComposer = React.forwardRef onPaste, attachments = [], onDeleteAttachment, - isUploading, + uploadCount = 0, uploadProgress, }, ref) => { const intl = useIntl(); @@ -80,6 +80,7 @@ const ChatComposer = React.forwardRef const [suggestions, setSuggestions] = useState(initialSuggestionState); const isSuggestionsAvailable = suggestions.list.length > 0; + const isUploading = uploadCount > 0; const hasAttachment = attachments.length > 0; const isOverCharacterLimit = maxCharacterCount && value?.length > maxCharacterCount; const isSubmitDisabled = disabled || isUploading || isOverCharacterLimit || (value.length === 0 && !hasAttachment); @@ -198,7 +199,7 @@ const ChatComposer = React.forwardRef disabled={disabled} attachments={attachments} onDeleteAttachment={onDeleteAttachment} - isUploading={isUploading} + uploadCount={uploadCount} uploadProgress={uploadProgress} /> {isSuggestionsAvailable ? ( diff --git a/app/soapbox/features/chats/components/chat-textarea.tsx b/app/soapbox/features/chats/components/chat-textarea.tsx index 2b491ed69..111a4cdc9 100644 --- a/app/soapbox/features/chats/components/chat-textarea.tsx +++ b/app/soapbox/features/chats/components/chat-textarea.tsx @@ -9,7 +9,7 @@ import ChatUpload from './chat-upload'; interface IChatTextarea extends React.ComponentProps { attachments?: Attachment[] onDeleteAttachment?: (i: number) => void - isUploading?: boolean + uploadCount?: number uploadProgress?: number } @@ -17,10 +17,12 @@ interface IChatTextarea extends React.ComponentProps { const ChatTextarea: React.FC = ({ attachments, onDeleteAttachment, - isUploading = false, + uploadCount = 0, uploadProgress = 0, ...rest }) => { + const isUploading = uploadCount > 0; + const handleDeleteAttachment = (i: number) => { return () => { if (onDeleteAttachment) { @@ -54,11 +56,11 @@ const ChatTextarea: React.FC = ({ ))} - {isUploading && ( + {Array.from(Array(uploadCount)).map(() => (
- )} + ))} )} diff --git a/app/soapbox/features/chats/components/chat.tsx b/app/soapbox/features/chats/components/chat.tsx index 758d180ab..b12d01ebe 100644 --- a/app/soapbox/features/chats/components/chat.tsx +++ b/app/soapbox/features/chats/components/chat.tsx @@ -57,7 +57,7 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { const [content, setContent] = useState(''); const [attachments, setAttachments] = useState([]); - const [isUploading, setIsUploading] = useState(false); + const [uploadCount, setUploadCount] = useState(0); const [uploadProgress, setUploadProgress] = useState(0); const [resetContentKey, setResetContentKey] = useState(fileKeyGen()); const [resetFileKey, setResetFileKey] = useState(fileKeyGen()); @@ -86,7 +86,7 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { } setContent(''); setAttachments([]); - setIsUploading(false); + setUploadCount(0); setUploadProgress(0); setResetFileKey(fileKeyGen()); setResetContentKey(fileKeyGen()); @@ -151,17 +151,21 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { return; } - setIsUploading(true); + setUploadCount(files.length); - const data = new FormData(); - data.append('file', files[0]); - - dispatch(uploadMedia(data, onUploadProgress)).then((response: any) => { - setAttachments([...attachments, normalizeAttachment(response.data)]); - setIsUploading(false); - }).catch(() => { - setIsUploading(false); + const promises = Array.from(files).map(async(file) => { + const data = new FormData(); + data.append('file', file); + const response = await dispatch(uploadMedia(data, onUploadProgress)); + return normalizeAttachment(response.data); }); + + return Promise.all(promises) + .then((newAttachments) => { + setAttachments([...attachments, ...newAttachments]); + setUploadCount(0); + }) + .catch(() => setUploadCount(0)); }; useEffect(() => { @@ -189,7 +193,7 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { onPaste={handlePaste} attachments={attachments} onDeleteAttachment={handleRemoveFile} - isUploading={isUploading} + uploadCount={uploadCount} uploadProgress={uploadProgress} /> diff --git a/app/soapbox/utils/features.ts b/app/soapbox/utils/features.ts index 3b1c14b77..b3a3860f3 100644 --- a/app/soapbox/utils/features.ts +++ b/app/soapbox/utils/features.ts @@ -284,7 +284,7 @@ const getInstanceFeatures = (instance: Instance) => { * Whether chat messages can accept a `media_id` attachment. * @see POST /api/v1/pleroma/chats/:id/messages */ - chatsMedia: v.software !== TRUTHSOCIAL, + chatsMedia: v.software !== TRUTHSOCIAL || v.build === UNRELEASED, /** * Whether chat messages have read receipts.