Finish new Message component, integrate into application
Also: - New schema version 8 with video/image thumbnails, screenshots, sizes - Upgrade messages not at current schema version when loading messages to show in conversation - New MessageDetail react component - New ConversationHeader react component
This commit is contained in:
parent
69f11c4a7b
commit
3c69886320
102 changed files with 9644 additions and 7381 deletions
209
ts/components/conversation/MessageDetail.tsx
Normal file
209
ts/components/conversation/MessageDetail.tsx
Normal file
|
@ -0,0 +1,209 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import moment from 'moment';
|
||||
|
||||
import { ContactName } from './ContactName';
|
||||
import { Message, Props as MessageProps } from './Message';
|
||||
import { Localizer } from '../../types/Util';
|
||||
|
||||
interface Contact {
|
||||
status: string;
|
||||
phoneNumber: string;
|
||||
name?: string;
|
||||
profileName?: string;
|
||||
avatarPath?: string;
|
||||
color: string;
|
||||
isOutgoingKeyError: boolean;
|
||||
|
||||
errors?: Array<Error>;
|
||||
onSendAnyway: () => void;
|
||||
onShowSafetyNumber: () => void;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
sentAt: number;
|
||||
receivedAt: number;
|
||||
|
||||
message: MessageProps;
|
||||
errors: Array<Error>;
|
||||
contacts: Array<Contact>;
|
||||
|
||||
i18n: Localizer;
|
||||
}
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
export class MessageDetail extends React.Component<Props> {
|
||||
public renderAvatar(contact: Contact) {
|
||||
const { i18n } = this.props;
|
||||
const { avatarPath, color, phoneNumber, name, profileName } = contact;
|
||||
|
||||
if (!avatarPath) {
|
||||
const initial = getInitial(name || '');
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-message-detail__contact__avatar',
|
||||
'module-message-detail__contact__default-avatar',
|
||||
`module-message-detail__contact__default-avatar--${color}`
|
||||
)}
|
||||
>
|
||||
{initial}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const title = `${name || phoneNumber}${
|
||||
!name && profileName ? ` ~${profileName}` : ''
|
||||
}`;
|
||||
|
||||
return (
|
||||
<img
|
||||
className="module-message-detail__contact__avatar"
|
||||
alt={i18n('contactAvatarAlt', [title])}
|
||||
src={avatarPath}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
public renderDeleteButton() {
|
||||
const { i18n, message } = this.props;
|
||||
|
||||
return (
|
||||
<div className="module-message-detail__delete-button-container">
|
||||
<button
|
||||
onClick={message.onDelete}
|
||||
className="module-message-detail__delete-button"
|
||||
>
|
||||
{i18n('deleteThisMessage')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public renderContact(contact: Contact) {
|
||||
const { i18n } = this.props;
|
||||
const errors = contact.errors || [];
|
||||
|
||||
const errorComponent = contact.isOutgoingKeyError ? (
|
||||
<div className="module-message-detail__contact__error-buttons">
|
||||
<button
|
||||
className="module-message-detail__contact__show-safety-number"
|
||||
onClick={contact.onShowSafetyNumber}
|
||||
>
|
||||
{i18n('showSafetyNumber')}
|
||||
</button>
|
||||
<button
|
||||
className="module-message-detail__contact__send-anyway"
|
||||
onClick={contact.onSendAnyway}
|
||||
>
|
||||
{i18n('sendAnyway')}
|
||||
</button>
|
||||
</div>
|
||||
) : null;
|
||||
const statusComponent = !contact.isOutgoingKeyError ? (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-message-detail__contact__status-icon',
|
||||
`module-message-detail__contact__status-icon--${contact.status}`
|
||||
)}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div key={contact.phoneNumber} className="module-message-detail__contact">
|
||||
{this.renderAvatar(contact)}
|
||||
<div className="module-message-detail__contact__text">
|
||||
<div className="module-message-detail__contact__name">
|
||||
<ContactName
|
||||
phoneNumber={contact.phoneNumber}
|
||||
name={contact.name}
|
||||
profileName={contact.profileName}
|
||||
i18n={i18n}
|
||||
/>
|
||||
</div>
|
||||
{errors.map((error, index) => (
|
||||
<div key={index} className="module-message-detail__contact__error">
|
||||
{error.message}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{errorComponent}
|
||||
{statusComponent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public renderContacts() {
|
||||
const { contacts } = this.props;
|
||||
|
||||
if (!contacts || !contacts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="module-message-detail__contact-container">
|
||||
{contacts.map(contact => this.renderContact(contact))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { errors, message, receivedAt, sentAt, i18n } = this.props;
|
||||
|
||||
return (
|
||||
<div className="module-message-detail">
|
||||
<div className="module-message-detail__message-container">
|
||||
<Message i18n={i18n} {...message} />
|
||||
</div>
|
||||
<table className="module-message-detail__info">
|
||||
<tbody>
|
||||
{(errors || []).map(error => (
|
||||
<tr>
|
||||
<td className="module-message-detail__label">
|
||||
{i18n('error')}
|
||||
</td>
|
||||
<td>
|
||||
{' '}
|
||||
<span className="error-message">{error.message}</span>{' '}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
<tr>
|
||||
<td className="module-message-detail__label">{i18n('sent')}</td>
|
||||
<td>
|
||||
{moment(sentAt).format('LLLL')}{' '}
|
||||
<span className="module-message-detail__unix-timestamp">
|
||||
({sentAt})
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{receivedAt ? (
|
||||
<tr>
|
||||
<td className="module-message-detail__label">
|
||||
{i18n('received')}
|
||||
</td>
|
||||
<td>
|
||||
{moment(receivedAt).format('LLLL')}{' '}
|
||||
<span className="module-message-detail__unix-timestamp">
|
||||
({receivedAt})
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
) : null}
|
||||
<tr>
|
||||
<td className="module-message-detail__label">
|
||||
{message.direction === 'incoming' ? i18n('from') : i18n('to')}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{this.renderContacts()}
|
||||
{this.renderDeleteButton()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue