Auto-select a newly created distribution list or group when sending story
This commit is contained in:
parent
81e4564687
commit
2db14e8d6f
14 changed files with 94 additions and 26 deletions
|
@ -56,7 +56,7 @@ export type PropsType = {
|
|||
onDistributionListCreated: (
|
||||
name: string,
|
||||
viewerUuids: Array<UUIDStringType>
|
||||
) => unknown;
|
||||
) => Promise<UUIDStringType>;
|
||||
onSelectedStoryList: (options: {
|
||||
conversationId: string;
|
||||
distributionId: string | undefined;
|
||||
|
@ -67,7 +67,7 @@ export type PropsType = {
|
|||
conversationIds: Array<string>
|
||||
) => unknown;
|
||||
signalConnections: Array<ConversationType>;
|
||||
toggleGroupsForStorySend: (cids: Array<string>) => unknown;
|
||||
toggleGroupsForStorySend: (cids: Array<string>) => Promise<void>;
|
||||
mostRecentActiveStoryTimestampByGroupOrDistributionList: Record<
|
||||
string,
|
||||
number
|
||||
|
@ -419,9 +419,17 @@ export function SendStoryModal({
|
|||
candidateConversations={candidateConversations}
|
||||
getPreferredBadge={getPreferredBadge}
|
||||
i18n={i18n}
|
||||
onCreateList={(name, uuids) => {
|
||||
onCreateList={async (name, uuids) => {
|
||||
const newDistributionListId = await onDistributionListCreated(
|
||||
name,
|
||||
uuids
|
||||
);
|
||||
|
||||
setSelectedContacts([]);
|
||||
onDistributionListCreated(name, uuids);
|
||||
setSelectedListIds(
|
||||
listIds => new Set([...listIds, newDistributionListId])
|
||||
);
|
||||
|
||||
setPage(Page.SendStory);
|
||||
}}
|
||||
onViewersUpdated={uuids => {
|
||||
|
@ -480,9 +488,10 @@ export function SendStoryModal({
|
|||
aria-label={i18n('ok')}
|
||||
className="SendStoryModal__ok"
|
||||
disabled={!chosenGroupIds.size}
|
||||
onClick={() => {
|
||||
toggleGroupsForStorySend(Array.from(chosenGroupIds));
|
||||
onClick={async () => {
|
||||
await toggleGroupsForStorySend(Array.from(chosenGroupIds));
|
||||
setChosenGroupIds(new Set());
|
||||
setSelectedGroupIds(chosenGroupIds);
|
||||
setPage(Page.SendStory);
|
||||
}}
|
||||
type="button"
|
||||
|
|
|
@ -54,7 +54,7 @@ export type PropsType = {
|
|||
onDistributionListCreated: (
|
||||
name: string,
|
||||
viewerUuids: Array<UUIDStringType>
|
||||
) => unknown;
|
||||
) => Promise<string>;
|
||||
onHideMyStoriesFrom: (viewerUuids: Array<UUIDStringType>) => unknown;
|
||||
onRemoveMembers: (listId: string, uuids: Array<UUIDStringType>) => unknown;
|
||||
onRepliesNReactionsChanged: (
|
||||
|
|
|
@ -2,16 +2,45 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { ActionCreatorsMapObject } from 'redux';
|
||||
import type { ThunkAction } from 'redux-thunk';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Type-level function from an action creator (which may be ThunkAction creator) to a
|
||||
* bound action creator.
|
||||
*
|
||||
* binding a thunk action creator changes it from:
|
||||
* (params) => ThunkAction<R, ...>
|
||||
* to:
|
||||
* (params) => R
|
||||
*
|
||||
* a regular action creator's type is unchanged
|
||||
*/
|
||||
type BoundActionCreator<A> = A extends (
|
||||
...params: infer P
|
||||
) => ThunkAction<infer R, any, any, any>
|
||||
? (...params: P) => R
|
||||
: A;
|
||||
|
||||
export type BoundActionCreatorsMapObject<T extends ActionCreatorsMapObject> = {
|
||||
[Property in keyof T]: BoundActionCreator<T[Property]>;
|
||||
};
|
||||
|
||||
export const useBoundActions = <T extends ActionCreatorsMapObject>(
|
||||
actions: T
|
||||
): T => {
|
||||
): BoundActionCreatorsMapObject<T> => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
return useMemo(() => {
|
||||
return bindActionCreators(actions, dispatch);
|
||||
// bindActionCreators from redux has the wrong type when using thunk actions
|
||||
// so we cast to the correct type
|
||||
return bindActionCreators(
|
||||
actions,
|
||||
dispatch
|
||||
) as any as BoundActionCreatorsMapObject<T>;
|
||||
}, [actions, dispatch]);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { ThunkAction } from 'redux-thunk';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import { Sound } from '../../util/Sound';
|
||||
import * as Errors from '../../types/errors';
|
||||
|
@ -106,7 +107,8 @@ export const actions = {
|
|||
setIsPlaying,
|
||||
};
|
||||
|
||||
export const useActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useActions = (): BoundActionCreatorsMapObject<typeof actions> =>
|
||||
useBoundActions(actions);
|
||||
|
||||
function setCurrentTime(value: number): CurrentTimeUpdated {
|
||||
globalMessageAudio.currentTime = value;
|
||||
|
|
|
@ -10,6 +10,7 @@ import type { StateType as RootStateType } from '../reducer';
|
|||
import { fileToBytes } from '../../util/fileToBytes';
|
||||
import { recorder } from '../../services/audioRecorder';
|
||||
import { stringToMIMEType } from '../../types/MIME';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
|
||||
export enum ErrorDialogAudioRecorderType {
|
||||
|
@ -76,7 +77,8 @@ export const actions = {
|
|||
startRecording,
|
||||
};
|
||||
|
||||
export const useActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useActions = (): BoundActionCreatorsMapObject<typeof actions> =>
|
||||
useBoundActions(actions);
|
||||
|
||||
function startRecording(): ThunkAction<
|
||||
void,
|
||||
|
|
|
@ -83,6 +83,7 @@ import {
|
|||
SelectedMessageSource,
|
||||
} from './conversationsEnums';
|
||||
import { markViewed as messageUpdaterMarkViewed } from '../../services/MessageUpdater';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
|
||||
import type { NoopActionType } from './noop';
|
||||
|
@ -935,8 +936,9 @@ export const actions = {
|
|||
verifyConversationsStoppingSend,
|
||||
};
|
||||
|
||||
export const useConversationsActions = (): typeof actions =>
|
||||
useBoundActions(actions);
|
||||
export const useConversationsActions = (): BoundActionCreatorsMapObject<
|
||||
typeof actions
|
||||
> => useBoundActions(actions);
|
||||
|
||||
function filterAvatarData(
|
||||
avatars: ReadonlyArray<AvatarDataType>,
|
||||
|
@ -2621,7 +2623,7 @@ function addMemberToGroup(
|
|||
|
||||
function toggleGroupsForStorySend(
|
||||
conversationIds: Array<string>
|
||||
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||
): ThunkAction<Promise<void>, RootStateType, unknown, NoopActionType> {
|
||||
return async dispatch => {
|
||||
await Promise.all(
|
||||
conversationIds.map(async conversationId => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { take, uniq } from 'lodash';
|
|||
import type { ThunkAction } from 'redux-thunk';
|
||||
import type { EmojiPickDataType } from '../../components/emoji/EmojiPicker';
|
||||
import dataInterface from '../../sql/Client';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
|
||||
const { updateEmojiUsage } = dataInterface;
|
||||
|
@ -31,7 +32,8 @@ export const actions = {
|
|||
useEmoji,
|
||||
};
|
||||
|
||||
export const useActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useActions = (): BoundActionCreatorsMapObject<typeof actions> =>
|
||||
useBoundActions(actions);
|
||||
|
||||
function onUseEmoji({
|
||||
shortName,
|
||||
|
|
|
@ -12,6 +12,7 @@ import type { UUIDStringType } from '../../types/UUID';
|
|||
import * as SingleServePromise from '../../services/singleServePromise';
|
||||
import { getMessageById } from '../../messages/getMessageById';
|
||||
import { getMessagePropsSelector } from '../selectors/message';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { longRunningTaskWrapper } from '../../util/longRunningTaskWrapper';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import { isGroupV1 } from '../../util/whatTypeOfConversation';
|
||||
|
@ -215,8 +216,9 @@ export const actions = {
|
|||
closeGV2MigrationDialog,
|
||||
};
|
||||
|
||||
export const useGlobalModalActions = (): typeof actions =>
|
||||
useBoundActions(actions);
|
||||
export const useGlobalModalActions = (): BoundActionCreatorsMapObject<
|
||||
typeof actions
|
||||
> => useBoundActions(actions);
|
||||
|
||||
function hideContactModal(): HideContactModalActionType {
|
||||
return {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { v4 as getGuid } from 'uuid';
|
|||
import type { ThunkAction } from 'redux-thunk';
|
||||
import type { StateType as RootStateType } from '../reducer';
|
||||
import * as storageShim from '../../shims/storage';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import type {
|
||||
ConversationColorType,
|
||||
|
@ -93,7 +94,8 @@ export const actions = {
|
|||
resetItems,
|
||||
};
|
||||
|
||||
export const useActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useActions = (): BoundActionCreatorsMapObject<typeof actions> =>
|
||||
useBoundActions(actions);
|
||||
|
||||
function putItem<K extends keyof StorageAccessType>(
|
||||
key: K,
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
} from '../../types/LinkPreview';
|
||||
import { assignWithNoUnnecessaryAllocation } from '../../util/assignWithNoUnnecessaryAllocation';
|
||||
import { maybeGrabLinkPreview } from '../../services/LinkPreview';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
|
||||
// State
|
||||
|
@ -84,8 +85,9 @@ export const actions = {
|
|||
removeLinkPreview,
|
||||
};
|
||||
|
||||
export const useLinkPreviewActions = (): typeof actions =>
|
||||
useBoundActions(actions);
|
||||
export const useLinkPreviewActions = (): BoundActionCreatorsMapObject<
|
||||
typeof actions
|
||||
> => useBoundActions(actions);
|
||||
|
||||
// Reducer
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import { omit } from 'lodash';
|
|||
import * as log from '../../logging/log';
|
||||
import * as Errors from '../../types/errors';
|
||||
import { replaceIndex } from '../../util/replaceIndex';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import type { StateType as RootStateType } from '../reducer';
|
||||
import { DEFAULT_PREFERRED_REACTION_EMOJI_SHORT_NAMES } from '../../reactions/constants';
|
||||
|
@ -97,7 +98,8 @@ export const actions = {
|
|||
selectDraftEmojiToBeReplaced,
|
||||
};
|
||||
|
||||
export const useActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useActions = (): BoundActionCreatorsMapObject<typeof actions> =>
|
||||
useBoundActions(actions);
|
||||
|
||||
function cancelCustomizePreferredReactionsModal(): CancelCustomizePreferredReactionsModalActionType {
|
||||
return { type: CANCEL_CUSTOMIZE_PREFERRED_REACTIONS_MODAL };
|
||||
|
|
|
@ -51,6 +51,7 @@ import { isGroup } from '../../util/whatTypeOfConversation';
|
|||
import { isNotNil } from '../../util/isNotNil';
|
||||
import { isStory } from '../../messages/helpers';
|
||||
import { sendStoryMessage as doSendStoryMessage } from '../../util/sendStoryMessage';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import { verifyStoryListMembers as doVerifyStoryListMembers } from '../../util/verifyStoryListMembers';
|
||||
import { viewSyncJobQueue } from '../../jobs/viewSyncJobQueue';
|
||||
|
@ -1317,7 +1318,9 @@ export const actions = {
|
|||
setStorySending,
|
||||
};
|
||||
|
||||
export const useStoriesActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useStoriesActions = (): BoundActionCreatorsMapObject<
|
||||
typeof actions
|
||||
> => useBoundActions(actions);
|
||||
|
||||
// Reducer
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import { UUID } from '../../types/UUID';
|
|||
import { deleteStoryForEveryone } from '../../util/deleteStoryForEveryone';
|
||||
import { replaceIndex } from '../../util/replaceIndex';
|
||||
import { storageServiceUploadJob } from '../../services/storage';
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
|
||||
// State
|
||||
|
@ -156,7 +157,12 @@ function createDistributionList(
|
|||
memberUuids: Array<UUIDStringType>,
|
||||
storageServiceDistributionListRecord?: StoryDistributionWithMembersType,
|
||||
shouldSave = true
|
||||
): ThunkAction<void, RootStateType, null, CreateListActionType> {
|
||||
): ThunkAction<
|
||||
Promise<UUIDStringType>,
|
||||
RootStateType,
|
||||
string,
|
||||
CreateListActionType
|
||||
> {
|
||||
return async dispatch => {
|
||||
const storyDistribution: StoryDistributionWithMembersType = {
|
||||
allowsReplies: true,
|
||||
|
@ -188,6 +194,8 @@ function createDistributionList(
|
|||
name: storyDistribution.name,
|
||||
},
|
||||
});
|
||||
|
||||
return storyDistribution.id;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -483,8 +491,8 @@ export const actions = {
|
|||
updateStoryViewers,
|
||||
};
|
||||
|
||||
export const useStoryDistributionListsActions = (): typeof actions =>
|
||||
useBoundActions(actions);
|
||||
export const useStoryDistributionListsActions =
|
||||
(): BoundActionCreatorsMapObject<typeof actions> => useBoundActions(actions);
|
||||
|
||||
// Reducer
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import type { ReplacementValuesType } from '../../types/Util';
|
||||
|
||||
|
@ -94,7 +95,9 @@ export const actions = {
|
|||
showToast,
|
||||
};
|
||||
|
||||
export const useToastActions = (): typeof actions => useBoundActions(actions);
|
||||
export const useToastActions = (): BoundActionCreatorsMapObject<
|
||||
typeof actions
|
||||
> => useBoundActions(actions);
|
||||
|
||||
// Reducer
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue