1 import { Component, linkEvent } from 'inferno';
3 PrivateMessage as PrivateMessageI,
4 DeletePrivateMessageForm,
5 MarkPrivateMessageAsReadForm,
7 } from 'lemmy-js-client';
8 import { WebSocketService, UserService } from '../services';
9 import { mdToHtml, toast } from '../utils';
10 import { MomentTime } from './moment-time';
11 import { PrivateMessageForm } from './private-message-form';
12 import { UserListing } from './user-listing';
13 import { i18n } from '../i18next';
15 interface PrivateMessageState {
22 interface PrivateMessageProps {
23 privateMessage: PrivateMessageI;
26 export class PrivateMessage extends Component<
30 private emptyState: PrivateMessageState = {
37 constructor(props: any, context: any) {
38 super(props, context);
40 this.state = this.emptyState;
41 this.handleReplyCancel = this.handleReplyCancel.bind(this);
42 this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
45 this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
50 UserService.Instance.user &&
51 UserService.Instance.user.id == this.props.privateMessage.creator_id
56 let message = this.props.privateMessage;
57 let userOther: UserView = this.mine
59 name: message.recipient_name,
60 preferred_username: message.recipient_preferred_username,
61 id: message.recipient_id,
62 avatar: message.recipient_avatar,
63 local: message.recipient_local,
64 actor_id: message.recipient_actor_id,
65 published: message.published,
68 number_of_comments: 0,
73 name: message.creator_name,
74 preferred_username: message.creator_preferred_username,
75 id: message.creator_id,
76 avatar: message.creator_avatar,
77 local: message.creator_local,
78 actor_id: message.creator_actor_id,
79 published: message.published,
82 number_of_comments: 0,
88 <div class="border-top border-light">
90 <ul class="list-inline mb-0 text-muted small">
91 {/* TODO refactor this */}
92 <li className="list-inline-item">
93 {this.mine ? i18n.t('to') : i18n.t('from')}
95 <li className="list-inline-item">
96 <UserListing user={userOther} />
98 <li className="list-inline-item">
100 <MomentTime data={message} />
103 <li className="list-inline-item">
105 className="pointer text-monospace"
106 onClick={linkEvent(this, this.handleMessageCollapse)}
108 {this.state.collapsed ? (
109 <svg class="icon icon-inline">
110 <use xlinkHref="#icon-plus-square"></use>
113 <svg class="icon icon-inline">
114 <use xlinkHref="#icon-minus-square"></use>
120 {this.state.showEdit && (
122 recipient={userOther}
123 privateMessage={message}
124 onEdit={this.handlePrivateMessageEdit}
125 onCreate={this.handlePrivateMessageCreate}
126 onCancel={this.handleReplyCancel}
129 {!this.state.showEdit && !this.state.collapsed && (
131 {this.state.viewSource ? (
132 <pre>{this.messageUnlessRemoved}</pre>
136 dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
139 <ul class="list-inline mb-0 text-muted font-weight-bold">
142 <li className="list-inline-item">
144 class="btn btn-link btn-animate text-muted"
145 onClick={linkEvent(this, this.handleMarkRead)}
148 ? i18n.t('mark_as_unread')
149 : i18n.t('mark_as_read')
153 class={`icon icon-inline ${
154 message.read && 'text-success'
157 <use xlinkHref="#icon-check"></use>
161 <li className="list-inline-item">
163 class="btn btn-link btn-animate text-muted"
164 onClick={linkEvent(this, this.handleReplyClick)}
165 data-tippy-content={i18n.t('reply')}
167 <svg class="icon icon-inline">
168 <use xlinkHref="#icon-reply1"></use>
176 <li className="list-inline-item">
178 class="btn btn-link btn-animate text-muted"
179 onClick={linkEvent(this, this.handleEditClick)}
180 data-tippy-content={i18n.t('edit')}
182 <svg class="icon icon-inline">
183 <use xlinkHref="#icon-edit"></use>
187 <li className="list-inline-item">
189 class="btn btn-link btn-animate text-muted"
190 onClick={linkEvent(this, this.handleDeleteClick)}
198 class={`icon icon-inline ${
199 message.deleted && 'text-danger'
202 <use xlinkHref="#icon-trash"></use>
208 <li className="list-inline-item">
210 class="btn btn-link btn-animate text-muted"
211 onClick={linkEvent(this, this.handleViewSource)}
212 data-tippy-content={i18n.t('view_source')}
215 class={`icon icon-inline ${
216 this.state.viewSource && 'text-success'
219 <use xlinkHref="#icon-file-text"></use>
227 {this.state.showReply && (
229 recipient={userOther}
230 onCreate={this.handlePrivateMessageCreate}
233 {/* A collapsed clearfix */}
234 {this.state.collapsed && <div class="row col-12"></div>}
239 get messageUnlessRemoved(): string {
240 let message = this.props.privateMessage;
241 return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
244 handleReplyClick(i: PrivateMessage) {
245 i.state.showReply = true;
249 handleEditClick(i: PrivateMessage) {
250 i.state.showEdit = true;
254 handleDeleteClick(i: PrivateMessage) {
255 let form: DeletePrivateMessageForm = {
256 edit_id: i.props.privateMessage.id,
257 deleted: !i.props.privateMessage.deleted,
259 WebSocketService.Instance.deletePrivateMessage(form);
262 handleReplyCancel() {
263 this.state.showReply = false;
264 this.state.showEdit = false;
265 this.setState(this.state);
268 handleMarkRead(i: PrivateMessage) {
269 let form: MarkPrivateMessageAsReadForm = {
270 edit_id: i.props.privateMessage.id,
271 read: !i.props.privateMessage.read,
273 WebSocketService.Instance.markPrivateMessageAsRead(form);
276 handleMessageCollapse(i: PrivateMessage) {
277 i.state.collapsed = !i.state.collapsed;
281 handleViewSource(i: PrivateMessage) {
282 i.state.viewSource = !i.state.viewSource;
286 handlePrivateMessageEdit() {
287 this.state.showEdit = false;
288 this.setState(this.state);
291 handlePrivateMessageCreate(message: PrivateMessageI) {
293 UserService.Instance.user &&
294 message.creator_id == UserService.Instance.user.id
296 this.state.showReply = false;
297 this.setState(this.state);
298 toast(i18n.t('message_sent'));