Delete for everyone: Track sends and show failure states

This commit is contained in:
Scott Nonnenberg 2022-03-04 11:22:31 -08:00 committed by GitHub
parent 688cca1806
commit 0a52318be6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 426 additions and 60 deletions

View file

@ -104,6 +104,8 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
canReply: true,
canDownload: true,
canDeleteForEveryone: overrideProps.canDeleteForEveryone || false,
canRetry: overrideProps.canRetry || false,
canRetryDeleteForEveryone: overrideProps.canRetryDeleteForEveryone || false,
checkForAccount: action('checkForAccount'),
clearSelectedMessage: action('clearSelectedMessage'),
collapseMetadata: overrideProps.collapseMetadata,
@ -165,6 +167,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
renderAudioAttachment,
replyToMessage: action('replyToMessage'),
retrySend: action('retrySend'),
retryDeleteForEveryone: action('retryDeleteForEveryone'),
scrollToQuotedMessage: action('scrollToQuotedMessage'),
selectMessage: action('selectMessage'),
showContactDetail: action('showContactDetail'),
@ -574,13 +577,23 @@ story.add('Sticker', () => {
});
story.add('Deleted', () => {
const props = createProps({
const propsSent = createProps({
conversationType: 'group',
deletedForEveryone: true,
status: 'sent',
});
const propsSending = createProps({
conversationType: 'group',
deletedForEveryone: true,
status: 'sending',
});
return renderBothDirections(props);
return (
<>
{renderBothDirections(propsSent)}
{renderBothDirections(propsSending)}
</>
);
});
story.add('Deleted with expireTimer', () => {
@ -596,6 +609,30 @@ story.add('Deleted with expireTimer', () => {
return renderBothDirections(props);
});
story.add('Deleted with error', () => {
const propsPartialError = createProps({
timestamp: Date.now() - 60 * 1000,
canDeleteForEveryone: true,
conversationType: 'group',
deletedForEveryone: true,
status: 'partial-sent',
});
const propsError = createProps({
timestamp: Date.now() - 60 * 1000,
canDeleteForEveryone: true,
conversationType: 'group',
deletedForEveryone: true,
status: 'error',
});
return (
<>
{renderBothDirections(propsPartialError)}
{renderBothDirections(propsError)}
</>
);
});
story.add('Can delete for everyone', () => {
const props = createProps({
status: 'read',
@ -609,6 +646,7 @@ story.add('Can delete for everyone', () => {
story.add('Error', () => {
const props = createProps({
status: 'error',
canRetry: true,
text: 'I hope you get this.',
});
@ -1298,6 +1336,8 @@ story.add('All the context menus', () => {
],
status: 'partial-sent',
canDeleteForEveryone: true,
canRetry: true,
canRetryDeleteForEveryone: true,
});
return <Message {...props} direction="outgoing" />;

View file

@ -197,6 +197,8 @@ export type PropsData = {
deletedForEveryone?: boolean;
canRetry: boolean;
canRetryDeleteForEveryone: boolean;
canReact: boolean;
canReply: boolean;
canDownload: boolean;
@ -234,6 +236,7 @@ export type PropsActions = {
{ emoji, remove }: { emoji: string; remove: boolean }
) => void;
replyToMessage: (id: string) => void;
retryDeleteForEveryone: (id: string) => void;
retrySend: (id: string) => void;
showForwardMessageModal: (id: string) => void;
deleteMessage: (id: string) => void;
@ -424,7 +427,7 @@ export class Message extends React.PureComponent<Props, State> {
public override componentDidMount(): void {
const { conversationId } = this.props;
window.ConversationController.onConvoMessageMount(conversationId);
window.ConversationController?.onConvoMessageMount(conversationId);
this.startSelectedTimer();
this.startDeleteForEveryoneTimerIfApplicable();
@ -1486,29 +1489,24 @@ export class Message extends React.PureComponent<Props, State> {
canDownload,
canReact,
canReply,
canRetry,
canRetryDeleteForEveryone,
deleteMessage,
deleteMessageForEveryone,
deletedForEveryone,
direction,
i18n,
id,
isSticker,
isTapToView,
replyToMessage,
retrySend,
retryDeleteForEveryone,
showForwardMessageModal,
showMessageDetail,
status,
text,
} = this.props;
const canForward = !isTapToView && !deletedForEveryone;
const showRetry =
(status === 'paused' ||
status === 'error' ||
status === 'partial-sent') &&
direction === 'outgoing';
const multipleAttachments = attachments && attachments.length > 1;
const shouldShowAdditional =
@ -1583,7 +1581,7 @@ export class Message extends React.PureComponent<Props, State> {
>
{i18n('moreInfo')}
</MenuItem>
{showRetry ? (
{canRetry ? (
<MenuItem
attributes={{
className:
@ -1599,6 +1597,22 @@ export class Message extends React.PureComponent<Props, State> {
{i18n('retrySend')}
</MenuItem>
) : null}
{canRetryDeleteForEveryone ? (
<MenuItem
attributes={{
className:
'module-message__context--icon module-message__context__delete-message-for-everyone',
}}
onClick={(event: React.MouseEvent) => {
event.stopPropagation();
event.preventDefault();
retryDeleteForEveryone(id);
}}
>
{i18n('retryDeleteForEveryone')}
</MenuItem>
) : null}
{canForward ? (
<MenuItem
attributes={{

View file

@ -29,6 +29,8 @@ const defaultMessage: MessageDataPropsType = {
}),
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
canDeleteForEveryone: true,
canDownload: true,
conversationColor: 'crimson',
@ -84,6 +86,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
renderReactionPicker: () => <div />,
replyToMessage: action('replyToMessage'),
retrySend: action('retrySend'),
retryDeleteForEveryone: action('retryDeleteForEveryone'),
showContactDetail: action('showContactDetail'),
showContactModal: action('showContactModal'),
showExpiredIncomingTapToViewToast: action(

View file

@ -81,6 +81,7 @@ export type PropsBackboneActions = Pick<
| 'renderEmojiPicker'
| 'renderReactionPicker'
| 'replyToMessage'
| 'retryDeleteForEveryone'
| 'retrySend'
| 'showContactDetail'
| 'showContactModal'
@ -303,6 +304,7 @@ export class MessageDetail extends React.Component<Props, State> {
renderEmojiPicker,
renderReactionPicker,
replyToMessage,
retryDeleteForEveryone,
retrySend,
showContactDetail,
showContactModal,
@ -358,6 +360,7 @@ export class MessageDetail extends React.Component<Props, State> {
renderEmojiPicker={renderEmojiPicker}
renderReactionPicker={renderReactionPicker}
replyToMessage={replyToMessage}
retryDeleteForEveryone={retryDeleteForEveryone}
retrySend={retrySend}
showForwardMessageModal={showForwardMessageModal}
scrollToQuotedMessage={() => {

View file

@ -61,7 +61,9 @@ export const MessageMetadata: FunctionComponent<PropsType> = props => {
if (isError || isPartiallySent || isPaused) {
let statusInfo: React.ReactChild;
if (isError) {
statusInfo = i18n('sendFailed');
statusInfo = deletedForEveryone
? i18n('deleteFailed')
: i18n('sendFailed');
} else if (isPaused) {
statusInfo = i18n('sendPaused');
} else {
@ -76,7 +78,9 @@ export const MessageMetadata: FunctionComponent<PropsType> = props => {
showMessageDetail(id);
}}
>
{i18n('partiallySent')}
{deletedForEveryone
? i18n('partiallyDeleted')
: i18n('partiallySent')}
</button>
);
}
@ -136,7 +140,7 @@ export const MessageMetadata: FunctionComponent<PropsType> = props => {
<Spinner svgSize="small" size="14px" direction={direction} />
</div>
) : null}
{!deletedForEveryone &&
{(!deletedForEveryone || status === 'sending') &&
!textPending &&
direction === 'outgoing' &&
status !== 'error' &&

View file

@ -39,6 +39,8 @@ const defaultMessageProps: MessagesProps = {
}),
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
canDeleteForEveryone: true,
canDownload: true,
checkForAccount: action('checkForAccount'),
@ -78,6 +80,7 @@ const defaultMessageProps: MessagesProps = {
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
replyToMessage: action('default--replyToMessage'),
retrySend: action('default--retrySend'),
retryDeleteForEveryone: action('default--retryDeleteForEveryone'),
scrollToQuotedMessage: action('default--scrollToQuotedMessage'),
selectMessage: action('default--selectMessage'),
showContactDetail: action('default--showContactDetail'),

View file

@ -50,6 +50,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'forest',
conversationId: 'conversation-id',
conversationType: 'group',
@ -72,6 +74,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'forest',
conversationId: 'conversation-id',
conversationType: 'group',
@ -108,6 +112,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'crimson',
conversationId: 'conversation-id',
conversationType: 'group',
@ -205,6 +211,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'plum',
conversationId: 'conversation-id',
conversationType: 'group',
@ -228,6 +236,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'crimson',
conversationId: 'conversation-id',
conversationType: 'group',
@ -251,6 +261,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'crimson',
conversationId: 'conversation-id',
conversationType: 'group',
@ -274,6 +286,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'crimson',
conversationId: 'conversation-id',
conversationType: 'group',
@ -297,6 +311,8 @@ const items: Record<string, TimelineItemType> = {
canDownload: true,
canReact: true,
canReply: true,
canRetry: true,
canRetryDeleteForEveryone: true,
conversationColor: 'crimson',
conversationId: 'conversation-id',
conversationType: 'group',
@ -340,6 +356,7 @@ const actions = () => ({
reactToMessage: action('reactToMessage'),
replyToMessage: action('replyToMessage'),
retryDeleteForEveryone: action('retryDeleteForEveryone'),
retrySend: action('retrySend'),
deleteMessage: action('deleteMessage'),
deleteMessageForEveryone: action('deleteMessageForEveryone'),

View file

@ -217,6 +217,7 @@ const getActions = createSelector(
'checkForAccount',
'reactToMessage',
'replyToMessage',
'retryDeleteForEveryone',
'retrySend',
'showForwardMessageModal',
'deleteMessage',

View file

@ -63,6 +63,7 @@ const getDefaultProps = () => ({
clearSelectedMessage: action('clearSelectedMessage'),
contactSupport: action('contactSupport'),
replyToMessage: action('replyToMessage'),
retryDeleteForEveryone: action('retryDeleteForEveryone'),
retrySend: action('retrySend'),
deleteMessage: action('deleteMessage'),
deleteMessageForEveryone: action('deleteMessageForEveryone'),