Moves blockAndReportSpam to redux

This commit is contained in:
Josh Perez 2022-12-06 14:03:09 -05:00 committed by GitHub
parent 92a512a16d
commit 105162dc66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 282 additions and 324 deletions

View file

@ -96,11 +96,10 @@ const useProps = (overrideProps: Partial<Props> = {}): Props => ({
clearShowPickerHint: action('clearShowPickerHint'), clearShowPickerHint: action('clearShowPickerHint'),
// Message Requests // Message Requests
conversationType: 'direct', conversationType: 'direct',
onAccept: action('onAccept'), acceptConversation: action('acceptConversation'),
onBlock: action('onBlock'), blockConversation: action('blockConversation'),
onBlockAndReportSpam: action('onBlockAndReportSpam'), blockAndReportSpam: action('blockAndReportSpam'),
onDelete: action('onDelete'), deleteConversation: action('deleteConversation'),
onUnblock: action('onUnblock'),
messageRequestsEnabled: boolean( messageRequestsEnabled: boolean(
'messageRequestsEnabled', 'messageRequestsEnabled',
overrideProps.messageRequestsEnabled || false overrideProps.messageRequestsEnabled || false

View file

@ -240,11 +240,10 @@ export function CompositionArea({
isMissingMandatoryProfileSharing, isMissingMandatoryProfileSharing,
left, left,
messageRequestsEnabled, messageRequestsEnabled,
onAccept, acceptConversation,
onBlock, blockConversation,
onBlockAndReportSpam, blockAndReportSpam,
onDelete, deleteConversation,
onUnblock,
title, title,
// GroupV1 Disabled Actions // GroupV1 Disabled Actions
isGroupV1AndDisabled, isGroupV1AndDisabled,
@ -497,14 +496,14 @@ export function CompositionArea({
) { ) {
return ( return (
<MessageRequestActions <MessageRequestActions
i18n={i18n} acceptConversation={acceptConversation}
blockAndReportSpam={blockAndReportSpam}
blockConversation={blockConversation}
conversationId={conversationId}
conversationType={conversationType} conversationType={conversationType}
deleteConversation={deleteConversation}
i18n={i18n}
isBlocked={isBlocked} isBlocked={isBlocked}
onBlock={onBlock}
onBlockAndReportSpam={onBlockAndReportSpam}
onUnblock={onUnblock}
onDelete={onDelete}
onAccept={onAccept}
title={title} title={title}
/> />
); );
@ -549,12 +548,13 @@ export function CompositionArea({
) { ) {
return ( return (
<MandatoryProfileSharingActions <MandatoryProfileSharingActions
i18n={i18n} acceptConversation={acceptConversation}
blockAndReportSpam={blockAndReportSpam}
blockConversation={blockConversation}
conversationId={conversationId}
conversationType={conversationType} conversationType={conversationType}
onBlock={onBlock} deleteConversation={deleteConversation}
onBlockAndReportSpam={onBlockAndReportSpam} i18n={i18n}
onDelete={onDelete}
onAccept={onAccept}
title={title} title={title}
/> />
); );

View file

@ -80,3 +80,10 @@ StoryVideoError.args = {
toastType: ToastType.StoryVideoError, toastType: ToastType.StoryVideoError,
}, },
}; };
export const ReportedSpamAndBlocked = Template.bind({});
ReportedSpamAndBlocked.args = {
toast: {
toastType: ToastType.ReportedSpamAndBlocked,
},
};

View file

@ -97,6 +97,14 @@ export function ToastManager({
return <ToastMessageBodyTooLong i18n={i18n} onClose={hideToast} />; return <ToastMessageBodyTooLong i18n={i18n} onClose={hideToast} />;
} }
if (toastType === ToastType.ReportedSpamAndBlocked) {
return (
<Toast onClose={hideToast}>
{i18n('MessageRequests--block-and-report-spam-success-toast')}
</Toast>
);
}
if (toastType === ToastType.StoryMuted) { if (toastType === ToastType.StoryMuted) {
return ( return (
<Toast onClose={hideToast} timeout={SHORT_TIMEOUT}> <Toast onClose={hideToast} timeout={SHORT_TIMEOUT}>

View file

@ -1,28 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import { action } from '@storybook/addon-actions';
import { ToastReportedSpamAndBlocked } from './ToastReportedSpamAndBlocked';
import { setupI18n } from '../util/setupI18n';
import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
const defaultProps = {
i18n,
onClose: action('onClose'),
};
export default {
title: 'Components/ToastReportedSpamAndBlocked',
};
export const _ToastReportedSpamAndBlocked = (): JSX.Element => (
<ToastReportedSpamAndBlocked {...defaultProps} />
);
_ToastReportedSpamAndBlocked.story = {
name: 'ToastReportedSpamAndBlocked',
};

View file

@ -1,22 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import type { LocalizerType } from '../types/Util';
import { Toast } from './Toast';
type PropsType = {
i18n: LocalizerType;
onClose: () => unknown;
};
export function ToastReportedSpamAndBlocked({
i18n,
onClose,
}: PropsType): JSX.Element {
return (
<Toast onClose={onClose}>
{i18n('MessageRequests--block-and-report-spam-success-toast')}
</Toast>
);
}

View file

@ -19,15 +19,15 @@ export default {
}; };
const getCommonProps = () => ({ const getCommonProps = () => ({
acceptConversation: action('acceptConversation'),
blockAndReportSpam: action('blockAndReportSpam'),
blockConversation: action('blockConversation'),
deleteConversation: action('deleteConversation'),
getPreferredBadge: () => undefined, getPreferredBadge: () => undefined,
i18n,
groupConversationId: 'convo-id', groupConversationId: 'convo-id',
onBlock: action('onBlock'), i18n,
onBlockAndReportSpam: action('onBlockAndReportSpam'),
onClose: action('onClose'), onClose: action('onClose'),
onDelete: action('onDelete'),
onShowContactModal: action('onShowContactModal'), onShowContactModal: action('onShowContactModal'),
onUnblock: action('onUnblock'),
removeMember: action('removeMember'), removeMember: action('removeMember'),
theme: ThemeType.light, theme: ThemeType.light,
}); });

View file

@ -25,14 +25,14 @@ import { missingCaseError } from '../../util/missingCaseError';
import { isInSystemContacts } from '../../util/isInSystemContacts'; import { isInSystemContacts } from '../../util/isInSystemContacts';
export type PropsType = { export type PropsType = {
acceptConversation: (conversationId: string) => unknown;
blockAndReportSpam: (conversationId: string) => unknown;
blockConversation: (conversationId: string) => unknown;
deleteConversation: (conversationId: string) => unknown;
getPreferredBadge: PreferredBadgeSelectorType; getPreferredBadge: PreferredBadgeSelectorType;
i18n: LocalizerType; i18n: LocalizerType;
onBlock: (conversationId: string) => unknown;
onBlockAndReportSpam: (conversationId: string) => unknown;
onClose: () => void; onClose: () => void;
onDelete: (conversationId: string) => unknown;
onShowContactModal: (contactId: string, conversationId?: string) => unknown; onShowContactModal: (contactId: string, conversationId?: string) => unknown;
onUnblock: (conversationId: string) => unknown;
removeMember: (conversationId: string) => unknown; removeMember: (conversationId: string) => unknown;
theme: ThemeType; theme: ThemeType;
} & ( } & (
@ -62,14 +62,14 @@ enum ConfirmationStateType {
export function ContactSpoofingReviewDialog(props: PropsType): JSX.Element { export function ContactSpoofingReviewDialog(props: PropsType): JSX.Element {
const { const {
acceptConversation,
blockAndReportSpam,
blockConversation,
deleteConversation,
getPreferredBadge, getPreferredBadge,
i18n, i18n,
onBlock,
onBlockAndReportSpam,
onClose, onClose,
onDelete,
onShowContactModal, onShowContactModal,
onUnblock,
removeMember, removeMember,
theme, theme,
} = props; } = props;
@ -96,21 +96,14 @@ export function ContactSpoofingReviewDialog(props: PropsType): JSX.Element {
case ConfirmationStateType.ConfirmingBlock: case ConfirmationStateType.ConfirmingBlock:
return ( return (
<MessageRequestActionsConfirmation <MessageRequestActionsConfirmation
i18n={i18n} acceptConversation={acceptConversation}
onBlock={() => { blockAndReportSpam={blockAndReportSpam}
onBlock(affectedConversation.id); blockConversation={blockConversation}
}} conversationId={affectedConversation.id}
onBlockAndReportSpam={() => {
onBlockAndReportSpam(affectedConversation.id);
}}
onUnblock={() => {
onUnblock(affectedConversation.id);
}}
onDelete={() => {
onDelete(affectedConversation.id);
}}
title={affectedConversation.title}
conversationType="direct" conversationType="direct"
deleteConversation={deleteConversation}
i18n={i18n}
title={affectedConversation.title}
state={ state={
type === ConfirmationStateType.ConfirmingDelete type === ConfirmationStateType.ConfirmingDelete
? MessageRequestState.deleting ? MessageRequestState.deleting
@ -279,7 +272,7 @@ export function ContactSpoofingReviewDialog(props: PropsType): JSX.Element {
<Button <Button
variant={ButtonVariant.SecondaryAffirmative} variant={ButtonVariant.SecondaryAffirmative}
onClick={() => { onClick={() => {
onUnblock(conversationInfo.conversation.id); acceptConversation(conversationInfo.conversation.id);
}} }}
> >
{i18n('MessageRequests--unblock')} {i18n('MessageRequests--unblock')}

View file

@ -15,16 +15,17 @@ const i18n = setupI18n('en', enMessages);
const getBaseProps = ( const getBaseProps = (
isGroup = false isGroup = false
): MandatoryProfileSharingActionsProps => ({ ): MandatoryProfileSharingActionsProps => ({
conversationId: '123',
i18n, i18n,
conversationType: isGroup ? 'group' : 'direct', conversationType: isGroup ? 'group' : 'direct',
firstName: text('firstName', 'Cayce'), firstName: text('firstName', 'Cayce'),
title: isGroup title: isGroup
? text('title', 'NYC Rock Climbers') ? text('title', 'NYC Rock Climbers')
: text('title', 'Cayce Bollard'), : text('title', 'Cayce Bollard'),
onBlock: action('block'), acceptConversation: action('acceptConversation'),
onBlockAndReportSpam: action('onBlockAndReportSpam'), blockAndReportSpam: action('blockAndReportSpam'),
onDelete: action('delete'), blockConversation: action('blockConversation'),
onAccept: action('accept'), deleteConversation: action('deleteConversation'),
}); });
export default { export default {

View file

@ -16,21 +16,26 @@ import type { LocalizerType } from '../../types/Util';
export type Props = { export type Props = {
i18n: LocalizerType; i18n: LocalizerType;
firstName?: string; firstName?: string;
onAccept(): unknown;
} & Omit<ContactNameProps, 'module'> & } & Omit<ContactNameProps, 'module'> &
Pick< Pick<
MessageRequestActionsConfirmationProps, MessageRequestActionsConfirmationProps,
'conversationType' | 'onBlock' | 'onBlockAndReportSpam' | 'onDelete' | 'acceptConversation'
| 'blockAndReportSpam'
| 'blockConversation'
| 'conversationId'
| 'conversationType'
| 'deleteConversation'
>; >;
export function MandatoryProfileSharingActions({ export function MandatoryProfileSharingActions({
acceptConversation,
blockAndReportSpam,
blockConversation,
conversationId,
conversationType, conversationType,
deleteConversation,
firstName, firstName,
i18n, i18n,
onAccept,
onBlock,
onBlockAndReportSpam,
onDelete,
title, title,
}: Props): JSX.Element { }: Props): JSX.Element {
const [mrState, setMrState] = React.useState(MessageRequestState.default); const [mrState, setMrState] = React.useState(MessageRequestState.default);
@ -39,15 +44,16 @@ export function MandatoryProfileSharingActions({
<> <>
{mrState !== MessageRequestState.default ? ( {mrState !== MessageRequestState.default ? (
<MessageRequestActionsConfirmation <MessageRequestActionsConfirmation
i18n={i18n} acceptConversation={() => {
onBlock={onBlock}
onBlockAndReportSpam={onBlockAndReportSpam}
onUnblock={() => {
throw new Error( throw new Error(
'Should not be able to unblock from MandatoryProfileSharingActions' 'Should not be able to unblock from MandatoryProfileSharingActions'
); );
}} }}
onDelete={onDelete} blockConversation={blockConversation}
conversationId={conversationId}
deleteConversation={deleteConversation}
i18n={i18n}
blockAndReportSpam={blockAndReportSpam}
title={title} title={title}
conversationType={conversationType} conversationType={conversationType}
state={mrState} state={mrState}
@ -103,7 +109,7 @@ export function MandatoryProfileSharingActions({
{i18n('MessageRequests--delete')} {i18n('MessageRequests--delete')}
</Button> </Button>
<Button <Button
onClick={onAccept} onClick={() => acceptConversation(conversationId)}
variant={ButtonVariant.SecondaryAffirmative} variant={ButtonVariant.SecondaryAffirmative}
> >
{i18n('MessageRequests--continue')} {i18n('MessageRequests--continue')}

View file

@ -13,17 +13,17 @@ import enMessages from '../../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages); const i18n = setupI18n('en', enMessages);
const getBaseProps = (isGroup = false): MessageRequestActionsProps => ({ const getBaseProps = (isGroup = false): MessageRequestActionsProps => ({
conversationId: '123',
i18n, i18n,
conversationType: isGroup ? 'group' : 'direct', conversationType: isGroup ? 'group' : 'direct',
firstName: text('firstName', 'Cayce'), firstName: text('firstName', 'Cayce'),
title: isGroup title: isGroup
? text('title', 'NYC Rock Climbers') ? text('title', 'NYC Rock Climbers')
: text('title', 'Cayce Bollard'), : text('title', 'Cayce Bollard'),
onBlock: action('block'), acceptConversation: action('acceptConversation'),
onDelete: action('delete'), blockAndReportSpam: action('blockAndReportSpam'),
onBlockAndReportSpam: action('blockAndReportSpam'), blockConversation: action('blockConversation'),
onUnblock: action('unblock'), deleteConversation: action('deleteConversation'),
onAccept: action('accept'),
}); });
export default { export default {

View file

@ -15,7 +15,6 @@ import type { LocalizerType } from '../../types/Util';
export type Props = { export type Props = {
i18n: LocalizerType; i18n: LocalizerType;
onAccept(): unknown;
} & Omit<ContactNameProps, 'module'> & } & Omit<ContactNameProps, 'module'> &
Omit< Omit<
MessageRequestActionsConfirmationProps, MessageRequestActionsConfirmationProps,
@ -23,15 +22,15 @@ export type Props = {
>; >;
export function MessageRequestActions({ export function MessageRequestActions({
acceptConversation,
blockAndReportSpam,
blockConversation,
conversationId,
conversationType, conversationType,
deleteConversation,
firstName, firstName,
i18n, i18n,
isBlocked, isBlocked,
onAccept,
onBlock,
onBlockAndReportSpam,
onDelete,
onUnblock,
title, title,
}: Props): JSX.Element { }: Props): JSX.Element {
const [mrState, setMrState] = React.useState(MessageRequestState.default); const [mrState, setMrState] = React.useState(MessageRequestState.default);
@ -40,15 +39,16 @@ export function MessageRequestActions({
<> <>
{mrState !== MessageRequestState.default ? ( {mrState !== MessageRequestState.default ? (
<MessageRequestActionsConfirmation <MessageRequestActionsConfirmation
i18n={i18n} acceptConversation={acceptConversation}
onBlock={onBlock} blockAndReportSpam={blockAndReportSpam}
onBlockAndReportSpam={onBlockAndReportSpam} blockConversation={blockConversation}
onUnblock={onUnblock} conversationId={conversationId}
onDelete={onDelete}
title={title}
conversationType={conversationType} conversationType={conversationType}
state={mrState} deleteConversation={deleteConversation}
i18n={i18n}
onChangeState={setMrState} onChangeState={setMrState}
state={mrState}
title={title}
/> />
) : null} ) : null}
<div className="module-message-request-actions"> <div className="module-message-request-actions">
@ -102,7 +102,7 @@ export function MessageRequestActions({
)} )}
{!isBlocked ? ( {!isBlocked ? (
<Button <Button
onClick={onAccept} onClick={() => acceptConversation(conversationId)}
variant={ButtonVariant.SecondaryAffirmative} variant={ButtonVariant.SecondaryAffirmative}
> >
{i18n('MessageRequests--accept')} {i18n('MessageRequests--accept')}

View file

@ -16,25 +16,27 @@ export enum MessageRequestState {
} }
export type Props = { export type Props = {
i18n: LocalizerType; acceptConversation(conversationId: string): unknown;
blockAndReportSpam(conversationId: string): unknown;
blockConversation(conversationId: string): unknown;
conversationId: string;
conversationType: 'group' | 'direct'; conversationType: 'group' | 'direct';
deleteConversation(conversationId: string): unknown;
i18n: LocalizerType;
isBlocked?: boolean; isBlocked?: boolean;
onBlock(): unknown;
onBlockAndReportSpam(): unknown;
onUnblock(): unknown;
onDelete(): unknown;
state: MessageRequestState;
onChangeState(state: MessageRequestState): unknown; onChangeState(state: MessageRequestState): unknown;
state: MessageRequestState;
} & Omit<ContactNameProps, 'module'>; } & Omit<ContactNameProps, 'module'>;
export function MessageRequestActionsConfirmation({ export function MessageRequestActionsConfirmation({
acceptConversation,
blockAndReportSpam,
blockConversation,
conversationId,
conversationType, conversationType,
deleteConversation,
i18n, i18n,
onBlock,
onBlockAndReportSpam,
onChangeState, onChangeState,
onDelete,
onUnblock,
state, state,
title, title,
}: Props): JSX.Element | null { }: Props): JSX.Element | null {
@ -58,14 +60,14 @@ export function MessageRequestActionsConfirmation({
? [ ? [
{ {
text: i18n('MessageRequests--block-and-report-spam'), text: i18n('MessageRequests--block-and-report-spam'),
action: onBlockAndReportSpam, action: () => blockAndReportSpam(conversationId),
style: 'negative' as const, style: 'negative' as const,
}, },
] ]
: []), : []),
{ {
text: i18n('MessageRequests--block'), text: i18n('MessageRequests--block'),
action: onBlock, action: () => blockConversation(conversationId),
style: 'negative', style: 'negative',
}, },
]} ]}
@ -95,7 +97,7 @@ export function MessageRequestActionsConfirmation({
actions={[ actions={[
{ {
text: i18n('MessageRequests--unblock'), text: i18n('MessageRequests--unblock'),
action: onUnblock, action: () => acceptConversation(conversationId),
style: 'affirmative', style: 'affirmative',
}, },
]} ]}
@ -123,7 +125,7 @@ export function MessageRequestActionsConfirmation({
actions={[ actions={[
{ {
text: i18n(`MessageRequests--delete-${conversationType}`), text: i18n(`MessageRequests--delete-${conversationType}`),
action: onDelete, action: () => deleteConversation(conversationId),
style: 'negative', style: 'negative',
}, },
]} ]}

View file

@ -321,10 +321,10 @@ const actions = () => ({
'reviewMessageRequestNameCollision' 'reviewMessageRequestNameCollision'
), ),
onBlock: action('onBlock'), acceptConversation: action('acceptConversation'),
onBlockAndReportSpam: action('onBlockAndReportSpam'), blockAndReportSpam: action('blockAndReportSpam'),
onDelete: action('onDelete'), blockConversation: action('blockConversation'),
onUnblock: action('onUnblock'), deleteConversation: action('deleteConversation'),
removeMember: action('removeMember'), removeMember: action('removeMember'),
unblurAvatar: action('unblurAvatar'), unblurAvatar: action('unblurAvatar'),

View file

@ -165,10 +165,10 @@ export type PropsActionsType = {
loadNewerMessages: (messageId: string) => unknown; loadNewerMessages: (messageId: string) => unknown;
loadNewestMessages: (messageId: string, setFocus?: boolean) => unknown; loadNewestMessages: (messageId: string, setFocus?: boolean) => unknown;
markMessageRead: (messageId: string) => unknown; markMessageRead: (messageId: string) => unknown;
onBlock: (conversationId: string) => unknown; blockConversation: (conversationId: string) => unknown;
onBlockAndReportSpam: (conversationId: string) => unknown; blockAndReportSpam: (conversationId: string) => unknown;
onDelete: (conversationId: string) => unknown; deleteConversation: (conversationId: string) => unknown;
onUnblock: (conversationId: string) => unknown; acceptConversation: (conversationId: string) => unknown;
peekGroupCallForTheFirstTime: (conversationId: string) => unknown; peekGroupCallForTheFirstTime: (conversationId: string) => unknown;
peekGroupCallIfItHasMembers: (conversationId: string) => unknown; peekGroupCallIfItHasMembers: (conversationId: string) => unknown;
removeMember: (conversationId: string) => unknown; removeMember: (conversationId: string) => unknown;
@ -224,10 +224,10 @@ const getActions = createSelector(
'loadNewestMessages', 'loadNewestMessages',
'markMessageRead', 'markMessageRead',
'markViewed', 'markViewed',
'onBlock', 'acceptConversation',
'onBlockAndReportSpam', 'blockAndReportSpam',
'onDelete', 'blockConversation',
'onUnblock', 'deleteConversation',
'peekGroupCallForTheFirstTime', 'peekGroupCallForTheFirstTime',
'peekGroupCallIfItHasMembers', 'peekGroupCallIfItHasMembers',
'removeMember', 'removeMember',
@ -827,10 +827,14 @@ export class Timeline extends React.Component<
public override render(): JSX.Element | null { public override render(): JSX.Element | null {
const { const {
acceptConversation,
acknowledgeGroupMemberNameCollisions, acknowledgeGroupMemberNameCollisions,
blockAndReportSpam,
blockConversation,
clearInvitedUuidsForNewlyCreatedGroup, clearInvitedUuidsForNewlyCreatedGroup,
closeContactSpoofingReview, closeContactSpoofingReview,
contactSpoofingReview, contactSpoofingReview,
deleteConversation,
getPreferredBadge, getPreferredBadge,
getTimestampForMessage, getTimestampForMessage,
haveNewest, haveNewest,
@ -844,15 +848,11 @@ export class Timeline extends React.Component<
items, items,
messageLoadingState, messageLoadingState,
oldestUnseenIndex, oldestUnseenIndex,
onBlock,
onBlockAndReportSpam,
onDelete,
onUnblock,
removeMember, removeMember,
renderContactSpoofingReviewDialog,
renderHeroRow, renderHeroRow,
renderItem, renderItem,
renderTypingBubble, renderTypingBubble,
renderContactSpoofingReviewDialog,
reviewGroupMemberNameCollision, reviewGroupMemberNameCollision,
reviewMessageRequestNameCollision, reviewMessageRequestNameCollision,
showContactModal, showContactModal,
@ -1082,14 +1082,14 @@ export class Timeline extends React.Component<
let contactSpoofingReviewDialog: ReactNode; let contactSpoofingReviewDialog: ReactNode;
if (contactSpoofingReview) { if (contactSpoofingReview) {
const commonProps = { const commonProps = {
acceptConversation,
blockAndReportSpam,
blockConversation,
deleteConversation,
getPreferredBadge, getPreferredBadge,
i18n, i18n,
onBlock,
onBlockAndReportSpam,
onClose: closeContactSpoofingReview, onClose: closeContactSpoofingReview,
onDelete,
onShowContactModal: showContactModal, onShowContactModal: showContactModal,
onUnblock,
removeMember, removeMember,
theme, theme,
}; };

View file

@ -40,10 +40,12 @@ const createProps = (
hasGroupLink = false, hasGroupLink = false,
expireTimer?: DurationInSeconds expireTimer?: DurationInSeconds
): Props => ({ ): Props => ({
acceptConversation: action('acceptConversation'),
addMembers: async () => { addMembers: async () => {
action('addMembers'); action('addMembers');
}, },
areWeASubscriber: false, areWeASubscriber: false,
blockConversation: action('blockConversation'),
canEditGroupInfo: false, canEditGroupInfo: false,
canAddNewMembers: false, canAddNewMembers: false,
conversation: expireTimer conversation: expireTimer
@ -90,9 +92,7 @@ const createProps = (
updateGroupAttributes: async () => { updateGroupAttributes: async () => {
action('updateGroupAttributes')(); action('updateGroupAttributes')();
}, },
onBlock: action('onBlock'),
onLeave: action('onLeave'), onLeave: action('onLeave'),
onUnblock: action('onUnblock'),
deleteAvatarFromDisk: action('deleteAvatarFromDisk'), deleteAvatarFromDisk: action('deleteAvatarFromDisk'),
replaceAvatar: action('replaceAvatar'), replaceAvatar: action('replaceAvatar'),
saveAvatarToDisk: action('saveAvatarToDisk'), saveAvatarToDisk: action('saveAvatarToDisk'),

View file

@ -96,9 +96,7 @@ export type StateProps = {
title?: string; title?: string;
}> }>
) => Promise<void>; ) => Promise<void>;
onBlock: () => void;
onLeave: () => void; onLeave: () => void;
onUnblock: () => void;
theme: ThemeType; theme: ThemeType;
userAvatarData: Array<AvatarDataType>; userAvatarData: Array<AvatarDataType>;
renderChooseGroupMembersModal: ( renderChooseGroupMembersModal: (
@ -110,6 +108,8 @@ export type StateProps = {
}; };
type ActionProps = { type ActionProps = {
acceptConversation: (id: string) => void;
blockConversation: (id: string) => void;
deleteAvatarFromDisk: DeleteAvatarFromDiskActionType; deleteAvatarFromDisk: DeleteAvatarFromDiskActionType;
loadRecentMediaItems: (id: string, limit: number) => void; loadRecentMediaItems: (id: string, limit: number) => void;
onOutgoingAudioCallInConversation: (conversationId: string) => unknown; onOutgoingAudioCallInConversation: (conversationId: string) => unknown;
@ -128,9 +128,11 @@ type ActionProps = {
export type Props = StateProps & ActionProps; export type Props = StateProps & ActionProps;
export function ConversationDetails({ export function ConversationDetails({
acceptConversation,
addMembers, addMembers,
areWeASubscriber, areWeASubscriber,
badges, badges,
blockConversation,
canEditGroupInfo, canEditGroupInfo,
canAddNewMembers, canAddNewMembers,
conversation, conversation,
@ -146,11 +148,9 @@ export function ConversationDetails({
memberships, memberships,
maxGroupSize, maxGroupSize,
maxRecommendedGroupSize, maxRecommendedGroupSize,
onBlock,
onLeave, onLeave,
onOutgoingAudioCallInConversation, onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation, onOutgoingVideoCallInConversation,
onUnblock,
pendingApprovalMemberships, pendingApprovalMemberships,
pendingMemberships, pendingMemberships,
renderChooseGroupMembersModal, renderChooseGroupMembersModal,
@ -551,15 +551,16 @@ export function ConversationDetails({
{!conversation.isMe && ( {!conversation.isMe && (
<ConversationDetailsActions <ConversationDetailsActions
acceptConversation={acceptConversation}
blockConversation={blockConversation}
cannotLeaveBecauseYouAreLastAdmin={cannotLeaveBecauseYouAreLastAdmin} cannotLeaveBecauseYouAreLastAdmin={cannotLeaveBecauseYouAreLastAdmin}
conversationId={conversation.id}
conversationTitle={conversation.title} conversationTitle={conversation.title}
i18n={i18n} i18n={i18n}
isBlocked={Boolean(conversation.isBlocked)} isBlocked={Boolean(conversation.isBlocked)}
isGroup={isGroup} isGroup={isGroup}
left={Boolean(conversation.left)} left={Boolean(conversation.left)}
onBlock={onBlock}
onLeave={onLeave} onLeave={onLeave}
onUnblock={onUnblock}
/> />
)} )}

View file

@ -19,19 +19,20 @@ export default {
}; };
const createProps = (overrideProps: Partial<Props> = {}): Props => ({ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
acceptConversation: action('acceptConversation'),
blockConversation: action('blockConversation'),
cannotLeaveBecauseYouAreLastAdmin: isBoolean( cannotLeaveBecauseYouAreLastAdmin: isBoolean(
overrideProps.cannotLeaveBecauseYouAreLastAdmin overrideProps.cannotLeaveBecauseYouAreLastAdmin
) )
? overrideProps.cannotLeaveBecauseYouAreLastAdmin ? overrideProps.cannotLeaveBecauseYouAreLastAdmin
: false, : false,
conversationId: '123',
conversationTitle: overrideProps.conversationTitle || '', conversationTitle: overrideProps.conversationTitle || '',
left: isBoolean(overrideProps.left) ? overrideProps.left : false,
onBlock: action('onBlock'),
onLeave: action('onLeave'),
onUnblock: action('onUnblock'),
i18n, i18n,
isBlocked: isBoolean(overrideProps.isBlocked), isBlocked: isBoolean(overrideProps.isBlocked),
isGroup: true, isGroup: true,
left: isBoolean(overrideProps.left) ? overrideProps.left : false,
onLeave: action('onLeave'),
}); });
export function Basic(): JSX.Element { export function Basic(): JSX.Element {

View file

@ -14,27 +14,29 @@ import { PanelSection } from './PanelSection';
import { ConversationDetailsIcon, IconType } from './ConversationDetailsIcon'; import { ConversationDetailsIcon, IconType } from './ConversationDetailsIcon';
export type Props = { export type Props = {
acceptConversation: (id: string) => void;
blockConversation: (id: string) => void;
cannotLeaveBecauseYouAreLastAdmin: boolean; cannotLeaveBecauseYouAreLastAdmin: boolean;
conversationId: string;
conversationTitle: string; conversationTitle: string;
i18n: LocalizerType; i18n: LocalizerType;
isBlocked: boolean; isBlocked: boolean;
isGroup: boolean; isGroup: boolean;
left: boolean; left: boolean;
onBlock: () => void;
onLeave: () => void; onLeave: () => void;
onUnblock: () => void;
}; };
export function ConversationDetailsActions({ export function ConversationDetailsActions({
acceptConversation,
blockConversation,
cannotLeaveBecauseYouAreLastAdmin, cannotLeaveBecauseYouAreLastAdmin,
conversationId,
conversationTitle, conversationTitle,
i18n, i18n,
isBlocked, isBlocked,
isGroup, isGroup,
left, left,
onBlock,
onLeave, onLeave,
onUnblock,
}: Props): JSX.Element { }: Props): JSX.Element {
const [confirmLeave, gLeave] = useState<boolean>(false); const [confirmLeave, gLeave] = useState<boolean>(false);
const [confirmGroupBlock, gGroupBlock] = useState<boolean>(false); const [confirmGroupBlock, gGroupBlock] = useState<boolean>(false);
@ -193,7 +195,7 @@ export function ConversationDetailsActions({
text: i18n( text: i18n(
'ConversationDetailsActions--block-group-modal-confirm' 'ConversationDetailsActions--block-group-modal-confirm'
), ),
action: onBlock, action: () => blockConversation(conversationId),
style: 'affirmative', style: 'affirmative',
}, },
]} ]}
@ -214,7 +216,7 @@ export function ConversationDetailsActions({
text: i18n( text: i18n(
'ConversationDetailsActions--unblock-group-modal-confirm' 'ConversationDetailsActions--unblock-group-modal-confirm'
), ),
action: onUnblock, action: () => acceptConversation(conversationId),
style: 'affirmative', style: 'affirmative',
}, },
]} ]}
@ -234,7 +236,7 @@ export function ConversationDetailsActions({
actions={[ actions={[
{ {
text: i18n('MessageRequests--block'), text: i18n('MessageRequests--block'),
action: onBlock, action: () => blockConversation(conversationId),
style: 'affirmative', style: 'affirmative',
}, },
]} ]}
@ -253,7 +255,7 @@ export function ConversationDetailsActions({
actions={[ actions={[
{ {
text: i18n('MessageRequests--unblock'), text: i18n('MessageRequests--unblock'),
action: onUnblock, action: () => acceptConversation(conversationId),
style: 'affirmative', style: 'affirmative',
}, },
]} ]}

View file

@ -104,6 +104,9 @@ import { SHOW_TOAST, ToastType } from './toast';
import { isMemberRequestingToJoin } from '../../util/isMemberRequestingToJoin'; import { isMemberRequestingToJoin } from '../../util/isMemberRequestingToJoin';
import { removePendingMember } from '../../util/removePendingMember'; import { removePendingMember } from '../../util/removePendingMember';
import { denyPendingApprovalRequest } from '../../util/denyPendingApprovalRequest'; import { denyPendingApprovalRequest } from '../../util/denyPendingApprovalRequest';
import { SignalService as Proto } from '../../protobuf';
import { addReportSpamJob } from '../../jobs/helpers/addReportSpamJob';
import { reportSpamJobQueue } from '../../jobs/reportSpamJobQueue';
// State // State
@ -840,8 +843,11 @@ export type ConversationActionType =
// Action Creators // Action Creators
export const actions = { export const actions = {
acceptConversation,
addMemberToGroup, addMemberToGroup,
approvePendingMembershipFromGroupV2, approvePendingMembershipFromGroupV2,
blockAndReportSpam,
blockConversation,
cancelConversationVerification, cancelConversationVerification,
changeHasGroupLink, changeHasGroupLink,
clearCancelledConversationVerification, clearCancelledConversationVerification,
@ -863,6 +869,7 @@ export const actions = {
conversationUnloaded, conversationUnloaded,
createGroup, createGroup,
deleteAvatarFromDisk, deleteAvatarFromDisk,
deleteConversation,
deleteMessageForEveryone, deleteMessageForEveryone,
destroyMessages, destroyMessages,
discardMessages, discardMessages,
@ -2205,6 +2212,121 @@ function revokePendingMembershipsFromGroupV2(
}; };
} }
function blockAndReportSpam(
conversationId: string
): ThunkAction<void, RootStateType, unknown, ShowToastActionType> {
return async dispatch => {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
log.error(
`blockAndReportSpam: Expected a conversation to be found for ${conversationId}. Doing nothing.`
);
return;
}
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
const idForLogging = conversation.idForLogging();
longRunningTaskWrapper({
name: 'blockAndReportSpam',
idForLogging,
task: async () => {
await Promise.all([
conversation.syncMessageRequestResponse(messageRequestEnum.BLOCK),
addReportSpamJob({
conversation: conversation.format(),
getMessageServerGuidsForSpam:
window.Signal.Data.getMessageServerGuidsForSpam,
jobQueue: reportSpamJobQueue,
}),
]);
dispatch({
type: SHOW_TOAST,
payload: {
toastType: ToastType.ReportedSpamAndBlocked,
},
});
},
});
};
}
function acceptConversation(conversationId: string): NoopActionType {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
throw new Error(
'acceptConversation: Expected a conversation to be found. Doing nothing'
);
}
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
longRunningTaskWrapper({
name: 'acceptConversation',
idForLogging: conversation.idForLogging(),
task: conversation.syncMessageRequestResponse.bind(
conversation,
messageRequestEnum.ACCEPT
),
});
return {
type: 'NOOP',
payload: null,
};
}
function blockConversation(conversationId: string): NoopActionType {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
throw new Error(
'blockConversation: Expected a conversation to be found. Doing nothing'
);
}
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
longRunningTaskWrapper({
name: 'blockConversation',
idForLogging: conversation.idForLogging(),
task: conversation.syncMessageRequestResponse.bind(
conversation,
messageRequestEnum.BLOCK
),
});
return {
type: 'NOOP',
payload: null,
};
}
function deleteConversation(conversationId: string): NoopActionType {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
throw new Error(
'deleteConversation: Expected a conversation to be found. Doing nothing'
);
}
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
longRunningTaskWrapper({
name: 'deleteConversation',
idForLogging: conversation.idForLogging(),
task: conversation.syncMessageRequestResponse.bind(
conversation,
messageRequestEnum.DELETE
),
});
return {
type: 'NOOP',
payload: null,
};
}
function loadRecentMediaItems( function loadRecentMediaItems(
conversationId: string, conversationId: string,
limit: number limit: number

View file

@ -13,6 +13,7 @@ export enum ToastType {
Error = 'Error', Error = 'Error',
FailedToDeleteUsername = 'FailedToDeleteUsername', FailedToDeleteUsername = 'FailedToDeleteUsername',
MessageBodyTooLong = 'MessageBodyTooLong', MessageBodyTooLong = 'MessageBodyTooLong',
ReportedSpamAndBlocked = 'ReportedSpamAndBlocked',
StoryMuted = 'StoryMuted', StoryMuted = 'StoryMuted',
StoryReact = 'StoryReact', StoryReact = 'StoryReact',
StoryReply = 'StoryReply', StoryReply = 'StoryReply',

View file

@ -54,9 +54,7 @@ export type SmartConversationDetailsProps = {
title?: string; title?: string;
}> }>
) => Promise<void>; ) => Promise<void>;
onBlock: () => void;
onLeave: () => void; onLeave: () => void;
onUnblock: () => void;
}; };
const ACCESS_ENUM = Proto.AccessControl.AccessRequired; const ACCESS_ENUM = Proto.AccessControl.AccessRequired;

View file

@ -21,21 +21,16 @@ export type PropsType = {
| 'getQuotedMessage' | 'getQuotedMessage'
| 'handleClickQuotedMessage' | 'handleClickQuotedMessage'
| 'id' | 'id'
| 'onAccept'
| 'onBlock'
| 'onBlockAndReportSpam'
| 'onCancelJoinRequest' | 'onCancelJoinRequest'
| 'onClearAttachments' | 'onClearAttachments'
| 'onClickAddPack' | 'onClickAddPack'
| 'onCloseLinkPreview' | 'onCloseLinkPreview'
| 'onDelete'
| 'onEditorStateChange' | 'onEditorStateChange'
| 'onPickSticker' | 'onPickSticker'
| 'onSelectMediaQuality' | 'onSelectMediaQuality'
| 'onSendMessage' | 'onSendMessage'
| 'onStartGroupMigration' | 'onStartGroupMigration'
| 'onTextTooLong' | 'onTextTooLong'
| 'onUnblock'
| 'openConversation' | 'openConversation'
>; >;
conversationHeaderProps: ConversationHeaderPropsType; conversationHeaderProps: ConversationHeaderPropsType;

View file

@ -76,10 +76,6 @@ export type TimelinePropsType = ExternalProps &
| 'loadOlderMessages' | 'loadOlderMessages'
| 'markAttachmentAsCorrupted' | 'markAttachmentAsCorrupted'
| 'markMessageRead' | 'markMessageRead'
| 'onBlock'
| 'onBlockAndReportSpam'
| 'onDelete'
| 'onUnblock'
| 'openConversation' | 'openConversation'
| 'openGiftBadge' | 'openGiftBadge'
| 'openLink' | 'openLink'

View file

@ -46,7 +46,6 @@ import type { ToastMessageBodyTooLong } from '../components/ToastMessageBodyTooL
import type { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound'; import type { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound';
import type { ToastPinnedConversationsFull } from '../components/ToastPinnedConversationsFull'; import type { ToastPinnedConversationsFull } from '../components/ToastPinnedConversationsFull';
import type { ToastReactionFailed } from '../components/ToastReactionFailed'; import type { ToastReactionFailed } from '../components/ToastReactionFailed';
import type { ToastReportedSpamAndBlocked } from '../components/ToastReportedSpamAndBlocked';
import type { ToastStickerPackInstallFailed } from '../components/ToastStickerPackInstallFailed'; import type { ToastStickerPackInstallFailed } from '../components/ToastStickerPackInstallFailed';
import type { ToastTapToViewExpiredIncoming } from '../components/ToastTapToViewExpiredIncoming'; import type { ToastTapToViewExpiredIncoming } from '../components/ToastTapToViewExpiredIncoming';
import type { ToastTapToViewExpiredOutgoing } from '../components/ToastTapToViewExpiredOutgoing'; import type { ToastTapToViewExpiredOutgoing } from '../components/ToastTapToViewExpiredOutgoing';
@ -96,7 +95,6 @@ export function showToast(Toast: typeof ToastUnsupportedMultiAttachment): void;
export function showToast(Toast: typeof ToastOriginalMessageNotFound): void; export function showToast(Toast: typeof ToastOriginalMessageNotFound): void;
export function showToast(Toast: typeof ToastPinnedConversationsFull): void; export function showToast(Toast: typeof ToastPinnedConversationsFull): void;
export function showToast(Toast: typeof ToastReactionFailed): void; export function showToast(Toast: typeof ToastReactionFailed): void;
export function showToast(Toast: typeof ToastReportedSpamAndBlocked): void;
export function showToast(Toast: typeof ToastStickerPackInstallFailed): void; export function showToast(Toast: typeof ToastStickerPackInstallFailed): void;
export function showToast(Toast: typeof ToastTapToViewExpiredIncoming): void; export function showToast(Toast: typeof ToastTapToViewExpiredIncoming): void;
export function showToast(Toast: typeof ToastTapToViewExpiredOutgoing): void; export function showToast(Toast: typeof ToastTapToViewExpiredOutgoing): void;

View file

@ -27,8 +27,6 @@ import { getMessageById } from '../messages/getMessageById';
import { getContactId } from '../messages/helpers'; import { getContactId } from '../messages/helpers';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import { enqueueReactionForSend } from '../reactions/enqueueReactionForSend'; import { enqueueReactionForSend } from '../reactions/enqueueReactionForSend';
import { addReportSpamJob } from '../jobs/helpers/addReportSpamJob';
import { reportSpamJobQueue } from '../jobs/reportSpamJobQueue';
import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions'; import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions';
import { import {
isDirectConversation, isDirectConversation,
@ -57,7 +55,6 @@ import type { EmbeddedContactType } from '../types/EmbeddedContact';
import { createConversationView } from '../state/roots/createConversationView'; import { createConversationView } from '../state/roots/createConversationView';
import { AttachmentToastType } from '../types/AttachmentToastType'; import { AttachmentToastType } from '../types/AttachmentToastType';
import type { CompositionAPIType } from '../components/CompositionArea'; import type { CompositionAPIType } from '../components/CompositionArea';
import { SignalService as Proto } from '../protobuf';
import { ToastBlocked } from '../components/ToastBlocked'; import { ToastBlocked } from '../components/ToastBlocked';
import { ToastBlockedGroup } from '../components/ToastBlockedGroup'; import { ToastBlockedGroup } from '../components/ToastBlockedGroup';
import { ToastCannotMixMultiAndNonMultiAttachments } from '../components/ToastCannotMixMultiAndNonMultiAttachments'; import { ToastCannotMixMultiAndNonMultiAttachments } from '../components/ToastCannotMixMultiAndNonMultiAttachments';
@ -75,7 +72,6 @@ import { ToastUnsupportedMultiAttachment } from '../components/ToastUnsupportedM
import { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound'; import { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound';
import { ToastPinnedConversationsFull } from '../components/ToastPinnedConversationsFull'; import { ToastPinnedConversationsFull } from '../components/ToastPinnedConversationsFull';
import { ToastReactionFailed } from '../components/ToastReactionFailed'; import { ToastReactionFailed } from '../components/ToastReactionFailed';
import { ToastReportedSpamAndBlocked } from '../components/ToastReportedSpamAndBlocked';
import { ToastTapToViewExpiredIncoming } from '../components/ToastTapToViewExpiredIncoming'; import { ToastTapToViewExpiredIncoming } from '../components/ToastTapToViewExpiredIncoming';
import { ToastTapToViewExpiredOutgoing } from '../components/ToastTapToViewExpiredOutgoing'; import { ToastTapToViewExpiredOutgoing } from '../components/ToastTapToViewExpiredOutgoing';
import { ToastUnableToLoadAttachment } from '../components/ToastUnableToLoadAttachment'; import { ToastUnableToLoadAttachment } from '../components/ToastUnableToLoadAttachment';
@ -368,7 +364,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
window.reduxActions.conversations.setSelectedConversationHeaderTitle(); window.reduxActions.conversations.setSelectedConversationHeaderTitle();
// setupTimeline // setupTimeline
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
const contactSupport = () => { const contactSupport = () => {
const baseUrl = const baseUrl =
@ -433,19 +428,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
}); });
}; };
const createMessageRequestResponseHandler =
(name: string, enumValue: number): ((conversationId: string) => void) =>
conversationId => {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
log.error(
`createMessageRequestResponseHandler: Expected a conversation to be found in ${name}. Doing nothing`
);
return;
}
this.syncMessageRequestResponse(name, conversation, enumValue);
};
const timelineProps = { const timelineProps = {
id: this.model.id, id: this.model.id,
@ -465,28 +447,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
loadNewestMessages: this.model.loadNewestMessages.bind(this.model), loadNewestMessages: this.model.loadNewestMessages.bind(this.model),
loadOlderMessages: this.model.loadOlderMessages.bind(this.model), loadOlderMessages: this.model.loadOlderMessages.bind(this.model),
markMessageRead, markMessageRead,
onBlock: createMessageRequestResponseHandler(
'onBlock',
messageRequestEnum.BLOCK
),
onBlockAndReportSpam: (conversationId: string) => {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
log.error(
`onBlockAndReportSpam: Expected a conversation to be found for ${conversationId}. Doing nothing.`
);
return;
}
this.blockAndReportSpam(conversation);
},
onDelete: createMessageRequestResponseHandler(
'onDelete',
messageRequestEnum.DELETE
),
onUnblock: createMessageRequestResponseHandler(
'onUnblock',
messageRequestEnum.ACCEPT
),
removeMember: (conversationId: string) => { removeMember: (conversationId: string) => {
longRunningTaskWrapper({ longRunningTaskWrapper({
idForLogging: this.model.idForLogging(), idForLogging: this.model.idForLogging(),
@ -518,37 +478,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
onTextTooLong: () => showToast(ToastMessageBodyTooLong), onTextTooLong: () => showToast(ToastMessageBodyTooLong),
getQuotedMessage: () => this.model.get('quotedMessageId'), getQuotedMessage: () => this.model.get('quotedMessageId'),
clearQuotedMessage: () => this.setQuoteMessage(null), clearQuotedMessage: () => this.setQuoteMessage(null),
onAccept: () => {
this.syncMessageRequestResponse(
'onAccept',
this.model,
messageRequestEnum.ACCEPT
);
},
onBlock: () => {
this.syncMessageRequestResponse(
'onBlock',
this.model,
messageRequestEnum.BLOCK
);
},
onUnblock: () => {
this.syncMessageRequestResponse(
'onUnblock',
this.model,
messageRequestEnum.ACCEPT
);
},
onDelete: () => {
this.syncMessageRequestResponse(
'onDelete',
this.model,
messageRequestEnum.DELETE
);
},
onBlockAndReportSpam: () => {
this.blockAndReportSpam(this.model);
},
onStartGroupMigration: () => this.startMigrationToGV2(), onStartGroupMigration: () => this.startMigrationToGV2(),
onCancelJoinRequest: async () => { onCancelJoinRequest: async () => {
await window.showConfirmationDialog({ await window.showConfirmationDialog({
@ -1008,39 +937,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
this.processAttachments(files); this.processAttachments(files);
} }
syncMessageRequestResponse(
name: string,
model: ConversationModel,
messageRequestType: number
): Promise<void> {
return longRunningTaskWrapper({
idForLogging: this.model.idForLogging(),
name,
task: model.syncMessageRequestResponse.bind(model, messageRequestType),
});
}
blockAndReportSpam(model: ConversationModel): Promise<void> {
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
return longRunningTaskWrapper({
idForLogging: this.model.idForLogging(),
name: 'blockAndReportSpam',
task: async () => {
await Promise.all([
model.syncMessageRequestResponse(messageRequestEnum.BLOCK),
addReportSpamJob({
conversation: model.format(),
getMessageServerGuidsForSpam:
window.Signal.Data.getMessageServerGuidsForSpam,
jobQueue: reportSpamJobQueue,
}),
]);
showToast(ToastReportedSpamAndBlocked);
},
});
}
async saveModel(): Promise<void> { async saveModel(): Promise<void> {
window.Signal.Data.updateConversation(this.model.attributes); window.Signal.Data.updateConversation(this.model.attributes);
} }
@ -1803,8 +1699,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
this.model.throttledGetProfiles(); this.model.throttledGetProfiles();
} }
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
// these methods are used in more than one place and should probably be // these methods are used in more than one place and should probably be
// dried up and hoisted to methods on ConversationView // dried up and hoisted to methods on ConversationView
@ -1816,14 +1710,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
}); });
}; };
const onBlock = () => {
this.syncMessageRequestResponse(
'onBlock',
this.model,
messageRequestEnum.BLOCK
);
};
const props = { const props = {
addMembers: this.model.addMembersV2.bind(this.model), addMembers: this.model.addMembersV2.bind(this.model),
conversationId: this.model.get('id'), conversationId: this.model.get('id'),
@ -1840,14 +1726,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
this.model this.model
), ),
onLeave, onLeave,
onBlock,
onUnblock: () => {
this.syncMessageRequestResponse(
'onUnblock',
this.model,
messageRequestEnum.ACCEPT
);
},
}; };
const view = new ReactWrapperView({ const view = new ReactWrapperView({