]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private-message-form.tsx
WIP:Aadd drone ci config
[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   PrivateMessageForm as PrivateMessageFormI,
6   EditPrivateMessageForm,
7   PrivateMessage,
8   PrivateMessageResponse,
9   UserView,
10   UserOperation,
11   WebSocketJsonResponse,
12 } from 'lemmy-js-client';
13 import { WebSocketService } from '../services';
14 import {
15   capitalizeFirstLetter,
16   wsJsonToRes,
17   toast,
18   setupTippy,
19   wsSubscribe,
20   isBrowser,
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: UserView;
29   privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
30   onCancel?(): any;
31   onCreate?(message: PrivateMessage): any;
32   onEdit?(message: PrivateMessage): any;
33 }
34
35 interface PrivateMessageFormState {
36   privateMessageForm: PrivateMessageFormI;
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     },
52     loading: false,
53     previewMode: false,
54     showDisclaimer: false,
55   };
56
57   constructor(props: any, context: any) {
58     super(props, context);
59
60     this.state = this.emptyState;
61
62     this.handleContentChange = this.handleContentChange.bind(this);
63
64     this.parseMessage = this.parseMessage.bind(this);
65     this.subscription = wsSubscribe(this.parseMessage);
66
67     if (this.props.privateMessage) {
68       this.state.privateMessageForm = {
69         content: this.props.privateMessage.content,
70         recipient_id: this.props.privateMessage.recipient_id,
71       };
72     }
73   }
74
75   componentDidMount() {
76     setupTippy();
77   }
78
79   componentDidUpdate() {
80     if (!this.state.loading && this.state.privateMessageForm.content) {
81       window.onbeforeunload = () => true;
82     } else {
83       window.onbeforeunload = undefined;
84     }
85   }
86
87   componentWillUnmount() {
88     if (isBrowser()) {
89       this.subscription.unsubscribe();
90       window.onbeforeunload = null;
91     }
92   }
93
94   render() {
95     return (
96       <div>
97         <Prompt
98           when={!this.state.loading && this.state.privateMessageForm.content}
99           message={i18n.t('block_leaving')}
100         />
101         <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
102           {!this.props.privateMessage && (
103             <div class="form-group row">
104               <label class="col-sm-2 col-form-label">
105                 {capitalizeFirstLetter(i18n.t('to'))}
106               </label>
107
108               <div class="col-sm-10 form-control-plaintext">
109                 <UserListing
110                   user={{
111                     name: this.props.recipient.name,
112                     preferred_username: this.props.recipient.preferred_username,
113                     avatar: this.props.recipient.avatar,
114                     id: this.props.recipient.id,
115                     local: this.props.recipient.local,
116                     actor_id: this.props.recipient.actor_id,
117                   }}
118                 />
119               </div>
120             </div>
121           )}
122           <div class="form-group row">
123             <label class="col-sm-2 col-form-label">
124               {i18n.t('message')}
125               <span
126                 onClick={linkEvent(this, this.handleShowDisclaimer)}
127                 class="ml-2 pointer text-danger"
128                 data-tippy-content={i18n.t('disclaimer')}
129               >
130                 <svg class={`icon icon-inline`}>
131                   <use xlinkHref="#icon-alert-triangle"></use>
132                 </svg>
133               </span>
134             </label>
135             <div class="col-sm-10">
136               <MarkdownTextArea
137                 initialContent={this.state.privateMessageForm.content}
138                 onContentChange={this.handleContentChange}
139               />
140             </div>
141           </div>
142
143           {this.state.showDisclaimer && (
144             <div class="form-group row">
145               <div class="offset-sm-2 col-sm-10">
146                 <div class="alert alert-danger" role="alert">
147                   <T i18nKey="private_message_disclaimer">
148                     #
149                     <a
150                       class="alert-link"
151                       target="_blank"
152                       rel="noopener"
153                       href="https://element.io/get-started"
154                     >
155                       #
156                     </a>
157                   </T>
158                 </div>
159               </div>
160             </div>
161           )}
162           <div class="form-group row">
163             <div class="offset-sm-2 col-sm-10">
164               <button
165                 type="submit"
166                 class="btn btn-secondary mr-2"
167                 disabled={this.state.loading}
168               >
169                 {this.state.loading ? (
170                   <svg class="icon icon-spinner spin">
171                     <use xlinkHref="#icon-spinner"></use>
172                   </svg>
173                 ) : this.props.privateMessage ? (
174                   capitalizeFirstLetter(i18n.t('save'))
175                 ) : (
176                   capitalizeFirstLetter(i18n.t('send_message'))
177                 )}
178               </button>
179               {this.props.privateMessage && (
180                 <button
181                   type="button"
182                   class="btn btn-secondary"
183                   onClick={linkEvent(this, this.handleCancel)}
184                 >
185                   {i18n.t('cancel')}
186                 </button>
187               )}
188               <ul class="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
189                 <li class="list-inline-item"></li>
190               </ul>
191             </div>
192           </div>
193         </form>
194       </div>
195     );
196   }
197
198   handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
199     event.preventDefault();
200     if (i.props.privateMessage) {
201       let editForm: EditPrivateMessageForm = {
202         edit_id: i.props.privateMessage.id,
203         content: i.state.privateMessageForm.content,
204       };
205       WebSocketService.Instance.editPrivateMessage(editForm);
206     } else {
207       WebSocketService.Instance.createPrivateMessage(
208         i.state.privateMessageForm
209       );
210     }
211     i.state.loading = true;
212     i.setState(i.state);
213   }
214
215   handleContentChange(val: string) {
216     this.state.privateMessageForm.content = val;
217     this.setState(this.state);
218   }
219
220   handleCancel(i: PrivateMessageForm) {
221     i.props.onCancel();
222   }
223
224   handlePreviewToggle(i: PrivateMessageForm, event: any) {
225     event.preventDefault();
226     i.state.previewMode = !i.state.previewMode;
227     i.setState(i.state);
228   }
229
230   handleShowDisclaimer(i: PrivateMessageForm) {
231     i.state.showDisclaimer = !i.state.showDisclaimer;
232     i.setState(i.state);
233   }
234
235   parseMessage(msg: WebSocketJsonResponse) {
236     let res = wsJsonToRes(msg);
237     if (msg.error) {
238       toast(i18n.t(msg.error), 'danger');
239       this.state.loading = false;
240       this.setState(this.state);
241       return;
242     } else if (
243       res.op == UserOperation.EditPrivateMessage ||
244       res.op == UserOperation.DeletePrivateMessage ||
245       res.op == UserOperation.MarkPrivateMessageAsRead
246     ) {
247       let data = res.data as PrivateMessageResponse;
248       this.state.loading = false;
249       this.props.onEdit(data.message);
250     } else if (res.op == UserOperation.CreatePrivateMessage) {
251       let data = res.data as PrivateMessageResponse;
252       this.state.loading = false;
253       this.props.onCreate(data.message);
254       this.setState(this.state);
255     }
256   }
257 }