From d18ed40a230b6d1defb6ed320510f0b696c8f372 Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Thu, 24 Mar 2022 14:46:17 -0700 Subject: [PATCH] Don't pass full group to spoofing review dialog --- .../ContactSpoofingReviewDialog.stories.tsx | 2 +- .../ContactSpoofingReviewDialog.tsx | 2 +- .../conversation/Timeline.stories.tsx | 22 +++++++- ts/components/conversation/Timeline.tsx | 39 ++++++------- .../smart/ContactSpoofingReviewDialog.tsx | 55 +++++++++++++++++++ ts/state/smart/Timeline.tsx | 10 +++- 6 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 ts/state/smart/ContactSpoofingReviewDialog.tsx diff --git a/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx b/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx index d39aab03c2a1..a289c5fadb59 100644 --- a/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx +++ b/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx @@ -23,7 +23,7 @@ const story = storiesOf( const getCommonProps = () => ({ getPreferredBadge: () => undefined, i18n, - group: getDefaultConversation(), + groupConversationId: 'convo-id', onBlock: action('onBlock'), onBlockAndReportSpam: action('onBlockAndReportSpam'), onClose: action('onClose'), diff --git a/ts/components/conversation/ContactSpoofingReviewDialog.tsx b/ts/components/conversation/ContactSpoofingReviewDialog.tsx index a7555ba6d153..aa2d8378e8db 100644 --- a/ts/components/conversation/ContactSpoofingReviewDialog.tsx +++ b/ts/components/conversation/ContactSpoofingReviewDialog.tsx @@ -24,7 +24,7 @@ import { assert } from '../../util/assert'; import { missingCaseError } from '../../util/missingCaseError'; import { isInSystemContacts } from '../../util/isInSystemContacts'; -type PropsType = { +export type PropsType = { getPreferredBadge: PreferredBadgeSelectorType; i18n: LocalizerType; onBlock: (conversationId: string) => unknown; diff --git a/ts/components/conversation/Timeline.stories.tsx b/ts/components/conversation/Timeline.stories.tsx index 4ecc521043b8..0a214192248a 100644 --- a/ts/components/conversation/Timeline.stories.tsx +++ b/ts/components/conversation/Timeline.stories.tsx @@ -15,8 +15,10 @@ import type { PropsType } from './Timeline'; import { Timeline } from './Timeline'; import type { TimelineItemType } from './TimelineItem'; import { TimelineItem } from './TimelineItem'; +import { ContactSpoofingReviewDialog } from './ContactSpoofingReviewDialog'; import { StorybookThemeContext } from '../../../.storybook/StorybookThemeContext'; import { ConversationHero } from './ConversationHero'; +import type { PropsType as SmartContactSpoofingReviewDialogPropsType } from '../../state/smart/ContactSpoofingReviewDialog'; import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation'; import { getRandomColor } from '../../test-both/helpers/getRandomColor'; import { TypingBubble } from './TypingBubble'; @@ -453,6 +455,24 @@ const renderItem = ({ /> ); +const renderContactSpoofingReviewDialog = ( + props: SmartContactSpoofingReviewDialogPropsType +) => { + if (props.type === ContactSpoofingType.MultipleGroupMembersWithSameTitle) { + return ( + + ); + } + + return ; +}; + const getAbout = () => text('about', '👍 Free to chat'); const getTitle = () => text('name', 'Cayce Bollard'); const getName = () => text('name', 'Cayce Bollard'); @@ -502,7 +522,6 @@ const renderTypingBubble = () => ( ); const useProps = (overrideProps: Partial = {}): PropsType => ({ - conversation: overrideProps.conversation || getDefaultConversation(), discardMessages: action('discardMessages'), getPreferredBadge: () => undefined, i18n, @@ -531,6 +550,7 @@ const useProps = (overrideProps: Partial = {}): PropsType => ({ renderItem, renderHeroRow, renderTypingBubble, + renderContactSpoofingReviewDialog, isSomeoneTyping: overrideProps.isSomeoneTyping || false, ...actions(), diff --git a/ts/components/conversation/Timeline.tsx b/ts/components/conversation/Timeline.tsx index 7f0334d86084..019a9a7c2155 100644 --- a/ts/components/conversation/Timeline.tsx +++ b/ts/components/conversation/Timeline.tsx @@ -29,7 +29,7 @@ import { TimelineWarning } from './TimelineWarning'; import { TimelineWarnings } from './TimelineWarnings'; import { NewlyCreatedGroupInvitedContactsDialog } from '../NewlyCreatedGroupInvitedContactsDialog'; import { ContactSpoofingType } from '../../util/contactSpoofing'; -import { ContactSpoofingReviewDialog } from './ContactSpoofingReviewDialog'; +import type { PropsType as SmartContactSpoofingReviewDialogPropsType } from '../../state/smart/ContactSpoofingReviewDialog'; import type { GroupNameCollisionsWithIdsByTitle } from '../../util/groupMemberNameCollisions'; import { hasUnacknowledgedCollisions } from '../../util/groupMemberNameCollisions'; import { TimelineFloatingHeader } from './TimelineFloatingHeader'; @@ -95,7 +95,6 @@ export type PropsDataType = { type PropsHousekeepingType = { id: string; - conversation: ConversationType; isConversationSelected: boolean; isGroupV1AndDisabled?: boolean; isIncomingMessageRequest: boolean; @@ -133,6 +132,9 @@ type PropsHousekeepingType = { updateSharedGroups: () => unknown ) => JSX.Element; renderTypingBubble: (id: string) => JSX.Element; + renderContactSpoofingReviewDialog: ( + props: SmartContactSpoofingReviewDialogPropsType + ) => JSX.Element; }; export type PropsActionsType = { @@ -764,7 +766,6 @@ export class Timeline extends React.Component< clearInvitedUuidsForNewlyCreatedGroup, closeContactSpoofingReview, contactSpoofingReview, - conversation, getPreferredBadge, getTimestampForMessage, haveNewest, @@ -786,6 +787,7 @@ export class Timeline extends React.Component< renderHeroRow, renderItem, renderTypingBubble, + renderContactSpoofingReviewDialog, reviewGroupMemberNameCollision, reviewMessageRequestNameCollision, showContactModal, @@ -1029,26 +1031,21 @@ export class Timeline extends React.Component< switch (contactSpoofingReview.type) { case ContactSpoofingType.DirectConversationWithSameTitle: - contactSpoofingReviewDialog = ( - - ); + contactSpoofingReviewDialog = renderContactSpoofingReviewDialog({ + ...commonProps, + type: ContactSpoofingType.DirectConversationWithSameTitle, + possiblyUnsafeConversation: + contactSpoofingReview.possiblyUnsafeConversation, + safeConversation: contactSpoofingReview.safeConversation, + }); break; case ContactSpoofingType.MultipleGroupMembersWithSameTitle: - contactSpoofingReviewDialog = ( - - ); + contactSpoofingReviewDialog = renderContactSpoofingReviewDialog({ + ...commonProps, + type: ContactSpoofingType.MultipleGroupMembersWithSameTitle, + groupConversationId: id, + collisionInfoByTitle: contactSpoofingReview.collisionInfoByTitle, + }); break; default: throw missingCaseError(contactSpoofingReview); diff --git a/ts/state/smart/ContactSpoofingReviewDialog.tsx b/ts/state/smart/ContactSpoofingReviewDialog.tsx new file mode 100644 index 000000000000..46ffacb61481 --- /dev/null +++ b/ts/state/smart/ContactSpoofingReviewDialog.tsx @@ -0,0 +1,55 @@ +// Copyright 2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import * as React from 'react'; +import { useSelector } from 'react-redux'; +import type { StateType } from '../reducer'; + +import type { PropsType as DownstreamPropsType } from '../../components/conversation/ContactSpoofingReviewDialog'; +import { ContactSpoofingReviewDialog } from '../../components/conversation/ContactSpoofingReviewDialog'; + +import type { ConversationType } from '../ducks/conversations'; +import type { GetConversationByIdType } from '../selectors/conversations'; +import { getConversationSelector } from '../selectors/conversations'; +import { ContactSpoofingType } from '../../util/contactSpoofing'; + +export type PropsType = Omit & + ( + | { + type: ContactSpoofingType.DirectConversationWithSameTitle; + possiblyUnsafeConversation: ConversationType; + safeConversation: ConversationType; + } + | { + type: ContactSpoofingType.MultipleGroupMembersWithSameTitle; + groupConversationId: string; + collisionInfoByTitle: Record< + string, + Array<{ + oldName?: string; + conversation: ConversationType; + }> + >; + } + ); + +export const SmartContactSpoofingReviewDialog: React.ComponentType< + PropsType +> = props => { + const { type } = props; + + const getConversation = useSelector( + getConversationSelector + ); + + if (type === ContactSpoofingType.MultipleGroupMembersWithSameTitle) { + return ( + + ); + } + + return ; +}; diff --git a/ts/state/smart/Timeline.tsx b/ts/state/smart/Timeline.tsx index 3a773e594238..526a06f18ff9 100644 --- a/ts/state/smart/Timeline.tsx +++ b/ts/state/smart/Timeline.tsx @@ -29,6 +29,8 @@ import { } from '../selectors/conversations'; import { SmartTimelineItem } from './TimelineItem'; +import { SmartContactSpoofingReviewDialog } from './ContactSpoofingReviewDialog'; +import type { PropsType as SmartContactSpoofingReviewDialogPropsType } from './ContactSpoofingReviewDialog'; import { SmartTypingBubble } from './TypingBubble'; import { SmartHeroRow } from './HeroRow'; import { renderAudioAttachment } from './renderAudioAttachment'; @@ -139,6 +141,12 @@ function renderItem({ ); } +function renderContactSpoofingReviewDialog( + props: SmartContactSpoofingReviewDialogPropsType +): JSX.Element { + return ; +} + function renderHeroRow( id: string, unblurAvatar: () => void, @@ -286,7 +294,6 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => { return { id, ...pick(conversation, ['unreadCount', 'isGroupV1AndDisabled']), - conversation, isConversationSelected: state.conversations.selectedConversationId === id, isIncomingMessageRequest: Boolean( conversation.messageRequestsEnabled && @@ -306,6 +313,7 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => { i18n: getIntl(state), theme: getTheme(state), renderItem, + renderContactSpoofingReviewDialog, renderHeroRow, renderTypingBubble, ...actions,