ConversationView: Move attachments processing into redux
This commit is contained in:
parent
ff6750e4fd
commit
452e0b7b31
25 changed files with 544 additions and 763 deletions
|
@ -33,7 +33,6 @@ export default {
|
|||
|
||||
const useProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||
addAttachment: action('addAttachment'),
|
||||
addPendingAttachment: action('addPendingAttachment'),
|
||||
conversationId: '123',
|
||||
i18n,
|
||||
onSendMessage: action('onSendMessage'),
|
||||
|
|
|
@ -12,7 +12,6 @@ import type {
|
|||
} from '../types/Util';
|
||||
import type { ErrorDialogAudioRecorderType } from '../state/ducks/audioRecorder';
|
||||
import { RecordingState } from '../state/ducks/audioRecorder';
|
||||
import type { HandleAttachmentsProcessingArgsType } from '../util/handleAttachmentsProcessing';
|
||||
import type { imageToBlurHash } from '../util/imageToBlurHash';
|
||||
import { Spinner } from './Spinner';
|
||||
import type {
|
||||
|
@ -76,10 +75,6 @@ export type OwnProps = Readonly<{
|
|||
conversationId: string,
|
||||
attachment: InMemoryAttachmentDraftType
|
||||
) => unknown;
|
||||
addPendingAttachment: (
|
||||
conversationId: string,
|
||||
pendingAttachment: AttachmentDraftType
|
||||
) => unknown;
|
||||
announcementsOnly?: boolean;
|
||||
areWeAdmin?: boolean;
|
||||
areWePending?: boolean;
|
||||
|
@ -112,7 +107,10 @@ export type OwnProps = Readonly<{
|
|||
onClearAttachments(): unknown;
|
||||
onClickQuotedMessage(): unknown;
|
||||
onCloseLinkPreview(): unknown;
|
||||
processAttachments: (options: HandleAttachmentsProcessingArgsType) => unknown;
|
||||
processAttachments: (options: {
|
||||
conversationId: string;
|
||||
files: ReadonlyArray<File>;
|
||||
}) => unknown;
|
||||
onSelectMediaQuality(isHQ: boolean): unknown;
|
||||
onSendMessage(options: {
|
||||
draftAttachments?: ReadonlyArray<AttachmentDraftType>;
|
||||
|
@ -171,7 +169,6 @@ export type Props = Pick<
|
|||
export function CompositionArea({
|
||||
// Base props
|
||||
addAttachment,
|
||||
addPendingAttachment,
|
||||
conversationId,
|
||||
i18n,
|
||||
onSendMessage,
|
||||
|
@ -733,13 +730,10 @@ export function CompositionArea({
|
|||
</div>
|
||||
) : null}
|
||||
<CompositionUpload
|
||||
addAttachment={addAttachment}
|
||||
addPendingAttachment={addPendingAttachment}
|
||||
conversationId={conversationId}
|
||||
draftAttachments={draftAttachments}
|
||||
i18n={i18n}
|
||||
processAttachments={processAttachments}
|
||||
removeAttachment={removeAttachment}
|
||||
ref={fileInputRef}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -2,116 +2,43 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import React, { forwardRef, useState } from 'react';
|
||||
import React, { forwardRef } from 'react';
|
||||
|
||||
import type {
|
||||
InMemoryAttachmentDraftType,
|
||||
AttachmentDraftType,
|
||||
} from '../types/Attachment';
|
||||
import type { AttachmentDraftType } from '../types/Attachment';
|
||||
import { isVideoAttachment, isImageAttachment } from '../types/Attachment';
|
||||
import { AttachmentToastType } from '../types/AttachmentToastType';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
|
||||
import { ToastCannotMixMultiAndNonMultiAttachments } from './ToastCannotMixMultiAndNonMultiAttachments';
|
||||
import { ToastDangerousFileType } from './ToastDangerousFileType';
|
||||
import { ToastFileSize } from './ToastFileSize';
|
||||
import { ToastMaxAttachments } from './ToastMaxAttachments';
|
||||
import { ToastUnsupportedMultiAttachment } from './ToastUnsupportedMultiAttachment';
|
||||
import { ToastUnableToLoadAttachment } from './ToastUnableToLoadAttachment';
|
||||
import type { HandleAttachmentsProcessingArgsType } from '../util/handleAttachmentsProcessing';
|
||||
import {
|
||||
getSupportedImageTypes,
|
||||
getSupportedVideoTypes,
|
||||
} from '../util/GoogleChrome';
|
||||
|
||||
export type PropsType = {
|
||||
addAttachment: (
|
||||
conversationId: string,
|
||||
attachment: InMemoryAttachmentDraftType
|
||||
) => unknown;
|
||||
addPendingAttachment: (
|
||||
conversationId: string,
|
||||
pendingAttachment: AttachmentDraftType
|
||||
) => unknown;
|
||||
conversationId: string;
|
||||
draftAttachments: ReadonlyArray<AttachmentDraftType>;
|
||||
i18n: LocalizerType;
|
||||
processAttachments: (options: HandleAttachmentsProcessingArgsType) => unknown;
|
||||
removeAttachment: (conversationId: string, filePath: string) => unknown;
|
||||
processAttachments: (options: {
|
||||
conversationId: string;
|
||||
files: ReadonlyArray<File>;
|
||||
}) => unknown;
|
||||
};
|
||||
|
||||
export const CompositionUpload = forwardRef<HTMLInputElement, PropsType>(
|
||||
function CompositionUploadInner(
|
||||
{
|
||||
addAttachment,
|
||||
addPendingAttachment,
|
||||
conversationId,
|
||||
draftAttachments,
|
||||
i18n,
|
||||
processAttachments,
|
||||
removeAttachment,
|
||||
},
|
||||
{ conversationId, draftAttachments, processAttachments },
|
||||
ref
|
||||
) {
|
||||
const [toastType, setToastType] = useState<
|
||||
AttachmentToastType | undefined
|
||||
>();
|
||||
|
||||
const onFileInputChange: ChangeEventHandler<
|
||||
HTMLInputElement
|
||||
> = async event => {
|
||||
const files = event.target.files || [];
|
||||
|
||||
await processAttachments({
|
||||
addAttachment,
|
||||
addPendingAttachment,
|
||||
conversationId,
|
||||
files: Array.from(files),
|
||||
draftAttachments,
|
||||
onShowToast: setToastType,
|
||||
removeAttachment,
|
||||
});
|
||||
};
|
||||
|
||||
function closeToast() {
|
||||
setToastType(undefined);
|
||||
}
|
||||
|
||||
let toast;
|
||||
|
||||
if (toastType === AttachmentToastType.ToastFileSize) {
|
||||
toast = (
|
||||
<ToastFileSize
|
||||
i18n={i18n}
|
||||
limit={100}
|
||||
onClose={closeToast}
|
||||
units="MB"
|
||||
/>
|
||||
);
|
||||
} else if (toastType === AttachmentToastType.ToastDangerousFileType) {
|
||||
toast = <ToastDangerousFileType i18n={i18n} onClose={closeToast} />;
|
||||
} else if (toastType === AttachmentToastType.ToastMaxAttachments) {
|
||||
toast = <ToastMaxAttachments i18n={i18n} onClose={closeToast} />;
|
||||
} else if (
|
||||
toastType === AttachmentToastType.ToastUnsupportedMultiAttachment
|
||||
) {
|
||||
toast = (
|
||||
<ToastUnsupportedMultiAttachment i18n={i18n} onClose={closeToast} />
|
||||
);
|
||||
} else if (
|
||||
toastType ===
|
||||
AttachmentToastType.ToastCannotMixMultiAndNonMultiAttachments
|
||||
) {
|
||||
toast = (
|
||||
<ToastCannotMixMultiAndNonMultiAttachments
|
||||
i18n={i18n}
|
||||
onClose={closeToast}
|
||||
/>
|
||||
);
|
||||
} else if (toastType === AttachmentToastType.ToastUnableToLoadAttachment) {
|
||||
toast = <ToastUnableToLoadAttachment i18n={i18n} onClose={closeToast} />;
|
||||
}
|
||||
|
||||
const anyVideoOrImageAttachments = draftAttachments.some(attachment => {
|
||||
return isImageAttachment(attachment) || isVideoAttachment(attachment);
|
||||
});
|
||||
|
@ -121,17 +48,14 @@ export const CompositionUpload = forwardRef<HTMLInputElement, PropsType>(
|
|||
: null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{toast}
|
||||
<input
|
||||
hidden
|
||||
multiple
|
||||
onChange={onFileInputChange}
|
||||
ref={ref}
|
||||
type="file"
|
||||
accept={acceptContentTypes?.join(',')}
|
||||
/>
|
||||
</>
|
||||
<input
|
||||
hidden
|
||||
multiple
|
||||
onChange={onFileInputChange}
|
||||
ref={ref}
|
||||
type="file"
|
||||
accept={acceptContentTypes?.join(',')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ToastCannotMixMultiAndNonMultiAttachments } from './ToastCannotMixMultiAndNonMultiAttachments';
|
||||
|
||||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const defaultProps = {
|
||||
i18n,
|
||||
onClose: action('onClose'),
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Components/ToastCannotMixMultiAndNonMultiAttachments',
|
||||
};
|
||||
|
||||
export const _ToastCannotMixMultiAndNonMultiAttachments = (): JSX.Element => (
|
||||
<ToastCannotMixMultiAndNonMultiAttachments {...defaultProps} />
|
||||
);
|
||||
|
||||
_ToastCannotMixMultiAndNonMultiAttachments.story = {
|
||||
name: 'ToastCannotMixMultiAndNonMultiAttachments',
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import { Toast } from './Toast';
|
||||
|
||||
type PropsType = {
|
||||
i18n: LocalizerType;
|
||||
onClose: () => unknown;
|
||||
};
|
||||
|
||||
export function ToastCannotMixMultiAndNonMultiAttachments({
|
||||
i18n,
|
||||
onClose,
|
||||
}: PropsType): JSX.Element {
|
||||
return (
|
||||
<Toast onClose={onClose}>
|
||||
{i18n('cannotSelectPhotosAndVideosAlongWithFiles')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
|
@ -20,7 +20,7 @@ export default {
|
|||
};
|
||||
|
||||
export const _ToastFileSize = (): JSX.Element => (
|
||||
<ToastFileSize {...defaultProps} limit={100} units="MB" />
|
||||
<ToastFileSize {...defaultProps} limit="100" units="MB" />
|
||||
);
|
||||
|
||||
_ToastFileSize.story = {
|
||||
|
|
|
@ -6,7 +6,7 @@ import type { LocalizerType } from '../types/Util';
|
|||
import { Toast } from './Toast';
|
||||
|
||||
export type ToastPropsType = {
|
||||
limit: number;
|
||||
limit: string;
|
||||
units: string;
|
||||
};
|
||||
|
||||
|
@ -23,8 +23,7 @@ export function ToastFileSize({
|
|||
}: PropsType): JSX.Element {
|
||||
return (
|
||||
<Toast onClose={onClose}>
|
||||
{i18n('fileSizeWarning')} {limit}
|
||||
{units}
|
||||
{i18n('icu:fileSizeWarning', { limit, units })}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,13 @@ AddingUserToGroup.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const CannotMixMultiAndNonMultiAttachments = Template.bind({});
|
||||
CannotMixMultiAndNonMultiAttachments.args = {
|
||||
toast: {
|
||||
toastType: ToastType.CannotMixMultiAndNonMultiAttachments,
|
||||
},
|
||||
};
|
||||
|
||||
export const CannotStartGroupCall = Template.bind({});
|
||||
CannotStartGroupCall.args = {
|
||||
toast: {
|
||||
|
@ -70,6 +77,13 @@ CopiedUsernameLink.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const DangerousFileType = Template.bind({});
|
||||
DangerousFileType.args = {
|
||||
toast: {
|
||||
toastType: ToastType.DangerousFileType,
|
||||
},
|
||||
};
|
||||
|
||||
export const DeleteForEveryoneFailed = Template.bind({});
|
||||
DeleteForEveryoneFailed.args = {
|
||||
toast: {
|
||||
|
@ -91,6 +105,24 @@ FailedToDeleteUsername.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const FileSize = Template.bind({});
|
||||
FileSize.args = {
|
||||
toast: {
|
||||
toastType: ToastType.FileSize,
|
||||
parameters: {
|
||||
limit: '100',
|
||||
units: 'MB',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const MaxAttachments = Template.bind({});
|
||||
MaxAttachments.args = {
|
||||
toast: {
|
||||
toastType: ToastType.MaxAttachments,
|
||||
},
|
||||
};
|
||||
|
||||
export const MessageBodyTooLong = Template.bind({});
|
||||
MessageBodyTooLong.args = {
|
||||
toast: {
|
||||
|
@ -105,13 +137,6 @@ PinnedConversationsFull.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const StoryMuted = Template.bind({});
|
||||
StoryMuted.args = {
|
||||
toast: {
|
||||
toastType: ToastType.StoryMuted,
|
||||
},
|
||||
};
|
||||
|
||||
export const ReportedSpamAndBlocked = Template.bind({});
|
||||
ReportedSpamAndBlocked.args = {
|
||||
toast: {
|
||||
|
@ -119,6 +144,13 @@ ReportedSpamAndBlocked.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const StoryMuted = Template.bind({});
|
||||
StoryMuted.args = {
|
||||
toast: {
|
||||
toastType: ToastType.StoryMuted,
|
||||
},
|
||||
};
|
||||
|
||||
export const StoryReact = Template.bind({});
|
||||
StoryReact.args = {
|
||||
toast: {
|
||||
|
@ -154,6 +186,20 @@ StoryVideoUnsupported.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const UnableToLoadAttachment = Template.bind({});
|
||||
UnableToLoadAttachment.args = {
|
||||
toast: {
|
||||
toastType: ToastType.UnableToLoadAttachment,
|
||||
},
|
||||
};
|
||||
|
||||
export const UnsupportedMultiAttachment = Template.bind({});
|
||||
UnsupportedMultiAttachment.args = {
|
||||
toast: {
|
||||
toastType: ToastType.UnsupportedMultiAttachment,
|
||||
},
|
||||
};
|
||||
|
||||
export const UserAddedToGroup = Template.bind({});
|
||||
UserAddedToGroup.args = {
|
||||
toast: {
|
||||
|
|
|
@ -42,6 +42,14 @@ export function ToastManager({
|
|||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.CannotMixMultiAndNonMultiAttachments) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>
|
||||
{i18n('cannotSelectPhotosAndVideosAlongWithFiles')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.CannotStartGroupCall) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>
|
||||
|
@ -66,6 +74,10 @@ export function ToastManager({
|
|||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.DangerousFileType) {
|
||||
return <Toast onClose={hideToast}>{i18n('dangerousFileType')}</Toast>;
|
||||
}
|
||||
|
||||
if (toastType === ToastType.DeleteForEveryoneFailed) {
|
||||
return <Toast onClose={hideToast}>{i18n('deleteForEveryoneFailed')}</Toast>;
|
||||
}
|
||||
|
@ -93,6 +105,18 @@ export function ToastManager({
|
|||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.FileSize) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>
|
||||
{i18n('icu:fileSizeWarning', toast?.parameters)}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.MaxAttachments) {
|
||||
return <Toast onClose={hideToast}>{i18n('maximumAttachments')}</Toast>;
|
||||
}
|
||||
|
||||
if (toastType === ToastType.MessageBodyTooLong) {
|
||||
return <ToastMessageBodyTooLong i18n={i18n} onClose={hideToast} />;
|
||||
}
|
||||
|
@ -157,6 +181,18 @@ export function ToastManager({
|
|||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.UnableToLoadAttachment) {
|
||||
return <Toast onClose={hideToast}>{i18n('unableToLoadAttachment')}</Toast>;
|
||||
}
|
||||
|
||||
if (toastType === ToastType.UnsupportedMultiAttachment) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>
|
||||
{i18n('cannotSelectPhotosAndVideosAlongWithFiles')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.UserAddedToGroup) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ToastMaxAttachments } from './ToastMaxAttachments';
|
||||
|
||||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const defaultProps = {
|
||||
i18n,
|
||||
onClose: action('onClose'),
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Components/ToastMaxAttachments',
|
||||
};
|
||||
|
||||
export const _ToastMaxAttachments = (): JSX.Element => (
|
||||
<ToastMaxAttachments {...defaultProps} />
|
||||
);
|
||||
|
||||
_ToastMaxAttachments.story = {
|
||||
name: 'ToastMaxAttachments',
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import { Toast } from './Toast';
|
||||
|
||||
type PropsType = {
|
||||
i18n: LocalizerType;
|
||||
onClose: () => unknown;
|
||||
};
|
||||
|
||||
export function ToastMaxAttachments({ i18n, onClose }: PropsType): JSX.Element {
|
||||
return <Toast onClose={onClose}>{i18n('maximumAttachments')}</Toast>;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ToastUnableToLoadAttachment } from './ToastUnableToLoadAttachment';
|
||||
|
||||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const defaultProps = {
|
||||
i18n,
|
||||
onClose: action('onClose'),
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Components/ToastUnableToLoadAttachment',
|
||||
};
|
||||
|
||||
export const _ToastUnableToLoadAttachment = (): JSX.Element => (
|
||||
<ToastUnableToLoadAttachment {...defaultProps} />
|
||||
);
|
||||
|
||||
_ToastUnableToLoadAttachment.story = {
|
||||
name: 'ToastUnableToLoadAttachment',
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ToastUnsupportedMultiAttachment } from './ToastUnsupportedMultiAttachment';
|
||||
|
||||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const defaultProps = {
|
||||
i18n,
|
||||
onClose: action('onClose'),
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Components/ToastUnsupportedMultiAttachment',
|
||||
};
|
||||
|
||||
export const _ToastUnsupportedMultiAttachment = (): JSX.Element => (
|
||||
<ToastUnsupportedMultiAttachment {...defaultProps} />
|
||||
);
|
||||
|
||||
_ToastUnsupportedMultiAttachment.story = {
|
||||
name: 'ToastUnsupportedMultiAttachment',
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import { Toast } from './Toast';
|
||||
|
||||
type PropsType = {
|
||||
i18n: LocalizerType;
|
||||
onClose: () => unknown;
|
||||
};
|
||||
|
||||
export function ToastUnsupportedMultiAttachment({
|
||||
i18n,
|
||||
onClose,
|
||||
}: PropsType): JSX.Element {
|
||||
return (
|
||||
<Toast onClose={onClose}>
|
||||
{i18n('cannotSelectPhotosAndVideosAlongWithFiles')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
|
@ -4,18 +4,82 @@
|
|||
import React from 'react';
|
||||
|
||||
export type PropsType = {
|
||||
conversationId: string;
|
||||
processAttachments: (options: {
|
||||
conversationId: string;
|
||||
files: ReadonlyArray<File>;
|
||||
}) => void;
|
||||
renderCompositionArea: () => JSX.Element;
|
||||
renderConversationHeader: () => JSX.Element;
|
||||
renderTimeline: () => JSX.Element;
|
||||
};
|
||||
|
||||
export function ConversationView({
|
||||
conversationId,
|
||||
processAttachments,
|
||||
renderCompositionArea,
|
||||
renderConversationHeader,
|
||||
renderTimeline,
|
||||
}: PropsType): JSX.Element {
|
||||
const onDrop = React.useCallback(
|
||||
(event: React.DragEvent<HTMLDivElement>) => {
|
||||
if (!event.dataTransfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.dataTransfer.types[0] !== 'Files') {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const { files } = event.dataTransfer;
|
||||
processAttachments({
|
||||
conversationId,
|
||||
files: Array.from(files),
|
||||
});
|
||||
},
|
||||
[conversationId, processAttachments]
|
||||
);
|
||||
|
||||
const onPaste = React.useCallback(
|
||||
(event: React.ClipboardEvent<HTMLDivElement>) => {
|
||||
if (!event.clipboardData) {
|
||||
return;
|
||||
}
|
||||
const { items } = event.clipboardData;
|
||||
|
||||
const anyImages = [...items].some(
|
||||
item => item.type.split('/')[0] === 'image'
|
||||
);
|
||||
if (!anyImages) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const files: Array<File> = [];
|
||||
for (let i = 0; i < items.length; i += 1) {
|
||||
if (items[i].type.split('/')[0] === 'image') {
|
||||
const file = items[i].getAsFile();
|
||||
if (file) {
|
||||
files.push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processAttachments({
|
||||
conversationId,
|
||||
files,
|
||||
});
|
||||
},
|
||||
[conversationId, processAttachments]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="ConversationView">
|
||||
<div className="ConversationView" onDrop={onDrop} onPaste={onPaste}>
|
||||
<div className="ConversationView__header">
|
||||
{renderConversationHeader()}
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue