Prevent replies/reactions on messages with errors

This commit is contained in:
Ken Powers 2020-02-07 18:13:46 -05:00 committed by GitHub
parent f37e73c723
commit 101070bf42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 31 deletions

View file

@ -534,6 +534,7 @@
timestamp: this.get('sent_at'), timestamp: this.get('sent_at'),
status: this.getMessagePropStatus(), status: this.getMessagePropStatus(),
contact: this.getPropsForEmbeddedContact(), contact: this.getPropsForEmbeddedContact(),
canReply: this.canReply(),
authorColor, authorColor,
authorName: contact.name, authorName: contact.name,
authorProfileName: contact.profileName, authorProfileName: contact.profileName,
@ -1305,6 +1306,24 @@
e.name === 'OutgoingIdentityKeyError' e.name === 'OutgoingIdentityKeyError'
); );
}, },
canReply() {
const errors = this.get('errors');
const isOutgoing = this.get('type') === 'outgoing';
const numDelivered = this.get('delivered');
// Case 1: We can reply if this is outgoing and delievered to at least one recipient
if (isOutgoing && numDelivered > 0) {
return true;
}
// Case 2: We can reply if there are no errors
if (errors && errors.length === 0) {
return true;
}
// Otherwise we cannot reply
return false;
},
// Called when the user ran into an error with a specific user, wants to send to them // Called when the user ran into an error with a specific user, wants to send to them
// One caller today: ConversationView.forceSend() // One caller today: ConversationView.forceSend()

View file

@ -2528,6 +2528,10 @@
}) })
: null; : null;
if (model && !model.canReply()) {
return;
}
if (model && !model.isNormalBubble()) { if (model && !model.isNormalBubble()) {
return; return;
} }

View file

@ -15,6 +15,7 @@ const book = storiesOf('Components/Conversation/Message', module);
const baseDataProps: Pick< const baseDataProps: Pick<
PropsData, PropsData,
| 'id' | 'id'
| 'canReply'
| 'conversationId' | 'conversationId'
| 'interactionMode' | 'interactionMode'
| 'conversationType' | 'conversationType'
@ -23,6 +24,7 @@ const baseDataProps: Pick<
| 'authorPhoneNumber' | 'authorPhoneNumber'
> = { > = {
id: 'asdf', id: 'asdf',
canReply: true,
conversationId: 'asdf', conversationId: 'asdf',
interactionMode: 'mouse', interactionMode: 'mouse',
conversationType: 'direct', conversationType: 'direct',

View file

@ -105,6 +105,8 @@ export type PropsData = {
reactions?: ReactionViewerProps['reactions']; reactions?: ReactionViewerProps['reactions'];
selectedReaction?: string; selectedReaction?: string;
canReply: boolean;
}; };
export type PropsHousekeeping = { export type PropsHousekeeping = {
@ -986,6 +988,7 @@ export class Message extends React.PureComponent<Props, State> {
const { const {
attachments, attachments,
// tslint:disable-next-line max-func-body-length // tslint:disable-next-line max-func-body-length
canReply,
direction, direction,
disableMenu, disableMenu,
id, id,
@ -1098,9 +1101,9 @@ export class Message extends React.PureComponent<Props, State> {
`module-message__buttons--${direction}` `module-message__buttons--${direction}`
)} )}
> >
{reactButton} {canReply ? reactButton : null}
{downloadButton} {downloadButton}
{replyButton} {canReply ? replyButton : null}
{menuButton} {menuButton}
</div> </div>
{reactionPickerRoot && {reactionPickerRoot &&
@ -1132,6 +1135,7 @@ export class Message extends React.PureComponent<Props, State> {
public renderContextMenu(triggerId: string) { public renderContextMenu(triggerId: string) {
const { const {
attachments, attachments,
canReply,
deleteMessage, deleteMessage,
direction, direction,
i18n, i18n,
@ -1163,32 +1167,36 @@ export class Message extends React.PureComponent<Props, State> {
{i18n('downloadAttachment')} {i18n('downloadAttachment')}
</MenuItem> </MenuItem>
) : null} ) : null}
<MenuItem {canReply ? (
attributes={{ <>
className: 'module-message__context__react', <MenuItem
}} attributes={{
onClick={(event: React.MouseEvent) => { className: 'module-message__context__react',
event.stopPropagation(); }}
event.preventDefault(); onClick={(event: React.MouseEvent) => {
event.stopPropagation();
event.preventDefault();
this.toggleReactionPicker(); this.toggleReactionPicker();
}} }}
> >
{i18n('reactToMessage')} {i18n('reactToMessage')}
</MenuItem> </MenuItem>
<MenuItem <MenuItem
attributes={{ attributes={{
className: 'module-message__context__reply', className: 'module-message__context__reply',
}} }}
onClick={(event: React.MouseEvent) => { onClick={(event: React.MouseEvent) => {
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
replyToMessage(id); replyToMessage(id);
}} }}
> >
{i18n('replyToMessage')} {i18n('replyToMessage')}
</MenuItem> </MenuItem>
</>
) : null}
<MenuItem <MenuItem
attributes={{ attributes={{
className: 'module-message__context__more-info', className: 'module-message__context__more-info',
@ -1831,10 +1839,14 @@ export class Message extends React.PureComponent<Props, State> {
}; };
public handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => { public handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
// Do not allow reactions to error messages
const { canReply } = this.props;
if ( if (
(event.key === 'E' || event.key === 'e') && (event.key === 'E' || event.key === 'e') &&
(event.metaKey || event.ctrlKey) && (event.metaKey || event.ctrlKey) &&
event.shiftKey event.shiftKey &&
canReply
) { ) {
this.toggleReactionPicker(); this.toggleReactionPicker();
} }

View file

@ -9250,17 +9250,17 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();", "line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();",
"lineNumber": 178, "lineNumber": 180,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-02-03T17:18:39.600Z" "updated": "2020-02-07T22:17:41.885Z"
}, },
{ {
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " > = React.createRef();", "line": " > = React.createRef();",
"lineNumber": 182, "lineNumber": 184,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-02-03T17:18:39.600Z" "updated": "2020-02-07T22:17:41.885Z"
}, },
{ {
"rule": "React-createRef", "rule": "React-createRef",