diff --git a/ts/components/CompositionArea.stories.tsx b/ts/components/CompositionArea.stories.tsx index eea87c05247d..94b13d5b5241 100644 --- a/ts/components/CompositionArea.stories.tsx +++ b/ts/components/CompositionArea.stories.tsx @@ -92,7 +92,7 @@ const useProps = (overrideProps: Partial = {}): Props => ({ blessedPacks: [], recentStickers: [], clearInstalledStickerPack: action('clearInstalledStickerPack'), - onClickAddPack: action('onClickAddPack'), + pushPanelForConversation: action('pushPanelForConversation'), sendStickerMessage: action('sendStickerMessage'), clearShowIntroduction: action('clearShowIntroduction'), showPickerHint: false, diff --git a/ts/components/CompositionArea.tsx b/ts/components/CompositionArea.tsx index 3b1fe3433e46..85e3b8ab11ad 100644 --- a/ts/components/CompositionArea.tsx +++ b/ts/components/CompositionArea.tsx @@ -42,6 +42,7 @@ import { AudioCapture } from './conversation/AudioCapture'; import { CompositionUpload } from './CompositionUpload'; import type { ConversationType, + PushPanelForConversationActionType, ShowConversationType, } from '../state/ducks/conversations'; import type { EmojiPickDataType } from './emoji/EmojiPicker'; @@ -61,6 +62,7 @@ import { MediaEditor } from './MediaEditor'; import { isImageTypeSupported } from '../util/GoogleChrome'; import * as KeyboardLayout from '../services/keyboardLayout'; import { usePrevious } from '../hooks/usePrevious'; +import { PanelType } from '../types/Panels'; export type OwnProps = Readonly<{ acceptedMessageRequest?: boolean; @@ -162,15 +164,15 @@ export type Props = Pick< | 'blessedPacks' | 'recentStickers' | 'clearInstalledStickerPack' - | 'onClickAddPack' | 'clearShowIntroduction' | 'showPickerHint' | 'clearShowPickerHint' > & MessageRequestActionsProps & Pick & - Pick & - OwnProps; + Pick & { + pushPanelForConversation: PushPanelForConversationActionType; + } & OwnProps; export function CompositionArea({ // Base props @@ -182,6 +184,7 @@ export function CompositionArea({ isDisabled, isSignalConversation, messageCompositionId, + pushPanelForConversation, processAttachments, removeAttachment, sendMultiMediaMessage, @@ -232,7 +235,6 @@ export function CompositionArea({ blessedPacks, recentStickers, clearInstalledStickerPack, - onClickAddPack, sendStickerMessage, clearShowIntroduction, showPickerHint, @@ -459,7 +461,11 @@ export function CompositionArea({ blessedPacks={blessedPacks} recentStickers={recentStickers} clearInstalledStickerPack={clearInstalledStickerPack} - onClickAddPack={onClickAddPack} + onClickAddPack={() => + pushPanelForConversation(conversationId, { + type: PanelType.StickerManager, + }) + } onPickSticker={(packId, stickerId) => sendStickerMessage(conversationId, { packId, stickerId }) } diff --git a/ts/components/StoryViewsNRepliesModal.tsx b/ts/components/StoryViewsNRepliesModal.tsx index d562212b24fd..f3697a6d6994 100644 --- a/ts/components/StoryViewsNRepliesModal.tsx +++ b/ts/components/StoryViewsNRepliesModal.tsx @@ -56,16 +56,15 @@ const MESSAGE_DEFAULT_PROPS = { markAttachmentAsCorrupted: shouldNeverBeCalled, markViewed: shouldNeverBeCalled, messageExpanded: shouldNeverBeCalled, - // Called when clicking mention, but shouldn't do anything. - showConversation: noop, openGiftBadge: shouldNeverBeCalled, openLink: shouldNeverBeCalled, previews: [], + pushPanelForConversation: shouldNeverBeCalled, renderAudioAttachment: () =>
, saveAttachment: shouldNeverBeCalled, scrollToQuotedMessage: shouldNeverBeCalled, - showContactDetail: shouldNeverBeCalled, showContactModal: shouldNeverBeCalled, + showConversation: noop, showExpiredIncomingTapToViewToast: shouldNeverBeCalled, showExpiredOutgoingTapToViewToast: shouldNeverBeCalled, showLightbox: shouldNeverBeCalled, diff --git a/ts/components/conversation/ConversationHeader.stories.tsx b/ts/components/conversation/ConversationHeader.stories.tsx index 21aa6ed7902b..7fd8bce8e808 100644 --- a/ts/components/conversation/ConversationHeader.stories.tsx +++ b/ts/components/conversation/ConversationHeader.stories.tsx @@ -49,12 +49,12 @@ const commonProps = { ), onShowAllMedia: action('onShowAllMedia'), - onShowGroupMembers: action('onShowGroupMembers'), onGoBack: action('onGoBack'), onArchive: action('onArchive'), onMarkUnread: action('onMarkUnread'), onMoveToInbox: action('onMoveToInbox'), + pushPanelForConversation: action('pushPanelForConversation'), setMuteExpiration: action('onSetMuteNotifications'), setPinned: action('setPinned'), viewUserStories: action('viewUserStories'), diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index 7b18df408baf..c8d510245e8c 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -18,7 +18,10 @@ import { Avatar, AvatarSize } from '../Avatar'; import { InContactsIcon } from '../InContactsIcon'; import type { LocalizerType, ThemeType } from '../../types/Util'; -import type { ConversationType } from '../../state/ducks/conversations'; +import type { + ConversationType, + PushPanelForConversationActionType, +} from '../../state/ducks/conversations'; import type { BadgeType } from '../../badges/types'; import type { HasStories } from '../../types/Stories'; import type { ViewUserStoriesActionCreatorType } from '../../state/ducks/stories'; @@ -34,6 +37,7 @@ import { useStartCallShortcuts, useKeyboardShortcuts, } from '../../hooks/useKeyboardShortcuts'; +import { PanelType } from '../../types/Panels'; export enum OutgoingCallButtonStyle { None, @@ -90,7 +94,7 @@ export type PropsActionsType = { onSearchInConversation: () => void; onShowAllMedia: () => void; onShowConversationDetails: () => void; - onShowGroupMembers: () => void; + pushPanelForConversation: PushPanelForConversationActionType; setDisappearingMessages: ( conversationId: string, seconds: DurationInSeconds @@ -349,7 +353,7 @@ export class ConversationHeader extends React.Component { onMoveToInbox, onShowAllMedia, onShowConversationDetails, - onShowGroupMembers, + pushPanelForConversation, setDisappearingMessages, setMuteExpiration, setPinned, @@ -478,7 +482,11 @@ export class ConversationHeader extends React.Component { ) : null} {isGroup && !hasGV2AdminEnabled ? ( - + + pushPanelForConversation(id, { type: PanelType.GroupV1Members }) + } + > {i18n('showMembers')} ) : null} diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 3f219f016bc0..fec37b860770 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -14,6 +14,7 @@ import type { ConversationType, ConversationTypeType, InteractionModeType, + PushPanelForConversationActionType, SaveAttachmentActionCreatorType, ShowConversationType, } from '../../state/ducks/conversations'; @@ -89,6 +90,7 @@ import { PaymentEventKind } from '../../types/Payment'; import type { AnyPaymentEvent } from '../../types/Payment'; import { Emojify } from './Emojify'; import { getPaymentEventDescription } from '../../messages/helpers'; +import { PanelType } from '../../types/Panels'; const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 10; const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18; @@ -302,13 +304,7 @@ export type PropsActions = { startConversation: (e164: string, uuid: UUIDStringType) => void; showConversation: ShowConversationType; openGiftBadge: (messageId: string) => void; - showContactDetail: (options: { - contact: EmbeddedContactType; - signalAccount?: { - phoneNumber: string; - uuid: UUIDStringType; - }; - }) => void; + pushPanelForConversation: PushPanelForConversationActionType; showContactModal: (contactId: string, conversationId?: string) => void; kickOffAttachmentDownload: (options: { @@ -1566,10 +1562,11 @@ export class Message extends React.PureComponent { public renderEmbeddedContact(): JSX.Element | null { const { contact, + conversationId, conversationType, direction, i18n, - showContactDetail, + pushPanelForConversation, text, } = this.props; if (!contact) { @@ -1601,9 +1598,12 @@ export class Message extends React.PureComponent { } : undefined; - showContactDetail({ - contact, - signalAccount, + pushPanelForConversation(conversationId, { + type: PanelType.ContactDetails, + args: { + contact, + signalAccount, + }, }); }} withContentAbove={withContentAbove} @@ -2238,6 +2238,7 @@ export class Message extends React.PureComponent { const { attachments, contact, + conversationId, showLightboxForViewOnceMedia, direction, giftBadge, @@ -2247,7 +2248,7 @@ export class Message extends React.PureComponent { kickOffAttachmentDownload, startConversation, openGiftBadge, - showContactDetail, + pushPanelForConversation, showLightbox, showExpiredIncomingTapToViewToast, showExpiredOutgoingTapToViewToast, @@ -2374,7 +2375,13 @@ export class Message extends React.PureComponent { uuid: contact.uuid, } : undefined; - showContactDetail({ contact, signalAccount }); + pushPanelForConversation(conversationId, { + type: PanelType.ContactDetails, + args: { + contact, + signalAccount, + }, + }); event.preventDefault(); event.stopPropagation(); diff --git a/ts/components/conversation/MessageDetail.stories.tsx b/ts/components/conversation/MessageDetail.stories.tsx index 65cd944de8f8..62599ca09edb 100644 --- a/ts/components/conversation/MessageDetail.stories.tsx +++ b/ts/components/conversation/MessageDetail.stories.tsx @@ -83,7 +83,7 @@ const createProps = (overrideProps: Partial = {}): Props => ({ openLink: action('openLink'), renderAudioAttachment: () =>
*AudioAttachment*
, saveAttachment: action('saveAttachment'), - showContactDetail: action('showContactDetail'), + pushPanelForConversation: action('pushPanelForConversation'), showContactModal: action('showContactModal'), showExpiredIncomingTapToViewToast: action( 'showExpiredIncomingTapToViewToast' diff --git a/ts/components/conversation/MessageDetail.tsx b/ts/components/conversation/MessageDetail.tsx index 74205c107c95..4bd714075c73 100644 --- a/ts/components/conversation/MessageDetail.tsx +++ b/ts/components/conversation/MessageDetail.tsx @@ -84,7 +84,6 @@ export type PropsBackboneActions = Pick< | 'openGiftBadge' | 'openLink' | 'renderAudioAttachment' - | 'showContactDetail' | 'showExpiredIncomingTapToViewToast' | 'showExpiredOutgoingTapToViewToast' | 'startConversation' @@ -95,6 +94,7 @@ export type PropsReduxActions = Pick< | 'checkForAccount' | 'clearSelectedMessage' | 'doubleCheckMissingQuoteReference' + | 'pushPanelForConversation' | 'saveAttachment' | 'showContactModal' | 'showConversation' @@ -292,9 +292,9 @@ export class MessageDetail extends React.Component { markViewed, openGiftBadge, openLink, + pushPanelForConversation, renderAudioAttachment, saveAttachment, - showContactDetail, showContactModal, showConversation, showExpiredIncomingTapToViewToast, @@ -339,6 +339,7 @@ export class MessageDetail extends React.Component { showConversation={showConversation} openGiftBadge={openGiftBadge} openLink={openLink} + pushPanelForConversation={pushPanelForConversation} renderAudioAttachment={renderAudioAttachment} saveAttachment={saveAttachment} shouldCollapseAbove={false} @@ -347,7 +348,6 @@ export class MessageDetail extends React.Component { scrollToQuotedMessage={() => { log.warn('MessageDetail: scrollToQuotedMessage called!'); }} - showContactDetail={showContactDetail} showContactModal={showContactModal} showExpiredIncomingTapToViewToast={ showExpiredIncomingTapToViewToast diff --git a/ts/components/conversation/Quote.stories.tsx b/ts/components/conversation/Quote.stories.tsx index 4e39c4d82c3a..f2ffecf66bb3 100644 --- a/ts/components/conversation/Quote.stories.tsx +++ b/ts/components/conversation/Quote.stories.tsx @@ -130,7 +130,7 @@ const defaultMessageProps: TimelineMessagesProps = { shouldCollapseAbove: false, shouldCollapseBelow: false, shouldHideMetadata: false, - showContactDetail: action('default--showContactDetail'), + pushPanelForConversation: action('default--pushPanelForConversation'), showContactModal: action('default--showContactModal'), showExpiredIncomingTapToViewToast: action( 'showExpiredIncomingTapToViewToast' diff --git a/ts/components/conversation/Timeline.stories.tsx b/ts/components/conversation/Timeline.stories.tsx index 5fb4542882e3..427f65fcfeee 100644 --- a/ts/components/conversation/Timeline.stories.tsx +++ b/ts/components/conversation/Timeline.stories.tsx @@ -283,7 +283,7 @@ const actions = () => ({ deleteMessageForEveryone: action('deleteMessageForEveryone'), showMessageDetail: action('showMessageDetail'), saveAttachment: action('saveAttachment'), - showContactDetail: action('showContactDetail'), + pushPanelForConversation: action('pushPanelForConversation'), showContactModal: action('showContactModal'), showConversation: action('showConversation'), kickOffAttachmentDownload: action('kickOffAttachmentDownload'), diff --git a/ts/components/conversation/Timeline.tsx b/ts/components/conversation/Timeline.tsx index 732035fcb6ef..448490e42cfe 100644 --- a/ts/components/conversation/Timeline.tsx +++ b/ts/components/conversation/Timeline.tsx @@ -248,7 +248,6 @@ const getActions = createSelector( 'showMessageDetail', 'openGiftBadge', 'setQuoteByMessageId', - 'showContactDetail', 'showContactModal', 'kickOffAttachmentDownload', 'markAttachmentAsCorrupted', @@ -257,6 +256,7 @@ const getActions = createSelector( 'showLightbox', 'showLightboxForViewOnceMedia', 'openLink', + 'pushPanelForConversation', 'scrollToQuotedMessage', 'showExpiredIncomingTapToViewToast', 'showExpiredOutgoingTapToViewToast', diff --git a/ts/components/conversation/TimelineItem.stories.tsx b/ts/components/conversation/TimelineItem.stories.tsx index 37d636b6b2ef..cb2997451d06 100644 --- a/ts/components/conversation/TimelineItem.stories.tsx +++ b/ts/components/conversation/TimelineItem.stories.tsx @@ -81,7 +81,7 @@ const getDefaultProps = () => ({ showConversation: action('showConversation'), openGiftBadge: action('openGiftBadge'), saveAttachment: action('saveAttachment'), - showContactDetail: action('showContactDetail'), + pushPanelForConversation: action('pushPanelForConversation'), showContactModal: action('showContactModal'), showLightbox: action('showLightbox'), toggleForwardMessageModal: action('toggleForwardMessageModal'), diff --git a/ts/components/conversation/TimelineMessage.stories.tsx b/ts/components/conversation/TimelineMessage.stories.tsx index 9519b2273372..6b714f89d9ce 100644 --- a/ts/components/conversation/TimelineMessage.stories.tsx +++ b/ts/components/conversation/TimelineMessage.stories.tsx @@ -308,7 +308,7 @@ const createProps = (overrideProps: Partial = {}): Props => ({ shouldHideMetadata: isBoolean(overrideProps.shouldHideMetadata) ? overrideProps.shouldHideMetadata : false, - showContactDetail: action('showContactDetail'), + pushPanelForConversation: action('pushPanelForConversation'), showContactModal: action('showContactModal'), showExpiredIncomingTapToViewToast: action( 'showExpiredIncomingTapToViewToast' diff --git a/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx b/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx index 76a4d3bcecad..7f8759e81ca7 100644 --- a/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx +++ b/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx @@ -81,13 +81,7 @@ const createProps = ( showAllMedia: action('showAllMedia'), showContactModal: action('showContactModal'), pushPanelForConversation: action('pushPanelForConversation'), - showGroupLinkManagement: action('showGroupLinkManagement'), - showGroupV2Permissions: action('showGroupV2Permissions'), - showConversationNotificationsSettings: action( - 'showConversationNotificationsSettings' - ), showConversation: action('showConversation'), - showPendingInvites: action('showPendingInvites'), showLightboxWithMedia: action('showLightboxWithMedia'), updateGroupAttributes: async () => { action('updateGroupAttributes')(); diff --git a/ts/components/conversation/conversation-details/ConversationDetails.tsx b/ts/components/conversation/conversation-details/ConversationDetails.tsx index bf883eec13ec..6b202f596f0e 100644 --- a/ts/components/conversation/conversation-details/ConversationDetails.tsx +++ b/ts/components/conversation/conversation-details/ConversationDetails.tsx @@ -82,10 +82,6 @@ export type StateProps = { pendingApprovalMemberships: ReadonlyArray; pendingMemberships: ReadonlyArray; showAllMedia: () => void; - showGroupLinkManagement: () => void; - showGroupV2Permissions: () => void; - showPendingInvites: () => void; - showConversationNotificationsSettings: () => void; updateGroupAttributes: ( _: Readonly<{ avatar?: undefined | Uint8Array; @@ -161,12 +157,8 @@ export function ConversationDetails({ setMuteExpiration, showAllMedia, showContactModal, - showConversationNotificationsSettings, showConversation, - showGroupLinkManagement, - showGroupV2Permissions, showLightboxWithMedia, - showPendingInvites, theme, toggleSafetyNumberModal, toggleAddUserToAnotherGroupModal, @@ -451,7 +443,11 @@ export function ConversationDetails({ /> } label={i18n('ConversationDetails--notifications')} - onClick={showConversationNotificationsSettings} + onClick={() => + pushPanelForConversation(conversation.id, { + type: PanelType.NotificationSettings, + }) + } right={ conversation.muteExpiresAt ? getMutedUntilText(conversation.muteExpiresAt, i18n) @@ -503,7 +499,11 @@ export function ConversationDetails({ /> } label={i18n('ConversationDetails--group-link')} - onClick={showGroupLinkManagement} + onClick={() => + pushPanelForConversation(conversation.id, { + type: PanelType.GroupLinkManagement, + }) + } right={hasGroupLink ? i18n('on') : i18n('off')} /> ) : null} @@ -515,7 +515,11 @@ export function ConversationDetails({ /> } label={i18n('ConversationDetails--requests-and-invites')} - onClick={showPendingInvites} + onClick={() => + pushPanelForConversation(conversation.id, { + type: PanelType.GroupInvites, + }) + } right={invitesCount} /> {isAdmin ? ( @@ -527,7 +531,11 @@ export function ConversationDetails({ /> } label={i18n('permissions')} - onClick={showGroupV2Permissions} + onClick={() => + pushPanelForConversation(conversation.id, { + type: PanelType.GroupPermissions, + }) + } /> ) : null} diff --git a/ts/signal.ts b/ts/signal.ts index d647b19909c7..443c03b49375 100644 --- a/ts/signal.ts +++ b/ts/signal.ts @@ -26,14 +26,9 @@ import { DisappearingTimeDialog } from './components/DisappearingTimeDialog'; // State import { createConversationDetails } from './state/roots/createConversationDetails'; import { createApp } from './state/roots/createApp'; -import { createGroupLinkManagement } from './state/roots/createGroupLinkManagement'; import { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal'; import { createMessageDetail } from './state/roots/createMessageDetail'; -import { createConversationNotificationsSettings } from './state/roots/createConversationNotificationsSettings'; -import { createGroupV2Permissions } from './state/roots/createGroupV2Permissions'; -import { createPendingInvites } from './state/roots/createPendingInvites'; import { createSafetyNumberViewer } from './state/roots/createSafetyNumberViewer'; -import { createStickerManager } from './state/roots/createStickerManager'; import { createShortcutGuideModal } from './state/roots/createShortcutGuideModal'; import { createStore } from './state/createStore'; @@ -401,15 +396,10 @@ export const setup = (options: { const Roots = { createApp, createConversationDetails, - createGroupLinkManagement, createGroupV2JoinModal, - createGroupV2Permissions, createMessageDetail, - createConversationNotificationsSettings, - createPendingInvites, createSafetyNumberViewer, createShortcutGuideModal, - createStickerManager, }; const Ducks = { diff --git a/ts/state/ducks/composer.ts b/ts/state/ducks/composer.ts index c239398081ed..08eaf274cf4f 100644 --- a/ts/state/ducks/composer.ts +++ b/ts/state/ducks/composer.ts @@ -15,6 +15,7 @@ import type { AttachmentDraftType, InMemoryAttachmentDraftType, } from '../../types/Attachment'; +import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions'; import type { DraftBodyRangesType, ReplacementValuesType, @@ -66,6 +67,7 @@ import { writeDraftAttachment } from '../../util/writeDraftAttachment'; import { getMessageById } from '../../messages/getMessageById'; import { canReply } from '../selectors/message'; import { getConversationSelector } from '../selectors/conversations'; +import { useBoundActions } from '../../hooks/useBoundActions'; // State @@ -153,6 +155,10 @@ export const actions = { setQuotedMessage, }; +export const useComposerActions = (): BoundActionCreatorsMapObject< + typeof actions +> => useBoundActions(actions); + function sendMultiMediaMessage( conversationId: string, options: { diff --git a/ts/state/roots/createConversationNotificationsSettings.tsx b/ts/state/roots/createConversationNotificationsSettings.tsx deleted file mode 100644 index 7a9da3a8555c..000000000000 --- a/ts/state/roots/createConversationNotificationsSettings.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import * as React from 'react'; -import { Provider } from 'react-redux'; - -import type { Store } from 'redux'; - -import type { OwnProps } from '../smart/ConversationNotificationsSettings'; -import { SmartConversationNotificationsSettings } from '../smart/ConversationNotificationsSettings'; - -export const createConversationNotificationsSettings = ( - store: Store, - props: OwnProps -): React.ReactElement => ( - - - -); diff --git a/ts/state/roots/createGroupLinkManagement.tsx b/ts/state/roots/createGroupLinkManagement.tsx deleted file mode 100644 index a59be7e46429..000000000000 --- a/ts/state/roots/createGroupLinkManagement.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import React from 'react'; -import { Provider } from 'react-redux'; - -import type { Store } from 'redux'; - -import type { SmartGroupLinkManagementProps } from '../smart/GroupLinkManagement'; -import { SmartGroupLinkManagement } from '../smart/GroupLinkManagement'; - -export const createGroupLinkManagement = ( - store: Store, - props: SmartGroupLinkManagementProps -): React.ReactElement => ( - - - -); diff --git a/ts/state/roots/createGroupV2Permissions.tsx b/ts/state/roots/createGroupV2Permissions.tsx deleted file mode 100644 index 771e71a4c231..000000000000 --- a/ts/state/roots/createGroupV2Permissions.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import React from 'react'; -import { Provider } from 'react-redux'; - -import type { Store } from 'redux'; - -import type { SmartGroupV2PermissionsProps } from '../smart/GroupV2Permissions'; -import { SmartGroupV2Permissions } from '../smart/GroupV2Permissions'; - -export const createGroupV2Permissions = ( - store: Store, - props: SmartGroupV2PermissionsProps -): React.ReactElement => ( - - - -); diff --git a/ts/state/roots/createPendingInvites.tsx b/ts/state/roots/createPendingInvites.tsx deleted file mode 100644 index ba7b07a9ee93..000000000000 --- a/ts/state/roots/createPendingInvites.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import React from 'react'; -import { Provider } from 'react-redux'; - -import type { Store } from 'redux'; - -import type { SmartPendingInvitesProps } from '../smart/PendingInvites'; -import { SmartPendingInvites } from '../smart/PendingInvites'; - -export const createPendingInvites = ( - store: Store, - props: SmartPendingInvitesProps -): React.ReactElement => ( - - - -); diff --git a/ts/state/roots/createStickerManager.tsx b/ts/state/roots/createStickerManager.tsx deleted file mode 100644 index 8b85f3bf27b7..000000000000 --- a/ts/state/roots/createStickerManager.tsx +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import React from 'react'; -import { Provider } from 'react-redux'; - -import type { Store } from 'redux'; - -import { SmartStickerManager } from '../smart/StickerManager'; - -export const createStickerManager = (store: Store): React.ReactElement => ( - - - -); diff --git a/ts/state/smart/ConversationDetails.tsx b/ts/state/smart/ConversationDetails.tsx index 89d61df75d75..e4e955b1a6ca 100644 --- a/ts/state/smart/ConversationDetails.tsx +++ b/ts/state/smart/ConversationDetails.tsx @@ -38,10 +38,6 @@ export type SmartConversationDetailsProps = { addMembers: (conversationIds: ReadonlyArray) => Promise; conversationId: string; showAllMedia: () => void; - showGroupLinkManagement: () => void; - showGroupV2Permissions: () => void; - showConversationNotificationsSettings: () => void; - showPendingInvites: () => void; updateGroupAttributes: ( _: Readonly<{ avatar?: undefined | Uint8Array; diff --git a/ts/state/smart/ConversationHeader.tsx b/ts/state/smart/ConversationHeader.tsx index 5ac0ed7b709e..49b178c4d2de 100644 --- a/ts/state/smart/ConversationHeader.tsx +++ b/ts/state/smart/ConversationHeader.tsx @@ -37,7 +37,6 @@ export type OwnProps = { onSearchInConversation: () => void; onShowAllMedia: () => void; onShowConversationDetails: () => void; - onShowGroupMembers: () => void; }; const getOutgoingCallButtonStyle = ( diff --git a/ts/state/smart/ConversationView.tsx b/ts/state/smart/ConversationView.tsx index 8ac6665d26be..69fdbfd51395 100644 --- a/ts/state/smart/ConversationView.tsx +++ b/ts/state/smart/ConversationView.tsx @@ -1,21 +1,31 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import type { CompositionAreaPropsType } from './CompositionArea'; import type { OwnProps as ConversationHeaderPropsType } from './ConversationHeader'; import type { StateType } from '../reducer'; +import type { ReactPanelRenderType } from '../../types/Panels'; import type { TimelinePropsType } from './Timeline'; import * as log from '../../logging/log'; +import { ContactDetail } from '../../components/conversation/ContactDetail'; import { ConversationView } from '../../components/conversation/ConversationView'; import { PanelType } from '../../types/Panels'; import { SmartChatColorPicker } from './ChatColorPicker'; import { SmartCompositionArea } from './CompositionArea'; +import { SmartConversationNotificationsSettings } from './ConversationNotificationsSettings'; import { SmartConversationHeader } from './ConversationHeader'; +import { SmartGroupLinkManagement } from './GroupLinkManagement'; +import { SmartGroupV2Permissions } from './GroupV2Permissions'; +import { SmartGV1Members } from './GV1Members'; +import { SmartPendingInvites } from './PendingInvites'; +import { SmartStickerManager } from './StickerManager'; import { SmartTimeline } from './Timeline'; +import { getIntl } from '../selectors/user'; import { getTopPanelRenderableByReact } from '../selectors/conversations'; -import { mapDispatchToProps } from '../actions'; +import { startConversation } from '../../util/startConversation'; +import { useComposerActions } from '../ducks/composer'; export type PropsType = { conversationId: string; @@ -24,7 +34,6 @@ export type PropsType = { | 'id' | 'onCancelJoinRequest' | 'onClearAttachments' - | 'onClickAddPack' | 'onCloseLinkPreview' | 'onEditorStateChange' | 'onSelectMediaQuality' @@ -34,46 +43,122 @@ export type PropsType = { timelineProps: TimelinePropsType; }; -const mapStateToProps = (state: StateType, props: PropsType) => { - const { - compositionAreaProps, - conversationHeaderProps, - conversationId, - timelineProps, - } = props; +export function SmartConversationView({ + compositionAreaProps, + conversationHeaderProps, + conversationId, + timelineProps, +}: PropsType): JSX.Element { + const topPanel = useSelector( + getTopPanelRenderableByReact + ); - const topPanel = getTopPanelRenderableByReact(state); + const { processAttachments } = useComposerActions(); + const i18n = useSelector(getIntl); - return { - conversationId, - renderCompositionArea: () => ( - - ), - renderConversationHeader: () => ( - - ), - renderTimeline: () => , - renderPanel: () => { - if (!topPanel) { - return; - } + return ( + ( + + )} + renderConversationHeader={() => ( + + )} + renderTimeline={() => } + renderPanel={() => { + if (!topPanel) { + return; + } - if (topPanel.type === PanelType.ChatColorEditor) { - return ( -
- -
- ); - } + if (topPanel.type === PanelType.ChatColorEditor) { + return ( +
+ +
+ ); + } - const unknownPanelType: never = topPanel.type; - log.warn(`renderPanel: Got unexpected panel type ${unknownPanelType}`); + if (topPanel.type === PanelType.ContactDetails) { + const { contact, signalAccount } = topPanel.args; - return undefined; - }, - }; -}; + return ( +
+ { + if (signalAccount) { + startConversation( + signalAccount.phoneNumber, + signalAccount.uuid + ); + } + }} + /> +
+ ); + } -const smart = connect(mapStateToProps, mapDispatchToProps); + if (topPanel.type === PanelType.GroupInvites) { + return ( +
+ +
+ ); + } -export const SmartConversationView = smart(ConversationView); + if (topPanel.type === PanelType.GroupLinkManagement) { + return ( +
+ +
+ ); + } + + if (topPanel.type === PanelType.GroupPermissions) { + return ( +
+ +
+ ); + } + + if (topPanel.type === PanelType.GroupV1Members) { + return ( +
+ +
+ ); + } + + if (topPanel.type === PanelType.NotificationSettings) { + return ( +
+ +
+ ); + } + + if (topPanel.type === PanelType.StickerManager) { + return ( +
+ +
+ ); + } + + log.warn('renderPanel: Got unexpected panel', topPanel); + + return undefined; + }} + /> + ); +} diff --git a/ts/state/smart/GV1Members.tsx b/ts/state/smart/GV1Members.tsx new file mode 100644 index 000000000000..81c774c34c4b --- /dev/null +++ b/ts/state/smart/GV1Members.tsx @@ -0,0 +1,54 @@ +// Copyright 2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import React from 'react'; +import { useSelector } from 'react-redux'; + +import { ConversationDetailsMembershipList } from '../../components/conversation/conversation-details/ConversationDetailsMembershipList'; +import { assertDev } from '../../util/assert'; +import { getGroupMemberships } from '../../util/getGroupMemberships'; +import { + getConversationByIdSelector, + getConversationByUuidSelector, +} from '../selectors/conversations'; +import { getIntl, getTheme } from '../selectors/user'; +import { getPreferredBadgeSelector } from '../selectors/badges'; +import { useGlobalModalActions } from '../ducks/globalModals'; + +export type PropsType = { + conversationId: string; +}; + +export function SmartGV1Members({ conversationId }: PropsType): JSX.Element { + const getPreferredBadge = useSelector(getPreferredBadgeSelector); + const i18n = useSelector(getIntl); + const theme = useSelector(getTheme); + const { showContactModal } = useGlobalModalActions(); + + const conversationSelector = useSelector(getConversationByIdSelector); + const conversationByUuidSelector = useSelector(getConversationByUuidSelector); + + const conversation = conversationSelector(conversationId); + assertDev( + conversation, + ' expected a conversation to be found' + ); + + const { memberships } = getGroupMemberships( + conversation, + conversationByUuidSelector + ); + + return ( + + ); +} diff --git a/ts/state/smart/MessageDetail.tsx b/ts/state/smart/MessageDetail.tsx index 30ec9a252bb7..294e00bde8bb 100644 --- a/ts/state/smart/MessageDetail.tsx +++ b/ts/state/smart/MessageDetail.tsx @@ -44,7 +44,6 @@ const mapStateToProps = ( markAttachmentAsCorrupted, openGiftBadge, openLink, - showContactDetail, showExpiredIncomingTapToViewToast, showExpiredOutgoingTapToViewToast, startConversation, @@ -79,7 +78,6 @@ const mapStateToProps = ( openGiftBadge, openLink, renderAudioAttachment, - showContactDetail, showExpiredIncomingTapToViewToast, showExpiredOutgoingTapToViewToast, startConversation, diff --git a/ts/state/smart/Timeline.tsx b/ts/state/smart/Timeline.tsx index 1e31a381eb87..5cc3a53f1c5f 100644 --- a/ts/state/smart/Timeline.tsx +++ b/ts/state/smart/Timeline.tsx @@ -80,7 +80,6 @@ export type TimelinePropsType = ExternalProps & | 'retryDeleteForEveryone' | 'retrySend' | 'scrollToQuotedMessage' - | 'showContactDetail' | 'showExpiredIncomingTapToViewToast' | 'showExpiredOutgoingTapToViewToast' | 'showMessageDetail' diff --git a/ts/types/Panels.ts b/ts/types/Panels.ts index ad0e2a8019b2..e0733edfc45b 100644 --- a/ts/types/Panels.ts +++ b/ts/types/Panels.ts @@ -18,10 +18,8 @@ export enum PanelType { StickerManager = 'StickerManager', } -export type ReactPanelRenderType = { type: PanelType.ChatColorEditor }; - -export type BackbonePanelRenderType = - | { type: PanelType.AllMedia } +export type ReactPanelRenderType = + | { type: PanelType.ChatColorEditor } | { type: PanelType.ContactDetails; args: { @@ -32,15 +30,18 @@ export type BackbonePanelRenderType = }; }; } - | { type: PanelType.ConversationDetails } | { type: PanelType.GroupInvites } | { type: PanelType.GroupLinkManagement } | { type: PanelType.GroupPermissions } | { type: PanelType.GroupV1Members } - | { type: PanelType.MessageDetails; args: { messageId: string } } | { type: PanelType.NotificationSettings } | { type: PanelType.StickerManager }; +export type BackbonePanelRenderType = + | { type: PanelType.AllMedia } + | { type: PanelType.ConversationDetails } + | { type: PanelType.MessageDetails; args: { messageId: string } }; + export type PanelRenderType = ReactPanelRenderType | BackbonePanelRenderType; export function isPanelHandledByReact( @@ -50,5 +51,14 @@ export function isPanelHandledByReact( return false; } - return panel.type === PanelType.ChatColorEditor; + return ( + panel.type === PanelType.ChatColorEditor || + panel.type === PanelType.ContactDetails || + panel.type === PanelType.GroupInvites || + panel.type === PanelType.GroupLinkManagement || + panel.type === PanelType.GroupPermissions || + panel.type === PanelType.GroupV1Members || + panel.type === PanelType.NotificationSettings || + panel.type === PanelType.StickerManager + ); } diff --git a/ts/util/getConversationTitleForPanelType.ts b/ts/util/getConversationTitleForPanelType.ts index cd5b7335ccc5..ad1717f72084 100644 --- a/ts/util/getConversationTitleForPanelType.ts +++ b/ts/util/getConversationTitleForPanelType.ts @@ -21,6 +21,10 @@ export function getConversationTitleForPanelType( return i18n('ChatColorPicker__menu-title'); } + if (panelType === PanelType.ContactDetails) { + return ''; + } + if (panelType === PanelType.ConversationDetails) { return ''; } @@ -41,11 +45,13 @@ export function getConversationTitleForPanelType( return i18n('ConversationDetails--notifications'); } + if (panelType === PanelType.StickerManager) { + return ''; + } + if ( - panelType === PanelType.ContactDetails || panelType === PanelType.GroupV1Members || - panelType === PanelType.MessageDetails || - panelType === PanelType.StickerManager + panelType === PanelType.MessageDetails ) { return undefined; } diff --git a/ts/views/conversation_view.tsx b/ts/views/conversation_view.tsx index 9c1b198322e3..55a3c4888e46 100644 --- a/ts/views/conversation_view.tsx +++ b/ts/views/conversation_view.tsx @@ -19,14 +19,10 @@ import { strictAssert } from '../util/assert'; import { enqueueReactionForSend } from '../reactions/enqueueReactionForSend'; import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions'; import { isGroup } from '../util/whatTypeOfConversation'; -import { getPreferredBadgeSelector } from '../state/selectors/badges'; import { isIncoming } from '../state/selectors/message'; import { getActiveCallState } from '../state/selectors/calling'; -import { getTheme } from '../state/selectors/user'; import { ReactWrapperView } from './ReactWrapperView'; -import { ConversationDetailsMembershipList } from '../components/conversation/conversation-details/ConversationDetailsMembershipList'; import * as log from '../logging/log'; -import type { EmbeddedContactType } from '../types/EmbeddedContact'; import { createConversationView } from '../state/roots/createConversationView'; import { ToastConversationArchived } from '../components/ToastConversationArchived'; import { ToastConversationMarkedUnread } from '../components/ToastConversationMarkedUnread'; @@ -44,7 +40,6 @@ import { showToast } from '../util/showToast'; import { UUIDKind } from '../types/UUID'; import type { UUIDStringType } from '../types/UUID'; import { retryDeleteForEveryone } from '../util/retryDeleteForEveryone'; -import { ContactDetail } from '../components/conversation/ContactDetail'; import { MediaGallery } from '../components/conversation/media-gallery/MediaGallery'; import type { ItemClickEvent } from '../components/conversation/media-gallery/types/ItemClickEvent'; import { @@ -86,13 +81,6 @@ type MessageActionsType = { ) => unknown; retrySend: (messageId: string) => unknown; retryDeleteForEveryone: (messageId: string) => unknown; - showContactDetail: (options: { - contact: EmbeddedContactType; - signalAccount?: { - phoneNumber: string; - uuid: UUIDStringType; - }; - }) => unknown; showExpiredIncomingTapToViewToast: () => unknown; showExpiredOutgoingTapToViewToast: () => unknown; showMessageDetail: (messageId: string) => unknown; @@ -202,9 +190,6 @@ export class ConversationView extends window.Backbone.View { onShowAllMedia: () => { this.showAllMedia(); }, - onShowGroupMembers: () => { - this.showGV1Members(); - }, onGoBack: () => { window.reduxActions.conversations.popPanelForConversation( this.model.id @@ -342,7 +327,6 @@ export class ConversationView extends window.Backbone.View { const compositionAreaProps = { id: this.model.id, - onClickAddPack: () => this.showStickerManager(), onTextTooLong: () => showToast(ToastMessageBodyTooLong), onCancelJoinRequest: async () => { await window.showConfirmationDialog({ @@ -411,15 +395,6 @@ export class ConversationView extends window.Backbone.View { const showMessageDetail = (messageId: string) => { this.showMessageDetail(messageId); }; - const showContactDetail = (options: { - contact: EmbeddedContactType; - signalAccount?: { - phoneNumber: string; - uuid: UUIDStringType; - }; - }) => { - this.showContactDetail(options); - }; const kickOffAttachmentDownload = async ( options: Readonly<{ messageId: string }> ) => { @@ -474,7 +449,6 @@ export class ConversationView extends window.Backbone.View { reactToMessage, retrySend, retryDeleteForEveryone, - showContactDetail, showExpiredIncomingTapToViewToast, showExpiredOutgoingTapToViewToast, showMessageDetail, @@ -809,139 +783,6 @@ export class ConversationView extends window.Backbone.View { return view; } - showGV1Members(): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.GroupV1Members, - }); - } - - getGV1Members(): Backbone.View { - const { contactCollection, id } = this.model; - - const memberships = - contactCollection?.map((conversation: ConversationModel) => { - return { - isAdmin: false, - member: conversation.format(), - }; - }) || []; - - const reduxState = window.reduxStore.getState(); - const getPreferredBadge = getPreferredBadgeSelector(reduxState); - const theme = getTheme(reduxState); - - const view = new ReactWrapperView({ - className: 'group-member-list panel', - JSX: ( - { - window.reduxActions.globalModals.showContactModal( - contactId, - this.model.id - ); - }} - theme={theme} - /> - ), - }); - - view.render(); - - return view; - } - - showGroupLinkManagement(): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.GroupLinkManagement, - }); - } - - getGroupLinkManagement(): Backbone.View { - const view = new ReactWrapperView({ - className: 'panel', - JSX: window.Signal.State.Roots.createGroupLinkManagement( - window.reduxStore, - { - conversationId: this.model.id, - } - ), - }); - - view.render(); - - return view; - } - - showGroupV2Permissions(): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.GroupPermissions, - }); - } - - getGroupV2Permissions(): Backbone.View { - const view = new ReactWrapperView({ - className: 'panel', - JSX: window.Signal.State.Roots.createGroupV2Permissions( - window.reduxStore, - { - conversationId: this.model.id, - } - ), - }); - - view.render(); - - return view; - } - - showPendingInvites(): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.GroupInvites, - }); - } - - getPendingInvites(): Backbone.View { - const view = new ReactWrapperView({ - className: 'panel', - JSX: window.Signal.State.Roots.createPendingInvites(window.reduxStore, { - conversationId: this.model.id, - ourUuid: window.textsecure.storage.user.getCheckedUuid().toString(), - }), - }); - - view.render(); - - return view; - } - - showConversationNotificationsSettings(): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.NotificationSettings, - }); - } - - getConversationNotificationsSettings(): Backbone.View { - const view = new ReactWrapperView({ - className: 'panel', - JSX: window.Signal.State.Roots.createConversationNotificationsSettings( - window.reduxStore, - { - conversationId: this.model.id, - } - ), - }); - - view.render(); - - return view; - } - showConversationDetails(): void { window.reduxActions.conversations.pushPanelForConversation(this.model.id, { type: PanelType.ConversationDetails, @@ -970,11 +811,6 @@ export class ConversationView extends window.Backbone.View { addMembers: this.model.addMembersV2.bind(this.model), conversationId: this.model.get('id'), showAllMedia: this.showAllMedia.bind(this), - showGroupLinkManagement: this.showGroupLinkManagement.bind(this), - showGroupV2Permissions: this.showGroupV2Permissions.bind(this), - showConversationNotificationsSettings: - this.showConversationNotificationsSettings.bind(this), - showPendingInvites: this.showPendingInvites.bind(this), updateGroupAttributes: this.model.updateGroupAttributesV2.bind( this.model ), @@ -1052,78 +888,6 @@ export class ConversationView extends window.Backbone.View { return view; } - showStickerManager(): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.StickerManager, - }); - } - - getStickerManager(): Backbone.View { - const view = new ReactWrapperView({ - className: ['sticker-manager-wrapper', 'panel'].join(' '), - JSX: window.Signal.State.Roots.createStickerManager(window.reduxStore), - onClose: () => { - window.reduxActions.conversations.popPanelForConversation( - this.model.id - ); - }, - }); - - view.render(); - - return view; - } - - showContactDetail({ - contact, - signalAccount, - }: { - contact: EmbeddedContactType; - signalAccount?: { - phoneNumber: string; - uuid: UUIDStringType; - }; - }): void { - window.reduxActions.conversations.pushPanelForConversation(this.model.id, { - type: PanelType.ContactDetails, - args: { contact, signalAccount }, - }); - } - - getContactDetail({ - contact, - signalAccount, - }: { - contact: EmbeddedContactType; - signalAccount?: { - phoneNumber: string; - uuid: UUIDStringType; - }; - }): Backbone.View { - const view = new ReactWrapperView({ - className: 'contact-detail-pane panel', - JSX: ( - { - if (signalAccount) { - startConversation(signalAccount.phoneNumber, signalAccount.uuid); - } - }} - /> - ), - onClose: () => { - window.reduxActions.conversations.popPanelForConversation( - this.model.id - ); - }, - }); - - return view; - } - pushPanel(panel: PanelRenderType): void { if (isPanelHandledByReact(panel)) { return; @@ -1140,24 +904,10 @@ export class ConversationView extends window.Backbone.View { let view: Backbone.View | undefined; if (type === PanelType.AllMedia) { view = this.getAllMedia(); - } else if (panel.type === PanelType.ContactDetails) { - view = this.getContactDetail(panel.args); } else if (type === PanelType.ConversationDetails) { view = this.getConversationDetails(); - } else if (type === PanelType.GroupInvites) { - view = this.getPendingInvites(); - } else if (type === PanelType.GroupLinkManagement) { - view = this.getGroupLinkManagement(); - } else if (type === PanelType.GroupPermissions) { - view = this.getGroupV2Permissions(); - } else if (type === PanelType.GroupV1Members) { - view = this.getGV1Members(); - } else if (type === PanelType.NotificationSettings) { - view = this.getConversationNotificationsSettings(); } else if (panel.type === PanelType.MessageDetails) { view = this.getMessageDetail(panel.args); - } else if (type === PanelType.StickerManager) { - view = this.getStickerManager(); } if (!view) { diff --git a/ts/window.d.ts b/ts/window.d.ts index a0df487abd75..96ebb969ceeb 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -38,15 +38,10 @@ import type { ReduxActions } from './state/types'; import type { createStore } from './state/createStore'; import type { createApp } from './state/roots/createApp'; import type { createConversationDetails } from './state/roots/createConversationDetails'; -import type { createGroupLinkManagement } from './state/roots/createGroupLinkManagement'; import type { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal'; -import type { createGroupV2Permissions } from './state/roots/createGroupV2Permissions'; import type { createMessageDetail } from './state/roots/createMessageDetail'; -import type { createConversationNotificationsSettings } from './state/roots/createConversationNotificationsSettings'; -import type { createPendingInvites } from './state/roots/createPendingInvites'; import type { createSafetyNumberViewer } from './state/roots/createSafetyNumberViewer'; import type { createShortcutGuideModal } from './state/roots/createShortcutGuideModal'; -import type { createStickerManager } from './state/roots/createStickerManager'; import type * as appDuck from './state/ducks/app'; import type * as callingDuck from './state/ducks/calling'; import type * as conversationsDuck from './state/ducks/conversations'; @@ -167,15 +162,10 @@ export type SignalCoreType = { Roots: { createApp: typeof createApp; createConversationDetails: typeof createConversationDetails; - createGroupLinkManagement: typeof createGroupLinkManagement; createGroupV2JoinModal: typeof createGroupV2JoinModal; - createGroupV2Permissions: typeof createGroupV2Permissions; createMessageDetail: typeof createMessageDetail; - createConversationNotificationsSettings: typeof createConversationNotificationsSettings; - createPendingInvites: typeof createPendingInvites; createSafetyNumberViewer: typeof createSafetyNumberViewer; createShortcutGuideModal: typeof createShortcutGuideModal; - createStickerManager: typeof createStickerManager; }; Ducks: { app: typeof appDuck;