1 import { Component, linkEvent } from 'inferno';
2 import { Prompt } from 'inferno-router';
3 import { Subscription } from 'rxjs';
4 import { retryWhen, delay, take } from 'rxjs/operators';
6 PrivateMessageForm as PrivateMessageFormI,
7 EditPrivateMessageForm,
8 PrivateMessageFormParams,
10 PrivateMessageResponse,
16 WebSocketJsonResponse,
17 } from '../interfaces';
18 import { WebSocketService } from '../services';
20 capitalizeFirstLetter,
25 import { UserListing } from './user-listing';
26 import { MarkdownTextArea } from './markdown-textarea';
27 import { i18n } from '../i18next';
28 import { T } from 'inferno-i18next';
30 interface PrivateMessageFormProps {
31 privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
32 params?: PrivateMessageFormParams;
34 onCreate?(message: PrivateMessage): any;
35 onEdit?(message: PrivateMessage): any;
38 interface PrivateMessageFormState {
39 privateMessageForm: PrivateMessageFormI;
43 showDisclaimer: boolean;
46 export class PrivateMessageForm extends Component<
47 PrivateMessageFormProps,
48 PrivateMessageFormState
50 private subscription: Subscription;
51 private emptyState: PrivateMessageFormState = {
59 showDisclaimer: false,
62 constructor(props: any, context: any) {
63 super(props, context);
65 this.state = this.emptyState;
67 this.handleContentChange = this.handleContentChange.bind(this);
69 if (this.props.privateMessage) {
70 this.state.privateMessageForm = {
71 content: this.props.privateMessage.content,
72 recipient_id: this.props.privateMessage.recipient_id,
76 if (this.props.params) {
77 this.state.privateMessageForm.recipient_id = this.props.params.recipient_id;
78 let form: GetUserDetailsForm = {
79 user_id: this.state.privateMessageForm.recipient_id,
80 sort: SortType[SortType.New],
83 WebSocketService.Instance.getUserDetails(form);
86 this.subscription = WebSocketService.Instance.subject
87 .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
89 msg => this.parseMessage(msg),
90 err => console.error(err),
91 () => console.log('complete')
99 componentDidUpdate() {
100 if (!this.state.loading && this.state.privateMessageForm.content) {
101 window.onbeforeunload = () => true;
103 window.onbeforeunload = undefined;
107 componentWillUnmount() {
108 this.subscription.unsubscribe();
109 window.onbeforeunload = null;
116 when={!this.state.loading && this.state.privateMessageForm.content}
117 message={i18n.t('block_leaving')}
119 <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
120 {!this.props.privateMessage && (
121 <div class="form-group row">
122 <label class="col-sm-2 col-form-label">
123 {capitalizeFirstLetter(i18n.t('to'))}
126 {this.state.recipient && (
127 <div class="col-sm-10 form-control-plaintext">
130 name: this.state.recipient.name,
131 preferred_username: this.state.recipient
133 avatar: this.state.recipient.avatar,
134 id: this.state.recipient.id,
135 local: this.state.recipient.local,
136 actor_id: this.state.recipient.actor_id,
143 <div class="form-group row">
144 <label class="col-sm-2 col-form-label">
147 onClick={linkEvent(this, this.handleShowDisclaimer)}
148 class="ml-2 pointer text-danger"
149 data-tippy-content={i18n.t('disclaimer')}
151 <svg class={`icon icon-inline`}>
152 <use xlinkHref="#icon-alert-triangle"></use>
156 <div class="col-sm-10">
158 initialContent={this.state.privateMessageForm.content}
159 onContentChange={this.handleContentChange}
164 {this.state.showDisclaimer && (
165 <div class="form-group row">
166 <div class="offset-sm-2 col-sm-10">
167 <div class="alert alert-danger" role="alert">
168 <T i18nKey="private_message_disclaimer">
174 href="https://element.io/get-started"
183 <div class="form-group row">
184 <div class="offset-sm-2 col-sm-10">
187 class="btn btn-secondary mr-2"
188 disabled={this.state.loading}
190 {this.state.loading ? (
191 <svg class="icon icon-spinner spin">
192 <use xlinkHref="#icon-spinner"></use>
194 ) : this.props.privateMessage ? (
195 capitalizeFirstLetter(i18n.t('save'))
197 capitalizeFirstLetter(i18n.t('send_message'))
200 {this.props.privateMessage && (
203 class="btn btn-secondary"
204 onClick={linkEvent(this, this.handleCancel)}
209 <ul class="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
210 <li class="list-inline-item"></li>
219 handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
220 event.preventDefault();
221 if (i.props.privateMessage) {
222 let editForm: EditPrivateMessageForm = {
223 edit_id: i.props.privateMessage.id,
224 content: i.state.privateMessageForm.content,
226 WebSocketService.Instance.editPrivateMessage(editForm);
228 WebSocketService.Instance.createPrivateMessage(
229 i.state.privateMessageForm
232 i.state.loading = true;
236 handleRecipientChange(i: PrivateMessageForm, event: any) {
237 i.state.recipient = event.target.value;
241 handleContentChange(val: string) {
242 this.state.privateMessageForm.content = val;
243 this.setState(this.state);
246 handleCancel(i: PrivateMessageForm) {
250 handlePreviewToggle(i: PrivateMessageForm, event: any) {
251 event.preventDefault();
252 i.state.previewMode = !i.state.previewMode;
256 handleShowDisclaimer(i: PrivateMessageForm) {
257 i.state.showDisclaimer = !i.state.showDisclaimer;
261 parseMessage(msg: WebSocketJsonResponse) {
262 let res = wsJsonToRes(msg);
264 toast(i18n.t(msg.error), 'danger');
265 this.state.loading = false;
266 this.setState(this.state);
269 res.op == UserOperation.EditPrivateMessage ||
270 res.op == UserOperation.DeletePrivateMessage ||
271 res.op == UserOperation.MarkPrivateMessageAsRead
273 let data = res.data as PrivateMessageResponse;
274 this.state.loading = false;
275 this.props.onEdit(data.message);
276 } else if (res.op == UserOperation.GetUserDetails) {
277 let data = res.data as UserDetailsResponse;
278 this.state.recipient = data.user;
279 this.state.privateMessageForm.recipient_id = data.user.id;
280 this.setState(this.state);
281 } else if (res.op == UserOperation.CreatePrivateMessage) {
282 let data = res.data as PrivateMessageResponse;
283 this.state.loading = false;
284 this.props.onCreate(data.message);
285 this.setState(this.state);