1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
4 PrivateMessage as PrivateMessageI,
5 EditPrivateMessageForm,
6 } from '../interfaces';
7 import { WebSocketService, UserService } from '../services';
8 import { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils';
9 import { MomentTime } from './moment-time';
10 import { PrivateMessageForm } from './private-message-form';
11 import { i18n } from '../i18next';
13 interface PrivateMessageState {
20 interface PrivateMessageProps {
21 privateMessage: PrivateMessageI;
24 export class PrivateMessage extends Component<
28 private emptyState: PrivateMessageState = {
35 constructor(props: any, context: any) {
36 super(props, context);
38 this.state = this.emptyState;
39 this.handleReplyCancel = this.handleReplyCancel.bind(this);
40 this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
43 this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
47 return UserService.Instance.user.id == this.props.privateMessage.creator_id;
51 let message = this.props.privateMessage;
53 <div class="border-top border-light">
55 <ul class="list-inline mb-0 text-muted small">
56 {/* TODO refactor this */}
57 <li className="list-inline-item">
58 {this.mine ? i18n.t('to') : i18n.t('from')}
60 <li className="list-inline-item">
62 className="text-body font-weight-bold"
65 ? `/u/${message.recipient_name}`
66 : `/u/${message.creator_name}`
70 ? message.recipient_avatar
71 : message.creator_avatar) &&
76 src={pictrsAvatarThumbnail(
78 ? message.recipient_avatar
79 : message.creator_avatar
81 class="rounded-circle mr-1"
85 {this.mine ? message.recipient_name : message.creator_name}
89 <li className="list-inline-item">
91 <MomentTime data={message} />
94 <li className="list-inline-item">
96 className="pointer text-monospace"
97 onClick={linkEvent(this, this.handleMessageCollapse)}
99 {this.state.collapsed ? (
100 <svg class="icon icon-inline">
101 <use xlinkHref="#icon-plus-square"></use>
104 <svg class="icon icon-inline">
105 <use xlinkHref="#icon-minus-square"></use>
111 {this.state.showEdit && (
113 privateMessage={message}
114 onEdit={this.handlePrivateMessageEdit}
115 onCancel={this.handleReplyCancel}
118 {!this.state.showEdit && !this.state.collapsed && (
120 {this.state.viewSource ? (
121 <pre>{this.messageUnlessRemoved}</pre>
125 dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
128 <ul class="list-inline mb-0 text-muted font-weight-bold">
131 <li className="list-inline-item">
133 class="btn btn-link btn-sm btn-animate text-muted"
134 onClick={linkEvent(this, this.handleMarkRead)}
137 ? i18n.t('mark_as_unread')
138 : i18n.t('mark_as_read')
142 class={`icon icon-inline ${
143 message.read && 'text-success'
146 <use xlinkHref="#icon-check"></use>
150 <li className="list-inline-item">
152 class="btn btn-link btn-sm btn-animate text-muted"
153 onClick={linkEvent(this, this.handleReplyClick)}
154 data-tippy-content={i18n.t('reply')}
156 <svg class="icon icon-inline">
157 <use xlinkHref="#icon-reply1"></use>
165 <li className="list-inline-item">
167 class="btn btn-link btn-sm btn-animate text-muted"
168 onClick={linkEvent(this, this.handleEditClick)}
169 data-tippy-content={i18n.t('edit')}
171 <svg class="icon icon-inline">
172 <use xlinkHref="#icon-edit"></use>
176 <li className="list-inline-item">
178 class="btn btn-link btn-sm btn-animate text-muted"
179 onClick={linkEvent(this, this.handleDeleteClick)}
187 class={`icon icon-inline ${
188 message.deleted && 'text-danger'
191 <use xlinkHref="#icon-trash"></use>
197 <li className="list-inline-item">
199 class="btn btn-link btn-sm btn-animate text-muted"
200 onClick={linkEvent(this, this.handleViewSource)}
201 data-tippy-content={i18n.t('view_source')}
204 class={`icon icon-inline ${
205 this.state.viewSource && 'text-success'
208 <use xlinkHref="#icon-file-text"></use>
216 {this.state.showReply && (
219 recipient_id: this.props.privateMessage.creator_id,
221 onCreate={this.handlePrivateMessageCreate}
224 {/* A collapsed clearfix */}
225 {this.state.collapsed && <div class="row col-12"></div>}
230 get messageUnlessRemoved(): string {
231 let message = this.props.privateMessage;
232 return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
235 handleReplyClick(i: PrivateMessage) {
236 i.state.showReply = true;
240 handleEditClick(i: PrivateMessage) {
241 i.state.showEdit = true;
245 handleDeleteClick(i: PrivateMessage) {
246 let form: EditPrivateMessageForm = {
247 edit_id: i.props.privateMessage.id,
248 deleted: !i.props.privateMessage.deleted,
250 WebSocketService.Instance.editPrivateMessage(form);
253 handleReplyCancel() {
254 this.state.showReply = false;
255 this.state.showEdit = false;
256 this.setState(this.state);
259 handleMarkRead(i: PrivateMessage) {
260 let form: EditPrivateMessageForm = {
261 edit_id: i.props.privateMessage.id,
262 read: !i.props.privateMessage.read,
264 WebSocketService.Instance.editPrivateMessage(form);
267 handleMessageCollapse(i: PrivateMessage) {
268 i.state.collapsed = !i.state.collapsed;
272 handleViewSource(i: PrivateMessage) {
273 i.state.viewSource = !i.state.viewSource;
277 handlePrivateMessageEdit() {
278 this.state.showEdit = false;
279 this.setState(this.state);
282 handlePrivateMessageCreate() {
283 this.state.showReply = false;
284 this.setState(this.state);
285 toast(i18n.t('message_sent'));