]> Untitled Git - lemmy.git/blob - ui/src/components/private-message.tsx
Initial post-listing community non-local.
[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             <li className="list-inline-item">
62               {this.mine ? i18n.t('to') : i18n.t('from')}
63             </li>
64             <li className="list-inline-item">
65               <Link
66                 className="text-body font-weight-bold"
67                 to={
68                   this.mine
69                     ? `/u/${message.recipient_name}`
70                     : `/u/${message.creator_name}`
71                 }
72               >
73                 {(this.mine
74                   ? message.recipient_avatar
75                   : message.creator_avatar) &&
76                   showAvatars() && (
77                     <img
78                       height="32"
79                       width="32"
80                       src={pictshareAvatarThumbnail(
81                         this.mine
82                           ? message.recipient_avatar
83                           : message.creator_avatar
84                       )}
85                       class="rounded-circle mr-1"
86                     />
87                   )}
88                 <span>
89                   {this.mine ? message.recipient_name : message.creator_name}
90                 </span>
91               </Link>
92             </li>
93             <li className="list-inline-item">
94               <span>
95                 <MomentTime data={message} />
96               </span>
97             </li>
98             <li className="list-inline-item">
99               <div
100                 className="pointer text-monospace"
101                 onClick={linkEvent(this, this.handleMessageCollapse)}
102               >
103                 {this.state.collapsed ? (
104                   <svg class="icon icon-inline">
105                     <use xlinkHref="#icon-plus-square"></use>
106                   </svg>
107                 ) : (
108                   <svg class="icon icon-inline">
109                     <use xlinkHref="#icon-minus-square"></use>
110                   </svg>
111                 )}
112               </div>
113             </li>
114           </ul>
115           {this.state.showEdit && (
116             <PrivateMessageForm
117               privateMessage={message}
118               onEdit={this.handlePrivateMessageEdit}
119               onCancel={this.handleReplyCancel}
120             />
121           )}
122           {!this.state.showEdit && !this.state.collapsed && (
123             <div>
124               {this.state.viewSource ? (
125                 <pre>{this.messageUnlessRemoved}</pre>
126               ) : (
127                 <div
128                   className="md-div"
129                   dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
130                 />
131               )}
132               <ul class="list-inline mb-0 text-muted font-weight-bold">
133                 {!this.mine && (
134                   <>
135                     <li className="list-inline-item">
136                       <button
137                         class="btn btn-link btn-sm btn-animate text-muted"
138                         onClick={linkEvent(this, this.handleMarkRead)}
139                         data-tippy-content={
140                           message.read
141                             ? i18n.t('mark_as_unread')
142                             : i18n.t('mark_as_read')
143                         }
144                       >
145                         <svg
146                           class={`icon icon-inline ${message.read &&
147                             'text-success'}`}
148                         >
149                           <use xlinkHref="#icon-check"></use>
150                         </svg>
151                       </button>
152                     </li>
153                     <li className="list-inline-item">
154                       <button
155                         class="btn btn-link btn-sm btn-animate text-muted"
156                         onClick={linkEvent(this, this.handleReplyClick)}
157                         data-tippy-content={i18n.t('reply')}
158                       >
159                         <svg class="icon icon-inline">
160                           <use xlinkHref="#icon-reply1"></use>
161                         </svg>
162                       </button>
163                     </li>
164                   </>
165                 )}
166                 {this.mine && (
167                   <>
168                     <li className="list-inline-item">
169                       <button
170                         class="btn btn-link btn-sm btn-animate text-muted"
171                         onClick={linkEvent(this, this.handleEditClick)}
172                         data-tippy-content={i18n.t('edit')}
173                       >
174                         <svg class="icon icon-inline">
175                           <use xlinkHref="#icon-edit"></use>
176                         </svg>
177                       </button>
178                     </li>
179                     <li className="list-inline-item">
180                       <button
181                         class="btn btn-link btn-sm btn-animate text-muted"
182                         onClick={linkEvent(this, this.handleDeleteClick)}
183                         data-tippy-content={
184                           !message.deleted
185                             ? i18n.t('delete')
186                             : i18n.t('restore')
187                         }
188                       >
189                         <svg
190                           class={`icon icon-inline ${message.deleted &&
191                             'text-danger'}`}
192                         >
193                           <use xlinkHref="#icon-trash"></use>
194                         </svg>
195                       </button>
196                     </li>
197                   </>
198                 )}
199                 <li className="list-inline-item">
200                   <button
201                     class="btn btn-link btn-sm btn-animate text-muted"
202                     onClick={linkEvent(this, this.handleViewSource)}
203                     data-tippy-content={i18n.t('view_source')}
204                   >
205                     <svg
206                       class={`icon icon-inline ${this.state.viewSource &&
207                         'text-success'}`}
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: EditPrivateMessageForm = {
248       edit_id: i.props.privateMessage.id,
249       deleted: !i.props.privateMessage.deleted,
250     };
251     WebSocketService.Instance.editPrivateMessage(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: EditPrivateMessageForm = {
262       edit_id: i.props.privateMessage.id,
263       read: !i.props.privateMessage.read,
264     };
265     WebSocketService.Instance.editPrivateMessage(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 }