Render attachments grouped by date

This commit is contained in:
Daniel Gasienica 2018-04-12 20:56:05 -04:00
parent e34347f290
commit d7b21ef5dc
7 changed files with 104 additions and 32 deletions

View file

@ -650,7 +650,8 @@
// Lightbox - or do we use the lightbox already in the app? // Lightbox - or do we use the lightbox already in the app?
const props = { const props = {
number: 10, media: [],
documents: [],
}; };
const view = new window.Whisper.ReactWrapper({ const view = new window.Whisper.ReactWrapper({

View file

@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import { ImageThumbnail } from './ImageThumbnail';
import { DocumentListEntry } from './DocumentListEntry'; import { DocumentListEntry } from './DocumentListEntry';
import { ImageThumbnail } from './ImageThumbnail';
import { Message } from './propTypes/Message'; import { Message } from './propTypes/Message';
import { missingCaseError } from '../../../missingCaseError';
const styles = { const styles = {
container: { container: {
@ -29,15 +31,34 @@ interface Props {
export class AttachmentListSection extends React.Component<Props, {}> { export class AttachmentListSection extends React.Component<Props, {}> {
public renderItems() { public renderItems() {
const { i18n, messages, type } = this.props; const { i18n, messages, type } = this.props;
const Component = type === 'media' ? ImageThumbnail : DocumentListEntry;
return messages.map((message) => ( return messages.map((message) => {
<Component const { attachments } = message;
key={message.id} const firstAttachment = attachments[0];
i18n={i18n}
message={message} switch (type) {
/> case 'media':
)); return (
<ImageThumbnail
key={message.id}
i18n={i18n}
message={message}
/>
);
case 'documents':
return (
<DocumentListEntry
key={message.id}
i18n={i18n}
fileSize={firstAttachment.size}
fileName={firstAttachment.fileName}
timestamp={message.received_at}
/>
);
default:
return missingCaseError(type);
}
});
} }
public render() { public render() {

View file

@ -7,7 +7,7 @@ import formatFileSize from 'filesize';
interface Props { interface Props {
fileName: string | null; fileName?: string;
fileSize?: number; fileSize?: number;
i18n: (key: string, values?: Array<string>) => string; i18n: (key: string, values?: Array<string>) => string;
timestamp: number; timestamp: number;

View file

@ -8,28 +8,38 @@ interface Props {
i18n: (value: string) => string; i18n: (value: string) => string;
} }
const size = {
width: 94,
height: 94,
};
const styles = { const styles = {
container: { container: {
...size,
backgroundColor: '#f3f3f3', backgroundColor: '#f3f3f3',
marginRight: 4, marginRight: 4,
marginBottom: 4, marginBottom: 4,
width: 94, },
height: 94, image: {
...size,
backgroundSize: 'cover',
}, },
}; };
export class ImageThumbnail extends React.Component<Props, {}> { export class ImageThumbnail extends React.Component<Props, {}> {
public renderContent() { public renderContent() {
const { i18n, message } = this.props; const {/* i18n, */message } = this.props;
if (!message.imageUrl) { if (!message.objectURL) {
return <LoadingIndicator />; return <LoadingIndicator />;
} }
return ( return (
<img <div
src={message.imageUrl} style={{
alt={`${i18n('messageCaption')}: ${message.body}`} ...styles.container,
...styles.image,
backgroundImage: `url("${message.objectURL}")`,
}}
/> />
); );
} }

View file

@ -10,24 +10,26 @@ const createRandomMessage = (props) => {
id: _.random(now).toString(), id: _.random(now).toString(),
received_at: _.random(now - YEAR_MS, now), received_at: _.random(now - YEAR_MS, now),
attachments: [{ attachments: [{
fileName,
data: null, data: null,
fileName,
size: _.random(1000, 1000 * 1000 * 50),
}], }],
// TODO: Revisit // TODO: Revisit
imageUrl: 'https://placekitten.com/94/94', objectURL: `https://placekitten.com/${_.random(50, 150)}/${_.random(50, 150)}`,
...props, ...props,
}; };
}; };
const startTime = Date.now(); const startTime = Date.now();
const messages = _.sortBy( const messages = _.sortBy(
_.range(30).map(createRandomMessage), _.range(25).map(createRandomMessage),
message => -message.received_at message => -message.received_at
); );
<MediaGallery <MediaGallery
i18n={(key) => key} i18n={window.i18n}
messages={messages} media={messages}
documents={messages}
/> />
``` ```

View file

@ -1,20 +1,26 @@
import React from 'react'; import React from 'react';
import moment from 'moment';
import { map } from 'lodash';
import { AttachmentListSection } from './AttachmentListSection'; import { AttachmentListSection } from './AttachmentListSection';
import { groupMessagesByDate } from './groupMessagesByDate';
import { Message } from './propTypes/Message'; import { Message } from './propTypes/Message';
type AttachmentType = 'media' | 'documents'; type AttachmentType = 'media' | 'documents';
interface Props { interface Props {
documents: Array<Message>;
i18n: (key: string, values?: Array<string>) => string; i18n: (key: string, values?: Array<string>) => string;
messages: Array<Message>; media: Array<Message>;
} }
interface State { interface State {
selectedTab: AttachmentType; selectedTab: AttachmentType;
} }
const MONTH_FORMAT = 'MMMM YYYY';
const COLOR_GREY = '#f3f3f3'; const COLOR_GREY = '#f3f3f3';
const tabStyle = { const tabStyle = {
@ -76,6 +82,10 @@ export class MediaGallery extends React.Component<Props, State> {
selectedTab: 'media', selectedTab: 'media',
}; };
private handleTabSelect = (event: TabSelectEvent): void => {
this.setState({selectedTab: event.type});
}
public render() { public render() {
const { selectedTab } = this.state; const { selectedTab } = this.state;
@ -96,17 +106,44 @@ export class MediaGallery extends React.Component<Props, State> {
/> />
</div> </div>
<div style={styles.attachmentsContainer}> <div style={styles.attachmentsContainer}>
<AttachmentListSection {this.renderSections()}
type={selectedTab}
i18n={this.props.i18n}
messages={this.props.messages}
/>
</div> </div>
</div> </div>
); );
} }
private handleTabSelect = (event: TabSelectEvent): void => { private renderSections() {
this.setState({selectedTab: event.type}); const { i18n, media, documents } = this.props;
const { selectedTab } = this.state;
const messages = selectedTab === 'media' ? media : documents;
const type = selectedTab;
if (!messages || messages.length === 0) {
// return <LoadingIndicator />;
return null;
}
const now = Date.now();
const groups = groupMessagesByDate(now, messages);
return map(groups, (annotations) => {
const first = annotations[0];
const date = moment(first.message.received_at);
const header = first.label === 'yearMonth'
? date.format(MONTH_FORMAT)
: i18n(first.label);
const groupMessages = map(annotations, 'message');
return (
<AttachmentListSection
key={header}
header={header}
i18n={i18n}
type={type}
messages={groupMessages}
/>
);
});
} }
} }

View file

@ -5,8 +5,9 @@ export interface Message {
attachments: Array<{ attachments: Array<{
data?: ArrayBuffer; data?: ArrayBuffer;
fileName?: string; fileName?: string;
size?: number;
}>; }>;
// TODO: Revisit // TODO: Revisit
imageUrl: string; objectURL?: string;
} }