1 import { Component, linkEvent } from 'inferno';
2 import { Link } 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,
24 pictshareAvatarThumbnail,
28 import autosize from 'autosize';
29 import { i18n } from '../i18next';
30 import { T } from 'inferno-i18next';
32 interface PrivateMessageFormProps {
33 privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
34 params?: PrivateMessageFormParams;
36 onCreate?(message: PrivateMessage): any;
37 onEdit?(message: PrivateMessage): any;
40 interface PrivateMessageFormState {
41 privateMessageForm: PrivateMessageFormI;
45 showDisclaimer: boolean;
48 export class PrivateMessageForm extends Component<
49 PrivateMessageFormProps,
50 PrivateMessageFormState
52 private subscription: Subscription;
53 private emptyState: PrivateMessageFormState = {
61 showDisclaimer: false,
64 constructor(props: any, context: any) {
65 super(props, context);
67 this.state = this.emptyState;
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')
96 autosize(document.querySelectorAll('textarea'));
99 componentWillUnmount() {
100 this.subscription.unsubscribe();
106 <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
107 {!this.props.privateMessage && (
108 <div class="form-group row">
109 <label class="col-sm-2 col-form-label">
110 {capitalizeFirstLetter(i18n.t('to'))}
113 {this.state.recipient && (
114 <div class="col-sm-10 form-control-plaintext">
116 className="text-info"
117 to={`/u/${this.state.recipient.name}`}
119 {this.state.recipient.avatar && showAvatars() && (
123 src={pictshareAvatarThumbnail(
124 this.state.recipient.avatar
126 class="rounded-circle mr-1"
129 <span>{this.state.recipient.name}</span>
135 <div class="form-group row">
136 <label class="col-sm-2 col-form-label">{i18n.t('message')}</label>
137 <div class="col-sm-10">
139 value={this.state.privateMessageForm.content}
140 onInput={linkEvent(this, this.handleContentChange)}
141 className={`form-control ${this.state.previewMode && 'd-none'}`}
145 {this.state.previewMode && (
148 dangerouslySetInnerHTML={mdToHtml(
149 this.state.privateMessageForm.content
154 {this.state.privateMessageForm.content && (
156 className={`mt-1 mr-2 btn btn-sm btn-secondary ${this.state
157 .previewMode && 'active'}`}
158 onClick={linkEvent(this, this.handlePreviewToggle)}
163 <ul class="float-right list-inline mb-1 text-muted small font-weight-bold">
164 <li class="list-inline-item">
166 onClick={linkEvent(this, this.handleShowDisclaimer)}
169 {i18n.t('disclaimer')}
172 <li class="list-inline-item">
173 <a href={markdownHelpUrl} target="_blank" class="text-muted">
174 {i18n.t('formatting_help')}
181 {this.state.showDisclaimer && (
182 <div class="form-group row">
183 <div class="col-sm-10">
184 <div class="alert alert-danger" role="alert">
185 <T i18nKey="private_message_disclaimer">
190 href="https://about.riot.im/"
199 <div class="form-group row">
200 <div class="col-sm-10">
201 <button type="submit" class="btn btn-secondary mr-2">
202 {this.state.loading ? (
203 <svg class="icon icon-spinner spin">
204 <use xlinkHref="#icon-spinner"></use>
206 ) : this.props.privateMessage ? (
207 capitalizeFirstLetter(i18n.t('save'))
209 capitalizeFirstLetter(i18n.t('send_message'))
212 {this.props.privateMessage && (
215 class="btn btn-secondary"
216 onClick={linkEvent(this, this.handleCancel)}
228 handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
229 event.preventDefault();
230 if (i.props.privateMessage) {
231 let editForm: EditPrivateMessageForm = {
232 edit_id: i.props.privateMessage.id,
233 content: i.state.privateMessageForm.content,
235 WebSocketService.Instance.editPrivateMessage(editForm);
237 WebSocketService.Instance.createPrivateMessage(
238 i.state.privateMessageForm
241 i.state.loading = true;
245 handleRecipientChange(i: PrivateMessageForm, event: any) {
246 i.state.recipient = event.target.value;
250 handleContentChange(i: PrivateMessageForm, event: any) {
251 i.state.privateMessageForm.content = event.target.value;
255 handleCancel(i: PrivateMessageForm) {
259 handlePreviewToggle(i: PrivateMessageForm, event: any) {
260 event.preventDefault();
261 i.state.previewMode = !i.state.previewMode;
265 handleShowDisclaimer(i: PrivateMessageForm) {
266 i.state.showDisclaimer = !i.state.showDisclaimer;
270 parseMessage(msg: WebSocketJsonResponse) {
271 let res = wsJsonToRes(msg);
273 toast(i18n.t(msg.error), 'danger');
274 this.state.loading = false;
275 this.setState(this.state);
277 } else if (res.op == UserOperation.EditPrivateMessage) {
278 let data = res.data as PrivateMessageResponse;
279 this.state.loading = false;
280 this.props.onEdit(data.message);
281 } else if (res.op == UserOperation.GetUserDetails) {
282 let data = res.data as UserDetailsResponse;
283 this.state.recipient = data.user;
284 this.state.privateMessageForm.recipient_id = data.user.id;
285 this.setState(this.state);
286 } else if (res.op == UserOperation.CreatePrivateMessage) {
287 let data = res.data as PrivateMessageResponse;
288 this.state.loading = false;
289 this.props.onCreate(data.message);
290 this.setState(this.state);