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