Merge branch 'chat-multi-upload' into 'develop'
Chats: allow uploading multiple attachments at once (if the backend supports it) See merge request soapbox-pub/soapbox!2313
This commit is contained in:
commit
ca9e59b56b
|
@ -47,7 +47,7 @@ interface IChatComposer extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaEl
|
||||||
resetContentKey: number | null
|
resetContentKey: number | null
|
||||||
attachments?: Attachment[]
|
attachments?: Attachment[]
|
||||||
onDeleteAttachment?: (i: number) => void
|
onDeleteAttachment?: (i: number) => void
|
||||||
isUploading?: boolean
|
uploadCount?: number
|
||||||
uploadProgress?: number
|
uploadProgress?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
||||||
onPaste,
|
onPaste,
|
||||||
attachments = [],
|
attachments = [],
|
||||||
onDeleteAttachment,
|
onDeleteAttachment,
|
||||||
isUploading,
|
uploadCount = 0,
|
||||||
uploadProgress,
|
uploadProgress,
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -82,6 +82,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
||||||
const [suggestions, setSuggestions] = useState<Suggestion>(initialSuggestionState);
|
const [suggestions, setSuggestions] = useState<Suggestion>(initialSuggestionState);
|
||||||
const isSuggestionsAvailable = suggestions.list.length > 0;
|
const isSuggestionsAvailable = suggestions.list.length > 0;
|
||||||
|
|
||||||
|
const isUploading = uploadCount > 0;
|
||||||
const hasAttachment = attachments.length > 0;
|
const hasAttachment = attachments.length > 0;
|
||||||
const isOverCharacterLimit = maxCharacterCount && value?.length > maxCharacterCount;
|
const isOverCharacterLimit = maxCharacterCount && value?.length > maxCharacterCount;
|
||||||
const isSubmitDisabled = disabled || isUploading || isOverCharacterLimit || (value.length === 0 && !hasAttachment);
|
const isSubmitDisabled = disabled || isUploading || isOverCharacterLimit || (value.length === 0 && !hasAttachment);
|
||||||
|
@ -200,7 +201,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
attachments={attachments}
|
attachments={attachments}
|
||||||
onDeleteAttachment={onDeleteAttachment}
|
onDeleteAttachment={onDeleteAttachment}
|
||||||
isUploading={isUploading}
|
uploadCount={uploadCount}
|
||||||
uploadProgress={uploadProgress}
|
uploadProgress={uploadProgress}
|
||||||
/>
|
/>
|
||||||
{isSuggestionsAvailable ? (
|
{isSuggestionsAvailable ? (
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ChatUpload from './chat-upload';
|
||||||
interface IChatTextarea extends React.ComponentProps<typeof Textarea> {
|
interface IChatTextarea extends React.ComponentProps<typeof Textarea> {
|
||||||
attachments?: Attachment[]
|
attachments?: Attachment[]
|
||||||
onDeleteAttachment?: (i: number) => void
|
onDeleteAttachment?: (i: number) => void
|
||||||
isUploading?: boolean
|
uploadCount?: number
|
||||||
uploadProgress?: number
|
uploadProgress?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,10 +17,12 @@ interface IChatTextarea extends React.ComponentProps<typeof Textarea> {
|
||||||
const ChatTextarea: React.FC<IChatTextarea> = ({
|
const ChatTextarea: React.FC<IChatTextarea> = ({
|
||||||
attachments,
|
attachments,
|
||||||
onDeleteAttachment,
|
onDeleteAttachment,
|
||||||
isUploading = false,
|
uploadCount = 0,
|
||||||
uploadProgress = 0,
|
uploadProgress = 0,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
|
const isUploading = uploadCount > 0;
|
||||||
|
|
||||||
const handleDeleteAttachment = (i: number) => {
|
const handleDeleteAttachment = (i: number) => {
|
||||||
return () => {
|
return () => {
|
||||||
if (onDeleteAttachment) {
|
if (onDeleteAttachment) {
|
||||||
|
@ -54,11 +56,11 @@ const ChatTextarea: React.FC<IChatTextarea> = ({
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{isUploading && (
|
{Array.from(Array(uploadCount)).map(() => (
|
||||||
<div className='ml-2 mt-2 flex'>
|
<div className='ml-2 mt-2 flex'>
|
||||||
<ChatPendingUpload progress={uploadProgress} />
|
<ChatPendingUpload progress={uploadProgress} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
||||||
|
|
||||||
const [content, setContent] = useState<string>('');
|
const [content, setContent] = useState<string>('');
|
||||||
const [attachments, setAttachments] = useState<Attachment[]>([]);
|
const [attachments, setAttachments] = useState<Attachment[]>([]);
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [uploadCount, setUploadCount] = useState(0);
|
||||||
const [uploadProgress, setUploadProgress] = useState(0);
|
const [uploadProgress, setUploadProgress] = useState(0);
|
||||||
const [resetContentKey, setResetContentKey] = useState<number>(fileKeyGen());
|
const [resetContentKey, setResetContentKey] = useState<number>(fileKeyGen());
|
||||||
const [resetFileKey, setResetFileKey] = useState<number>(fileKeyGen());
|
const [resetFileKey, setResetFileKey] = useState<number>(fileKeyGen());
|
||||||
|
@ -86,7 +86,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
||||||
}
|
}
|
||||||
setContent('');
|
setContent('');
|
||||||
setAttachments([]);
|
setAttachments([]);
|
||||||
setIsUploading(false);
|
setUploadCount(0);
|
||||||
setUploadProgress(0);
|
setUploadProgress(0);
|
||||||
setResetFileKey(fileKeyGen());
|
setResetFileKey(fileKeyGen());
|
||||||
setResetContentKey(fileKeyGen());
|
setResetContentKey(fileKeyGen());
|
||||||
|
@ -151,17 +151,21 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsUploading(true);
|
setUploadCount(files.length);
|
||||||
|
|
||||||
const data = new FormData();
|
const promises = Array.from(files).map(async(file) => {
|
||||||
data.append('file', files[0]);
|
const data = new FormData();
|
||||||
|
data.append('file', file);
|
||||||
dispatch(uploadMedia(data, onUploadProgress)).then((response: any) => {
|
const response = await dispatch(uploadMedia(data, onUploadProgress));
|
||||||
setAttachments([...attachments, normalizeAttachment(response.data)]);
|
return normalizeAttachment(response.data);
|
||||||
setIsUploading(false);
|
|
||||||
}).catch(() => {
|
|
||||||
setIsUploading(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
.then((newAttachments) => {
|
||||||
|
setAttachments([...attachments, ...newAttachments]);
|
||||||
|
setUploadCount(0);
|
||||||
|
})
|
||||||
|
.catch(() => setUploadCount(0));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -189,7 +193,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
||||||
onPaste={handlePaste}
|
onPaste={handlePaste}
|
||||||
attachments={attachments}
|
attachments={attachments}
|
||||||
onDeleteAttachment={handleRemoveFile}
|
onDeleteAttachment={handleRemoveFile}
|
||||||
isUploading={isUploading}
|
uploadCount={uploadCount}
|
||||||
uploadProgress={uploadProgress}
|
uploadProgress={uploadProgress}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
@ -284,7 +284,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
||||||
* Whether chat messages can accept a `media_id` attachment.
|
* Whether chat messages can accept a `media_id` attachment.
|
||||||
* @see POST /api/v1/pleroma/chats/:id/messages
|
* @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.
|
* Whether chat messages have read receipts.
|
||||||
|
|
Loading…
Reference in New Issue