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