]> Untitled Git - lemmy.git/blob - ui/src/components/private-message.tsx
Merge branch 'master' of https://github.com/makigi-io/makigi into makigi-io-master
[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 { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils';
9 import { MomentTime } from './moment-time';
10 import { PrivateMessageForm } from './private-message-form';
11 import { i18n } from '../i18next';
12
13 interface PrivateMessageState {
14   showReply: boolean;
15   showEdit: boolean;
16   collapsed: boolean;
17   viewSource: boolean;
18 }
19
20 interface PrivateMessageProps {
21   privateMessage: PrivateMessageI;
22 }
23
24 export class PrivateMessage extends Component<
25   PrivateMessageProps,
26   PrivateMessageState
27 > {
28   private emptyState: PrivateMessageState = {
29     showReply: false,
30     showEdit: false,
31     collapsed: false,
32     viewSource: false,
33   };
34
35   constructor(props: any, context: any) {
36     super(props, context);
37
38     this.state = this.emptyState;
39     this.handleReplyCancel = this.handleReplyCancel.bind(this);
40     this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
41       this
42     );
43     this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
44   }
45
46   get mine(): boolean {
47     return UserService.Instance.user.id == this.props.privateMessage.creator_id;
48   }
49
50   render() {
51     let message = this.props.privateMessage;
52     return (
53       <div class="border-top border-light">
54         <div>
55           <ul class="list-inline mb-0 text-muted small">
56             {/* TODO refactor this */}
57             <li className="list-inline-item">
58               {this.mine ? i18n.t('to') : i18n.t('from')}
59             </li>
60             <li className="list-inline-item">
61               <Link
62                 className="text-body font-weight-bold"
63                 to={
64                   this.mine
65                     ? `/u/${message.recipient_name}`
66                     : `/u/${message.creator_name}`
67                 }
68               >
69                 {(this.mine
70                   ? message.recipient_avatar
71                   : message.creator_avatar) &&
72                   showAvatars() && (
73                     <img
74                       height="32"
75                       width="32"
76                       src={pictrsAvatarThumbnail(
77                         this.mine
78                           ? message.recipient_avatar
79                           : message.creator_avatar
80                       )}
81                       class="rounded-circle mr-1"
82                     />
83                   )}
84                 <span>
85                   {this.mine ? message.recipient_name : message.creator_name}
86                 </span>
87               </Link>
88             </li>
89             <li className="list-inline-item">
90               <span>
91                 <MomentTime data={message} />
92               </span>
93             </li>
94             <li className="list-inline-item">
95               <div
96                 className="pointer text-monospace"
97                 onClick={linkEvent(this, this.handleMessageCollapse)}
98               >
99                 {this.state.collapsed ? (
100                   <svg class="icon icon-inline">
101                     <use xlinkHref="#icon-plus-square"></use>
102                   </svg>
103                 ) : (
104                   <svg class="icon icon-inline">
105                     <use xlinkHref="#icon-minus-square"></use>
106                   </svg>
107                 )}
108               </div>
109             </li>
110           </ul>
111           {this.state.showEdit && (
112             <PrivateMessageForm
113               privateMessage={message}
114               onEdit={this.handlePrivateMessageEdit}
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-sm 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-sm 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-sm 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-sm 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-sm 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: EditPrivateMessageForm = {
247       edit_id: i.props.privateMessage.id,
248       deleted: !i.props.privateMessage.deleted,
249     };
250     WebSocketService.Instance.editPrivateMessage(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: EditPrivateMessageForm = {
261       edit_id: i.props.privateMessage.id,
262       read: !i.props.privateMessage.read,
263     };
264     WebSocketService.Instance.editPrivateMessage(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() {
283     this.state.showReply = false;
284     this.setState(this.state);
285     toast(i18n.t('message_sent'));
286   }
287 }