]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private_message/private-message-form.tsx
1b9cb50c74c79c4b4758171ae0e4b73e46e59a7e
[lemmy-ui.git] / src / shared / components / private_message / private-message-form.tsx
1 import { myAuthRequired } from "@utils/app";
2 import { capitalizeFirstLetter } from "@utils/helpers";
3 import { Component, InfernoNode, linkEvent } from "inferno";
4 import { T } from "inferno-i18next-dess";
5 import {
6   CreatePrivateMessage,
7   EditPrivateMessage,
8   Person,
9   PrivateMessageView,
10 } from "lemmy-js-client";
11 import { relTags } from "../../config";
12 import { i18n } from "../../i18next";
13 import { setupTippy } from "../../tippy";
14 import { Icon, Spinner } from "../common/icon";
15 import { MarkdownTextArea } from "../common/markdown-textarea";
16 import NavigationPrompt from "../common/navigation-prompt";
17 import { PersonListing } from "../person/person-listing";
18
19 interface PrivateMessageFormProps {
20   recipient: Person;
21   privateMessageView?: PrivateMessageView; // If a pm is given, that means this is an edit
22   onCancel?(): any;
23   onCreate?(form: CreatePrivateMessage): void;
24   onEdit?(form: EditPrivateMessage): void;
25 }
26
27 interface PrivateMessageFormState {
28   content?: string;
29   loading: boolean;
30   previewMode: boolean;
31   showDisclaimer: boolean;
32   submitted: boolean;
33 }
34
35 export class PrivateMessageForm extends Component<
36   PrivateMessageFormProps,
37   PrivateMessageFormState
38 > {
39   state: PrivateMessageFormState = {
40     loading: false,
41     previewMode: false,
42     showDisclaimer: false,
43     content: this.props.privateMessageView
44       ? this.props.privateMessageView.private_message.content
45       : undefined,
46     submitted: false,
47   };
48
49   constructor(props: any, context: any) {
50     super(props, context);
51
52     this.handleContentChange = this.handleContentChange.bind(this);
53   }
54
55   componentDidMount() {
56     setupTippy();
57   }
58
59   componentWillReceiveProps(
60     nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageFormProps>
61   ): void {
62     if (this.props != nextProps) {
63       this.setState({ loading: false, content: undefined, previewMode: false });
64     }
65   }
66   // TODO
67   // <Prompt
68   //   when={!this.state.loading && this.state.content}
69   //   message={i18n.t("block_leaving")}
70   // />
71
72   render() {
73     return (
74       <form
75         className="private-message-form"
76         onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}
77       >
78         <NavigationPrompt
79           when={
80             !this.state.loading && !!this.state.content && !this.state.submitted
81           }
82         />
83         {!this.props.privateMessageView && (
84           <div className="mb-3 row">
85             <label className="col-sm-2 col-form-label">
86               {capitalizeFirstLetter(i18n.t("to"))}
87             </label>
88
89             <div className="col-sm-10 form-control-plaintext">
90               <PersonListing person={this.props.recipient} />
91             </div>
92           </div>
93         )}
94         <div className="mb-3 row">
95           <label className="col-sm-2 col-form-label">
96             {i18n.t("message")}
97             <button
98               className="btn btn-link text-warning d-inline-block"
99               onClick={linkEvent(this, this.handleShowDisclaimer)}
100               data-tippy-content={i18n.t("private_message_disclaimer")}
101               aria-label={i18n.t("private_message_disclaimer")}
102             >
103               <Icon icon="alert-triangle" classes="icon-inline" />
104             </button>
105           </label>
106           <div className="col-sm-10">
107             <MarkdownTextArea
108               initialContent={this.state.content}
109               onContentChange={this.handleContentChange}
110               allLanguages={[]}
111               siteLanguages={[]}
112               hideNavigationWarnings
113             />
114           </div>
115         </div>
116
117         {this.state.showDisclaimer && (
118           <div className="mb-3 row">
119             <div className="offset-sm-2 col-sm-10">
120               <div className="alert alert-danger" role="alert">
121                 <T i18nKey="private_message_disclaimer">
122                   #
123                   <a
124                     className="alert-link"
125                     rel={relTags}
126                     href="https://element.io/get-started"
127                   >
128                     #
129                   </a>
130                 </T>
131               </div>
132             </div>
133           </div>
134         )}
135         <div className="mb-3 row">
136           <div className="offset-sm-2 col-sm-10">
137             <button
138               type="submit"
139               className="btn btn-secondary me-2"
140               disabled={this.state.loading}
141             >
142               {this.state.loading ? (
143                 <Spinner />
144               ) : this.props.privateMessageView ? (
145                 capitalizeFirstLetter(i18n.t("save"))
146               ) : (
147                 capitalizeFirstLetter(i18n.t("send_message"))
148               )}
149             </button>
150             {this.props.privateMessageView && (
151               <button
152                 type="button"
153                 className="btn btn-secondary"
154                 onClick={linkEvent(this, this.handleCancel)}
155               >
156                 {i18n.t("cancel")}
157               </button>
158             )}
159             <ul className="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
160               <li className="list-inline-item"></li>
161             </ul>
162           </div>
163         </div>
164       </form>
165     );
166   }
167
168   handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
169     event.preventDefault();
170     i.setState({ loading: true, submitted: true });
171     const pm = i.props.privateMessageView;
172     const auth = myAuthRequired();
173     const content = i.state.content ?? "";
174     if (pm) {
175       i.props.onEdit?.({
176         private_message_id: pm.private_message.id,
177         content,
178         auth,
179       });
180     } else {
181       i.props.onCreate?.({
182         content,
183         recipient_id: i.props.recipient.id,
184         auth,
185       });
186     }
187   }
188
189   handleContentChange(val: string) {
190     this.setState({ content: val });
191   }
192
193   handleCancel(i: PrivateMessageForm) {
194     i.props.onCancel?.();
195   }
196
197   handlePreviewToggle(i: PrivateMessageForm, event: any) {
198     event.preventDefault();
199     i.setState({ previewMode: !i.state.previewMode });
200   }
201
202   handleShowDisclaimer(i: PrivateMessageForm) {
203     i.setState({ showDisclaimer: !i.state.showDisclaimer });
204   }
205 }