]> Untitled Git - lemmy.git/blob - ui/src/components/private-message.tsx
routes.api: fix get_captcha endpoint (#1135)
[lemmy.git] / ui / src / components / private-message.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
3 import {
4   PrivateMessage as PrivateMessageI,
5   DeletePrivateMessageForm,
6   MarkPrivateMessageAsReadForm,
7 } from 'lemmy-js-client';
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 { UserListing, UserOther } from './user-listing';
13 import { i18n } from '../i18next';
14
15 interface PrivateMessageState {
16   showReply: boolean;
17   showEdit: boolean;
18   collapsed: boolean;
19   viewSource: boolean;
20 }
21
22 interface PrivateMessageProps {
23   privateMessage: PrivateMessageI;
24 }
25
26 export class PrivateMessage extends Component<
27   PrivateMessageProps,
28   PrivateMessageState
29 > {
30   private emptyState: PrivateMessageState = {
31     showReply: false,
32     showEdit: false,
33     collapsed: false,
34     viewSource: false,
35   };
36
37   constructor(props: any, context: any) {
38     super(props, context);
39
40     this.state = this.emptyState;
41     this.handleReplyCancel = this.handleReplyCancel.bind(this);
42     this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
43       this
44     );
45     this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
46   }
47
48   get mine(): boolean {
49     return (
50       UserService.Instance.user &&
51       UserService.Instance.user.id == this.props.privateMessage.creator_id
52     );
53   }
54
55   render() {
56     let message = this.props.privateMessage;
57     let userOther: UserOther = this.mine
58       ? {
59           name: message.recipient_name,
60           preferred_username: message.recipient_preferred_username,
61           id: message.id,
62           avatar: message.recipient_avatar,
63           local: message.recipient_local,
64           actor_id: message.recipient_actor_id,
65           published: message.published,
66         }
67       : {
68           name: message.creator_name,
69           preferred_username: message.creator_preferred_username,
70           id: message.id,
71           avatar: message.creator_avatar,
72           local: message.creator_local,
73           actor_id: message.creator_actor_id,
74           published: message.published,
75         };
76
77     return (
78       <div class="border-top border-light">
79         <div>
80           <ul class="list-inline mb-0 text-muted small">
81             {/* TODO refactor this */}
82             <li className="list-inline-item">
83               {this.mine ? i18n.t('to') : i18n.t('from')}
84             </li>
85             <li className="list-inline-item">
86               <UserListing user={userOther} />
87             </li>
88             <li className="list-inline-item">
89               <span>
90                 <MomentTime data={message} />
91               </span>
92             </li>
93             <li className="list-inline-item">
94               <div
95                 className="pointer text-monospace"
96                 onClick={linkEvent(this, this.handleMessageCollapse)}
97               >
98                 {this.state.collapsed ? (
99                   <svg class="icon icon-inline">
100                     <use xlinkHref="#icon-plus-square"></use>
101                   </svg>
102                 ) : (
103                   <svg class="icon icon-inline">
104                     <use xlinkHref="#icon-minus-square"></use>
105                   </svg>
106                 )}
107               </div>
108             </li>
109           </ul>
110           {this.state.showEdit && (
111             <PrivateMessageForm
112               privateMessage={message}
113               onEdit={this.handlePrivateMessageEdit}
114               onCreate={this.handlePrivateMessageCreate}
115               onCancel={this.handleReplyCancel}
116             />
117           )}
118           {!this.state.showEdit && !this.state.collapsed && (
119             <div>
120               {this.state.viewSource ? (
121                 <pre>{this.messageUnlessRemoved}</pre>
122               ) : (
123                 <div
124                   className="md-div"
125                   dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
126                 />
127               )}
128               <ul class="list-inline mb-0 text-muted font-weight-bold">
129                 {!this.mine && (
130                   <>
131                     <li className="list-inline-item">
132                       <button
133                         class="btn btn-link btn-animate text-muted"
134                         onClick={linkEvent(this, this.handleMarkRead)}
135                         data-tippy-content={
136                           message.read
137                             ? i18n.t('mark_as_unread')
138                             : i18n.t('mark_as_read')
139                         }
140                       >
141                         <svg
142                           class={`icon icon-inline ${
143                             message.read && 'text-success'
144                           }`}
145                         >
146                           <use xlinkHref="#icon-check"></use>
147                         </svg>
148                       </button>
149                     </li>
150                     <li className="list-inline-item">
151                       <button
152                         class="btn btn-link btn-animate text-muted"
153                         onClick={linkEvent(this, this.handleReplyClick)}
154                         data-tippy-content={i18n.t('reply')}
155                       >
156                         <svg class="icon icon-inline">
157                           <use xlinkHref="#icon-reply1"></use>
158                         </svg>
159                       </button>
160                     </li>
161                   </>
162                 )}
163                 {this.mine && (
164                   <>
165                     <li className="list-inline-item">
166                       <button
167                         class="btn btn-link btn-animate text-muted"
168                         onClick={linkEvent(this, this.handleEditClick)}
169                         data-tippy-content={i18n.t('edit')}
170                       >
171                         <svg class="icon icon-inline">
172                           <use xlinkHref="#icon-edit"></use>
173                         </svg>
174                       </button>
175                     </li>
176                     <li className="list-inline-item">
177                       <button
178                         class="btn btn-link btn-animate text-muted"
179                         onClick={linkEvent(this, this.handleDeleteClick)}
180                         data-tippy-content={
181                           !message.deleted
182                             ? i18n.t('delete')
183                             : i18n.t('restore')
184                         }
185                       >
186                         <svg
187                           class={`icon icon-inline ${
188                             message.deleted && 'text-danger'
189                           }`}
190                         >
191                           <use xlinkHref="#icon-trash"></use>
192                         </svg>
193                       </button>
194                     </li>
195                   </>
196                 )}
197                 <li className="list-inline-item">
198                   <button
199                     class="btn btn-link btn-animate text-muted"
200                     onClick={linkEvent(this, this.handleViewSource)}
201                     data-tippy-content={i18n.t('view_source')}
202                   >
203                     <svg
204                       class={`icon icon-inline ${
205                         this.state.viewSource && 'text-success'
206                       }`}
207                     >
208                       <use xlinkHref="#icon-file-text"></use>
209                     </svg>
210                   </button>
211                 </li>
212               </ul>
213             </div>
214           )}
215         </div>
216         {this.state.showReply && (
217           <PrivateMessageForm
218             params={{
219               recipient_id: this.props.privateMessage.creator_id,
220             }}
221             onCreate={this.handlePrivateMessageCreate}
222           />
223         )}
224         {/* A collapsed clearfix */}
225         {this.state.collapsed && <div class="row col-12"></div>}
226       </div>
227     );
228   }
229
230   get messageUnlessRemoved(): string {
231     let message = this.props.privateMessage;
232     return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
233   }
234
235   handleReplyClick(i: PrivateMessage) {
236     i.state.showReply = true;
237     i.setState(i.state);
238   }
239
240   handleEditClick(i: PrivateMessage) {
241     i.state.showEdit = true;
242     i.setState(i.state);
243   }
244
245   handleDeleteClick(i: PrivateMessage) {
246     let form: DeletePrivateMessageForm = {
247       edit_id: i.props.privateMessage.id,
248       deleted: !i.props.privateMessage.deleted,
249     };
250     WebSocketService.Instance.deletePrivateMessage(form);
251   }
252
253   handleReplyCancel() {
254     this.state.showReply = false;
255     this.state.showEdit = false;
256     this.setState(this.state);
257   }
258
259   handleMarkRead(i: PrivateMessage) {
260     let form: MarkPrivateMessageAsReadForm = {
261       edit_id: i.props.privateMessage.id,
262       read: !i.props.privateMessage.read,
263     };
264     WebSocketService.Instance.markPrivateMessageAsRead(form);
265   }
266
267   handleMessageCollapse(i: PrivateMessage) {
268     i.state.collapsed = !i.state.collapsed;
269     i.setState(i.state);
270   }
271
272   handleViewSource(i: PrivateMessage) {
273     i.state.viewSource = !i.state.viewSource;
274     i.setState(i.state);
275   }
276
277   handlePrivateMessageEdit() {
278     this.state.showEdit = false;
279     this.setState(this.state);
280   }
281
282   handlePrivateMessageCreate(message: PrivateMessageI) {
283     if (
284       UserService.Instance.user &&
285       message.creator_id == UserService.Instance.user.id
286     ) {
287       this.state.showReply = false;
288       this.setState(this.state);
289       toast(i18n.t('message_sent'));
290     }
291   }
292 }