import React from 'react'; import PropTypes from 'prop-types'; import { Thread, Message, localized, Utils, Actions, AttachmentStore, MessageStore, } from 'mailspring-exports'; import { RetinaImg, InjectedComponentSet, InjectedComponent } from 'mailspring-component-kit'; import MessageParticipants from './message-participants'; import MessageItemBody from './message-item-body'; import MessageTimestamp from './message-timestamp'; import MessageControls from './message-controls'; interface MessageItemProps { thread: Thread; message: Message; messages: Message[]; collapsed: boolean; pending: boolean; isMostRecent: boolean; className: string; } interface MessageItemState { filePreviewPaths: { [fileId: string]: string }; downloads: { [fileId: string]: null; }; detailedHeaders: boolean; } export default class MessageItem extends React.Component { static displayName = 'MessageItem'; static propTypes = { thread: PropTypes.object.isRequired, message: PropTypes.object.isRequired, messages: PropTypes.array.isRequired, collapsed: PropTypes.bool, pending: PropTypes.bool, isMostRecent: PropTypes.bool, className: PropTypes.string, }; _headerEl: HTMLElement; constructor(props, context) { super(props, context); const fileIds = this.props.message.fileIds(); this.state = { // Holds the downloadData (if any) for all of our files. It's a hash // keyed by a fileId. The value is the downloadData. downloads: AttachmentStore.getDownloadDataForFiles(fileIds), filePreviewPaths: AttachmentStore.previewPathsForFiles(fileIds), detailedHeaders: AppEnv.config.get('core.reading.detailedHeaders'), }; } private _storeUnlisten?: () => void; componentDidMount() { this._storeUnlisten = AttachmentStore.listen(this._onDownloadStoreChange); } shouldComponentUpdate(nextProps, nextState) { return !Utils.isEqualReact(nextProps, this.props) || !Utils.isEqualReact(nextState, this.state); } componentWillUnmount() { if (this._storeUnlisten) { this._storeUnlisten(); } } _onClickParticipants = (e: React.MouseEvent) => { let el = e.target as HTMLElement; while (el !== e.currentTarget) { if (el.classList.contains('collapsed-participants')) { this.setState({ detailedHeaders: true }); e.stopPropagation(); return; } el = el.parentElement; } return; }; _onClickHeader = e => { this._onToggleCollapsed(); }; _onDownloadAll = () => { Actions.fetchAndSaveAllFiles(this.props.message.files); }; _onToggleCollapsed = () => { if (this.props.isMostRecent) { return; } Actions.toggleMessageIdExpanded(this.props.message.id); }; _onDownloadStoreChange = () => { const fileIds = this.props.message.fileIds(); this.setState({ downloads: AttachmentStore.getDownloadDataForFiles(fileIds), filePreviewPaths: AttachmentStore.previewPathsForFiles(fileIds), }); }; _renderDownloadAllButton() { return (
{`${this.props.message.files.length} ${localized('attachments')}`}
-
{localized('Download All')}
); } _renderAttachments() { const { files = [], body, id } = this.props.message; const { filePreviewPaths, downloads } = this.state; let attachedFiles = files.filter( f => !f.contentId || !(body || '').includes(`cid:${f.contentId}`) ); for (const extension of MessageStore.extensions()) { if (!extension.filterMessageFiles) continue; attachedFiles = extension.filterMessageFiles({ message: this.props.message, files: attachedFiles, }); } return (
{files.length > 1 ? this._renderDownloadAllButton() : null} {attachedFiles.length > 0 && (
)}
); } _renderFooterStatus() { return ( ); } _renderHeader() { const { message, thread, messages, pending } = this.props; return (
(this._headerEl = el)} className={`message-header ${pending && 'pending'}`} onClick={this._onClickHeader} >
!message.from.find(fc => fc.email === c.email))} onClick={this._onClickParticipants} isDetailed={this.state.detailedHeaders} /> {this._renderSubject()} {this._renderFolder()} {this._renderHeaderDetailToggle()}
); } _renderHeaderDetailToggle() { if (this.props.pending) { return null; } if (this.state.detailedHeaders) { return (
{ this.setState({ detailedHeaders: false }); e.stopPropagation(); }} >
); } return (
{ this.setState({ detailedHeaders: true }); e.stopPropagation(); }} >
); } _renderSubject() { if (!this.state.detailedHeaders) { return false; } const subject = this.props.message.subject; return (
{localized('Subject')}: 
{subject}
); } _renderFolder() { if (!this.state.detailedHeaders) { return false; } const folder = this.props.message.folder; if (!folder || folder.role === 'al') { return false; } return (
{localized('Folder')}: 
{folder.displayName}
); } _renderCollapsed() { const { message: { snippet, from, files, date, draft }, className, } = this.props; const attachmentIcon = Utils.showIconForAttachments(files) ? (
) : null; return (
{from && from[0] && from[0].displayName({ compact: !AppEnv.config.get('core.reading.detailedNames') })}
{snippet}
{draft && (
)}
{attachmentIcon}
); } _renderFull() { return (
{this._renderHeader()} {this._renderAttachments()} {this._renderFooterStatus()}
); } render() { return this.props.collapsed ? this._renderCollapsed() : this._renderFull(); } }