Show error when editing messages after max edits
This commit is contained in:
parent
6d66bf1600
commit
bb8e7af905
6 changed files with 49 additions and 8 deletions
|
@ -3771,6 +3771,14 @@
|
||||||
"messageformat": "Okay",
|
"messageformat": "Okay",
|
||||||
"description": "Button to dismiss popup dialog when user-initiated task has gone wrong"
|
"description": "Button to dismiss popup dialog when user-initiated task has gone wrong"
|
||||||
},
|
},
|
||||||
|
"icu:MessageMaxEditsModal__Title": {
|
||||||
|
"messageformat": "Can't edit message",
|
||||||
|
"description": "Title in popup dialog when attempting to edit a message too many times."
|
||||||
|
},
|
||||||
|
"icu:MessageMaxEditsModal__Description": {
|
||||||
|
"messageformat": "Only {max, number} edits can be applied to this message.",
|
||||||
|
"description": "Description text in popup dialog when attempting to edit a message too many times."
|
||||||
|
},
|
||||||
"icu:unknown-sgnl-link": {
|
"icu:unknown-sgnl-link": {
|
||||||
"messageformat": "Sorry, that sgnl:// link didn't make sense!",
|
"messageformat": "Sorry, that sgnl:// link didn't make sense!",
|
||||||
"description": "Shown if you click on a sgnl:// link not currently supported by Desktop"
|
"description": "Shown if you click on a sgnl:// link not currently supported by Desktop"
|
||||||
|
|
|
@ -29,10 +29,12 @@ import * as Attachment from '../../types/Attachment';
|
||||||
import { isFileDangerous } from '../../util/isFileDangerous';
|
import { isFileDangerous } from '../../util/isFileDangerous';
|
||||||
import type {
|
import type {
|
||||||
ShowSendAnywayDialogActionType,
|
ShowSendAnywayDialogActionType,
|
||||||
|
ShowErrorModalActionType,
|
||||||
ToggleProfileEditorErrorActionType,
|
ToggleProfileEditorErrorActionType,
|
||||||
} from './globalModals';
|
} from './globalModals';
|
||||||
import {
|
import {
|
||||||
SHOW_SEND_ANYWAY_DIALOG,
|
SHOW_SEND_ANYWAY_DIALOG,
|
||||||
|
SHOW_ERROR_MODAL,
|
||||||
TOGGLE_PROFILE_EDITOR_ERROR,
|
TOGGLE_PROFILE_EDITOR_ERROR,
|
||||||
} from './globalModals';
|
} from './globalModals';
|
||||||
import {
|
import {
|
||||||
|
@ -90,6 +92,7 @@ import {
|
||||||
getMe,
|
getMe,
|
||||||
getMessagesByConversation,
|
getMessagesByConversation,
|
||||||
} from '../selectors/conversations';
|
} from '../selectors/conversations';
|
||||||
|
import { getIntl } from '../selectors/user';
|
||||||
import type { AvatarDataType, AvatarUpdateType } from '../../types/Avatar';
|
import type { AvatarDataType, AvatarUpdateType } from '../../types/Avatar';
|
||||||
import { getDefaultAvatars } from '../../types/Avatar';
|
import { getDefaultAvatars } from '../../types/Avatar';
|
||||||
import { getAvatarData } from '../../util/getAvatarData';
|
import { getAvatarData } from '../../util/getAvatarData';
|
||||||
|
@ -164,7 +167,11 @@ import {
|
||||||
} from './composer';
|
} from './composer';
|
||||||
import { ReceiptType } from '../../types/Receipt';
|
import { ReceiptType } from '../../types/Receipt';
|
||||||
import { Sound, SoundType } from '../../util/Sound';
|
import { Sound, SoundType } from '../../util/Sound';
|
||||||
import { canEditMessage } from '../../util/canEditMessage';
|
import {
|
||||||
|
canEditMessage,
|
||||||
|
isWithinMaxEdits,
|
||||||
|
MESSAGE_MAX_EDIT_COUNT,
|
||||||
|
} from '../../util/canEditMessage';
|
||||||
import type { ChangeNavTabActionType } from './nav';
|
import type { ChangeNavTabActionType } from './nav';
|
||||||
import { CHANGE_NAV_TAB, NavTab, actions as navActions } from './nav';
|
import { CHANGE_NAV_TAB, NavTab, actions as navActions } from './nav';
|
||||||
import { sortByMessageOrder } from '../../types/ForwardDraft';
|
import { sortByMessageOrder } from '../../types/ForwardDraft';
|
||||||
|
@ -1770,7 +1777,12 @@ function discardEditMessage(
|
||||||
function setMessageToEdit(
|
function setMessageToEdit(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
messageId: string
|
messageId: string
|
||||||
): ThunkAction<void, RootStateType, unknown, SetFocusActionType> {
|
): ThunkAction<
|
||||||
|
void,
|
||||||
|
RootStateType,
|
||||||
|
unknown,
|
||||||
|
SetFocusActionType | ShowErrorModalActionType
|
||||||
|
> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const conversation = window.ConversationController.get(conversationId);
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
|
|
||||||
|
@ -1787,6 +1799,20 @@ function setMessageToEdit(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isWithinMaxEdits(message)) {
|
||||||
|
const i18n = getIntl(getState());
|
||||||
|
dispatch({
|
||||||
|
type: SHOW_ERROR_MODAL,
|
||||||
|
payload: {
|
||||||
|
title: i18n('icu:MessageMaxEditsModal__Title'),
|
||||||
|
description: i18n('icu:MessageMaxEditsModal__Description', {
|
||||||
|
max: MESSAGE_MAX_EDIT_COUNT,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setQuoteByMessageId(conversationId, undefined)(
|
setQuoteByMessageId(conversationId, undefined)(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
|
|
|
@ -135,7 +135,7 @@ const CLOSE_GV2_MIGRATION_DIALOG = 'globalModals/CLOSE_GV2_MIGRATION_DIALOG';
|
||||||
const SHOW_STICKER_PACK_PREVIEW = 'globalModals/SHOW_STICKER_PACK_PREVIEW';
|
const SHOW_STICKER_PACK_PREVIEW = 'globalModals/SHOW_STICKER_PACK_PREVIEW';
|
||||||
const CLOSE_STICKER_PACK_PREVIEW = 'globalModals/CLOSE_STICKER_PACK_PREVIEW';
|
const CLOSE_STICKER_PACK_PREVIEW = 'globalModals/CLOSE_STICKER_PACK_PREVIEW';
|
||||||
const CLOSE_ERROR_MODAL = 'globalModals/CLOSE_ERROR_MODAL';
|
const CLOSE_ERROR_MODAL = 'globalModals/CLOSE_ERROR_MODAL';
|
||||||
const SHOW_ERROR_MODAL = 'globalModals/SHOW_ERROR_MODAL';
|
export const SHOW_ERROR_MODAL = 'globalModals/SHOW_ERROR_MODAL';
|
||||||
const SHOW_FORMATTING_WARNING_MODAL =
|
const SHOW_FORMATTING_WARNING_MODAL =
|
||||||
'globalModals/SHOW_FORMATTING_WARNING_MODAL';
|
'globalModals/SHOW_FORMATTING_WARNING_MODAL';
|
||||||
const SHOW_SEND_EDIT_WARNING_MODAL =
|
const SHOW_SEND_EDIT_WARNING_MODAL =
|
||||||
|
@ -286,7 +286,7 @@ type CloseErrorModalActionType = ReadonlyDeep<{
|
||||||
type: typeof CLOSE_ERROR_MODAL;
|
type: typeof CLOSE_ERROR_MODAL;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type ShowErrorModalActionType = ReadonlyDeep<{
|
export type ShowErrorModalActionType = ReadonlyDeep<{
|
||||||
type: typeof SHOW_ERROR_MODAL;
|
type: typeof SHOW_ERROR_MODAL;
|
||||||
payload: {
|
payload: {
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
|
@ -1215,6 +1215,7 @@ export const getConversationTitle = createSelector(
|
||||||
getConversationTitleForPanelType(i18n, panel?.type)
|
getConversationTitleForPanelType(i18n, panel?.type)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Note that this doesn't take into account max edit count. See canEditMessage.
|
||||||
export const getLastEditableMessageId = createSelector(
|
export const getLastEditableMessageId = createSelector(
|
||||||
getConversationMessages,
|
getConversationMessages,
|
||||||
getMessages,
|
getMessages,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { isMoreRecentThan } from './timestamp';
|
||||||
import { isOutgoing } from '../messages/helpers';
|
import { isOutgoing } from '../messages/helpers';
|
||||||
import { isSent, someSendStatus } from '../messages/MessageSendState';
|
import { isSent, someSendStatus } from '../messages/MessageSendState';
|
||||||
|
|
||||||
const MAX_EDIT_COUNT = 10;
|
export const MESSAGE_MAX_EDIT_COUNT = 10;
|
||||||
|
|
||||||
export function canEditMessage(message: MessageAttributesType): boolean {
|
export function canEditMessage(message: MessageAttributesType): boolean {
|
||||||
const result =
|
const result =
|
||||||
|
@ -16,7 +16,6 @@ export function canEditMessage(message: MessageAttributesType): boolean {
|
||||||
!message.deletedForEveryone &&
|
!message.deletedForEveryone &&
|
||||||
isOutgoing(message) &&
|
isOutgoing(message) &&
|
||||||
isMoreRecentThan(message.sent_at, DAY) &&
|
isMoreRecentThan(message.sent_at, DAY) &&
|
||||||
(message.editHistory?.length ?? 0) <= MAX_EDIT_COUNT &&
|
|
||||||
someSendStatus(message.sendStateByConversationId, isSent) &&
|
someSendStatus(message.sendStateByConversationId, isSent) &&
|
||||||
Boolean(message.body);
|
Boolean(message.body);
|
||||||
|
|
||||||
|
@ -35,3 +34,7 @@ export function canEditMessage(message: MessageAttributesType): boolean {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isWithinMaxEdits(message: MessageAttributesType): boolean {
|
||||||
|
return (message.editHistory?.length ?? 0) <= MESSAGE_MAX_EDIT_COUNT;
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { ErrorWithToast } from '../types/ErrorWithToast';
|
||||||
import { SendStatus } from '../messages/MessageSendState';
|
import { SendStatus } from '../messages/MessageSendState';
|
||||||
import { ToastType } from '../types/Toast';
|
import { ToastType } from '../types/Toast';
|
||||||
import type { AciString } from '../types/ServiceId';
|
import type { AciString } from '../types/ServiceId';
|
||||||
import { canEditMessage } from './canEditMessage';
|
import { canEditMessage, isWithinMaxEdits } from './canEditMessage';
|
||||||
import {
|
import {
|
||||||
conversationJobQueue,
|
conversationJobQueue,
|
||||||
conversationQueueJobEnum,
|
conversationQueueJobEnum,
|
||||||
|
@ -77,7 +77,10 @@ export async function sendEditedMessage(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canEditMessage(targetMessage.attributes)) {
|
if (
|
||||||
|
!canEditMessage(targetMessage.attributes) ||
|
||||||
|
!isWithinMaxEdits(targetMessage.attributes)
|
||||||
|
) {
|
||||||
throw new ErrorWithToast(
|
throw new ErrorWithToast(
|
||||||
`${idLog}: cannot edit`,
|
`${idLog}: cannot edit`,
|
||||||
ToastType.CannotEditMessage
|
ToastType.CannotEditMessage
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue