]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private-message-form.tsx
First pass at v2_api
[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 { UserService, WebSocketService } from '../services';
13 import {
14   capitalizeFirstLetter,
15   wsJsonToRes,
16   toast,
17   setupTippy,
18   wsSubscribe,
19   isBrowser,
20   wsUserOp,
21 } from '../utils';
22 import { UserListing } from './user-listing';
23 import { MarkdownTextArea } from './markdown-textarea';
24 import { i18n } from '../i18next';
25 import { T } from 'inferno-i18next';
26
27 interface PrivateMessageFormProps {
28   recipient: UserSafe;
29   privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit
30   onCancel?(): any;
31   onCreate?(message: PrivateMessageView): any;
32   onEdit?(message: PrivateMessageView): any;
33 }
34
35 interface PrivateMessageFormState {
36   privateMessageForm: CreatePrivateMessage;
37   loading: boolean;
38   previewMode: boolean;
39   showDisclaimer: boolean;
40 }
41
42 export class PrivateMessageForm extends Component<
43   PrivateMessageFormProps,
44   PrivateMessageFormState
45 > {
46   private subscription: Subscription;
47   private emptyState: PrivateMessageFormState = {
48     privateMessageForm: {
49       content: null,
50       recipient_id: this.props.recipient.id,
51       auth: UserService.Instance.authField(),
52     },
53     loading: false,
54     previewMode: false,
55     showDisclaimer: false,
56   };
57
58   constructor(props: any, context: any) {
59     super(props, context);
60
61     this.state = this.emptyState;
62
63     this.handleContentChange = this.handleContentChange.bind(this);
64
65     this.parseMessage = this.parseMessage.bind(this);
66     this.subscription = wsSubscribe(this.parseMessage);
67
68     // Its an edit
69     if (this.props.privateMessage) {
70       this.state.privateMessageForm.content = this.props.privateMessage.private_message.content;
71     }
72   }
73
74   componentDidMount() {
75     setupTippy();
76   }
77
78   componentDidUpdate() {
79     if (!this.state.loading && this.state.privateMessageForm.content) {
80       window.onbeforeunload = () => true;
81     } else {
82       window.onbeforeunload = undefined;
83     }
84   }
85
86   componentWillUnmount() {
87     if (isBrowser()) {
88       this.subscription.unsubscribe();
89       window.onbeforeunload = null;
90     }
91   }
92
93   render() {
94     return (
95       <div>
96         <Prompt
97           when={!this.state.loading && this.state.privateMessageForm.content}
98           message={i18n.t('block_leaving')}
99         />
100         <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
101           {!this.props.privateMessage && (
102             <div class="form-group row">
103               <label class="col-sm-2 col-form-label">
104                 {capitalizeFirstLetter(i18n.t('to'))}
105               </label>
106
107               <div class="col-sm-10 form-control-plaintext">
108                 <UserListing user={this.props.recipient} />
109               </div>
110             </div>
111           )}
112           <div class="form-group row">
113             <label class="col-sm-2 col-form-label">
114               {i18n.t('message')}
115               <span
116                 onClick={linkEvent(this, this.handleShowDisclaimer)}
117                 class="ml-2 pointer text-danger"
118                 data-tippy-content={i18n.t('disclaimer')}
119               >
120                 <svg class={`icon icon-inline`}>
121                   <use xlinkHref="#icon-alert-triangle"></use>
122                 </svg>
123               </span>
124             </label>
125             <div class="col-sm-10">
126               <MarkdownTextArea
127                 initialContent={this.state.privateMessageForm.content}
128                 onContentChange={this.handleContentChange}
129               />
130             </div>
131           </div>
132
133           {this.state.showDisclaimer && (
134             <div class="form-group row">
135               <div class="offset-sm-2 col-sm-10">
136                 <div class="alert alert-danger" role="alert">
137                   <T i18nKey="private_message_disclaimer">
138                     #
139                     <a
140                       class="alert-link"
141                       target="_blank"
142                       rel="noopener"
143                       href="https://element.io/get-started"
144                     >
145                       #
146                     </a>
147                   </T>
148                 </div>
149               </div>
150             </div>
151           )}
152           <div class="form-group row">
153             <div class="offset-sm-2 col-sm-10">
154               <button
155                 type="submit"
156                 class="btn btn-secondary mr-2"
157                 disabled={this.state.loading}
158               >
159                 {this.state.loading ? (
160                   <svg class="icon icon-spinner spin">
161                     <use xlinkHref="#icon-spinner"></use>
162                   </svg>
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         edit_id: i.props.privateMessage.private_message.id,
193         content: i.state.privateMessageForm.content,
194         auth: UserService.Instance.authField(),
195       };
196       WebSocketService.Instance.client.editPrivateMessage(form);
197     } else {
198       WebSocketService.Instance.client.createPrivateMessage(
199         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     if (msg.error) {
229       toast(i18n.t(msg.error), 'danger');
230       this.state.loading = false;
231       this.setState(this.state);
232       return;
233     } else if (
234       op == UserOperation.EditPrivateMessage ||
235       op == UserOperation.DeletePrivateMessage ||
236       op == UserOperation.MarkPrivateMessageAsRead
237     ) {
238       let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
239       this.state.loading = false;
240       this.props.onEdit(data.private_message_view);
241     } else if (op == UserOperation.CreatePrivateMessage) {
242       let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
243       this.state.loading = false;
244       this.props.onCreate(data.private_message_view);
245       this.setState(this.state);
246     }
247   }
248 }