Take an author object in <Message>

This commit is contained in:
Evan Hahn 2021-04-27 14:55:21 -05:00 committed by Scott Nonnenberg
parent bca664b5d9
commit 5f17d01f49
7 changed files with 67 additions and 71 deletions

View file

@ -66,12 +66,18 @@ const renderAudioAttachment: Props['renderAudioAttachment'] = props => (
<MessageAudioContainer {...props} /> <MessageAudioContainer {...props} />
); );
const createAuthorProp = (
overrides: Partial<Props['author']> = {}
): Props['author'] => ({
id: 'some-id',
color: select('authorColor', Colors, Colors[0]),
...overrides,
title: text('authorTitle', overrides.title || ''),
});
const createProps = (overrideProps: Partial<Props> = {}): Props => ({ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
attachments: overrideProps.attachments, attachments: overrideProps.attachments,
authorId: overrideProps.authorId || 'some-id', author: overrideProps.author || createAuthorProp(),
authorColor: select('authorColor', Colors, Colors[0]),
authorAvatarPath: overrideProps.authorAvatarPath,
authorTitle: text('authorTitle', overrideProps.authorTitle || ''),
bodyRanges: overrideProps.bodyRanges, bodyRanges: overrideProps.bodyRanges,
canReply: true, canReply: true,
canDownload: true, canDownload: true,
@ -212,7 +218,7 @@ story.add('Pending', () => {
story.add('Collapsed Metadata', () => { story.add('Collapsed Metadata', () => {
const props = createProps({ const props = createProps({
authorTitle: 'Fred Willard', author: createAuthorProp({ title: 'Fred Willard' }),
collapseMetadata: true, collapseMetadata: true,
conversationType: 'group', conversationType: 'group',
text: 'Hello there from a pal!', text: 'Hello there from a pal!',
@ -425,7 +431,7 @@ story.add('Reactions (short message)', () => {
story.add('Avatar in Group', () => { story.add('Avatar in Group', () => {
const props = createProps({ const props = createProps({
authorAvatarPath: pngUrl, author: createAuthorProp({ avatarPath: pngUrl }),
conversationType: 'group', conversationType: 'group',
status: 'sent', status: 'sent',
text: 'Hello it is me, the saxophone.', text: 'Hello it is me, the saxophone.',
@ -921,15 +927,16 @@ story.add('Dangerous File Type', () => {
}); });
story.add('Colors', () => { story.add('Colors', () => {
const defaultProps = createProps({
text:
'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
});
return ( return (
<> <>
{Colors.map(color => ( {Colors.map(color => (
<Message {...defaultProps} authorColor={color} /> <Message
{...createProps({
author: createAuthorProp({ color }),
text:
'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
})}
/>
))} ))}
</> </>
); );

View file

@ -8,6 +8,7 @@ import { drop, groupBy, orderBy, take } from 'lodash';
import { ContextMenu, ContextMenuTrigger, MenuItem } from 'react-contextmenu'; import { ContextMenu, ContextMenuTrigger, MenuItem } from 'react-contextmenu';
import { Manager, Popper, Reference } from 'react-popper'; import { Manager, Popper, Reference } from 'react-popper';
import { ConversationType } from '../../state/ducks/conversations';
import { Avatar } from '../Avatar'; import { Avatar } from '../Avatar';
import { Spinner } from '../Spinner'; import { Spinner } from '../Spinner';
import { MessageBody } from './MessageBody'; import { MessageBody } from './MessageBody';
@ -105,12 +106,16 @@ export type PropsData = {
timestamp: number; timestamp: number;
status?: MessageStatusType; status?: MessageStatusType;
contact?: ContactType; contact?: ContactType;
authorId: string; author: Pick<
authorTitle: string; ConversationType,
authorName?: string; | 'avatarPath'
authorProfileName?: string; | 'color'
authorPhoneNumber?: string; | 'id'
authorColor?: ColorType; | 'name'
| 'phoneNumber'
| 'profileName'
| 'title'
>;
conversationType: ConversationTypesType; conversationType: ConversationTypesType;
attachments?: Array<AttachmentType>; attachments?: Array<AttachmentType>;
quote?: { quote?: {
@ -128,7 +133,6 @@ export type PropsData = {
referencedMessageNotFound: boolean; referencedMessageNotFound: boolean;
}; };
previews: Array<LinkPreviewType>; previews: Array<LinkPreviewType>;
authorAvatarPath?: string;
isExpired?: boolean; isExpired?: boolean;
isTapToView?: boolean; isTapToView?: boolean;
@ -633,10 +637,7 @@ export class Message extends React.Component<Props, State> {
public renderAuthor(): JSX.Element | null { public renderAuthor(): JSX.Element | null {
const { const {
authorTitle, author,
authorName,
authorPhoneNumber,
authorProfileName,
collapseMetadata, collapseMetadata,
conversationType, conversationType,
direction, direction,
@ -653,7 +654,7 @@ export class Message extends React.Component<Props, State> {
if ( if (
direction !== 'incoming' || direction !== 'incoming' ||
conversationType !== 'group' || conversationType !== 'group' ||
!authorTitle !author.title
) { ) {
return null; return null;
} }
@ -669,10 +670,10 @@ export class Message extends React.Component<Props, State> {
return ( return (
<div className={moduleName}> <div className={moduleName}>
<ContactName <ContactName
title={authorTitle} title={author.title}
phoneNumber={authorPhoneNumber} phoneNumber={author.phoneNumber}
name={authorName} name={author.name}
profileName={authorProfileName} profileName={author.profileName}
module={moduleName} module={moduleName}
i18n={i18n} i18n={i18n}
/> />
@ -996,8 +997,8 @@ export class Message extends React.Component<Props, State> {
public renderQuote(): JSX.Element | null { public renderQuote(): JSX.Element | null {
const { const {
author,
conversationType, conversationType,
authorColor,
direction, direction,
disableScroll, disableScroll,
i18n, i18n,
@ -1012,7 +1013,7 @@ export class Message extends React.Component<Props, State> {
const withContentAbove = const withContentAbove =
conversationType === 'group' && direction === 'incoming'; conversationType === 'group' && direction === 'incoming';
const quoteColor = const quoteColor =
direction === 'incoming' ? authorColor : quote.authorColor; direction === 'incoming' ? author.color : quote.authorColor;
const { referencedMessageNotFound } = quote; const { referencedMessageNotFound } = quote;
const clickHandler = disableScroll const clickHandler = disableScroll
@ -1104,14 +1105,8 @@ export class Message extends React.Component<Props, State> {
public renderAvatar(): JSX.Element | undefined { public renderAvatar(): JSX.Element | undefined {
const { const {
authorAvatarPath, author,
authorId,
authorName,
authorPhoneNumber,
authorProfileName,
authorTitle,
collapseMetadata, collapseMetadata,
authorColor,
conversationType, conversationType,
direction, direction,
i18n, i18n,
@ -1135,18 +1130,18 @@ export class Message extends React.Component<Props, State> {
<button <button
type="button" type="button"
className="module-message__author-avatar" className="module-message__author-avatar"
onClick={() => showContactModal(authorId)} onClick={() => showContactModal(author.id)}
tabIndex={0} tabIndex={0}
> >
<Avatar <Avatar
avatarPath={authorAvatarPath} avatarPath={author.avatarPath}
color={authorColor} color={author.color}
conversationType="direct" conversationType="direct"
i18n={i18n} i18n={i18n}
name={authorName} name={author.name}
phoneNumber={authorPhoneNumber} phoneNumber={author.phoneNumber}
profileName={authorProfileName} profileName={author.profileName}
title={authorTitle} title={author.title}
size={28} size={28}
/> />
</button> </button>
@ -2191,7 +2186,7 @@ export class Message extends React.Component<Props, State> {
public renderContainer(): JSX.Element { public renderContainer(): JSX.Element {
const { const {
authorColor, author,
deletedForEveryone, deletedForEveryone,
direction, direction,
isSticker, isSticker,
@ -2216,13 +2211,13 @@ export class Message extends React.Component<Props, State> {
? 'module-message__container--with-tap-to-view-expired' ? 'module-message__container--with-tap-to-view-expired'
: null, : null,
!isSticker && direction === 'incoming' !isSticker && direction === 'incoming'
? `module-message__container--incoming-${authorColor}` ? `module-message__container--incoming-${author.color}`
: null, : null,
isTapToView && isAttachmentPending && !isTapToViewExpired isTapToView && isAttachmentPending && !isTapToViewExpired
? 'module-message__container--with-tap-to-view-pending' ? 'module-message__container--with-tap-to-view-pending'
: null, : null,
isTapToView && isAttachmentPending && !isTapToViewExpired isTapToView && isAttachmentPending && !isTapToViewExpired
? `module-message__container--${direction}-${authorColor}-tap-to-view-pending` ? `module-message__container--${direction}-${author.color}-tap-to-view-pending`
: null, : null,
isTapToViewError isTapToViewError
? 'module-message__container--with-tap-to-view-error' ? 'module-message__container--with-tap-to-view-error'
@ -2249,7 +2244,7 @@ export class Message extends React.Component<Props, State> {
public render(): JSX.Element | null { public render(): JSX.Element | null {
const { const {
authorId, author,
attachments, attachments,
direction, direction,
id, id,
@ -2260,7 +2255,7 @@ export class Message extends React.Component<Props, State> {
// This id is what connects our triple-dot click with our associated pop-up menu. // This id is what connects our triple-dot click with our associated pop-up menu.
// It needs to be unique. // It needs to be unique.
const triggerId = String(id || `${authorId}-${timestamp}`); const triggerId = String(id || `${author.id}-${timestamp}`);
if (expired) { if (expired) {
return null; return null;

View file

@ -17,8 +17,10 @@ const i18n = setupI18n('en', enMessages);
const story = storiesOf('Components/Conversation/MessageDetail', module); const story = storiesOf('Components/Conversation/MessageDetail', module);
const defaultMessage: MessageDataPropsType = { const defaultMessage: MessageDataPropsType = {
authorId: 'some-id', author: {
authorTitle: 'Max', id: 'some-id',
title: 'Max',
},
canReply: true, canReply: true,
canDeleteForEveryone: true, canDeleteForEveryone: true,
canDownload: true, canDownload: true,

View file

@ -27,8 +27,10 @@ const i18n = setupI18n('en', enMessages);
const story = storiesOf('Components/Conversation/Quote', module); const story = storiesOf('Components/Conversation/Quote', module);
const defaultMessageProps: MessagesProps = { const defaultMessageProps: MessagesProps = {
authorId: 'some-id', author: {
authorTitle: 'Person X', id: 'some-id',
title: 'Person X',
},
canReply: true, canReply: true,
canDeleteForEveryone: true, canDeleteForEveryone: true,
canDownload: true, canDownload: true,

View file

@ -84,8 +84,10 @@ storiesOf('Components/Conversation/TimelineItem', module)
id: 'id-1', id: 'id-1',
direction: 'incoming', direction: 'incoming',
timestamp: Date.now(), timestamp: Date.now(),
authorPhoneNumber: '(202) 555-2001', author: {
authorColor: 'green', phoneNumber: '(202) 555-2001',
color: 'green',
},
text: '🔥', text: '🔥',
}, },
} as TimelineItemProps['item']; } as TimelineItemProps['item'];

View file

@ -884,12 +884,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
getPropsForMessage(): PropsForMessage { getPropsForMessage(): PropsForMessage {
const sourceId = this.getContactId(); const sourceId = this.getContactId();
const contact = this.findAndFormatContact(sourceId); const contact = this.findAndFormatContact(sourceId);
const contactModel = this.findContact(sourceId);
const authorColor = contactModel ? contactModel.getColor() : undefined;
const authorAvatarPath = contactModel
? contactModel.getAbsoluteAvatarPath()
: undefined;
const expirationLength = this.get('expireTimer') * 1000; const expirationLength = this.get('expireTimer') * 1000;
const expireTimerStart = this.get('expirationStartTimestamp'); const expireTimerStart = this.get('expirationStartTimestamp');
@ -921,6 +915,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
).emoji; ).emoji;
return { return {
author: contact,
text: this.createNonBreakingLastSeparator(this.get('body')), text: this.createNonBreakingLastSeparator(this.get('body')),
textPending: this.get('bodyPending'), textPending: this.get('bodyPending'),
id: this.id, id: this.id,
@ -933,17 +928,10 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
canReply: this.canReply(), canReply: this.canReply(),
canDeleteForEveryone: this.canDeleteForEveryone(), canDeleteForEveryone: this.canDeleteForEveryone(),
canDownload: this.canDownload(), canDownload: this.canDownload(),
authorId: contact.id,
authorTitle: contact.title,
authorColor,
authorName: contact.name,
authorProfileName: contact.profileName,
authorPhoneNumber: contact.phoneNumber,
conversationType: isGroup ? 'group' : 'direct', conversationType: isGroup ? 'group' : 'direct',
attachments: this.getAttachmentsForMessage(), attachments: this.getAttachmentsForMessage(),
previews: this.getPropsForPreview(), previews: this.getPropsForPreview(),
quote: this.getPropsForQuote(), quote: this.getPropsForQuote(),
authorAvatarPath,
isExpired: this.hasExpired, isExpired: this.hasExpired,
expirationLength, expirationLength,
expirationTimestamp, expirationTimestamp,

View file

@ -16573,7 +16573,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();", "line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();",
"lineNumber": 242, "lineNumber": 246,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2021-03-05T19:57:01.431Z", "updated": "2021-03-05T19:57:01.431Z",
"reasonDetail": "Used for managing focus only" "reasonDetail": "Used for managing focus only"
@ -16582,7 +16582,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " public audioButtonRef: React.RefObject<HTMLButtonElement> = React.createRef();", "line": " public audioButtonRef: React.RefObject<HTMLButtonElement> = React.createRef();",
"lineNumber": 244, "lineNumber": 248,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2021-03-05T19:57:01.431Z", "updated": "2021-03-05T19:57:01.431Z",
"reasonDetail": "Used for propagating click from the Message to MessageAudio's button" "reasonDetail": "Used for propagating click from the Message to MessageAudio's button"
@ -16591,7 +16591,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " public reactionsContainerRef: React.RefObject<HTMLDivElement> = React.createRef();", "line": " public reactionsContainerRef: React.RefObject<HTMLDivElement> = React.createRef();",
"lineNumber": 246, "lineNumber": 250,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2021-03-05T19:57:01.431Z", "updated": "2021-03-05T19:57:01.431Z",
"reasonDetail": "Used for detecting clicks outside reaction viewer" "reasonDetail": "Used for detecting clicks outside reaction viewer"