]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private-message.tsx
a0e86a77fa1caaab927f0d930abc7de54412fd48
[lemmy-ui.git] / src / shared / components / private-message.tsx
1 import { Component, linkEvent } from 'inferno';
2 import {
3   PrivateMessage as PrivateMessageI,
4   DeletePrivateMessageForm,
5   MarkPrivateMessageAsReadForm,
6   UserView,
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';
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: UserView = this.mine
58       ? {
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,
66           number_of_posts: 0,
67           post_score: 0,
68           number_of_comments: 0,
69           comment_score: 0,
70           banned: false,
71         }
72       : {
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,
80           number_of_posts: 0,
81           post_score: 0,
82           number_of_comments: 0,
83           comment_score: 0,
84           banned: false,
85         };
86
87     return (
88       <div class="border-top border-light">
89         <div>
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')}
94             </li>
95             <li className="list-inline-item">
96               <UserListing user={userOther} />
97             </li>
98             <li className="list-inline-item">
99               <span>
100                 <MomentTime data={message} />
101               </span>
102             </li>
103             <li className="list-inline-item">
104               <div
105                 className="pointer text-monospace"
106                 onClick={linkEvent(this, this.handleMessageCollapse)}
107               >
108                 {this.state.collapsed ? (
109                   <svg class="icon icon-inline">
110                     <use xlinkHref="#icon-plus-square"></use>
111                   </svg>
112                 ) : (
113                   <svg class="icon icon-inline">
114                     <use xlinkHref="#icon-minus-square"></use>
115                   </svg>
116                 )}
117               </div>
118             </li>
119           </ul>
120           {this.state.showEdit && (
121             <PrivateMessageForm
122               recipient={userOther}
123               privateMessage={message}
124               onEdit={this.handlePrivateMessageEdit}
125               onCreate={this.handlePrivateMessageCreate}
126               onCancel={this.handleReplyCancel}
127             />
128           )}
129           {!this.state.showEdit && !this.state.collapsed && (
130             <div>
131               {this.state.viewSource ? (
132                 <pre>{this.messageUnlessRemoved}</pre>
133               ) : (
134                 <div
135                   className="md-div"
136                   dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
137                 />
138               )}
139               <ul class="list-inline mb-0 text-muted font-weight-bold">
140                 {!this.mine && (
141                   <>
142                     <li className="list-inline-item">
143                       <button
144                         class="btn btn-link btn-animate text-muted"
145                         onClick={linkEvent(this, this.handleMarkRead)}
146                         data-tippy-content={
147                           message.read
148                             ? i18n.t('mark_as_unread')
149                             : i18n.t('mark_as_read')
150                         }
151                       >
152                         <svg
153                           class={`icon icon-inline ${
154                             message.read && 'text-success'
155                           }`}
156                         >
157                           <use xlinkHref="#icon-check"></use>
158                         </svg>
159                       </button>
160                     </li>
161                     <li className="list-inline-item">
162                       <button
163                         class="btn btn-link btn-animate text-muted"
164                         onClick={linkEvent(this, this.handleReplyClick)}
165                         data-tippy-content={i18n.t('reply')}
166                       >
167                         <svg class="icon icon-inline">
168                           <use xlinkHref="#icon-reply1"></use>
169                         </svg>
170                       </button>
171                     </li>
172                   </>
173                 )}
174                 {this.mine && (
175                   <>
176                     <li className="list-inline-item">
177                       <button
178                         class="btn btn-link btn-animate text-muted"
179                         onClick={linkEvent(this, this.handleEditClick)}
180                         data-tippy-content={i18n.t('edit')}
181                       >
182                         <svg class="icon icon-inline">
183                           <use xlinkHref="#icon-edit"></use>
184                         </svg>
185                       </button>
186                     </li>
187                     <li className="list-inline-item">
188                       <button
189                         class="btn btn-link btn-animate text-muted"
190                         onClick={linkEvent(this, this.handleDeleteClick)}
191                         data-tippy-content={
192                           !message.deleted
193                             ? i18n.t('delete')
194                             : i18n.t('restore')
195                         }
196                       >
197                         <svg
198                           class={`icon icon-inline ${
199                             message.deleted && 'text-danger'
200                           }`}
201                         >
202                           <use xlinkHref="#icon-trash"></use>
203                         </svg>
204                       </button>
205                     </li>
206                   </>
207                 )}
208                 <li className="list-inline-item">
209                   <button
210                     class="btn btn-link btn-animate text-muted"
211                     onClick={linkEvent(this, this.handleViewSource)}
212                     data-tippy-content={i18n.t('view_source')}
213                   >
214                     <svg
215                       class={`icon icon-inline ${
216                         this.state.viewSource && 'text-success'
217                       }`}
218                     >
219                       <use xlinkHref="#icon-file-text"></use>
220                     </svg>
221                   </button>
222                 </li>
223               </ul>
224             </div>
225           )}
226         </div>
227         {this.state.showReply && (
228           <PrivateMessageForm
229             recipient={userOther}
230             onCreate={this.handlePrivateMessageCreate}
231           />
232         )}
233         {/* A collapsed clearfix */}
234         {this.state.collapsed && <div class="row col-12"></div>}
235       </div>
236     );
237   }
238
239   get messageUnlessRemoved(): string {
240     let message = this.props.privateMessage;
241     return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
242   }
243
244   handleReplyClick(i: PrivateMessage) {
245     i.state.showReply = true;
246     i.setState(i.state);
247   }
248
249   handleEditClick(i: PrivateMessage) {
250     i.state.showEdit = true;
251     i.setState(i.state);
252   }
253
254   handleDeleteClick(i: PrivateMessage) {
255     let form: DeletePrivateMessageForm = {
256       edit_id: i.props.privateMessage.id,
257       deleted: !i.props.privateMessage.deleted,
258     };
259     WebSocketService.Instance.deletePrivateMessage(form);
260   }
261
262   handleReplyCancel() {
263     this.state.showReply = false;
264     this.state.showEdit = false;
265     this.setState(this.state);
266   }
267
268   handleMarkRead(i: PrivateMessage) {
269     let form: MarkPrivateMessageAsReadForm = {
270       edit_id: i.props.privateMessage.id,
271       read: !i.props.privateMessage.read,
272     };
273     WebSocketService.Instance.markPrivateMessageAsRead(form);
274   }
275
276   handleMessageCollapse(i: PrivateMessage) {
277     i.state.collapsed = !i.state.collapsed;
278     i.setState(i.state);
279   }
280
281   handleViewSource(i: PrivateMessage) {
282     i.state.viewSource = !i.state.viewSource;
283     i.setState(i.state);
284   }
285
286   handlePrivateMessageEdit() {
287     this.state.showEdit = false;
288     this.setState(this.state);
289   }
290
291   handlePrivateMessageCreate(message: PrivateMessageI) {
292     if (
293       UserService.Instance.user &&
294       message.creator_id == UserService.Instance.user.id
295     ) {
296       this.state.showReply = false;
297       this.setState(this.state);
298       toast(i18n.t('message_sent'));
299     }
300   }
301 }