]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private_message/private-message-form.tsx
338584b393ea3e6c1aa077c7dc2b0c83bd679719
[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 { I18NextService } from "../../services";
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={I18NextService.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(I18NextService.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             {I18NextService.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={I18NextService.i18n.t(
101                 "private_message_disclaimer"
102               )}
103               aria-label={I18NextService.i18n.t("private_message_disclaimer")}
104             >
105               <Icon icon="alert-triangle" classes="icon-inline" />
106             </button>
107           </label>
108           <div className="col-sm-10">
109             <MarkdownTextArea
110               initialContent={this.state.content}
111               onContentChange={this.handleContentChange}
112               allLanguages={[]}
113               siteLanguages={[]}
114               hideNavigationWarnings
115             />
116           </div>
117         </div>
118
119         {this.state.showDisclaimer && (
120           <div className="mb-3 row">
121             <div className="offset-sm-2 col-sm-10">
122               <div className="alert alert-danger" role="alert">
123                 <T i18nKey="private_message_disclaimer">
124                   #
125                   <a
126                     className="alert-link"
127                     rel={relTags}
128                     href="https://element.io/get-started"
129                   >
130                     #
131                   </a>
132                 </T>
133               </div>
134             </div>
135           </div>
136         )}
137         <div className="mb-3 row">
138           <div className="offset-sm-2 col-sm-10">
139             <button
140               type="submit"
141               className="btn btn-secondary me-2"
142               disabled={this.state.loading}
143             >
144               {this.state.loading ? (
145                 <Spinner />
146               ) : this.props.privateMessageView ? (
147                 capitalizeFirstLetter(I18NextService.i18n.t("save"))
148               ) : (
149                 capitalizeFirstLetter(I18NextService.i18n.t("send_message"))
150               )}
151             </button>
152             {this.props.privateMessageView && (
153               <button
154                 type="button"
155                 className="btn btn-secondary"
156                 onClick={linkEvent(this, this.handleCancel)}
157               >
158                 {I18NextService.i18n.t("cancel")}
159               </button>
160             )}
161             <ul className="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
162               <li className="list-inline-item"></li>
163             </ul>
164           </div>
165         </div>
166       </form>
167     );
168   }
169
170   handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
171     event.preventDefault();
172     i.setState({ loading: true, submitted: true });
173     const pm = i.props.privateMessageView;
174     const auth = myAuthRequired();
175     const content = i.state.content ?? "";
176     if (pm) {
177       i.props.onEdit?.({
178         private_message_id: pm.private_message.id,
179         content,
180         auth,
181       });
182     } else {
183       i.props.onCreate?.({
184         content,
185         recipient_id: i.props.recipient.id,
186         auth,
187       });
188     }
189   }
190
191   handleContentChange(val: string) {
192     this.setState({ content: val });
193   }
194
195   handleCancel(i: PrivateMessageForm) {
196     i.props.onCancel?.();
197   }
198
199   handlePreviewToggle(i: PrivateMessageForm, event: any) {
200     event.preventDefault();
201     i.setState({ previewMode: !i.state.previewMode });
202   }
203
204   handleShowDisclaimer(i: PrivateMessageForm) {
205     i.setState({ showDisclaimer: !i.state.showDisclaimer });
206   }
207 }