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);
49 UserService.Instance.user &&
50 UserService.Instance.user.id == this.props.privateMessage.creator_id
55 let message = this.props.privateMessage;
57 <div class="border-top border-light">
59 <ul class="list-inline mb-0 text-muted small">
60 {/* TODO refactor this */}
61 <li className="list-inline-item">
62 {this.mine ? i18n.t('to') : i18n.t('from')}
64 <li className="list-inline-item">
66 className="text-body font-weight-bold"
69 ? `/u/${message.recipient_name}`
70 : `/u/${message.creator_name}`
74 ? message.recipient_avatar
75 : message.creator_avatar) &&
80 src={pictrsAvatarThumbnail(
82 ? message.recipient_avatar
83 : message.creator_avatar
85 class="rounded-circle mr-1"
89 {this.mine ? message.recipient_name : message.creator_name}
93 <li className="list-inline-item">
95 <MomentTime data={message} />
98 <li className="list-inline-item">
100 className="pointer text-monospace"
101 onClick={linkEvent(this, this.handleMessageCollapse)}
103 {this.state.collapsed ? (
104 <svg class="icon icon-inline">
105 <use xlinkHref="#icon-plus-square"></use>
108 <svg class="icon icon-inline">
109 <use xlinkHref="#icon-minus-square"></use>
115 {this.state.showEdit && (
117 privateMessage={message}
118 onEdit={this.handlePrivateMessageEdit}
119 onCreate={this.handlePrivateMessageCreate}
120 onCancel={this.handleReplyCancel}
123 {!this.state.showEdit && !this.state.collapsed && (
125 {this.state.viewSource ? (
126 <pre>{this.messageUnlessRemoved}</pre>
130 dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
133 <ul class="list-inline mb-0 text-muted font-weight-bold">
136 <li className="list-inline-item">
138 class="btn btn-link btn-animate text-muted"
139 onClick={linkEvent(this, this.handleMarkRead)}
142 ? i18n.t('mark_as_unread')
143 : i18n.t('mark_as_read')
147 class={`icon icon-inline ${
148 message.read && 'text-success'
151 <use xlinkHref="#icon-check"></use>
155 <li className="list-inline-item">
157 class="btn btn-link btn-animate text-muted"
158 onClick={linkEvent(this, this.handleReplyClick)}
159 data-tippy-content={i18n.t('reply')}
161 <svg class="icon icon-inline">
162 <use xlinkHref="#icon-reply1"></use>
170 <li className="list-inline-item">
172 class="btn btn-link btn-animate text-muted"
173 onClick={linkEvent(this, this.handleEditClick)}
174 data-tippy-content={i18n.t('edit')}
176 <svg class="icon icon-inline">
177 <use xlinkHref="#icon-edit"></use>
181 <li className="list-inline-item">
183 class="btn btn-link btn-animate text-muted"
184 onClick={linkEvent(this, this.handleDeleteClick)}
192 class={`icon icon-inline ${
193 message.deleted && 'text-danger'
196 <use xlinkHref="#icon-trash"></use>
202 <li className="list-inline-item">
204 class="btn btn-link btn-animate text-muted"
205 onClick={linkEvent(this, this.handleViewSource)}
206 data-tippy-content={i18n.t('view_source')}
209 class={`icon icon-inline ${
210 this.state.viewSource && 'text-success'
213 <use xlinkHref="#icon-file-text"></use>
221 {this.state.showReply && (
224 recipient_id: this.props.privateMessage.creator_id,
226 onCreate={this.handlePrivateMessageCreate}
229 {/* A collapsed clearfix */}
230 {this.state.collapsed && <div class="row col-12"></div>}
235 get messageUnlessRemoved(): string {
236 let message = this.props.privateMessage;
237 return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
240 handleReplyClick(i: PrivateMessage) {
241 i.state.showReply = true;
245 handleEditClick(i: PrivateMessage) {
246 i.state.showEdit = true;
250 handleDeleteClick(i: PrivateMessage) {
251 let form: DeletePrivateMessageForm = {
252 edit_id: i.props.privateMessage.id,
253 deleted: !i.props.privateMessage.deleted,
255 WebSocketService.Instance.deletePrivateMessage(form);
258 handleReplyCancel() {
259 this.state.showReply = false;
260 this.state.showEdit = false;
261 this.setState(this.state);
264 handleMarkRead(i: PrivateMessage) {
265 let form: MarkPrivateMessageAsReadForm = {
266 edit_id: i.props.privateMessage.id,
267 read: !i.props.privateMessage.read,
269 WebSocketService.Instance.markPrivateMessageAsRead(form);
272 handleMessageCollapse(i: PrivateMessage) {
273 i.state.collapsed = !i.state.collapsed;
277 handleViewSource(i: PrivateMessage) {
278 i.state.viewSource = !i.state.viewSource;
282 handlePrivateMessageEdit() {
283 this.state.showEdit = false;
284 this.setState(this.state);
287 handlePrivateMessageCreate(message: PrivateMessageI) {
289 UserService.Instance.user &&
290 message.creator_id == UserService.Instance.user.id
292 this.state.showReply = false;
293 this.setState(this.state);
294 toast(i18n.t('message_sent'));