]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private_message/private-message-form.tsx
Change from using Link to NavLink. resolve #269
[lemmy-ui.git] / src / shared / components / private_message / private-message-form.tsx
1 import { Component, linkEvent } from "inferno";
2 import { T } from "inferno-i18next-dess";
3 import { Prompt } from "inferno-router";
4 import {
5   CreatePrivateMessage,
6   EditPrivateMessage,
7   PersonSafe,
8   PrivateMessageResponse,
9   PrivateMessageView,
10   UserOperation,
11 } from "lemmy-js-client";
12 import { Subscription } from "rxjs";
13 import { i18n } from "../../i18next";
14 import { WebSocketService } from "../../services";
15 import {
16   authField,
17   capitalizeFirstLetter,
18   isBrowser,
19   setupTippy,
20   toast,
21   wsClient,
22   wsJsonToRes,
23   wsSubscribe,
24   wsUserOp,
25 } from "../../utils";
26 import { Icon, Spinner } from "../common/icon";
27 import { MarkdownTextArea } from "../common/markdown-textarea";
28 import { PersonListing } from "../person/person-listing";
29
30 interface PrivateMessageFormProps {
31   recipient: PersonSafe;
32   privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit
33   onCancel?(): any;
34   onCreate?(message: PrivateMessageView): any;
35   onEdit?(message: PrivateMessageView): any;
36 }
37
38 interface PrivateMessageFormState {
39   privateMessageForm: CreatePrivateMessage;
40   loading: boolean;
41   previewMode: boolean;
42   showDisclaimer: boolean;
43 }
44
45 export class PrivateMessageForm extends Component<
46   PrivateMessageFormProps,
47   PrivateMessageFormState
48 > {
49   private subscription: Subscription;
50   private emptyState: PrivateMessageFormState = {
51     privateMessageForm: {
52       content: null,
53       recipient_id: this.props.recipient.id,
54       auth: authField(),
55     },
56     loading: false,
57     previewMode: false,
58     showDisclaimer: false,
59   };
60
61   constructor(props: any, context: any) {
62     super(props, context);
63
64     this.state = this.emptyState;
65
66     this.handleContentChange = this.handleContentChange.bind(this);
67
68     this.parseMessage = this.parseMessage.bind(this);
69     this.subscription = wsSubscribe(this.parseMessage);
70
71     // Its an edit
72     if (this.props.privateMessage) {
73       this.state.privateMessageForm.content =
74         this.props.privateMessage.private_message.content;
75     }
76   }
77
78   componentDidMount() {
79     setupTippy();
80   }
81
82   componentDidUpdate() {
83     if (!this.state.loading && this.state.privateMessageForm.content) {
84       window.onbeforeunload = () => true;
85     } else {
86       window.onbeforeunload = undefined;
87     }
88   }
89
90   componentWillUnmount() {
91     if (isBrowser()) {
92       this.subscription.unsubscribe();
93       window.onbeforeunload = null;
94     }
95   }
96
97   render() {
98     return (
99       <div>
100         <Prompt
101           when={!this.state.loading && this.state.privateMessageForm.content}
102           message={i18n.t("block_leaving")}
103         />
104         <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
105           {!this.props.privateMessage && (
106             <div class="form-group row">
107               <label class="col-sm-2 col-form-label">
108                 {capitalizeFirstLetter(i18n.t("to"))}
109               </label>
110
111               <div class="col-sm-10 form-control-plaintext">
112                 <PersonListing person={this.props.recipient} />
113               </div>
114             </div>
115           )}
116           <div class="form-group row">
117             <label class="col-sm-2 col-form-label">
118               {i18n.t("message")}
119               <button
120                 class="btn btn-link text-warning d-inline-block"
121                 onClick={linkEvent(this, this.handleShowDisclaimer)}
122                 data-tippy-content={i18n.t("private_message_disclaimer")}
123                 aria-label={i18n.t("private_message_disclaimer")}
124               >
125                 <Icon icon="alert-triangle" classes="icon-inline" />
126               </button>
127             </label>
128             <div class="col-sm-10">
129               <MarkdownTextArea
130                 initialContent={this.state.privateMessageForm.content}
131                 onContentChange={this.handleContentChange}
132               />
133             </div>
134           </div>
135
136           {this.state.showDisclaimer && (
137             <div class="form-group row">
138               <div class="offset-sm-2 col-sm-10">
139                 <div class="alert alert-danger" role="alert">
140                   <T i18nKey="private_message_disclaimer">
141                     #
142                     <a
143                       class="alert-link"
144                       rel="noopener"
145                       href="https://element.io/get-started"
146                     >
147                       #
148                     </a>
149                   </T>
150                 </div>
151               </div>
152             </div>
153           )}
154           <div class="form-group row">
155             <div class="offset-sm-2 col-sm-10">
156               <button
157                 type="submit"
158                 class="btn btn-secondary mr-2"
159                 disabled={this.state.loading}
160               >
161                 {this.state.loading ? (
162                   <Spinner />
163                 ) : this.props.privateMessage ? (
164                   capitalizeFirstLetter(i18n.t("save"))
165                 ) : (
166                   capitalizeFirstLetter(i18n.t("send_message"))
167                 )}
168               </button>
169               {this.props.privateMessage && (
170                 <button
171                   type="button"
172                   class="btn btn-secondary"
173                   onClick={linkEvent(this, this.handleCancel)}
174                 >
175                   {i18n.t("cancel")}
176                 </button>
177               )}
178               <ul class="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
179                 <li class="list-inline-item"></li>
180               </ul>
181             </div>
182           </div>
183         </form>
184       </div>
185     );
186   }
187
188   handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
189     event.preventDefault();
190     if (i.props.privateMessage) {
191       let form: EditPrivateMessage = {
192         private_message_id: i.props.privateMessage.private_message.id,
193         content: i.state.privateMessageForm.content,
194         auth: authField(),
195       };
196       WebSocketService.Instance.send(wsClient.editPrivateMessage(form));
197     } else {
198       WebSocketService.Instance.send(
199         wsClient.createPrivateMessage(i.state.privateMessageForm)
200       );
201     }
202     i.state.loading = true;
203     i.setState(i.state);
204   }
205
206   handleContentChange(val: string) {
207     this.state.privateMessageForm.content = val;
208     this.setState(this.state);
209   }
210
211   handleCancel(i: PrivateMessageForm) {
212     i.props.onCancel();
213   }
214
215   handlePreviewToggle(i: PrivateMessageForm, event: any) {
216     event.preventDefault();
217     i.state.previewMode = !i.state.previewMode;
218     i.setState(i.state);
219   }
220
221   handleShowDisclaimer(i: PrivateMessageForm) {
222     i.state.showDisclaimer = !i.state.showDisclaimer;
223     i.setState(i.state);
224   }
225
226   parseMessage(msg: any) {
227     let op = wsUserOp(msg);
228     console.log(msg);
229     if (msg.error) {
230       toast(i18n.t(msg.error), "danger");
231       this.state.loading = false;
232       this.setState(this.state);
233       return;
234     } else if (
235       op == UserOperation.EditPrivateMessage ||
236       op == UserOperation.DeletePrivateMessage ||
237       op == UserOperation.MarkPrivateMessageAsRead
238     ) {
239       let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
240       this.state.loading = false;
241       this.props.onEdit(data.private_message_view);
242     } else if (op == UserOperation.CreatePrivateMessage) {
243       let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
244       this.state.loading = false;
245       this.props.onCreate(data.private_message_view);
246       this.setState(this.state);
247     }
248   }
249 }