1 import { None, Option, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import { T } from "inferno-i18next-dess";
4 import { Prompt } from "inferno-router";
9 PrivateMessageResponse,
14 } from "lemmy-js-client";
15 import { Subscription } from "rxjs";
16 import { i18n } from "../../i18next";
17 import { WebSocketService } from "../../services";
20 capitalizeFirstLetter,
28 import { Icon, Spinner } from "../common/icon";
29 import { MarkdownTextArea } from "../common/markdown-textarea";
30 import { PersonListing } from "../person/person-listing";
32 interface PrivateMessageFormProps {
33 recipient: PersonSafe;
34 privateMessageView: Option<PrivateMessageView>; // If a pm is given, that means this is an edit
36 onCreate?(message: PrivateMessageView): any;
37 onEdit?(message: PrivateMessageView): any;
40 interface PrivateMessageFormState {
41 privateMessageForm: CreatePrivateMessage;
44 showDisclaimer: boolean;
47 export class PrivateMessageForm extends Component<
48 PrivateMessageFormProps,
49 PrivateMessageFormState
51 private subscription: Subscription;
52 private emptyState: PrivateMessageFormState = {
53 privateMessageForm: new CreatePrivateMessage({
55 recipient_id: this.props.recipient.id,
56 auth: auth().unwrap(),
60 showDisclaimer: false,
63 constructor(props: any, context: any) {
64 super(props, context);
66 this.state = this.emptyState;
68 this.handleContentChange = this.handleContentChange.bind(this);
70 this.parseMessage = this.parseMessage.bind(this);
71 this.subscription = wsSubscribe(this.parseMessage);
74 if (this.props.privateMessageView.isSome()) {
75 this.state.privateMessageForm.content =
76 this.props.privateMessageView.unwrap().private_message.content;
84 componentDidUpdate() {
85 if (!this.state.loading && this.state.privateMessageForm.content) {
86 window.onbeforeunload = () => true;
88 window.onbeforeunload = undefined;
92 componentWillUnmount() {
94 this.subscription.unsubscribe();
95 window.onbeforeunload = null;
103 when={!this.state.loading && this.state.privateMessageForm.content}
104 message={i18n.t("block_leaving")}
106 <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
107 {this.props.privateMessageView.isNone() && (
108 <div className="form-group row">
109 <label className="col-sm-2 col-form-label">
110 {capitalizeFirstLetter(i18n.t("to"))}
113 <div className="col-sm-10 form-control-plaintext">
114 <PersonListing person={this.props.recipient} />
118 <div className="form-group row">
119 <label className="col-sm-2 col-form-label">
122 className="btn btn-link text-warning d-inline-block"
123 onClick={linkEvent(this, this.handleShowDisclaimer)}
124 data-tippy-content={i18n.t("private_message_disclaimer")}
125 aria-label={i18n.t("private_message_disclaimer")}
127 <Icon icon="alert-triangle" classes="icon-inline" />
130 <div className="col-sm-10">
132 initialContent={Some(this.state.privateMessageForm.content)}
133 initialLanguageId={None}
137 onContentChange={this.handleContentChange}
143 {this.state.showDisclaimer && (
144 <div className="form-group row">
145 <div className="offset-sm-2 col-sm-10">
146 <div className="alert alert-danger" role="alert">
147 <T i18nKey="private_message_disclaimer">
150 className="alert-link"
152 href="https://element.io/get-started"
161 <div className="form-group row">
162 <div className="offset-sm-2 col-sm-10">
165 className="btn btn-secondary mr-2"
166 disabled={this.state.loading}
168 {this.state.loading ? (
170 ) : this.props.privateMessageView.isSome() ? (
171 capitalizeFirstLetter(i18n.t("save"))
173 capitalizeFirstLetter(i18n.t("send_message"))
176 {this.props.privateMessageView.isSome() && (
179 className="btn btn-secondary"
180 onClick={linkEvent(this, this.handleCancel)}
185 <ul className="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
186 <li className="list-inline-item"></li>
195 handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
196 event.preventDefault();
197 i.props.privateMessageView.match({
199 let form = new EditPrivateMessage({
200 private_message_id: pm.private_message.id,
201 content: i.state.privateMessageForm.content,
202 auth: auth().unwrap(),
204 WebSocketService.Instance.send(wsClient.editPrivateMessage(form));
206 none: WebSocketService.Instance.send(
207 wsClient.createPrivateMessage(i.state.privateMessageForm)
210 i.setState({ loading: true });
213 handleContentChange(val: string) {
214 this.setState(s => ((s.privateMessageForm.content = val), s));
217 handleCancel(i: PrivateMessageForm) {
221 handlePreviewToggle(i: PrivateMessageForm, event: any) {
222 event.preventDefault();
223 i.setState({ previewMode: !i.state.previewMode });
226 handleShowDisclaimer(i: PrivateMessageForm) {
227 i.setState({ showDisclaimer: !i.state.showDisclaimer });
230 parseMessage(msg: any) {
231 let op = wsUserOp(msg);
234 toast(i18n.t(msg.error), "danger");
235 this.setState({ loading: false });
238 op == UserOperation.EditPrivateMessage ||
239 op == UserOperation.DeletePrivateMessage ||
240 op == UserOperation.MarkPrivateMessageAsRead
242 let data = wsJsonToRes<PrivateMessageResponse>(
244 PrivateMessageResponse
246 this.setState({ loading: false });
247 this.props.onEdit(data.private_message_view);
248 } else if (op == UserOperation.CreatePrivateMessage) {
249 let data = wsJsonToRes<PrivateMessageResponse>(
251 PrivateMessageResponse
253 this.props.onCreate(data.private_message_view);