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 } from '../interfaces';
17 import { WebSocketService } from '../services';
20 capitalizeFirstLetter,
24 pictshareAvatarThumbnail,
26 import autosize from 'autosize';
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 if (this.props.privateMessage) {
68 this.state.privateMessageForm = {
69 content: this.props.privateMessage.content,
70 recipient_id: this.props.privateMessage.recipient_id,
74 if (this.props.params) {
75 this.state.privateMessageForm.recipient_id = this.props.params.recipient_id;
76 let form: GetUserDetailsForm = {
77 user_id: this.state.privateMessageForm.recipient_id,
78 sort: SortType[SortType.New],
81 WebSocketService.Instance.getUserDetails(form);
84 this.subscription = WebSocketService.Instance.subject
85 .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
87 msg => this.parseMessage(msg),
88 err => console.error(err),
89 () => console.log('complete')
94 autosize(document.querySelectorAll('textarea'));
97 componentWillUnmount() {
98 this.subscription.unsubscribe();
104 <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
105 {!this.props.privateMessage && (
106 <div class="form-group row">
107 <label class="col-sm-2 col-form-label">
108 {capitalizeFirstLetter(i18n.t('to'))}
111 {this.state.recipient && (
112 <div class="col-sm-10 form-control-plaintext">
114 className="text-info"
115 to={`/u/${this.state.recipient.name}`}
117 {this.state.recipient.avatar && showAvatars() && (
121 src={pictshareAvatarThumbnail(
122 this.state.recipient.avatar
124 class="rounded-circle mr-1"
127 <span>{this.state.recipient.name}</span>
133 <div class="form-group row">
134 <label class="col-sm-2 col-form-label">{i18n.t('message')}</label>
135 <div class="col-sm-10">
137 value={this.state.privateMessageForm.content}
138 onInput={linkEvent(this, this.handleContentChange)}
139 className={`form-control ${this.state.previewMode && 'd-none'}`}
143 {this.state.previewMode && (
146 dangerouslySetInnerHTML={mdToHtml(
147 this.state.privateMessageForm.content
152 {this.state.privateMessageForm.content && (
154 className={`mt-1 mr-2 btn btn-sm btn-secondary ${this.state
155 .previewMode && 'active'}`}
156 onClick={linkEvent(this, this.handlePreviewToggle)}
161 <ul class="float-right list-inline mb-1 text-muted small font-weight-bold">
162 <li class="list-inline-item">
164 onClick={linkEvent(this, this.handleShowDisclaimer)}
167 {i18n.t('disclaimer')}
170 <li class="list-inline-item">
171 <a href={markdownHelpUrl} target="_blank" class="text-muted">
172 {i18n.t('formatting_help')}
179 {this.state.showDisclaimer && (
180 <div class="form-group row">
181 <div class="col-sm-10">
182 <div class="alert alert-danger" role="alert">
183 <T i18nKey="private_message_disclaimer">
188 href="https://about.riot.im/"
197 <div class="form-group row">
198 <div class="col-sm-10">
199 <button type="submit" class="btn btn-secondary mr-2">
200 {this.state.loading ? (
201 <svg class="icon icon-spinner spin">
202 <use xlinkHref="#icon-spinner"></use>
204 ) : this.props.privateMessage ? (
205 capitalizeFirstLetter(i18n.t('save'))
207 capitalizeFirstLetter(i18n.t('send_message'))
210 {this.props.privateMessage && (
213 class="btn btn-secondary"
214 onClick={linkEvent(this, this.handleCancel)}
226 handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
227 event.preventDefault();
228 if (i.props.privateMessage) {
229 let editForm: EditPrivateMessageForm = {
230 edit_id: i.props.privateMessage.id,
231 content: i.state.privateMessageForm.content,
233 WebSocketService.Instance.editPrivateMessage(editForm);
235 WebSocketService.Instance.createPrivateMessage(
236 i.state.privateMessageForm
239 i.state.loading = true;
243 handleRecipientChange(i: PrivateMessageForm, event: any) {
244 i.state.recipient = event.target.value;
248 handleContentChange(i: PrivateMessageForm, event: any) {
249 i.state.privateMessageForm.content = event.target.value;
253 handleCancel(i: PrivateMessageForm) {
257 handlePreviewToggle(i: PrivateMessageForm, event: any) {
258 event.preventDefault();
259 i.state.previewMode = !i.state.previewMode;
263 handleShowDisclaimer(i: PrivateMessageForm) {
264 i.state.showDisclaimer = !i.state.showDisclaimer;
268 parseMessage(msg: any) {
269 let op: UserOperation = msgOp(msg);
271 alert(i18n.t(msg.error));
272 this.state.loading = false;
273 this.setState(this.state);
275 } else if (op == UserOperation.EditPrivateMessage) {
276 this.state.loading = false;
277 let res: PrivateMessageResponse = msg;
278 this.props.onEdit(res.message);
279 } else if (op == UserOperation.GetUserDetails) {
280 let res: UserDetailsResponse = msg;
281 this.state.recipient = res.user;
282 this.state.privateMessageForm.recipient_id = res.user.id;
283 this.setState(this.state);
284 } else if (op == UserOperation.CreatePrivateMessage) {
285 this.state.loading = false;
286 let res: PrivateMessageResponse = msg;
287 this.props.onCreate(res.message);
288 this.setState(this.state);