🎨 Autoformat code
This commit is contained in:
parent
2fae89f0e8
commit
424965f876
15 changed files with 158 additions and 140 deletions
|
@ -1,6 +1,8 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import * as MIME from './types/MIME';
|
||||
|
||||
|
||||
interface MIMETypeSupportMap {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
@ -24,7 +26,7 @@ const SUPPORTED_IMAGE_MIME_TYPES: MIMETypeSupportMap = {
|
|||
};
|
||||
|
||||
export const isImageTypeSupported = (mimeType: MIME.MIMEType): boolean =>
|
||||
SUPPORTED_IMAGE_MIME_TYPES[mimeType] === true;
|
||||
SUPPORTED_IMAGE_MIME_TYPES[mimeType] === true;
|
||||
|
||||
const SUPPORTED_VIDEO_MIME_TYPES: MIMETypeSupportMap = {
|
||||
'video/mp4': true,
|
||||
|
@ -34,4 +36,4 @@ const SUPPORTED_VIDEO_MIME_TYPES: MIMETypeSupportMap = {
|
|||
|
||||
// See: https://www.chromium.org/audio-video
|
||||
export const isVideoTypeSupported = (mimeType: MIME.MIMEType): boolean =>
|
||||
SUPPORTED_VIDEO_MIME_TYPES[mimeType] === true;
|
||||
SUPPORTED_VIDEO_MIME_TYPES[mimeType] === true;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
import { DocumentListEntry } from './DocumentListEntry';
|
||||
|
@ -5,13 +8,11 @@ import { ImageThumbnail } from './ImageThumbnail';
|
|||
import { Message } from './propTypes/Message';
|
||||
import { missingCaseError } from '../../../missingCaseError';
|
||||
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
width: '100%',
|
||||
},
|
||||
header: {
|
||||
},
|
||||
header: {},
|
||||
itemContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
|
@ -32,18 +33,14 @@ export class AttachmentListSection extends React.Component<Props, {}> {
|
|||
public renderItems() {
|
||||
const { i18n, messages, type } = this.props;
|
||||
|
||||
return messages.map((message) => {
|
||||
return messages.map(message => {
|
||||
const { attachments } = message;
|
||||
const firstAttachment = attachments[0];
|
||||
|
||||
switch (type) {
|
||||
case 'media':
|
||||
return (
|
||||
<ImageThumbnail
|
||||
key={message.id}
|
||||
i18n={i18n}
|
||||
message={message}
|
||||
/>
|
||||
<ImageThumbnail key={message.id} i18n={i18n} message={message} />
|
||||
);
|
||||
case 'documents':
|
||||
return (
|
||||
|
@ -67,9 +64,7 @@ export class AttachmentListSection extends React.Component<Props, {}> {
|
|||
return (
|
||||
<div style={styles.container}>
|
||||
<div style={styles.header}>{header}</div>
|
||||
<div style={styles.itemContainer}>
|
||||
{this.renderItems()}
|
||||
</div>
|
||||
<div style={styles.itemContainer}>{this.renderItems()}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
import moment from 'moment';
|
||||
|
@ -5,7 +8,6 @@ import formatFileSize from 'filesize';
|
|||
|
||||
// import { LoadingIndicator } from './LoadingIndicator';
|
||||
|
||||
|
||||
interface Props {
|
||||
fileName?: string;
|
||||
fileSize?: number;
|
||||
|
@ -59,28 +61,20 @@ export class DocumentListEntry extends React.Component<Props, {}> {
|
|||
// }
|
||||
|
||||
return (
|
||||
<div
|
||||
style={styles.itemContainer}
|
||||
>
|
||||
<div style={styles.itemContainer}>
|
||||
<img
|
||||
src="images/file.svg"
|
||||
width="48"
|
||||
height="48"
|
||||
style={styles.itemIcon}
|
||||
/>
|
||||
<div
|
||||
style={styles.itemMetadata}
|
||||
>
|
||||
<div style={styles.itemMetadata}>
|
||||
<strong>{fileName}</strong>
|
||||
<span
|
||||
style={styles.itemFileSize}
|
||||
>
|
||||
<span style={styles.itemFileSize}>
|
||||
{typeof fileSize === 'number' ? formatFileSize(fileSize) : ''}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={styles.itemDate}
|
||||
>
|
||||
<div style={styles.itemDate}>
|
||||
{moment(timestamp).format('ddd, MMM D, Y')}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -88,10 +82,6 @@ export class DocumentListEntry extends React.Component<Props, {}> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div style={styles.container}>
|
||||
{this.renderContent()}
|
||||
</div>
|
||||
);
|
||||
return <div style={styles.container}>{this.renderContent()}</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
import { LoadingIndicator } from './LoadingIndicator';
|
||||
|
@ -27,7 +30,7 @@ const styles = {
|
|||
|
||||
export class ImageThumbnail extends React.Component<Props, {}> {
|
||||
public renderContent() {
|
||||
const {/* i18n, */message } = this.props;
|
||||
const { /* i18n, */ message } = this.props;
|
||||
|
||||
if (!message.objectURL) {
|
||||
return <LoadingIndicator />;
|
||||
|
@ -45,10 +48,6 @@ export class ImageThumbnail extends React.Component<Props, {}> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div style={styles.container}>
|
||||
{this.renderContent()}
|
||||
</div>
|
||||
);
|
||||
return <div style={styles.container}>{this.renderContent()}</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
export const LoadingIndicator = () => {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
import moment from 'moment';
|
||||
|
@ -7,7 +10,6 @@ import { AttachmentListSection } from './AttachmentListSection';
|
|||
import { groupMessagesByDate } from './groupMessagesByDate';
|
||||
import { Message } from './propTypes/Message';
|
||||
|
||||
|
||||
type AttachmentType = 'media' | 'documents';
|
||||
|
||||
interface Props {
|
||||
|
@ -58,13 +60,12 @@ const Tab = ({
|
|||
onSelect,
|
||||
type,
|
||||
}: {
|
||||
isSelected: boolean,
|
||||
label: string,
|
||||
onSelect?: (event: TabSelectEvent) => void,
|
||||
type: AttachmentType,
|
||||
isSelected: boolean;
|
||||
label: string;
|
||||
onSelect?: (event: TabSelectEvent) => void;
|
||||
type: AttachmentType;
|
||||
}) => {
|
||||
const handleClick = onSelect ?
|
||||
() => onSelect({ type }) : undefined;
|
||||
const handleClick = onSelect ? () => onSelect({ type }) : undefined;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -76,7 +77,6 @@ const Tab = ({
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
export class MediaGallery extends React.Component<Props, State> {
|
||||
public state: State = {
|
||||
selectedTab: 'media',
|
||||
|
@ -101,16 +101,14 @@ export class MediaGallery extends React.Component<Props, State> {
|
|||
onSelect={this.handleTabSelect}
|
||||
/>
|
||||
</div>
|
||||
<div style={styles.attachmentsContainer}>
|
||||
{this.renderSections()}
|
||||
</div>
|
||||
<div style={styles.attachmentsContainer}>{this.renderSections()}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private handleTabSelect = (event: TabSelectEvent): void => {
|
||||
this.setState({selectedTab: event.type});
|
||||
}
|
||||
this.setState({ selectedTab: event.type });
|
||||
};
|
||||
|
||||
private renderSections() {
|
||||
const { i18n, media, documents } = this.props;
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import moment from 'moment';
|
||||
import { groupBy, sortBy } from 'lodash';
|
||||
import { compact, groupBy, sortBy } from 'lodash';
|
||||
|
||||
import { Message } from './propTypes/Message';
|
||||
|
||||
|
||||
export const groupMessagesByDate = (timestamp: number, messages: Array<Message>): any => {
|
||||
export const groupMessagesByDate = (
|
||||
timestamp: number,
|
||||
messages: Array<Message>
|
||||
): any => {
|
||||
const referenceDateTime = moment.utc(timestamp);
|
||||
const today = moment(referenceDateTime).startOf('day');
|
||||
const yesterday = moment(referenceDateTime).subtract(1, 'day').startOf('day');
|
||||
const yesterday = moment(referenceDateTime)
|
||||
.subtract(1, 'day')
|
||||
.startOf('day');
|
||||
const thisWeek = moment(referenceDateTime).startOf('isoWeek');
|
||||
const thisMonth = moment(referenceDateTime).startOf('month');
|
||||
|
||||
const sorted = sortBy(messages, (message) => -message.received_at);
|
||||
const annotations = sorted.map((message) => {
|
||||
const sorted = sortBy(messages, message => -message.received_at);
|
||||
const annotations = sorted.map(message => {
|
||||
const date = moment.utc(message.received_at);
|
||||
|
||||
if (date.isAfter(today)) {
|
||||
|
@ -42,7 +49,7 @@ export const groupMessagesByDate = (timestamp: number, messages: Array<Message>)
|
|||
}
|
||||
|
||||
return {
|
||||
order: (date.year() * 100) + date.month(),
|
||||
order: date.year() * 100 + date.month(),
|
||||
label: 'yearMonth',
|
||||
message,
|
||||
};
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
export interface Message {
|
||||
id: string;
|
||||
body?: string;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
// `missingCaseError` is useful for compile-time checking that all `case`s in
|
||||
// a `switch` statement have been handled, e.g.
|
||||
//
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import 'mocha';
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { groupMessagesByDate } from
|
||||
'../../../components/conversation/media-gallery/groupMessagesByDate';
|
||||
import { Message } from
|
||||
'../../../components/conversation/media-gallery/propTypes/Message';
|
||||
|
||||
import { groupMessagesByDate } from '../../../components/conversation/media-gallery/groupMessagesByDate';
|
||||
import { Message } from '../../../components/conversation/media-gallery/propTypes/Message';
|
||||
|
||||
const toMessage = (date: Date): Message => ({
|
||||
id: date.toUTCString(),
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import is from '@sindresorhus/is';
|
||||
|
||||
import * as GoogleChrome from '../GoogleChrome';
|
||||
import { MIMEType } from './MIME';
|
||||
|
||||
|
||||
export interface Attachment {
|
||||
fileName?: string;
|
||||
contentType?: MIMEType;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import is from '@sindresorhus/is';
|
||||
import { Message } from './Message';
|
||||
|
||||
|
||||
interface ConversationLastMessageUpdate {
|
||||
lastMessage: string | null;
|
||||
timestamp: number | null;
|
||||
|
@ -13,10 +15,10 @@ export const createLastMessageUpdate = ({
|
|||
lastMessage,
|
||||
lastMessageNotificationText,
|
||||
}: {
|
||||
currentLastMessageText: string | null,
|
||||
currentTimestamp: number | null,
|
||||
lastMessage: Message | null,
|
||||
lastMessageNotificationText: string | null,
|
||||
currentLastMessageText: string | null;
|
||||
currentTimestamp: number | null;
|
||||
lastMessage: Message | null;
|
||||
lastMessageNotificationText: string | null;
|
||||
}): ConversationLastMessageUpdate => {
|
||||
if (lastMessage === null) {
|
||||
return {
|
||||
|
@ -30,13 +32,14 @@ export const createLastMessageUpdate = ({
|
|||
const isExpiringMessage = is.object(lastMessage.expirationTimerUpdate);
|
||||
const shouldUpdateTimestamp = !isVerifiedChangeMessage && !isExpiringMessage;
|
||||
|
||||
const newTimestamp = shouldUpdateTimestamp ?
|
||||
lastMessage.sent_at :
|
||||
currentTimestamp;
|
||||
const newTimestamp = shouldUpdateTimestamp
|
||||
? lastMessage.sent_at
|
||||
: currentTimestamp;
|
||||
|
||||
const shouldUpdateLastMessageText = !isVerifiedChangeMessage;
|
||||
const newLastMessageText = shouldUpdateLastMessageText ?
|
||||
lastMessageNotificationText : currentLastMessageText;
|
||||
const newLastMessageText = shouldUpdateLastMessageText
|
||||
? lastMessageNotificationText
|
||||
: currentLastMessageText;
|
||||
|
||||
return {
|
||||
lastMessage: newLastMessageText,
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
export type MIMEType = string & { _mimeTypeBrand: any };
|
||||
|
||||
export const isJPEG = (value: MIMEType): boolean => value === 'image/jpeg';
|
||||
|
||||
export const isJPEG = (value: MIMEType): boolean =>
|
||||
value === 'image/jpeg';
|
||||
export const isImage = (value: MIMEType): boolean => value.startsWith('image/');
|
||||
|
||||
export const isImage = (value: MIMEType): boolean =>
|
||||
value.startsWith('image/');
|
||||
export const isVideo = (value: MIMEType): boolean => value.startsWith('video/');
|
||||
|
||||
export const isVideo = (value: MIMEType): boolean =>
|
||||
value.startsWith('video/');
|
||||
|
||||
export const isAudio = (value: MIMEType): boolean =>
|
||||
value.startsWith('audio/');
|
||||
export const isAudio = (value: MIMEType): boolean => value.startsWith('audio/');
|
||||
|
|
|
@ -1,52 +1,63 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import { Attachment } from './Attachment';
|
||||
|
||||
export type Message = IncomingMessage | OutgoingMessage | VerifiedChangeMessage;
|
||||
|
||||
export type Message
|
||||
= IncomingMessage
|
||||
| OutgoingMessage
|
||||
| VerifiedChangeMessage;
|
||||
export type IncomingMessage = Readonly<
|
||||
{
|
||||
type: 'incoming';
|
||||
// Required
|
||||
attachments: Array<Attachment>;
|
||||
id: string;
|
||||
received_at: number;
|
||||
|
||||
export type IncomingMessage = Readonly<{
|
||||
type: 'incoming';
|
||||
// Required
|
||||
attachments: Array<Attachment>;
|
||||
id: string;
|
||||
received_at: number;
|
||||
// Optional
|
||||
body?: string;
|
||||
decrypted_at?: number;
|
||||
errors?: Array<any>;
|
||||
flags?: number;
|
||||
source?: string;
|
||||
sourceDevice?: number;
|
||||
} & SharedMessageProperties &
|
||||
Message4 &
|
||||
ExpirationTimerUpdate
|
||||
>;
|
||||
|
||||
// Optional
|
||||
body?: string;
|
||||
decrypted_at?: number;
|
||||
errors?: Array<any>;
|
||||
flags?: number;
|
||||
source?: string;
|
||||
sourceDevice?: number;
|
||||
} & SharedMessageProperties & Message4 & ExpirationTimerUpdate>;
|
||||
export type OutgoingMessage = Readonly<
|
||||
{
|
||||
type: 'outgoing';
|
||||
|
||||
export type OutgoingMessage = Readonly<{
|
||||
type: 'outgoing';
|
||||
// Required
|
||||
attachments: Array<Attachment>;
|
||||
delivered: number;
|
||||
delivered_to: Array<string>;
|
||||
destination: string; // PhoneNumber
|
||||
expirationStartTimestamp: number;
|
||||
id: string;
|
||||
received_at: number;
|
||||
sent: boolean;
|
||||
sent_to: Array<string>; // Array<PhoneNumber>
|
||||
|
||||
// Required
|
||||
attachments: Array<Attachment>;
|
||||
delivered: number;
|
||||
delivered_to: Array<string>;
|
||||
destination: string; // PhoneNumber
|
||||
expirationStartTimestamp: number;
|
||||
id: string;
|
||||
received_at: number;
|
||||
sent: boolean;
|
||||
sent_to: Array<string>; // Array<PhoneNumber>
|
||||
// Optional
|
||||
body?: string;
|
||||
expires_at?: number;
|
||||
expireTimer?: number;
|
||||
recipients?: Array<string>; // Array<PhoneNumber>
|
||||
synced: boolean;
|
||||
} & SharedMessageProperties &
|
||||
Message4 &
|
||||
ExpirationTimerUpdate
|
||||
>;
|
||||
|
||||
// Optional
|
||||
body?: string;
|
||||
expires_at?: number;
|
||||
expireTimer?: number;
|
||||
recipients?: Array<string>; // Array<PhoneNumber>
|
||||
synced: boolean;
|
||||
} & SharedMessageProperties & Message4 & ExpirationTimerUpdate>;
|
||||
|
||||
export type VerifiedChangeMessage = Readonly<{
|
||||
type: 'verified-change';
|
||||
} & SharedMessageProperties & Message4 & ExpirationTimerUpdate>;
|
||||
export type VerifiedChangeMessage = Readonly<
|
||||
{
|
||||
type: 'verified-change';
|
||||
} & SharedMessageProperties &
|
||||
Message4 &
|
||||
ExpirationTimerUpdate
|
||||
>;
|
||||
|
||||
type SharedMessageProperties = Readonly<{
|
||||
conversationId: string;
|
||||
|
@ -59,7 +70,7 @@ type ExpirationTimerUpdate = Readonly<{
|
|||
expireTimer: number;
|
||||
fromSync: boolean;
|
||||
source: string; // PhoneNumber
|
||||
}>,
|
||||
}>;
|
||||
}>;
|
||||
|
||||
type Message4 = Readonly<{
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import { partition } from 'lodash';
|
||||
|
||||
import * as Attachment from '../Attachment';
|
||||
import { Message } from '../message';
|
||||
import { Message } from '../Message';
|
||||
|
||||
export const initializeAttachmentMetadata = async (
|
||||
message: Message
|
||||
): Promise<Message> => {
|
||||
const numAttachments = message.attachments.length;
|
||||
const [numVisualMediaAttachments, numFileAttachments] = partition(
|
||||
message.attachments,
|
||||
Attachment.isVisualMedia
|
||||
).map(attachments => attachments.length);
|
||||
|
||||
export const initializeAttachmentMetadata =
|
||||
async (message: Message): Promise<Message> => {
|
||||
const numAttachments = message.attachments.length;
|
||||
const [numVisualMediaAttachments, numFileAttachments] =
|
||||
partition(message.attachments, Attachment.isVisualMedia)
|
||||
.map((attachments) => attachments.length);
|
||||
|
||||
return {
|
||||
...message,
|
||||
numAttachments,
|
||||
numVisualMediaAttachments,
|
||||
numFileAttachments,
|
||||
};
|
||||
return {
|
||||
...message,
|
||||
numAttachments,
|
||||
numVisualMediaAttachments,
|
||||
numFileAttachments,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue