1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
4 PrivateMessage as PrivateMessageI,
5 DeletePrivateMessageForm,
6 MarkPrivateMessageAsReadForm,
7 } from '../interfaces';
8 import { WebSocketService, UserService } from '../services';
9 import { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils';
10 import { MomentTime } from './moment-time';
11 import { PrivateMessageForm } from './private-message-form';
12 import { i18n } from '../i18next';
14 interface PrivateMessageState {
21 interface PrivateMessageProps {
22 privateMessage: PrivateMessageI;
25 export class PrivateMessage extends Component<
29 private emptyState: PrivateMessageState = {
36 constructor(props: any, context: any) {
37 super(props, context);
39 this.state = this.emptyState;
40 this.handleReplyCancel = this.handleReplyCancel.bind(this);
41 this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
44 this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
48 return UserService.Instance.user.id == this.props.privateMessage.creator_id;
52 let message = this.props.privateMessage;
54 <div class="border-top border-light">
56 <ul class="list-inline mb-0 text-muted small">
57 {/* TODO refactor this */}
58 <li className="list-inline-item">
59 {this.mine ? i18n.t('to') : i18n.t('from')}
61 <li className="list-inline-item">
63 className="text-body font-weight-bold"
66 ? `/u/${message.recipient_name}`
67 : `/u/${message.creator_name}`
71 ? message.recipient_avatar
72 : message.creator_avatar) &&
77 src={pictrsAvatarThumbnail(
79 ? message.recipient_avatar
80 : message.creator_avatar
82 class="rounded-circle mr-1"
86 {this.mine ? message.recipient_name : message.creator_name}
90 <li className="list-inline-item">
92 <MomentTime data={message} />
95 <li className="list-inline-item">
97 className="pointer text-monospace"
98 onClick={linkEvent(this, this.handleMessageCollapse)}
100 {this.state.collapsed ? (
101 <svg class="icon icon-inline">
102 <use xlinkHref="#icon-plus-square"></use>
105 <svg class="icon icon-inline">
106 <use xlinkHref="#icon-minus-square"></use>
112 {this.state.showEdit && (
114 privateMessage={message}
115 onEdit={this.handlePrivateMessageEdit}
116 onCancel={this.handleReplyCancel}
119 {!this.state.showEdit && !this.state.collapsed && (
121 {this.state.viewSource ? (
122 <pre>{this.messageUnlessRemoved}</pre>
126 dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
129 <ul class="list-inline mb-0 text-muted font-weight-bold">
132 <li className="list-inline-item">
134 class="btn btn-link btn-animate text-muted"
135 onClick={linkEvent(this, this.handleMarkRead)}
138 ? i18n.t('mark_as_unread')
139 : i18n.t('mark_as_read')
143 class={`icon icon-inline ${
144 message.read && 'text-success'
147 <use xlinkHref="#icon-check"></use>
151 <li className="list-inline-item">
153 class="btn btn-link btn-animate text-muted"
154 onClick={linkEvent(this, this.handleReplyClick)}
155 data-tippy-content={i18n.t('reply')}
157 <svg class="icon icon-inline">
158 <use xlinkHref="#icon-reply1"></use>
166 <li className="list-inline-item">
168 class="btn btn-link btn-animate text-muted"
169 onClick={linkEvent(this, this.handleEditClick)}
170 data-tippy-content={i18n.t('edit')}
172 <svg class="icon icon-inline">
173 <use xlinkHref="#icon-edit"></use>
177 <li className="list-inline-item">
179 class="btn btn-link btn-animate text-muted"
180 onClick={linkEvent(this, this.handleDeleteClick)}
188 class={`icon icon-inline ${
189 message.deleted && 'text-danger'
192 <use xlinkHref="#icon-trash"></use>
198 <li className="list-inline-item">
200 class="btn btn-link btn-animate text-muted"
201 onClick={linkEvent(this, this.handleViewSource)}
202 data-tippy-content={i18n.t('view_source')}
205 class={`icon icon-inline ${
206 this.state.viewSource && 'text-success'
209 <use xlinkHref="#icon-file-text"></use>
217 {this.state.showReply && (
220 recipient_id: this.props.privateMessage.creator_id,
222 onCreate={this.handlePrivateMessageCreate}
225 {/* A collapsed clearfix */}
226 {this.state.collapsed && <div class="row col-12"></div>}
231 get messageUnlessRemoved(): string {
232 let message = this.props.privateMessage;
233 return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
236 handleReplyClick(i: PrivateMessage) {
237 i.state.showReply = true;
241 handleEditClick(i: PrivateMessage) {
242 i.state.showEdit = true;
246 handleDeleteClick(i: PrivateMessage) {
247 let form: DeletePrivateMessageForm = {
248 edit_id: i.props.privateMessage.id,
249 deleted: !i.props.privateMessage.deleted,
251 WebSocketService.Instance.deletePrivateMessage(form);
254 handleReplyCancel() {
255 this.state.showReply = false;
256 this.state.showEdit = false;
257 this.setState(this.state);
260 handleMarkRead(i: PrivateMessage) {
261 let form: MarkPrivateMessageAsReadForm = {
262 edit_id: i.props.privateMessage.id,
263 read: !i.props.privateMessage.read,
265 WebSocketService.Instance.markPrivateMessageAsRead(form);
268 handleMessageCollapse(i: PrivateMessage) {
269 i.state.collapsed = !i.state.collapsed;
273 handleViewSource(i: PrivateMessage) {
274 i.state.viewSource = !i.state.viewSource;
278 handlePrivateMessageEdit() {
279 this.state.showEdit = false;
280 this.setState(this.state);
283 handlePrivateMessageCreate() {
284 this.state.showReply = false;
285 this.setState(this.state);
286 toast(i18n.t('message_sent'));