From f0fad6edfaaf54dff135f282a407fa4c1c8f773f Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 8 Jul 2021 16:43:32 +1000 Subject: [PATCH] uniformized props for Message --- ts/components/conversation/ContactName.tsx | 2 +- ts/components/conversation/Message.tsx | 19 +----- .../conversation/message/MessageMetadata.tsx | 12 ++-- .../message/OutgoingMessageStatus.tsx | 2 +- .../conversation/SessionConversation.tsx | 6 +- .../conversation/SessionMessagesList.tsx | 58 +++++++++++-------- ts/interactions/messageInteractions.ts | 2 +- ts/models/message.ts | 3 +- ts/models/messageType.ts | 19 +++--- ts/state/ducks/conversations.ts | 5 +- 10 files changed, 59 insertions(+), 69 deletions(-) diff --git a/ts/components/conversation/ContactName.tsx b/ts/components/conversation/ContactName.tsx index f897db492..d94806db6 100644 --- a/ts/components/conversation/ContactName.tsx +++ b/ts/components/conversation/ContactName.tsx @@ -5,7 +5,7 @@ import { Emojify } from './Emojify'; type Props = { phoneNumber: string; - name?: string; + name?: string | null; profileName?: string; module?: string; boldProfileName?: Boolean; diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 6a5d5a83d..666bcee49 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -29,7 +29,6 @@ import _ from 'lodash'; import { animation, contextMenu, Item, Menu } from 'react-contexify'; import uuid from 'uuid'; import { InView } from 'react-intersection-observer'; -import { withTheme } from 'styled-components'; import { MessageMetadata } from './message/MessageMetadata'; import { PubKey } from '../../session/types'; import { MessageRegularProps } from '../../models/messageType'; @@ -56,7 +55,7 @@ interface State { const EXPIRATION_CHECK_MINIMUM = 2000; const EXPIRED_DELAY = 600; -class MessageInner extends React.PureComponent { +export class Message extends React.PureComponent { public expirationCheckInterval: any; public expiredTimeout: any; public ctxMenuID: string; @@ -279,14 +278,7 @@ class MessageInner extends React.PureComponent { // tslint:disable-next-line cyclomatic-complexity public renderPreview() { - const { - attachments, - conversationType, - direction, - onClickLinkPreview, - previews, - quote, - } = this.props; + const { attachments, conversationType, direction, previews, quote } = this.props; // Attachments take precedence over Link Previews if (attachments && attachments.length) { @@ -316,11 +308,6 @@ class MessageInner extends React.PureComponent { 'module-message__link-preview', withContentAbove ? 'module-message__link-preview--with-content-above' : null )} - onClick={() => { - if (onClickLinkPreview) { - onClickLinkPreview(first.url); - } - }} > {first.image && previewHasImage && isFullSizeImage ? ( { await removeSenderFromModerator(this.props.authorPhoneNumber, this.props.convoId); } } - -export const Message = withTheme(MessageInner); diff --git a/ts/components/conversation/message/MessageMetadata.tsx b/ts/components/conversation/message/MessageMetadata.tsx index 01eaae99a..15b55adae 100644 --- a/ts/components/conversation/message/MessageMetadata.tsx +++ b/ts/components/conversation/message/MessageMetadata.tsx @@ -4,25 +4,24 @@ import { OutgoingMessageStatus } from './OutgoingMessageStatus'; import { MetadataBadges } from './MetadataBadge'; import { Timestamp } from '../Timestamp'; import { ExpireTimer } from '../ExpireTimer'; -import styled, { DefaultTheme } from 'styled-components'; +import styled, { DefaultTheme, useTheme } from 'styled-components'; import { MessageDeliveryStatus, MessageModelType } from '../../../models/messageType'; type Props = { disableMenu?: boolean; isAdmin?: boolean; isDeletable: boolean; - text?: string; + text?: string | null; id: string; collapseMetadata?: boolean; direction: MessageModelType; timestamp: number; serverTimestamp?: number; - status?: MessageDeliveryStatus; + status?: MessageDeliveryStatus | null; expirationLength?: number; expirationTimestamp?: number; isPublic?: boolean; isShowingImage: boolean; - theme: DefaultTheme; }; // for some reason, we have to extend a styled component as this: // props => @@ -68,9 +67,10 @@ export const MessageMetadata = (props: Props) => { isShowingImage, isPublic, isAdmin, - theme, } = props; + const theme = useTheme(); + if (collapseMetadata) { return null; } @@ -80,7 +80,7 @@ export const MessageMetadata = (props: Props) => { const showError = status === 'error' && isOutgoing; const showStatus = Boolean(status?.length && isOutgoing); - const messageStatusColor = withImageNoCaption ? 'white' : props.theme.colors.sentMessageText; + const messageStatusColor = withImageNoCaption ? 'white' : theme.colors.sentMessageText; return ( {showError ? ( diff --git a/ts/components/conversation/message/OutgoingMessageStatus.tsx b/ts/components/conversation/message/OutgoingMessageStatus.tsx index 1b7ce5a32..48118f910 100644 --- a/ts/components/conversation/message/OutgoingMessageStatus.tsx +++ b/ts/components/conversation/message/OutgoingMessageStatus.tsx @@ -61,7 +61,7 @@ const MessageStatusError = () => { }; export const OutgoingMessageStatus = (props: { - status?: MessageDeliveryStatus; + status?: MessageDeliveryStatus | null; iconColor: string; isInMessageView?: boolean; }) => { diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index 1c3fea4be..e94399cb5 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -26,6 +26,7 @@ import { ReduxConversationType, PropsForMessage, SortedMessageModelProps, + fetchMessagesForConversation, } from '../../../state/ducks/conversations'; import { MessageView } from '../../MainViewController'; import { pushUnblockToSend } from '../../../session/utils/Toast'; @@ -304,7 +305,7 @@ export class SessionConversation extends React.Component { Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT, unreadCount ); - window.inboxStore?.dispatch( + (window.inboxStore?.dispatch as any)( fetchMessagesForConversation({ conversationKey: selectedConversationKey, count: messagesToFetch, @@ -991,6 +992,3 @@ export class SessionConversation extends React.Component { window.inboxStore?.dispatch(updateMentionsMembers(allMembers)); } } -function fetchMessagesForConversation(arg0: { conversationKey: string; count: number }): any { - throw new Error('Function not implemented.'); -} diff --git a/ts/components/session/conversation/SessionMessagesList.tsx b/ts/components/session/conversation/SessionMessagesList.tsx index 0a01f0a2d..4603a2bad 100644 --- a/ts/components/session/conversation/SessionMessagesList.tsx +++ b/ts/components/session/conversation/SessionMessagesList.tsx @@ -10,7 +10,11 @@ import { contextMenu } from 'react-contexify'; import { AttachmentType } from '../../../types/Attachment'; import { GroupNotification } from '../../conversation/GroupNotification'; import { GroupInvitation } from '../../conversation/GroupInvitation'; -import { ReduxConversationType, SortedMessageModelProps } from '../../../state/ducks/conversations'; +import { + fetchMessagesForConversation, + ReduxConversationType, + SortedMessageModelProps, +} from '../../../state/ducks/conversations'; import { SessionLastSeenIndicator } from './SessionLastSeenIndicator'; import { ToastUtils } from '../../../session/utils'; import { TypingBubble } from '../../conversation/TypingBubble'; @@ -303,20 +307,12 @@ export class SessionMessagesList extends React.Component { multiSelectMode: boolean, playableMessageIndex: number ) { - const regularProps: MessageRegularProps = { ...messageProps.propsForMessage }; - const messageId = messageProps.propsForMessage.id; + const selected = !!messageProps?.propsForMessage.id && this.props.selectedMessages.includes(messageId); - regularProps.selected = selected; - regularProps.firstMessageOfSeries = firstMessageOfSeries; - - regularProps.multiSelectMode = multiSelectMode; - regularProps.onSelectMessage = this.props.selectMessage; - regularProps.onDeleteMessage = this.props.deleteMessage; - regularProps.onReply = this.props.replyToMessage; - regularProps.onShowDetail = async () => { + const onShowDetail = async () => { const found = await getMessageById(messageId); if (found) { const messageDetailsProps = await found.getPropsForMessageDetail(); @@ -327,10 +323,16 @@ export class SessionMessagesList extends React.Component { } }; - regularProps.onClickAttachment = (attachment: AttachmentType) => { + const onClickAttachment = (attachment: AttachmentType) => { this.props.onClickAttachment(attachment, messageProps.propsForMessage); }; - regularProps.onDownload = (attachment: AttachmentType) => { + + // tslint:disable-next-line: no-async-without-await + const onQuoteClick = messageProps.propsForMessage.quote + ? this.scrollToQuoteMessage + : async () => {}; + + const onDownload = (attachment: AttachmentType) => { const messageTimestamp = messageProps.propsForMessage.timestamp || messageProps.propsForMessage.serverTimestamp || @@ -343,14 +345,23 @@ export class SessionMessagesList extends React.Component { }); }; - regularProps.isQuotedMessageToAnimate = messageId === this.state.animateQuotedMessageId; - - // tslint:disable-next-line: no-async-without-await - const onQuoteClick = regularProps.quote ? this.scrollToQuoteMessage : async () => {}; - - regularProps.nextMessageToPlay = this.state.nextMessageToPlay; - regularProps.playableMessageIndex = playableMessageIndex; - regularProps.playNextMessage = this.playNextMessage; + const regularProps: MessageRegularProps = { + ...messageProps.propsForMessage, + selected, + firstMessageOfSeries, + multiSelectMode, + isQuotedMessageToAnimate: messageId === this.state.animateQuotedMessageId, + nextMessageToPlay: this.state.nextMessageToPlay, + playableMessageIndex, + onSelectMessage: this.props.selectMessage, + onDeleteMessage: this.props.deleteMessage, + onReply: this.props.replyToMessage, + onShowDetail, + onClickAttachment, + onDownload, + playNextMessage: this.playNextMessage, + onQuoteClick, + }; return ; } @@ -461,7 +472,7 @@ export class SessionMessagesList extends React.Component { const oldLen = messagesProps.length; const previousTopMessage = messagesProps[oldLen - 1]?.propsForMessage.id; - window.inboxStore?.dispatch( + (window.inboxStore?.dispatch as any)( fetchMessagesForConversation({ conversationKey, count: numMessages }) ); if (previousTopMessage && oldLen !== messagesProps.length) { @@ -623,6 +634,3 @@ export class SessionMessagesList extends React.Component { return scrollHeight - scrollTop - clientHeight; } } -function fetchMessagesForConversation(arg0: { conversationKey: string; count: number }): any { - throw new Error('Function not implemented.'); -} diff --git a/ts/interactions/messageInteractions.ts b/ts/interactions/messageInteractions.ts index bfc21fbd0..6c01091b5 100644 --- a/ts/interactions/messageInteractions.ts +++ b/ts/interactions/messageInteractions.ts @@ -111,7 +111,7 @@ export function unbanUser(userToUnBan: string, conversationId: string) { ); } -export function copyBodyToClipboard(body?: string) { +export function copyBodyToClipboard(body?: string | null) { window.clipboard.writeText(body); ToastUtils.pushCopiedToClipBoard(); diff --git a/ts/models/message.ts b/ts/models/message.ts index bb8321918..7ef692a51 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -548,7 +548,7 @@ export class MessageModel extends Backbone.Model { text: this.createNonBreakingLastSeparator(this.get('body')), id: this.id as string, direction: (this.isIncoming() ? 'incoming' : 'outgoing') as MessageModelType, - timestamp: this.get('sent_at'), + timestamp: this.get('sent_at') || 0, receivedAt: this.get('received_at'), serverTimestamp: this.get('serverTimestamp'), serverId: this.get('serverId'), @@ -574,6 +574,7 @@ export class MessageModel extends Backbone.Model { weAreAdmin, isDeletable, isSenderAdmin, + isExpired: this.isExpired(), }; return props; diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts index b4475a88b..2f11399a3 100644 --- a/ts/models/messageType.ts +++ b/ts/models/messageType.ts @@ -51,7 +51,7 @@ export interface MessageAttributes { * timestamp is the sent_at timestamp, which is the envelope.timestamp */ timestamp?: number; - status: MessageDeliveryStatus; + status?: MessageDeliveryStatus; dataMessage: any; sent_to: any; sent: boolean; @@ -202,20 +202,20 @@ export interface MessageRegularProps { isDeletable: boolean; isAdmin?: boolean; weAreAdmin?: boolean; - text?: string; + text: string | null; id: string; collapseMetadata?: boolean; direction: MessageModelType; timestamp: number; serverTimestamp?: number; - status?: MessageDeliveryStatus; + status?: MessageDeliveryStatus | null; // What if changed this over to a single contact like quote, and put the events on it? contact?: Contact & { onSendMessage?: () => void; onClick?: () => void; }; - authorName?: string; - authorProfileName?: string; + authorName?: string | null; + authorProfileName?: string | null; /** Note: this should be formatted for display */ authorPhoneNumber: string; conversationType: ConversationTypeEnum; @@ -247,16 +247,13 @@ export interface MessageRegularProps { isQuotedMessageToAnimate?: boolean; isTrustedForAttachmentDownload: boolean; - onClickAttachment?: (attachment: AttachmentType) => void; - onClickLinkPreview?: (url: string) => void; + onClickAttachment: (attachment: AttachmentType) => void; onSelectMessage: (messageId: string) => void; - onReply?: (messagId: number) => void; - onDownload?: (attachment: AttachmentType) => void; + onReply: (messagId: number) => void; + onDownload: (attachment: AttachmentType) => void; onDeleteMessage: (messageId: string) => void; onShowDetail: () => void; - markRead: (readAt: number) => Promise; onQuoteClick: (options: QuoteClickOptions) => Promise; - theme: DefaultTheme; playableMessageIndex?: number; nextMessageToPlay?: number; diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 679420629..d9dcd7080 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -137,7 +137,7 @@ export type PropsForMessage = { text: string | null; id: string; direction: MessageModelType; - timestamp: number | undefined; + timestamp: number; receivedAt: number | undefined; serverTimestamp: number | undefined; serverId: number | undefined; @@ -161,6 +161,7 @@ export type PropsForMessage = { weAreAdmin: boolean; isSenderAdmin: boolean; isDeletable: boolean; + isExpired: boolean; }; export type LastMessageType = { @@ -287,7 +288,7 @@ type FetchedMessageResults = { messagesProps: Array; }; -const fetchMessagesForConversation = createAsyncThunk( +export const fetchMessagesForConversation = createAsyncThunk( 'messages/fetchByConversationKey', async ({ conversationKey,