Skip to content

Commit

Permalink
fix: do not send two upload requests when offline support is enabled (#…
Browse files Browse the repository at this point in the history
…2328)

* fix: do not send two upload requests when offline support is enabled

* fix: filenames

* fix: catch axios canceled error

* fix: types import for FileUpload and ImageUpload

* fix: image compress logic when uploading image while offline support is enabled (#2331)

---------

Co-authored-by: Khushal Agarwal <[email protected]>
  • Loading branch information
santhoshvai and khushal87 authored Nov 24, 2023
1 parent 89b5efa commit c05b335
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 84 deletions.
3 changes: 2 additions & 1 deletion package/src/components/Attachment/AudioAttachment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { I18nManager, StyleSheet, Text, TouchableOpacity, View } from 'react-nat
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';

import { FileUpload, useTheme } from '../../contexts';
import { useTheme } from '../../contexts';
import { Pause, Play } from '../../icons';
import {
PlaybackStatus,
Expand All @@ -13,6 +13,7 @@ import {
VideoPayloadData,
VideoProgressData,
} from '../../native';
import type { FileUpload } from '../../types/types';
import { ProgressControl } from '../ProgressControl/ProgressControl';

dayjs.extend(duration);
Expand Down
31 changes: 27 additions & 4 deletions package/src/components/Channel/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import { FlatList as FlatListDefault, pickDocument } from '../../native';
import * as dbApi from '../../store/apis';
import type { DefaultStreamChatGenerics } from '../../types/types';
import { addReactionToLocalState } from '../../utils/addReactionToLocalState';
import { compressedImageURI } from '../../utils/compressImage';
import { DBSyncManager } from '../../utils/DBSyncManager';
import { patchMessageTextCommand } from '../../utils/patchMessageTextCommand';
import { removeReactionFromLocalState } from '../../utils/removeReactionFromLocalState';
Expand Down Expand Up @@ -589,6 +590,13 @@ const ChannelWithContext = <

const { setTargetedMessage, targetedMessage } = useTargetedMessage();

/**
* This ref will hold the abort controllers for
* requests made for uploading images/files in the messageInputContext
* Its a map of filename to AbortController
*/
const uploadAbortControllerRef = useRef<Map<string, AbortController>>(new Map());

const channelId = channel?.id || '';
useEffect(() => {
const initChannel = () => {
Expand Down Expand Up @@ -1290,20 +1298,28 @@ const ChannelWithContext = <
if (updatedMessage.attachments?.length) {
for (let i = 0; i < updatedMessage.attachments?.length; i++) {
const attachment = updatedMessage.attachments[i];
const image = attachment.originalImage;
const file = attachment.originalFile;
// check if image_url is not a remote url
if (
attachment.type === 'image' &&
file?.uri &&
image?.uri &&
attachment.image_url &&
isLocalUrl(attachment.image_url)
) {
const filename = file.name ?? file.uri.replace(/^(file:\/\/|content:\/\/)/, '');
const filename = image.name ?? image.uri.replace(/^(file:\/\/|content:\/\/)/, '');
// if any upload is in progress, cancel it
const controller = uploadAbortControllerRef.current.get(filename);
if (controller) {
controller.abort();
uploadAbortControllerRef.current.delete(filename);
}
const compressedUri = await compressedImageURI(image, compressImageQuality);
const contentType = lookup(filename) || 'multipart/form-data';

const uploadResponse = doImageUploadRequest
? await doImageUploadRequest(file, channel)
: await channel.sendImage(file.uri, filename, contentType);
? await doImageUploadRequest(image, channel)
: await channel.sendImage(compressedUri, filename, contentType);

attachment.image_url = uploadResponse.file;
delete attachment.originalFile;
Expand All @@ -1321,6 +1337,12 @@ const ChannelWithContext = <
isLocalUrl(attachment.asset_url) &&
file?.uri
) {
// if any upload is in progress, cancel it
const controller = uploadAbortControllerRef.current.get(file.name);
if (controller) {
controller.abort();
uploadAbortControllerRef.current.delete(file.name);
}
const response = doDocUploadRequest
? await doDocUploadRequest(file, channel)
: await channel.sendFile(file.uri, file.name, file.mimeType);
Expand Down Expand Up @@ -1851,6 +1873,7 @@ const ChannelWithContext = <
StickyHeader,
targetedMessage,
threadList,
uploadAbortControllerRef,
watcherCount,
watchers,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const useCreateChannelContext = <
StickyHeader,
targetedMessage,
threadList,
uploadAbortControllerRef,
watcherCount,
watchers,
}: ChannelContextValue<StreamChatGenerics>) => {
Expand Down Expand Up @@ -79,6 +80,7 @@ export const useCreateChannelContext = <
StickyHeader,
targetedMessage,
threadList,
uploadAbortControllerRef,
watcherCount,
watchers,
}),
Expand Down
3 changes: 1 addition & 2 deletions package/src/components/MessageInput/FileUploadPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { UploadProgressIndicator } from './UploadProgressIndicator';

import { ChatContextValue, useChatContext } from '../../contexts';
import {
FileUpload,
MessageInputContextValue,
useMessageInputContext,
} from '../../contexts/messageInputContext/MessageInputContext';
Expand All @@ -20,7 +19,7 @@ import { useTranslationContext } from '../../contexts/translationContext/Transla
import { Close } from '../../icons/Close';
import { Warning } from '../../icons/Warning';
import { isAudioPackageAvailable } from '../../native';
import type { DefaultStreamChatGenerics } from '../../types/types';
import type { DefaultStreamChatGenerics, FileUpload } from '../../types/types';
import { FileState, getIndicatorTypeForFileState, ProgressIndicatorTypes } from '../../utils/utils';
import { getFileSizeDisplayText } from '../Attachment/FileAttachment';
import { WritingDirectionAwareText } from '../RTLComponents/WritingDirectionAwareText';
Expand Down
3 changes: 1 addition & 2 deletions package/src/components/MessageInput/ImageUploadPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ import { UploadProgressIndicator } from './UploadProgressIndicator';

import { ChatContextValue, useChatContext } from '../../contexts';
import {
ImageUpload,
MessageInputContextValue,
useMessageInputContext,
} from '../../contexts/messageInputContext/MessageInputContext';
import { useTheme } from '../../contexts/themeContext/ThemeContext';
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
import { Close } from '../../icons/Close';
import { Warning } from '../../icons/Warning';
import type { DefaultStreamChatGenerics } from '../../types/types';
import type { DefaultStreamChatGenerics, ImageUpload } from '../../types/types';
import { getIndicatorTypeForFileState, ProgressIndicatorTypes } from '../../utils/utils';

const IMAGE_PREVIEW_SIZE = 100;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { act } from 'react-test-renderer';
import { fireEvent, render } from '@testing-library/react-native';

import {
FileUpload,
MessageInputContext,
MessageInputContextValue,
} from '../../../contexts/messageInputContext/MessageInputContext';
import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
import { defaultTheme } from '../../../contexts/themeContext/utils/theme';

import { generateFileUploadPreview } from '../../../mock-builders/generator/attachment';
import type { FileUpload } from '../../../types/types';
import { AudioAttachment, AudioAttachmentProps } from '../../Attachment/AudioAttachment';

jest.mock('../../../native.ts', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { act } from 'react-test-renderer';
import { fireEvent, render } from '@testing-library/react-native';

import {
FileUpload,
MessageInputContext,
MessageInputContextValue,
} from '../../../contexts/messageInputContext/MessageInputContext';
import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
import { defaultTheme } from '../../../contexts/themeContext/utils/theme';

import { generateFileUploadPreview } from '../../../mock-builders/generator/attachment';
import type { FileUpload } from '../../../types/types';
import { AudioAttachment, AudioAttachmentProps } from '../../Attachment/AudioAttachment';

jest.mock('../../../native.ts', () => {
Expand Down
5 changes: 5 additions & 0 deletions package/src/contexts/channelContext/ChannelContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ export type ChannelContextValue<
scrollToFirstUnreadThreshold: number;
setLastRead: React.Dispatch<React.SetStateAction<Date | undefined>>;
setTargetedMessage: (messageId: string) => void;
/**
* Abort controller for cancelling async requests made for uploading images/files
* Its a map of filename and AbortController
*/
uploadAbortControllerRef: React.MutableRefObject<Map<string, AbortController>>;
/**
*
* ```json
Expand Down
Loading

0 comments on commit c05b335

Please sign in to comment.