]> Untitled Git - lemmy-ui.git/blob - src/shared/components/private_message/private-message-form.tsx
feat: Clean up the Create Private Message page a bit
[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 } 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   submitted: boolean;
32 }
33
34 export class PrivateMessageForm extends Component<
35   PrivateMessageFormProps,
36   PrivateMessageFormState
37 > {
38   state: PrivateMessageFormState = {
39     loading: false,
40     previewMode: false,
41     content: this.props.privateMessageView
42       ? this.props.privateMessageView.private_message.content
43       : undefined,
44     submitted: false,
45   };
46
47   constructor(props: any, context: any) {
48     super(props, context);
49
50     this.handleContentChange = this.handleContentChange.bind(this);
51   }
52
53   componentDidMount() {
54     setupTippy();
55   }
56
57   componentWillReceiveProps(
58     nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageFormProps>
59   ): void {
60     if (this.props != nextProps) {
61       this.setState({ loading: false, content: undefined, previewMode: false });
62     }
63   }
64   // TODO
65   // <Prompt
66   //   when={!this.state.loading && this.state.content}
67   //   message={I18NextService.i18n.t("block_leaving")}
68   // />
69
70   render() {
71     return (
72       <form className="private-message-form">
73         <NavigationPrompt
74           when={
75             !this.state.loading && !!this.state.content && !this.state.submitted
76           }
77         />
78         {!this.props.privateMessageView && (
79           <div className="mb-3 row align-items-baseline">
80             <label className="col-sm-2 col-form-label">
81               {capitalizeFirstLetter(I18NextService.i18n.t("to"))}
82             </label>
83
84             <div className="col-sm-10">
85               <PersonListing person={this.props.recipient} />
86             </div>
87           </div>
88         )}
89         <div className="alert alert-warning small">
90           <Icon icon="alert-triangle" classes="icon-inline me-1" />
91           <T parent="span" i18nKey="private_message_disclaimer">
92             #
93             <a
94               className="alert-link"
95               rel={relTags}
96               href="https://element.io/get-started"
97             >
98               #
99             </a>
100           </T>
101         </div>
102         <div className="mb-3 row">
103           <label className="col-sm-2 col-form-label">
104             {I18NextService.i18n.t("message")}
105           </label>
106           <div className="col-sm-10">
107             <MarkdownTextArea
108               onSubmit={() => {
109                 this.handlePrivateMessageSubmit(this, event);
110               }}
111               initialContent={this.state.content}
112               onContentChange={this.handleContentChange}
113               allLanguages={[]}
114               siteLanguages={[]}
115               hideNavigationWarnings
116               buttonTitle={
117                 this.props.privateMessageView
118                   ? capitalizeFirstLetter(I18NextService.i18n.t("save"))
119                   : capitalizeFirstLetter(I18NextService.i18n.t("send_message"))
120               }
121             />
122           </div>
123         </div>
124
125         <div className="mb-3 d-flex justify-content-end">
126           {this.props.privateMessageView && (
127             <button
128               type="button"
129               className="btn btn-secondary w-auto"
130               onClick={linkEvent(this, this.handleCancel)}
131             >
132               {I18NextService.i18n.t("cancel")}
133             </button>
134           )}
135         </div>
136       </form>
137     );
138   }
139
140   handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
141     event.preventDefault();
142     i.setState({ loading: true, submitted: true });
143     const pm = i.props.privateMessageView;
144     const auth = myAuthRequired();
145     const content = i.state.content ?? "";
146     if (pm) {
147       i.props.onEdit?.({
148         private_message_id: pm.private_message.id,
149         content,
150         auth,
151       });
152     } else {
153       i.props.onCreate?.({
154         content,
155         recipient_id: i.props.recipient.id,
156         auth,
157       });
158     }
159   }
160
161   handleContentChange(val: string) {
162     this.setState({ content: val });
163   }
164
165   handleCancel(i: PrivateMessageForm) {
166     i.props.onCancel?.();
167   }
168
169   handlePreviewToggle(i: PrivateMessageForm, event: any) {
170     event.preventDefault();
171     i.setState({ previewMode: !i.state.previewMode });
172   }
173 }