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