Chats: support multiple attachments
This commit is contained in:
parent
dbf2e53b93
commit
ef5001d38b
4 changed files with 29 additions and 12 deletions
|
@ -73,6 +73,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
|||
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocked_by']));
|
||||
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
|
||||
const maxCharacterCount = useAppSelector((state) => state.instance.getIn(['configuration', 'chats', 'max_characters']) as number);
|
||||
const attachmentLimit = useAppSelector(state => state.instance.configuration.getIn(['chats', 'max_media_attachments']) as number);
|
||||
|
||||
const [suggestions, setSuggestions] = useState<Suggestion>(initialSuggestionState);
|
||||
const isSuggestionsAvailable = suggestions.list.length > 0;
|
||||
|
@ -172,6 +173,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
|||
resetFileKey={resetFileKey}
|
||||
iconClassName='w-5 h-5'
|
||||
className='text-primary-500'
|
||||
disabled={attachments.length >= attachmentLimit}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
|
|
|
@ -5,17 +5,21 @@ import { defineMessages, useIntl } from 'react-intl';
|
|||
|
||||
import { uploadMedia } from 'soapbox/actions/media';
|
||||
import { Stack } from 'soapbox/components/ui';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import { normalizeAttachment } from 'soapbox/normalizers';
|
||||
import { IChat, useChatActions } from 'soapbox/queries/chats';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
import ChatComposer from './chat-composer';
|
||||
import ChatMessageList from './chat-message-list';
|
||||
|
||||
import type { Attachment } from 'soapbox/types/entities';
|
||||
|
||||
const fileKeyGen = (): number => Math.floor((Math.random() * 0x10000));
|
||||
|
||||
const messages = defineMessages({
|
||||
failedToSend: { id: 'chat.failed_to_send', defaultMessage: 'Message failed to send.' },
|
||||
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
||||
});
|
||||
|
||||
interface ChatInterface {
|
||||
|
@ -49,18 +53,19 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
const dispatch = useAppDispatch();
|
||||
|
||||
const { createChatMessage, acceptChat } = useChatActions(chat.id);
|
||||
const attachmentLimit = useAppSelector(state => state.instance.configuration.getIn(['chats', 'max_media_attachments']) as number);
|
||||
|
||||
const [content, setContent] = useState<string>('');
|
||||
const [attachment, setAttachment] = useState<any>(undefined);
|
||||
const [attachments, setAttachments] = useState<Attachment[]>([]);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [resetFileKey, setResetFileKey] = useState<number>(fileKeyGen());
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
|
||||
const isSubmitDisabled = content.length === 0 && !attachment;
|
||||
const isSubmitDisabled = content.length === 0 && attachments.length === 0;
|
||||
|
||||
const submitMessage = () => {
|
||||
createChatMessage.mutate({ chatId: chat.id, content, mediaId: attachment?.id }, {
|
||||
createChatMessage.mutate({ chatId: chat.id, content, mediaIds: attachments.map(a => a.id) }, {
|
||||
onSuccess: () => {
|
||||
setErrorMessage(undefined);
|
||||
},
|
||||
|
@ -79,7 +84,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
clearNativeInputValue(inputRef.current);
|
||||
}
|
||||
setContent('');
|
||||
setAttachment(undefined);
|
||||
setAttachments([]);
|
||||
setIsUploading(false);
|
||||
setUploadProgress(0);
|
||||
setResetFileKey(fileKeyGen());
|
||||
|
@ -127,7 +132,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
const handleMouseOver = () => markRead();
|
||||
|
||||
const handleRemoveFile = () => {
|
||||
setAttachment(undefined);
|
||||
setAttachments([]);
|
||||
setResetFileKey(fileKeyGen());
|
||||
};
|
||||
|
||||
|
@ -137,13 +142,18 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
};
|
||||
|
||||
const handleFiles = (files: FileList) => {
|
||||
if (files.length + attachments.length > attachmentLimit) {
|
||||
toast.error(messages.uploadErrorLimit);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsUploading(true);
|
||||
|
||||
const data = new FormData();
|
||||
data.append('file', files[0]);
|
||||
|
||||
dispatch(uploadMedia(data, onUploadProgress)).then((response: any) => {
|
||||
setAttachment(normalizeAttachment(response.data));
|
||||
setAttachments([...attachments, normalizeAttachment(response.data)]);
|
||||
setIsUploading(false);
|
||||
}).catch(() => {
|
||||
setIsUploading(false);
|
||||
|
@ -172,7 +182,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
onSelectFile={handleFiles}
|
||||
resetFileKey={resetFileKey}
|
||||
onPaste={handlePaste}
|
||||
attachments={attachment ? [attachment] : []}
|
||||
attachments={attachments}
|
||||
onDeleteAttachment={handleRemoveFile}
|
||||
isUploading={isUploading}
|
||||
uploadProgress={uploadProgress}
|
||||
|
|
|
@ -22,7 +22,8 @@ export const InstanceRecord = ImmutableRecord({
|
|||
configuration: ImmutableMap<string, any>({
|
||||
media_attachments: ImmutableMap<string, any>(),
|
||||
chats: ImmutableMap<string, number>({
|
||||
max_characters: 500,
|
||||
max_characters: 5000,
|
||||
max_media_attachments: 1,
|
||||
}),
|
||||
polls: ImmutableMap<string, number>({
|
||||
max_options: 4,
|
||||
|
|
|
@ -233,9 +233,13 @@ const useChatActions = (chatId: string) => {
|
|||
};
|
||||
|
||||
const createChatMessage = useMutation(
|
||||
(
|
||||
{ chatId, content, mediaId }: { chatId: string, content: string, mediaId?: string },
|
||||
) => api.post<IChatMessage>(`/api/v1/pleroma/chats/${chatId}/messages`, { content, media_id: mediaId, media_ids: [mediaId] }),
|
||||
({ chatId, content, mediaIds }: { chatId: string, content: string, mediaIds?: string[] }) => {
|
||||
return api.post<IChatMessage>(`/api/v1/pleroma/chats/${chatId}/messages`, {
|
||||
content,
|
||||
media_id: (mediaIds && mediaIds.length === 1) ? mediaIds[0] : undefined, // Pleroma backwards-compat
|
||||
media_ids: mediaIds,
|
||||
});
|
||||
},
|
||||
{
|
||||
retry: false,
|
||||
onMutate: async (variables) => {
|
||||
|
|
Loading…
Reference in a new issue