split Message metadatas rendering to a sub component

pull/1381/head
Audric Ackermann 4 years ago
parent 0a6a49eda5
commit 7f5515cf6b

@ -603,10 +603,6 @@
isRss: !!this.get('isRss'),
isKickedFromGroup:
conversation && conversation.get('isKickedFromGroup'),
senderIsModerator:
!!this.get('isPublic') &&
conversation &&
conversation.isModerator(phoneNumber),
isDeletable:
!this.get('isPublic') ||
isModerator ||

@ -4,10 +4,8 @@ import classNames from 'classnames';
import { Avatar } from '../Avatar';
import { Spinner } from '../Spinner';
import { MessageBody } from './MessageBody';
import { ExpireTimer } from './ExpireTimer';
import { ImageGrid } from './ImageGrid';
import { Image } from './Image';
import { Timestamp } from './Timestamp';
import { ContactName } from './ContactName';
import { Quote, QuotedAttachmentType } from './Quote';
import { EmbeddedContact } from './EmbeddedContact';
@ -38,10 +36,8 @@ import _ from 'lodash';
import { animation, contextMenu, Item, Menu } from 'react-contexify';
import uuid from 'uuid';
import { InView } from 'react-intersection-observer';
import { MetadataBadges } from './message/MetadataBadge';
import { MetadataSpacer } from './message/MetadataUtilComponent';
import { DefaultTheme, withTheme } from 'styled-components';
import { OutgoingMessageStatus } from './message/OutgoingMessageStatus';
import { MessageMetadata } from './message/MessageMetadata';
// Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -55,7 +51,6 @@ interface LinkPreviewType {
export interface Props {
disableMenu?: boolean;
senderIsModerator?: boolean;
isDeletable: boolean;
isModerator?: boolean;
text?: string;
@ -212,96 +207,6 @@ class MessageInner extends React.PureComponent<Props, State> {
});
}
public renderMetadataBadges(withImageNoCaption: boolean) {
const { direction, isPublic, senderIsModerator, id } = this.props;
return (
<MetadataBadges
direction={direction}
isPublic={isPublic}
senderIsModerator={senderIsModerator}
id={id}
withImageNoCaption={withImageNoCaption}
/>
);
}
public renderMetadata() {
const {
collapseMetadata,
direction,
expirationLength,
expirationTimestamp,
status,
text,
bodyPending,
timestamp,
serverTimestamp,
} = this.props;
if (collapseMetadata) {
return null;
}
const isOutgoing = direction === 'outgoing';
const isShowingImage = this.isShowingImage();
const withImageNoCaption = Boolean(!text && isShowingImage);
const showError = status === 'error' && isOutgoing;
const showStatus = Boolean(!bodyPending && status?.length && isOutgoing);
return (
<div
className={classNames(
'module-message__metadata',
withImageNoCaption
? 'module-message__metadata--with-image-no-caption'
: null
)}
>
{showError ? (
<span
className={classNames(
'module-message__metadata__date',
`module-message__metadata__date--${direction}`,
withImageNoCaption
? 'module-message__metadata__date--with-image-no-caption'
: null
)}
>
{window.i18n('sendFailed')}
</span>
) : (
<Timestamp
timestamp={serverTimestamp || timestamp}
extended={true}
direction={direction}
withImageNoCaption={withImageNoCaption}
module="module-message__metadata__date"
/>
)}
{this.renderMetadataBadges(withImageNoCaption)}
{expirationLength && expirationTimestamp ? (
<ExpireTimer
direction={direction}
expirationLength={expirationLength}
expirationTimestamp={expirationTimestamp}
withImageNoCaption={withImageNoCaption}
/>
) : null}
<MetadataSpacer />
{bodyPending ? <Spinner size="mini" direction={direction} /> : null}
<MetadataSpacer />
{showStatus ? (
<OutgoingMessageStatus
withImageNoCaption={withImageNoCaption}
theme={this.props.theme}
status={status}
/>
) : null}
</div>
);
}
// tslint:disable-next-line max-func-body-length cyclomatic-complexity
public renderAttachment() {
const {
@ -686,7 +591,7 @@ class MessageInner extends React.PureComponent<Props, State> {
authorPhoneNumber,
authorProfileName,
collapseMetadata,
senderIsModerator,
isModerator,
conversationType,
direction,
onShowUserDetails,
@ -717,7 +622,7 @@ class MessageInner extends React.PureComponent<Props, State> {
}}
pubkey={authorPhoneNumber}
/>
{senderIsModerator && (
{isModerator && (
<div className="module-avatar__icon--crown-wrapper">
<div className="module-avatar__icon--crown" />
</div>
@ -910,7 +815,7 @@ class MessageInner extends React.PureComponent<Props, State> {
return;
}
public isShowingImage() {
public isShowingImage(): boolean {
const { attachments, previews } = this.props;
const { imageBroken } = this.state;
@ -921,10 +826,10 @@ class MessageInner extends React.PureComponent<Props, State> {
if (attachments && attachments.length) {
const displayImage = canDisplayImage(attachments);
return (
return Boolean(
displayImage &&
((isImage(attachments) && hasImage(attachments)) ||
(isVideo(attachments) && hasVideoScreenshot(attachments)))
((isImage(attachments) && hasImage(attachments)) ||
(isVideo(attachments) && hasVideoScreenshot(attachments)))
);
}
@ -1078,7 +983,10 @@ class MessageInner extends React.PureComponent<Props, State> {
{this.renderPreview()}
{this.renderEmbeddedContact()}
{this.renderText()}
{this.renderMetadata()}
<MessageMetadata
{...this.props}
isShowingImage={this.isShowingImage()}
/>
</div>
{this.renderError(!isIncoming)}
{this.renderContextMenu()}

@ -0,0 +1,116 @@
import React from 'react';
import classNames from 'classnames';
import { MetadataSpacer } from './MetadataUtilComponent';
import { OutgoingMessageStatus } from './OutgoingMessageStatus';
import { Spinner } from '../../Spinner';
import { MetadataBadges } from './MetadataBadge';
import { Timestamp } from '../Timestamp';
import { ExpireTimer } from '../ExpireTimer';
import { DefaultTheme } from 'styled-components';
type Props = {
disableMenu?: boolean;
isModerator?: boolean;
isDeletable: boolean;
text?: string;
bodyPending?: boolean;
id: string;
collapseMetadata?: boolean;
direction: 'incoming' | 'outgoing';
timestamp: number;
serverTimestamp?: number;
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error' | 'pow';
expirationLength?: number;
expirationTimestamp?: number;
isPublic?: boolean;
isShowingImage: boolean;
theme: DefaultTheme;
};
export const MessageMetadata = (props: Props) => {
const {
id,
collapseMetadata,
direction,
expirationLength,
expirationTimestamp,
status,
text,
bodyPending,
timestamp,
serverTimestamp,
isShowingImage,
isPublic,
isModerator,
theme,
} = props;
if (collapseMetadata) {
return null;
}
const isOutgoing = direction === 'outgoing';
const withImageNoCaption = Boolean(!text && isShowingImage);
const showError = status === 'error' && isOutgoing;
const showStatus = Boolean(!bodyPending && status?.length && isOutgoing);
return (
<div
className={classNames(
'module-message__metadata',
withImageNoCaption
? 'module-message__metadata--with-image-no-caption'
: null
)}
>
{showError ? (
<span
className={classNames(
'module-message__metadata__date',
`module-message__metadata__date--${direction}`,
withImageNoCaption
? 'module-message__metadata__date--with-image-no-caption'
: null
)}
>
{window.i18n('sendFailed')}
</span>
) : (
<Timestamp
timestamp={serverTimestamp || timestamp}
extended={true}
direction={direction}
withImageNoCaption={withImageNoCaption}
module="module-message__metadata__date"
/>
)}
<MetadataBadges
direction={direction}
isPublic={isPublic}
isModerator={isModerator}
id={id}
withImageNoCaption={withImageNoCaption}
/>
{expirationLength && expirationTimestamp ? (
<ExpireTimer
direction={direction}
expirationLength={expirationLength}
expirationTimestamp={expirationTimestamp}
withImageNoCaption={withImageNoCaption}
/>
) : null}
<MetadataSpacer />
{bodyPending ? <Spinner size="mini" direction={direction} /> : null}
<MetadataSpacer />
{showStatus ? (
<OutgoingMessageStatus
withImageNoCaption={withImageNoCaption}
theme={theme}
status={status}
/>
) : null}
</div>
);
};

@ -50,21 +50,15 @@ type BadgesProps = {
id: string;
direction: string;
isPublic?: boolean;
senderIsModerator?: boolean;
isModerator?: boolean;
withImageNoCaption: boolean;
};
export const MetadataBadges = (props: BadgesProps): JSX.Element => {
const {
id,
direction,
isPublic,
senderIsModerator,
withImageNoCaption,
} = props;
const { id, direction, isPublic, isModerator, withImageNoCaption } = props;
const badges = [
(isPublic && 'Public') || null,
(senderIsModerator && 'Mod') || null,
(isModerator && 'Mod') || null,
].filter(nonNullish);
if (!badges || badges.length === 0) {

@ -124,30 +124,30 @@ export function isImage(attachments?: Array<AttachmentType>) {
);
}
export function isImageAttachment(attachment: AttachmentType) {
return (
export function isImageAttachment(attachment: AttachmentType): boolean {
return Boolean(
attachment &&
attachment.contentType &&
isImageTypeSupported(attachment.contentType)
attachment.contentType &&
isImageTypeSupported(attachment.contentType)
);
}
export function hasImage(attachments?: Array<AttachmentType>) {
return (
export function hasImage(attachments?: Array<AttachmentType>): boolean {
return Boolean(
attachments &&
attachments[0] &&
(attachments[0].url || attachments[0].pending)
attachments[0] &&
(attachments[0].url || attachments[0].pending)
);
}
export function isVideo(attachments?: Array<AttachmentType>) {
return attachments && isVideoAttachment(attachments[0]);
export function isVideo(attachments?: Array<AttachmentType>): boolean {
return Boolean(attachments && isVideoAttachment(attachments[0]));
}
export function isVideoAttachment(attachment?: AttachmentType): boolean {
return (
return Boolean(
!!attachment &&
!!attachment.contentType &&
isVideoTypeSupported(attachment.contentType)
!!attachment.contentType &&
isVideoTypeSupported(attachment.contentType)
);
}

Loading…
Cancel
Save