// Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect, useState } from 'react'; import { get, has } from 'lodash'; import type { AttachmentType, InMemoryAttachmentDraftType, } from '../types/Attachment'; import type { ConversationType } from '../state/ducks/conversations'; import type { LinkPreviewSourceType } from '../types/LinkPreview'; import type { LinkPreviewType } from '../types/message/LinkPreviews'; import type { LocalizerType } from '../types/Util'; import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import type { Props as StickerButtonProps } from './stickers/StickerButton'; import type { StoryDistributionListDataType } from '../state/ducks/storyDistributionLists'; import type { UUIDStringType } from '../types/UUID'; import { IMAGE_JPEG, TEXT_ATTACHMENT } from '../types/MIME'; import { isVideoAttachment } from '../types/Attachment'; import { SendStoryModal } from './SendStoryModal'; import { MediaEditor } from './MediaEditor'; import { TextStoryCreator } from './TextStoryCreator'; export type PropsType = { candidateConversations: Array; debouncedMaybeGrabLinkPreview: ( message: string, source: LinkPreviewSourceType ) => unknown; distributionLists: Array; file?: File; getPreferredBadge: PreferredBadgeSelectorType; groupConversations: Array; groupStories: Array; i18n: LocalizerType; linkPreview?: LinkPreviewType; me: ConversationType; onClose: () => unknown; onDistributionListCreated: ( name: string, viewerUuids: Array ) => unknown; onSelectedStoryList: (memberUuids: Array) => unknown; onSend: ( listIds: Array, conversationIds: Array, attachment: AttachmentType ) => unknown; processAttachment: ( file: File ) => Promise; sendStoryModalOpenStateChanged: (isOpen: boolean) => unknown; signalConnections: Array; tagGroupsAsNewGroupStory: (cids: Array) => unknown; } & Pick; export const StoryCreator = ({ candidateConversations, debouncedMaybeGrabLinkPreview, distributionLists, file, getPreferredBadge, groupConversations, groupStories, i18n, installedPacks, linkPreview, me, onClose, onDistributionListCreated, onSelectedStoryList, onSend, processAttachment, recentStickers, sendStoryModalOpenStateChanged, signalConnections, tagGroupsAsNewGroupStory, }: PropsType): JSX.Element => { const [draftAttachment, setDraftAttachment] = useState< AttachmentType | undefined >(); const [attachmentUrl, setAttachmentUrl] = useState(); useEffect(() => { let url: string | undefined; let unmounted = false; async function loadAttachment(): Promise { if (!file || unmounted) { return; } const attachment = await processAttachment(file); if (!attachment || unmounted) { return; } if (isVideoAttachment(attachment)) { setDraftAttachment(attachment); } else if (attachment && has(attachment, 'data')) { url = URL.createObjectURL(new Blob([get(attachment, 'data')])); setAttachmentUrl(url); } } loadAttachment(); return () => { unmounted = true; if (url) { URL.revokeObjectURL(url); } }; }, [file, processAttachment]); useEffect(() => { sendStoryModalOpenStateChanged(Boolean(draftAttachment)); }, [draftAttachment, sendStoryModalOpenStateChanged]); return ( <> {draftAttachment && ( setDraftAttachment(undefined)} onDistributionListCreated={onDistributionListCreated} onSelectedStoryList={onSelectedStoryList} onSend={(listIds, groupIds) => { onSend(listIds, groupIds, draftAttachment); setDraftAttachment(undefined); onClose(); }} signalConnections={signalConnections} tagGroupsAsNewGroupStory={tagGroupsAsNewGroupStory} /> )} {attachmentUrl && ( { setDraftAttachment({ contentType: IMAGE_JPEG, data, size: data.byteLength, }); }} recentStickers={recentStickers} /> )} {!file && ( { setDraftAttachment({ contentType: TEXT_ATTACHMENT, textAttachment, size: textAttachment.text?.length || 0, }); }} /> )} ); };