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