Keep story creator around until we've verified contacts and queued job

This commit is contained in:
Scott Nonnenberg 2022-11-01 17:36:16 -07:00 committed by GitHub
parent 4fc1b6388c
commit 9fba33943a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 178 additions and 41 deletions

View file

@ -587,6 +587,7 @@ export const CompositionArea = ({
<MediaEditor <MediaEditor
i18n={i18n} i18n={i18n}
imageSrc={attachmentToEdit.url} imageSrc={attachmentToEdit.url}
isSending={false}
onClose={() => setAttachmentToEdit(undefined)} onClose={() => setAttachmentToEdit(undefined)}
onDone={data => { onDone={data => {
const newAttachment = { const newAttachment = {

View file

@ -27,6 +27,7 @@ const getDefaultProps = (): PropsType => ({
imageSrc: IMAGE_2, imageSrc: IMAGE_2,
onClose: action('onClose'), onClose: action('onClose'),
onDone: action('onDone'), onDone: action('onDone'),
isSending: false,
// StickerButtonProps // StickerButtonProps
installedPacks, installedPacks,
@ -49,6 +50,10 @@ export const Portrait = (): JSX.Element => (
<MediaEditor {...getDefaultProps()} imageSrc={IMAGE_4} /> <MediaEditor {...getDefaultProps()} imageSrc={IMAGE_4} />
); );
export const Sending = (): JSX.Element => (
<MediaEditor {...getDefaultProps()} isSending />
);
export const WithCaption = (): JSX.Element => ( export const WithCaption = (): JSX.Element => (
<MediaEditor <MediaEditor
{...getDefaultProps()} {...getDefaultProps()}

View file

@ -39,11 +39,13 @@ import type { SmartCompositionTextAreaProps } from '../state/smart/CompositionTe
import { Emojify } from './conversation/Emojify'; import { Emojify } from './conversation/Emojify';
import { AddNewLines } from './conversation/AddNewLines'; import { AddNewLines } from './conversation/AddNewLines';
import { useConfirmDiscard } from '../hooks/useConfirmDiscard'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard';
import { Spinner } from './Spinner';
export type PropsType = { export type PropsType = {
doneButtonLabel?: string; doneButtonLabel?: string;
i18n: LocalizerType; i18n: LocalizerType;
imageSrc: string; imageSrc: string;
isSending: boolean;
onClose: () => unknown; onClose: () => unknown;
onDone: (data: Uint8Array, caption?: string | undefined) => unknown; onDone: (data: Uint8Array, caption?: string | undefined) => unknown;
} & Pick<StickerButtonProps, 'installedPacks' | 'recentStickers'> & } & Pick<StickerButtonProps, 'installedPacks' | 'recentStickers'> &
@ -106,6 +108,7 @@ export const MediaEditor = ({
doneButtonLabel, doneButtonLabel,
i18n, i18n,
imageSrc, imageSrc,
isSending,
onClose, onClose,
onDone, onDone,
@ -1102,7 +1105,7 @@ export const MediaEditor = ({
/> />
</div> </div>
<Button <Button
disabled={!image || isSaving} disabled={!image || isSaving || isSending}
onClick={async () => { onClick={async () => {
if (!fabricCanvas) { if (!fabricCanvas) {
return; return;
@ -1160,7 +1163,11 @@ export const MediaEditor = ({
theme={Theme.Dark} theme={Theme.Dark}
variant={ButtonVariant.Primary} variant={ButtonVariant.Primary}
> >
{doneButtonLabel || i18n('save')} {isSending ? (
<Spinner svgSize="small" />
) : (
doneButtonLabel || i18n('save')
)}
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -14,9 +14,9 @@ import type {
} from '../types/Stories'; } from '../types/Stories';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
import type { PropsType as SmartStoryCreatorPropsType } from '../state/smart/StoryCreator';
import type { ShowToastActionCreatorType } from '../state/ducks/toast'; import type { ShowToastActionCreatorType } from '../state/ducks/toast';
import type { import type {
AddStoryData,
ViewUserStoriesActionCreatorType, ViewUserStoriesActionCreatorType,
ViewStoryActionCreatorType, ViewStoryActionCreatorType,
} from '../state/ducks/stories'; } from '../state/ducks/stories';
@ -27,6 +27,7 @@ import { getWidthFromPreferredWidth } from '../util/leftPaneWidth';
import { useEscapeHandling } from '../hooks/useEscapeHandling'; import { useEscapeHandling } from '../hooks/useEscapeHandling';
export type PropsType = { export type PropsType = {
addStoryData: AddStoryData;
deleteStoryForEveryone: (story: StoryViewType) => unknown; deleteStoryForEveryone: (story: StoryViewType) => unknown;
getPreferredBadge: PreferredBadgeSelectorType; getPreferredBadge: PreferredBadgeSelectorType;
hiddenStories: Array<ConversationStoryType>; hiddenStories: Array<ConversationStoryType>;
@ -37,7 +38,8 @@ export type PropsType = {
onSaveStory: (story: StoryViewType) => unknown; onSaveStory: (story: StoryViewType) => unknown;
preferredWidthFromStorage: number; preferredWidthFromStorage: number;
queueStoryDownload: (storyId: string) => unknown; queueStoryDownload: (storyId: string) => unknown;
renderStoryCreator: (props: SmartStoryCreatorPropsType) => JSX.Element; renderStoryCreator: () => JSX.Element;
setAddStoryData: (data: AddStoryData) => unknown;
showConversation: ShowConversationType; showConversation: ShowConversationType;
showStoriesSettings: () => unknown; showStoriesSettings: () => unknown;
showToast: ShowToastActionCreatorType; showToast: ShowToastActionCreatorType;
@ -51,15 +53,8 @@ export type PropsType = {
hasViewReceiptSetting: boolean; hasViewReceiptSetting: boolean;
}; };
type AddStoryType =
| {
type: 'Media';
file: File;
}
| { type: 'Text' }
| undefined;
export const Stories = ({ export const Stories = ({
addStoryData,
deleteStoryForEveryone, deleteStoryForEveryone,
getPreferredBadge, getPreferredBadge,
hiddenStories, hiddenStories,
@ -71,6 +66,7 @@ export const Stories = ({
preferredWidthFromStorage, preferredWidthFromStorage,
queueStoryDownload, queueStoryDownload,
renderStoryCreator, renderStoryCreator,
setAddStoryData,
showConversation, showConversation,
showStoriesSettings, showStoriesSettings,
showToast, showToast,
@ -87,7 +83,6 @@ export const Stories = ({
requiresFullWidth: true, requiresFullWidth: true,
}); });
const [addStoryData, setAddStoryData] = useState<AddStoryType>();
const [isMyStories, setIsMyStories] = useState(false); const [isMyStories, setIsMyStories] = useState(false);
// only handle ESC if not showing a child that handles their own ESC // only handle ESC if not showing a child that handles their own ESC
@ -102,11 +97,7 @@ export const Stories = ({
return ( return (
<div className={classNames('Stories', themeClassName(Theme.Dark))}> <div className={classNames('Stories', themeClassName(Theme.Dark))}>
{addStoryData && {addStoryData && renderStoryCreator()}
renderStoryCreator({
file: addStoryData.type === 'Media' ? addStoryData.file : undefined,
onClose: () => setAddStoryData(undefined),
})}
<div className="Stories__pane" style={{ width }}> <div className="Stories__pane" style={{ width }}>
{isMyStories && myStories.length ? ( {isMyStories && myStories.length ? (
<MyStories <MyStories

View file

@ -40,6 +40,9 @@ export default {
installedPacks: { installedPacks: {
defaultValue: [], defaultValue: [],
}, },
isSending: {
defaultValue: false,
},
linkPreview: { linkPreview: {
defaultValue: undefined, defaultValue: undefined,
}, },
@ -95,3 +98,8 @@ FirstTime.args = {
FirstTime.story = { FirstTime.story = {
name: 'First time posting a story', name: 'First time posting a story',
}; };
export const Sending = Template.bind({});
Sending.args = {
isSending: true,
};

View file

@ -30,6 +30,7 @@ export type PropsType = {
) => unknown; ) => unknown;
file?: File; file?: File;
i18n: LocalizerType; i18n: LocalizerType;
isSending: boolean;
linkPreview?: LinkPreviewType; linkPreview?: LinkPreviewType;
onClose: () => unknown; onClose: () => unknown;
onSend: ( onSend: (
@ -78,6 +79,7 @@ export const StoryCreator = ({
hasFirstStoryPostExperience, hasFirstStoryPostExperience,
i18n, i18n,
installedPacks, installedPacks,
isSending,
linkPreview, linkPreview,
me, me,
onClose, onClose,
@ -162,7 +164,6 @@ export const StoryCreator = ({
onSend={(listIds, groupIds) => { onSend={(listIds, groupIds) => {
onSend(listIds, groupIds, draftAttachment); onSend(listIds, groupIds, draftAttachment);
setDraftAttachment(undefined); setDraftAttachment(undefined);
onClose();
}} }}
onViewersUpdated={onViewersUpdated} onViewersUpdated={onViewersUpdated}
setMyStoriesToAllSignalConnections={ setMyStoriesToAllSignalConnections={
@ -179,6 +180,7 @@ export const StoryCreator = ({
i18n={i18n} i18n={i18n}
imageSrc={attachmentUrl} imageSrc={attachmentUrl}
installedPacks={installedPacks} installedPacks={installedPacks}
isSending={isSending}
onClose={onClose} onClose={onClose}
supportsCaption supportsCaption
renderCompositionTextArea={renderCompositionTextArea} renderCompositionTextArea={renderCompositionTextArea}
@ -197,6 +199,7 @@ export const StoryCreator = ({
<TextStoryCreator <TextStoryCreator
debouncedMaybeGrabLinkPreview={debouncedMaybeGrabLinkPreview} debouncedMaybeGrabLinkPreview={debouncedMaybeGrabLinkPreview}
i18n={i18n} i18n={i18n}
isSending={isSending}
linkPreview={linkPreview} linkPreview={linkPreview}
onClose={onClose} onClose={onClose}
onDone={textAttachment => { onDone={textAttachment => {

View file

@ -29,6 +29,7 @@ import {
import { objectMap } from '../util/objectMap'; import { objectMap } from '../util/objectMap';
import { handleOutsideClick } from '../util/handleOutsideClick'; import { handleOutsideClick } from '../util/handleOutsideClick';
import { ConfirmDiscardDialog } from './ConfirmDiscardDialog'; import { ConfirmDiscardDialog } from './ConfirmDiscardDialog';
import { Spinner } from './Spinner';
export type PropsType = { export type PropsType = {
debouncedMaybeGrabLinkPreview: ( debouncedMaybeGrabLinkPreview: (
@ -37,6 +38,7 @@ export type PropsType = {
options?: MaybeGrabLinkPreviewOptionsType options?: MaybeGrabLinkPreviewOptionsType
) => unknown; ) => unknown;
i18n: LocalizerType; i18n: LocalizerType;
isSending: boolean;
linkPreview?: LinkPreviewType; linkPreview?: LinkPreviewType;
onClose: () => unknown; onClose: () => unknown;
onDone: (textAttachment: TextAttachmentType) => unknown; onDone: (textAttachment: TextAttachmentType) => unknown;
@ -122,6 +124,7 @@ function getBgButtonAriaLabel(
export const TextStoryCreator = ({ export const TextStoryCreator = ({
debouncedMaybeGrabLinkPreview, debouncedMaybeGrabLinkPreview,
i18n, i18n,
isSending,
linkPreview, linkPreview,
onClose, onClose,
onDone, onDone,
@ -566,12 +569,16 @@ export const TextStoryCreator = ({
)} )}
</div> </div>
<Button <Button
disabled={!hasChanges} disabled={!hasChanges || isSending}
onClick={() => onDone(textAttachment)} onClick={() => onDone(textAttachment)}
theme={Theme.Dark} theme={Theme.Dark}
variant={ButtonVariant.Primary} variant={ButtonVariant.Primary}
> >
{i18n('StoryCreator__next')} {isSending ? (
<Spinner svgSize="small" />
) : (
i18n('StoryCreator__next')
)}
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -3,6 +3,8 @@
import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; import type { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { isEqual, pick } from 'lodash'; import { isEqual, pick } from 'lodash';
import * as Errors from '../../types/errors';
import type { AttachmentType } from '../../types/Attachment'; import type { AttachmentType } from '../../types/Attachment';
import type { BodyRangeType } from '../../types/Util'; import type { BodyRangeType } from '../../types/Util';
import type { ConversationModel } from '../../models/conversations'; import type { ConversationModel } from '../../models/conversations';
@ -87,6 +89,18 @@ export type SelectedStoryDataType = {
viewTarget?: StoryViewTargetType; viewTarget?: StoryViewTargetType;
}; };
export type AddStoryData =
| {
type: 'Media';
file: File;
sending?: boolean;
}
| {
type: 'Text';
sending?: boolean;
}
| undefined;
// State // State
export type StoriesStateType = { export type StoriesStateType = {
@ -97,6 +111,7 @@ export type StoriesStateType = {
replies: Array<MessageAttributesType>; replies: Array<MessageAttributesType>;
}; };
readonly selectedStoryData?: SelectedStoryDataType; readonly selectedStoryData?: SelectedStoryDataType;
readonly addStoryData: AddStoryData;
readonly sendStoryModalData?: { readonly sendStoryModalData?: {
untrustedUuids: Array<string>; untrustedUuids: Array<string>;
verifiedUuids: Array<string>; verifiedUuids: Array<string>;
@ -117,6 +132,8 @@ const STORY_CHANGED = 'stories/STORY_CHANGED';
const TOGGLE_VIEW = 'stories/TOGGLE_VIEW'; const TOGGLE_VIEW = 'stories/TOGGLE_VIEW';
const VIEW_STORY = 'stories/VIEW_STORY'; const VIEW_STORY = 'stories/VIEW_STORY';
const REMOVE_ALL_STORIES = 'stories/REMOVE_ALL_STORIES'; const REMOVE_ALL_STORIES = 'stories/REMOVE_ALL_STORIES';
const SET_ADD_STORY_DATA = 'stories/SET_ADD_STORY_DATA';
const SET_STORY_SENDING = 'stories/SET_STORY_SENDING';
type DOEStoryActionType = { type DOEStoryActionType = {
type: typeof DOE_STORY; type: typeof DOE_STORY;
@ -175,6 +192,16 @@ type RemoveAllStoriesActionType = {
type: typeof REMOVE_ALL_STORIES; type: typeof REMOVE_ALL_STORIES;
}; };
type SetAddStoryDataType = {
type: typeof SET_ADD_STORY_DATA;
payload: AddStoryData;
};
type SetStorySendingType = {
type: typeof SET_STORY_SENDING;
payload: boolean;
};
export type StoriesActionType = export type StoriesActionType =
| DOEStoryActionType | DOEStoryActionType
| ListMembersVerified | ListMembersVerified
@ -188,7 +215,9 @@ export type StoriesActionType =
| StoryChangedActionType | StoryChangedActionType
| ToggleViewActionType | ToggleViewActionType
| ViewStoryActionType | ViewStoryActionType
| RemoveAllStoriesActionType; | RemoveAllStoriesActionType
| SetAddStoryDataType
| SetStorySendingType;
// Action Creators // Action Creators
@ -451,10 +480,22 @@ function sendStoryMessage(
listIds: Array<UUIDStringType>, listIds: Array<UUIDStringType>,
conversationIds: Array<string>, conversationIds: Array<string>,
attachment: AttachmentType attachment: AttachmentType
): ThunkAction<void, RootStateType, unknown, SendStoryModalOpenStateChanged> { ): ThunkAction<
void,
RootStateType,
unknown,
SendStoryModalOpenStateChanged | SetStorySendingType | SetAddStoryDataType
> {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const { stories } = getState(); const { stories } = getState();
const { openedAtTimestamp, sendStoryModalData } = stories; const { openedAtTimestamp, sendStoryModalData } = stories;
// Add spinners in the story creator
dispatch({
type: SET_STORY_SENDING,
payload: true,
});
assertDev( assertDev(
openedAtTimestamp, openedAtTimestamp,
'sendStoryMessage: openedAtTimestamp is undefined, cannot send' 'sendStoryMessage: openedAtTimestamp is undefined, cannot send'
@ -464,11 +505,6 @@ function sendStoryMessage(
'sendStoryMessage: sendStoryModalData is not defined, cannot send' 'sendStoryMessage: sendStoryModalData is not defined, cannot send'
); );
dispatch({
type: SEND_STORY_MODAL_OPEN_STATE_CHANGED,
payload: undefined,
});
if (sendStoryModalData.untrustedUuids.length) { if (sendStoryModalData.untrustedUuids.length) {
log.info('sendStoryMessage: SN changed for some conversations'); log.info('sendStoryMessage: SN changed for some conversations');
@ -491,12 +527,39 @@ function sendStoryMessage(
); );
if (!result) { if (!result) {
log.info('sendStoryMessage: did not send'); log.info('sendStoryMessage: failed to verify untrusted; stopping send');
dispatch({
type: SET_STORY_SENDING,
payload: false,
});
return; return;
} }
// Clear all untrusted and verified uuids; we're clear to send!
dispatch({
type: SEND_STORY_MODAL_OPEN_STATE_CHANGED,
payload: undefined,
});
} }
await doSendStoryMessage(listIds, conversationIds, attachment); try {
await doSendStoryMessage(listIds, conversationIds, attachment);
// Note: Only when we've successfully queued the message do we dismiss the story
// composer view.
dispatch({
type: SET_ADD_STORY_DATA,
payload: undefined,
});
} catch (error) {
log.error('sendStoryMessage:', Errors.toLogFormat(error));
// Get rid of spinners in the story creator
dispatch({
type: SET_STORY_SENDING,
payload: false,
});
}
}; };
} }
@ -1111,6 +1174,20 @@ const viewStory: ViewStoryActionCreatorType = (
}; };
}; };
function setAddStoryData(addStoryData: AddStoryData): SetAddStoryDataType {
return {
type: SET_ADD_STORY_DATA,
payload: addStoryData,
};
}
function setStorySending(sending: boolean): SetStorySendingType {
return {
type: SET_STORY_SENDING,
payload: sending,
};
}
function setStoriesDisabled( function setStoriesDisabled(
value: boolean value: boolean
): ThunkAction<void, RootStateType, unknown, never> { ): ThunkAction<void, RootStateType, unknown, never> {
@ -1134,7 +1211,9 @@ export const actions = {
verifyStoryListMembers, verifyStoryListMembers,
viewUserStories, viewUserStories,
viewStory, viewStory,
setAddStoryData,
setStoriesDisabled, setStoriesDisabled,
setStorySending,
}; };
export const useStoriesActions = (): typeof actions => useBoundActions(actions); export const useStoriesActions = (): typeof actions => useBoundActions(actions);
@ -1147,6 +1226,7 @@ export function getEmptyState(
return { return {
lastOpenedAtTimestamp: undefined, lastOpenedAtTimestamp: undefined,
openedAtTimestamp: undefined, openedAtTimestamp: undefined,
addStoryData: undefined,
stories: [], stories: [],
...overrideState, ...overrideState,
}; };
@ -1475,5 +1555,31 @@ export function reducer(
}; };
} }
if (action.type === SET_ADD_STORY_DATA) {
return {
...state,
addStoryData: action.payload,
};
}
if (action.type === SET_STORY_SENDING) {
const existing = state.addStoryData;
if (!existing) {
log.warn(
'stories/reducer: Set story sending, but no existing addStoryData'
);
return state;
}
return {
...state,
addStoryData: {
...existing,
sending: action.payload,
},
};
}
return state; return state;
} }

View file

@ -21,6 +21,7 @@ import type {
SelectedStoryDataType, SelectedStoryDataType,
StoryDataType, StoryDataType,
StoriesStateType, StoriesStateType,
AddStoryData,
} from '../ducks/stories'; } from '../ducks/stories';
import { HasStories, MY_STORIES_ID } from '../../types/Stories'; import { HasStories, MY_STORIES_ID } from '../../types/Stories';
import { ReadStatus } from '../../messages/MessageReadStatus'; import { ReadStatus } from '../../messages/MessageReadStatus';
@ -58,6 +59,11 @@ export const getSelectedStoryData = createSelector(
selectedStoryData selectedStoryData
); );
export const getAddStoryData = createSelector(
getStoriesState,
({ addStoryData }): AddStoryData => addStoryData
);
function getReactionUniqueId(reaction: MessageReactionType): string { function getReactionUniqueId(reaction: MessageReactionType): string {
return `${reaction.fromId}:${reaction.targetAuthorUuid}:${reaction.timestamp}`; return `${reaction.fromId}:${reaction.targetAuthorUuid}:${reaction.timestamp}`;
} }

View file

@ -6,7 +6,6 @@ import { useSelector } from 'react-redux';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import type { StateType } from '../reducer'; import type { StateType } from '../reducer';
import type { PropsType as SmartStoryCreatorPropsType } from './StoryCreator';
import { SmartStoryCreator } from './StoryCreator'; import { SmartStoryCreator } from './StoryCreator';
import { Stories } from '../../components/Stories'; import { Stories } from '../../components/Stories';
import { getMe } from '../selectors/conversations'; import { getMe } from '../selectors/conversations';
@ -17,6 +16,7 @@ import {
getPreferredLeftPaneWidth, getPreferredLeftPaneWidth,
} from '../selectors/items'; } from '../selectors/items';
import { import {
getAddStoryData,
getSelectedStoryData, getSelectedStoryData,
getStories, getStories,
shouldShowStoriesView, shouldShowStoriesView,
@ -27,11 +27,8 @@ import { useGlobalModalActions } from '../ducks/globalModals';
import { useStoriesActions } from '../ducks/stories'; import { useStoriesActions } from '../ducks/stories';
import { useToastActions } from '../ducks/toast'; import { useToastActions } from '../ducks/toast';
function renderStoryCreator({ function renderStoryCreator(): JSX.Element {
file, return <SmartStoryCreator />;
onClose,
}: SmartStoryCreatorPropsType): JSX.Element {
return <SmartStoryCreator file={file} onClose={onClose} />;
} }
export function SmartStories(): JSX.Element | null { export function SmartStories(): JSX.Element | null {
@ -52,6 +49,7 @@ export function SmartStories(): JSX.Element | null {
); );
const getPreferredBadge = useSelector(getPreferredBadgeSelector); const getPreferredBadge = useSelector(getPreferredBadgeSelector);
const addStoryData = useSelector(getAddStoryData);
const { hiddenStories, myStories, stories } = useSelector(getStories); const { hiddenStories, myStories, stories } = useSelector(getStories);
const me = useSelector(getMe); const me = useSelector(getMe);
@ -70,6 +68,7 @@ export function SmartStories(): JSX.Element | null {
return ( return (
<Stories <Stories
addStoryData={addStoryData}
getPreferredBadge={getPreferredBadge} getPreferredBadge={getPreferredBadge}
hiddenStories={hiddenStories} hiddenStories={hiddenStories}
i18n={i18n} i18n={i18n}

View file

@ -31,21 +31,20 @@ import { useLinkPreviewActions } from '../ducks/linkPreviews';
import { useStoriesActions } from '../ducks/stories'; import { useStoriesActions } from '../ducks/stories';
import { useStoryDistributionListsActions } from '../ducks/storyDistributionLists'; import { useStoryDistributionListsActions } from '../ducks/storyDistributionLists';
import { SmartCompositionTextArea } from './CompositionTextArea'; import { SmartCompositionTextArea } from './CompositionTextArea';
import { getAddStoryData } from '../selectors/stories';
export type PropsType = { export type PropsType = {
file?: File; file?: File;
onClose: () => unknown; onClose: () => unknown;
}; };
export function SmartStoryCreator({ export function SmartStoryCreator(): JSX.Element | null {
file,
onClose,
}: PropsType): JSX.Element | null {
const { debouncedMaybeGrabLinkPreview } = useLinkPreviewActions(); const { debouncedMaybeGrabLinkPreview } = useLinkPreviewActions();
const { const {
sendStoryModalOpenStateChanged, sendStoryModalOpenStateChanged,
sendStoryMessage, sendStoryMessage,
verifyStoryListMembers, verifyStoryListMembers,
setAddStoryData,
} = useStoriesActions(); } = useStoriesActions();
const { toggleGroupsForStorySend } = useConversationsActions(); const { toggleGroupsForStorySend } = useConversationsActions();
const { const {
@ -72,6 +71,10 @@ export function SmartStoryCreator({
const recentStickers = useSelector(getRecentStickers); const recentStickers = useSelector(getRecentStickers);
const signalConnections = useSelector(getAllSignalConnections); const signalConnections = useSelector(getAllSignalConnections);
const addStoryData = useSelector(getAddStoryData);
const file = addStoryData?.type === 'Media' ? addStoryData.file : undefined;
const isSending = addStoryData?.sending || false;
return ( return (
<StoryCreator <StoryCreator
candidateConversations={candidateConversations} candidateConversations={candidateConversations}
@ -84,9 +87,10 @@ export function SmartStoryCreator({
hasFirstStoryPostExperience={!hasSetMyStoriesPrivacy} hasFirstStoryPostExperience={!hasSetMyStoriesPrivacy}
i18n={i18n} i18n={i18n}
installedPacks={installedPacks} installedPacks={installedPacks}
isSending={isSending}
linkPreview={linkPreviewForSource(LinkPreviewSourceType.StoryCreator)} linkPreview={linkPreviewForSource(LinkPreviewSourceType.StoryCreator)}
me={me} me={me}
onClose={onClose} onClose={() => setAddStoryData(undefined)}
onDeleteList={deleteDistributionList} onDeleteList={deleteDistributionList}
onDistributionListCreated={createDistributionList} onDistributionListCreated={createDistributionList}
onHideMyStoriesFrom={hideMyStoriesFrom} onHideMyStoriesFrom={hideMyStoriesFrom}