Improve types for ConversationType's lastMessage

This commit is contained in:
Evan Hahn 2021-09-20 14:20:53 -05:00 committed by GitHub
parent c19a801b89
commit 4e43459d34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 68 deletions

View file

@ -230,6 +230,7 @@ story.add('Contact checkboxes: disabled', () => (
MessageStatuses.reduce((m, s) => ({ ...m, [s]: s }), {}), MessageStatuses.reduce((m, s) => ({ ...m, [s]: s }), {}),
'read' 'read'
), ),
deletedForEveryone: false,
}, },
lastUpdated: date( lastUpdated: date(
'lastUpdated', 'lastUpdated',
@ -264,6 +265,7 @@ story.add('Contact checkboxes: disabled', () => (
lastMessage: { lastMessage: {
text: 'Just a second', text: 'Just a second',
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
name: 'Myself', name: 'Myself',
title: 'Myself', title: 'Myself',
@ -277,7 +279,7 @@ story.add('Contact checkboxes: disabled', () => (
MessageStatuses.map(status => ({ MessageStatuses.map(status => ({
type: RowType.Conversation, type: RowType.Conversation,
conversation: createConversation({ conversation: createConversation({
lastMessage: { text: status, status }, lastMessage: { text: status, status, deletedForEveryone: false },
}), }),
})) }))
)} )}
@ -302,11 +304,7 @@ story.add('Contact checkboxes: disabled', () => (
story.add('Conversation: Deleted for everyone', () => story.add('Conversation: Deleted for everyone', () =>
renderConversation({ renderConversation({
lastMessage: { lastMessage: { deletedForEveryone: true },
status: 'sent',
text: 'You should not see this!',
deletedForEveryone: true,
},
}) })
); );
@ -316,6 +314,7 @@ story.add('Contact checkboxes: disabled', () => (
lastMessage: { lastMessage: {
text: 'A Message', text: 'A Message',
status: 'delivered', status: 'delivered',
deletedForEveryone: false,
}, },
}) })
); );
@ -326,7 +325,11 @@ story.add('Contact checkboxes: disabled', () => (
[4, 10, 250].map(unreadCount => ({ [4, 10, 250].map(unreadCount => ({
type: RowType.Conversation, type: RowType.Conversation,
conversation: createConversation({ conversation: createConversation({
lastMessage: { text: 'Hey there!', status: 'delivered' }, lastMessage: {
text: 'Hey there!',
status: 'delivered',
deletedForEveryone: false,
},
unreadCount, unreadCount,
}), }),
})) }))
@ -343,6 +346,7 @@ story.add('Contact checkboxes: disabled', () => (
lastMessage: { lastMessage: {
text: 'Hey there!', text: 'Hey there!',
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
isSelected: true, isSelected: true,
}) })
@ -353,6 +357,7 @@ story.add('Contact checkboxes: disabled', () => (
lastMessage: { lastMessage: {
text: '🔥', text: '🔥',
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
}) })
); );
@ -362,6 +367,7 @@ story.add('Contact checkboxes: disabled', () => (
lastMessage: { lastMessage: {
text: 'Download at http://signal.org', text: 'Download at http://signal.org',
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
}) })
); );
@ -394,6 +400,7 @@ Line 4, well.`,
lastMessage: { lastMessage: {
text: messageText, text: messageText,
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
}), }),
})) }))
@ -420,6 +427,7 @@ Line 4, well.`,
lastMessage: { lastMessage: {
text: messageText, text: messageText,
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
}), }),
})) }))
@ -449,9 +457,9 @@ Line 4, well.`,
story.add('Conversation: Missing Text', () => story.add('Conversation: Missing Text', () =>
renderConversation({ renderConversation({
lastMessage: { lastMessage: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any text: '',
text: undefined as any,
status: 'sent', status: 'sent',
deletedForEveryone: false,
}, },
}) })
); );
@ -469,6 +477,7 @@ Line 4, well.`,
lastMessage: { lastMessage: {
text: '@Leia Organa I know', text: '@Leia Organa I know',
status: 'read', status: 'read',
deletedForEveryone: false,
}, },
}) })
); );

View file

@ -97,60 +97,44 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
let messageText: ReactNode = null; let messageText: ReactNode = null;
let messageStatusIcon: ReactNode = null; let messageStatusIcon: ReactNode = null;
if (lastMessage || typingContact) { if (!acceptedMessageRequest) {
const messageBody = lastMessage ? lastMessage.text : ''; messageText = (
const showingDraft = shouldShowDraft && draftPreview; <span className={`${MESSAGE_TEXT_CLASS_NAME}__message-request`}>
const deletedForEveryone = Boolean( {i18n('ConversationListItem--message-request')}
lastMessage && lastMessage.deletedForEveryone </span>
); );
} else if (typingContact) {
/* eslint-disable no-nested-ternary */ messageText = <TypingAnimation i18n={i18n} />;
} else if (shouldShowDraft && draftPreview) {
messageText = ( messageText = (
<> <>
{muteExpiresAt && Date.now() < muteExpiresAt ? ( <span className={`${MESSAGE_TEXT_CLASS_NAME}__draft-prefix`}>
<span className={`${MESSAGE_TEXT_CLASS_NAME}__muted`} /> {i18n('ConversationListItem--draft-prefix')}
) : null} </span>
{!acceptedMessageRequest ? ( <MessageBody
<span className={`${MESSAGE_TEXT_CLASS_NAME}__message-request`}> text={truncateMessageText(draftPreview)}
{i18n('ConversationListItem--message-request')} disableJumbomoji
</span> disableLinks
) : typingContact ? ( i18n={i18n}
<TypingAnimation i18n={i18n} /> />
) : (
<>
{showingDraft ? (
<>
<span className={`${MESSAGE_TEXT_CLASS_NAME}__draft-prefix`}>
{i18n('ConversationListItem--draft-prefix')}
</span>
<MessageBody
text={truncateMessageText(draftPreview)}
disableJumbomoji
disableLinks
i18n={i18n}
/>
</>
) : deletedForEveryone ? (
<span
className={`${MESSAGE_TEXT_CLASS_NAME}__deleted-for-everyone`}
>
{i18n('message--deletedForEveryone')}
</span>
) : (
<MessageBody
text={truncateMessageText(messageBody)}
disableJumbomoji
disableLinks
i18n={i18n}
/>
)}
</>
)}
</> </>
); );
/* eslint-enable no-nested-ternary */ } else if (lastMessage?.deletedForEveryone) {
messageText = (
if (!showingDraft && lastMessage && lastMessage.status) { <span className={`${MESSAGE_TEXT_CLASS_NAME}__deleted-for-everyone`}>
{i18n('message--deletedForEveryone')}
</span>
);
} else if (lastMessage) {
messageText = (
<MessageBody
text={truncateMessageText(lastMessage.text)}
disableJumbomoji
disableLinks
i18n={i18n}
/>
);
if (lastMessage.status) {
messageStatusIcon = ( messageStatusIcon = (
<div <div
className={classNames( className={classNames(
@ -162,6 +146,16 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
} }
} }
const isMuted = Boolean(muteExpiresAt && Date.now() < muteExpiresAt);
if (isMuted) {
messageText = (
<>
<span className={`${MESSAGE_TEXT_CLASS_NAME}__muted`} />
{messageText}
</>
);
}
const onClickItem = useCallback(() => onClick(id), [onClick, id]); const onClickItem = useCallback(() => onClick(id), [onClick, id]);
return ( return (

View file

@ -7,6 +7,7 @@ import { compact } from 'lodash';
import { import {
ConversationAttributesType, ConversationAttributesType,
ConversationModelCollectionType, ConversationModelCollectionType,
LastMessageStatus,
MessageAttributesType, MessageAttributesType,
MessageModelCollectionType, MessageModelCollectionType,
QuotedMessageType, QuotedMessageType,
@ -50,6 +51,7 @@ import { BodyRangesType } from '../types/Util';
import { getTextWithMentions } from '../util'; import { getTextWithMentions } from '../util';
import { migrateColor } from '../util/migrateColor'; import { migrateColor } from '../util/migrateColor';
import { isNotNil } from '../util/isNotNil'; import { isNotNil } from '../util/isNotNil';
import { dropNull } from '../util/dropNull';
import { ourProfileKeyService } from '../services/ourProfileKey'; import { ourProfileKeyService } from '../services/ourProfileKey';
import { getSendOptions } from '../util/getSendOptions'; import { getSendOptions } from '../util/getSendOptions';
import { isConversationAccepted } from '../util/isConversationAccepted'; import { isConversationAccepted } from '../util/isConversationAccepted';
@ -1348,6 +1350,28 @@ export class ConversationModel extends window.Backbone
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const color = this.getColor()!; const color = this.getColor()!;
let lastMessage:
| undefined
| {
status?: LastMessageStatus;
text: string;
deletedForEveryone: false;
}
| { deletedForEveryone: true };
if (this.get('lastMessageDeletedForEveryone')) {
lastMessage = { deletedForEveryone: true };
} else {
const lastMessageText = this.get('lastMessage');
if (lastMessageText) {
lastMessage = {
status: dropNull(this.get('lastMessageStatus')),
text: lastMessageText,
deletedForEveryone: false,
};
}
}
const typingValues = window._.values(this.contactTypingTimers || {}); const typingValues = window._.values(this.contactTypingTimers || {});
const typingMostRecent = window._.first( const typingMostRecent = window._.first(
window._.sortBy(typingValues, 'timestamp') window._.sortBy(typingValues, 'timestamp')
@ -1440,11 +1464,7 @@ export class ConversationModel extends window.Backbone
isUntrusted: this.isUntrusted(), isUntrusted: this.isUntrusted(),
isVerified: this.isVerified(), isVerified: this.isVerified(),
isFetchingUUID: this.isFetchingUUID, isFetchingUUID: this.isFetchingUUID,
lastMessage: { lastMessage,
status: this.get('lastMessageStatus')!,
text: this.get('lastMessage')!,
deletedForEveryone: this.get('lastMessageDeletedForEveryone')!,
},
lastUpdated: this.get('timestamp')!, lastUpdated: this.get('timestamp')!,
left: Boolean(this.get('left')), left: Boolean(this.get('left')),
markedUnread: this.get('markedUnread')!, markedUnread: this.get('markedUnread')!,

View file

@ -116,11 +116,13 @@ export type ConversationType = {
timestamp?: number; timestamp?: number;
inboxPosition?: number; inboxPosition?: number;
left?: boolean; left?: boolean;
lastMessage?: { lastMessage?:
status: LastMessageStatus; | {
text: string; status?: LastMessageStatus;
deletedForEveryone?: boolean; text: string;
}; deletedForEveryone: false;
}
| { deletedForEveryone: true };
markedUnread?: boolean; markedUnread?: boolean;
phoneNumber?: string; phoneNumber?: string;
membersCount?: number; membersCount?: number;