]> Untitled Git - lemmy.git/blob - ui/src/components/private-message.tsx
Merge branch 'admin_settings' into dev
[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 ${message.read &&
148                             'text-success'}`}
149                         >
150                           <use xlinkHref="#icon-check"></use>
151                         </svg>
152                       </button>
153                     </li>
154                     <li className="list-inline-item">
155                       <button
156                         class="btn btn-link btn-sm btn-animate text-muted"
157                         onClick={linkEvent(this, this.handleReplyClick)}
158                         data-tippy-content={i18n.t('reply')}
159                       >
160                         <svg class="icon icon-inline">
161                           <use xlinkHref="#icon-reply1"></use>
162                         </svg>
163                       </button>
164                     </li>
165                   </>
166                 )}
167                 {this.mine && (
168                   <>
169                     <li className="list-inline-item">
170                       <button
171                         class="btn btn-link btn-sm btn-animate text-muted"
172                         onClick={linkEvent(this, this.handleEditClick)}
173                         data-tippy-content={i18n.t('edit')}
174                       >
175                         <svg class="icon icon-inline">
176                           <use xlinkHref="#icon-edit"></use>
177                         </svg>
178                       </button>
179                     </li>
180                     <li className="list-inline-item">
181                       <button
182                         class="btn btn-link btn-sm btn-animate text-muted"
183                         onClick={linkEvent(this, this.handleDeleteClick)}
184                         data-tippy-content={
185                           !message.deleted
186                             ? i18n.t('delete')
187                             : i18n.t('restore')
188                         }
189                       >
190                         <svg
191                           class={`icon icon-inline ${message.deleted &&
192                             'text-danger'}`}
193                         >
194                           <use xlinkHref="#icon-trash"></use>
195                         </svg>
196                       </button>
197                     </li>
198                   </>
199                 )}
200                 <li className="list-inline-item">
201                   <button
202                     class="btn btn-link btn-sm btn-animate text-muted"
203                     onClick={linkEvent(this, this.handleViewSource)}
204                     data-tippy-content={i18n.t('view_source')}
205                   >
206                     <svg
207                       class={`icon icon-inline ${this.state.viewSource &&
208                         'text-success'}`}
209                     >
210                       <use xlinkHref="#icon-file-text"></use>
211                     </svg>
212                   </button>
213                 </li>
214               </ul>
215             </div>
216           )}
217         </div>
218         {this.state.showReply && (
219           <PrivateMessageForm
220             params={{
221               recipient_id: this.props.privateMessage.creator_id,
222             }}
223             onCreate={this.handlePrivateMessageCreate}
224           />
225         )}
226         {/* A collapsed clearfix */}
227         {this.state.collapsed && <div class="row col-12"></div>}
228       </div>
229     );
230   }
231
232   get messageUnlessRemoved(): string {
233     let message = this.props.privateMessage;
234     return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
235   }
236
237   handleReplyClick(i: PrivateMessage) {
238     i.state.showReply = true;
239     i.setState(i.state);
240   }
241
242   handleEditClick(i: PrivateMessage) {
243     i.state.showEdit = true;
244     i.setState(i.state);
245   }
246
247   handleDeleteClick(i: PrivateMessage) {
248     let form: EditPrivateMessageForm = {
249       edit_id: i.props.privateMessage.id,
250       deleted: !i.props.privateMessage.deleted,
251     };
252     WebSocketService.Instance.editPrivateMessage(form);
253   }
254
255   handleReplyCancel() {
256     this.state.showReply = false;
257     this.state.showEdit = false;
258     this.setState(this.state);
259   }
260
261   handleMarkRead(i: PrivateMessage) {
262     let form: EditPrivateMessageForm = {
263       edit_id: i.props.privateMessage.id,
264       read: !i.props.privateMessage.read,
265     };
266     WebSocketService.Instance.editPrivateMessage(form);
267   }
268
269   handleMessageCollapse(i: PrivateMessage) {
270     i.state.collapsed = !i.state.collapsed;
271     i.setState(i.state);
272   }
273
274   handleViewSource(i: PrivateMessage) {
275     i.state.viewSource = !i.state.viewSource;
276     i.setState(i.state);
277   }
278
279   handlePrivateMessageEdit() {
280     this.state.showEdit = false;
281     this.setState(this.state);
282   }
283
284   handlePrivateMessageCreate() {
285     this.state.showReply = false;
286     this.setState(this.state);
287     toast(i18n.t('message_sent'));
288   }
289 }