stream-chat-react-native-core
Version:
The official React Native and Expo components for Stream Chat, a service for building chat applications
148 lines (130 loc) • 4.45 kB
text/typescript
import {
Attachment,
AttachmentPreUploadMiddleware,
FileReference,
isLocalImageAttachment,
isLocalVideoAttachment,
LocalAttachment,
MessageComposer,
MessageComposerMiddlewareState,
MessageCompositionMiddleware,
MessageDraftComposerMiddlewareValueState,
MessageDraftCompositionMiddleware,
MiddlewareHandlerParams,
} from 'stream-chat';
import { isLocalUrl } from '../utils/utils';
export const localAttachmentToAttachment = (localAttachment: LocalAttachment) => {
const { localMetadata, ...attachment } = localAttachment;
if (isLocalImageAttachment(localAttachment)) {
const isRemoteUri = !!attachment.image_url && !isLocalUrl(attachment.image_url);
if (isRemoteUri) return attachment as Attachment;
return {
...attachment,
image_url: localMetadata?.previewUri,
localId: localMetadata?.id,
originalFile: localMetadata.file,
} as Attachment;
} else {
const isRemoteUri = !!attachment.asset_url && !isLocalUrl(attachment.asset_url);
if (isRemoteUri) return attachment as Attachment;
return {
...attachment,
asset_url: (localMetadata.file as FileReference).uri,
localId: localMetadata?.id,
originalFile: localMetadata.file,
} as Attachment;
}
};
export const createAttachmentsCompositionMiddleware = (
composer: MessageComposer,
): MessageCompositionMiddleware => ({
handlers: {
compose: ({
state,
next,
forward,
}: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {
const { attachmentManager } = composer;
if (!attachmentManager) return forward();
const attachments = (state.message.attachments ?? []).concat(
attachmentManager.attachments
// Blocked attachments (e.g. over the size limit) are permanent
// validation failures the server will reject, so never serialize
// them into the outgoing message.
.filter((attachment) => attachment.localMetadata.uploadState !== 'blocked')
.map(localAttachmentToAttachment),
);
// prevent introducing attachments array into the payload sent to the server
if (!attachments.length) return forward();
return next({
...state,
localMessage: {
...state.localMessage,
attachments: [...attachments],
},
message: {
...state.message,
attachments: [...attachments],
},
});
},
},
id: 'stream-io/message-composer-middleware/attachments',
});
export const createDraftAttachmentsCompositionMiddleware = (
composer: MessageComposer,
): MessageDraftCompositionMiddleware => ({
handlers: {
compose: ({
state,
next,
forward,
}: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {
const { attachmentManager } = composer;
if (!attachmentManager) return forward();
const attachments = (state.draft.attachments ?? []).concat(
attachmentManager.attachments
// Don't persist blocked attachments (e.g. over the size limit) into
// the draft — they are permanent validation failures.
.filter((attachment) => attachment.localMetadata.uploadState !== 'blocked')
.map(localAttachmentToAttachment),
);
return next({
...state,
draft: {
...state.draft,
attachments,
},
});
},
},
id: 'stream-io/message-composer-middleware/draft-attachments',
});
const createVideoAttachmentPreviewMiddleware = (): AttachmentPreUploadMiddleware => ({
id: 'stream-io/message-composer-ui-middleware/video-attachment-preview',
handlers: {
prepare: ({ next, forward, state }) => {
const { attachment } = state;
if (!attachment || !isLocalVideoAttachment(attachment)) {
return forward();
}
return next({
...state,
attachment: {
...attachment,
localMetadata: {
...attachment.localMetadata,
previewUri: attachment.thumb_url,
},
},
});
},
},
});
export const setupVideoAttachmentPreviewMiddleware = (messageComposer: MessageComposer) => {
messageComposer.attachmentManager.preUploadMiddlewareExecutor.insert({
middleware: [createVideoAttachmentPreviewMiddleware()],
position: { after: 'stream-io/attachment-manager-middleware/file-upload-config-check' },
unique: true,
});
};