]> Untitled Git - lemmy-ui.git/blob - src/shared/components/comment/comment-form.tsx
Merge branch 'LemmyNet:main' into multiple-images-upload
[lemmy-ui.git] / src / shared / components / comment / comment-form.tsx
1 import { Either, None, Option, Some } from "@sniptt/monads";
2 import { Component } from "inferno";
3 import { T } from "inferno-i18next-dess";
4 import { Link } from "inferno-router";
5 import {
6   CommentNode as CommentNodeI,
7   CommentResponse,
8   CreateComment,
9   EditComment,
10   Language,
11   UserOperation,
12   wsJsonToRes,
13   wsUserOp,
14 } from "lemmy-js-client";
15 import { Subscription } from "rxjs";
16 import { i18n } from "../../i18next";
17 import { UserService, WebSocketService } from "../../services";
18 import {
19   auth,
20   capitalizeFirstLetter,
21   myFirstDiscussionLanguageId,
22   wsClient,
23   wsSubscribe,
24 } from "../../utils";
25 import { Icon } from "../common/icon";
26 import { MarkdownTextArea } from "../common/markdown-textarea";
27
28 interface CommentFormProps {
29   /**
30    * Can either be the parent, or the editable comment. The right side is a postId.
31    */
32   node: Either<CommentNodeI, number>;
33   edit?: boolean;
34   disabled?: boolean;
35   focus?: boolean;
36   onReplyCancel?(): any;
37   allLanguages: Language[];
38 }
39
40 interface CommentFormState {
41   buttonTitle: string;
42   finished: boolean;
43   formId: Option<string>;
44 }
45
46 export class CommentForm extends Component<CommentFormProps, CommentFormState> {
47   private subscription: Subscription;
48   private emptyState: CommentFormState = {
49     buttonTitle: this.props.node.isRight()
50       ? capitalizeFirstLetter(i18n.t("post"))
51       : this.props.edit
52       ? capitalizeFirstLetter(i18n.t("save"))
53       : capitalizeFirstLetter(i18n.t("reply")),
54     finished: false,
55     formId: None,
56   };
57
58   constructor(props: any, context: any) {
59     super(props, context);
60
61     this.handleCommentSubmit = this.handleCommentSubmit.bind(this);
62     this.handleReplyCancel = this.handleReplyCancel.bind(this);
63
64     this.state = this.emptyState;
65
66     this.parseMessage = this.parseMessage.bind(this);
67     this.subscription = wsSubscribe(this.parseMessage);
68   }
69
70   componentWillUnmount() {
71     this.subscription.unsubscribe();
72   }
73
74   render() {
75     let initialContent = this.props.node.match({
76       left: node =>
77         this.props.edit ? Some(node.comment_view.comment.content) : None,
78       right: () => None,
79     });
80
81     let selectedLang = this.props.node
82       .left()
83       .map(n => n.comment_view.comment.language_id)
84       .or(myFirstDiscussionLanguageId(UserService.Instance.myUserInfo));
85
86     return (
87       <div className="mb-3">
88         {UserService.Instance.myUserInfo.isSome() ? (
89           <MarkdownTextArea
90             initialContent={initialContent}
91             initialLanguageId={selectedLang}
92             showLanguage
93             buttonTitle={Some(this.state.buttonTitle)}
94             maxLength={None}
95             finished={this.state.finished}
96             replyType={this.props.node.isLeft()}
97             focus={this.props.focus}
98             disabled={this.props.disabled}
99             onSubmit={this.handleCommentSubmit}
100             onReplyCancel={this.handleReplyCancel}
101             placeholder={Some(i18n.t("comment_here"))}
102             allLanguages={this.props.allLanguages}
103           />
104         ) : (
105           <div className="alert alert-warning" role="alert">
106             <Icon icon="alert-triangle" classes="icon-inline mr-2" />
107             <T i18nKey="must_login" class="d-inline">
108               #
109               <Link className="alert-link" to="/login">
110                 #
111               </Link>
112             </T>
113           </div>
114         )}
115       </div>
116     );
117   }
118
119   handleCommentSubmit(msg: {
120     val: Option<string>;
121     formId: string;
122     languageId: Option<number>;
123   }) {
124     let content = msg.val;
125     let language_id = msg.languageId;
126     this.setState({ formId: Some(msg.formId) });
127
128     this.props.node.match({
129       left: node => {
130         if (this.props.edit) {
131           let form = new EditComment({
132             content,
133             distinguished: None,
134             form_id: this.state.formId,
135             comment_id: node.comment_view.comment.id,
136             language_id,
137             auth: auth().unwrap(),
138           });
139           WebSocketService.Instance.send(wsClient.editComment(form));
140         } else {
141           let form = new CreateComment({
142             content: content.unwrap(),
143             form_id: this.state.formId,
144             post_id: node.comment_view.post.id,
145             parent_id: Some(node.comment_view.comment.id),
146             language_id,
147             auth: auth().unwrap(),
148           });
149           WebSocketService.Instance.send(wsClient.createComment(form));
150         }
151       },
152       right: postId => {
153         let form = new CreateComment({
154           content: content.unwrap(),
155           form_id: this.state.formId,
156           post_id: postId,
157           parent_id: None,
158           language_id,
159           auth: auth().unwrap(),
160         });
161         WebSocketService.Instance.send(wsClient.createComment(form));
162       },
163     });
164     this.setState(this.state);
165   }
166
167   handleReplyCancel() {
168     this.props.onReplyCancel();
169   }
170
171   parseMessage(msg: any) {
172     let op = wsUserOp(msg);
173     console.log(msg);
174
175     // Only do the showing and hiding if logged in
176     if (UserService.Instance.myUserInfo.isSome()) {
177       if (
178         op == UserOperation.CreateComment ||
179         op == UserOperation.EditComment
180       ) {
181         let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
182
183         // This only finishes this form, if the randomly generated form_id matches the one received
184         if (this.state.formId.unwrapOr("") == data.form_id.unwrapOr("")) {
185           this.setState({ finished: true });
186
187           // Necessary because it broke tribute for some reason
188           this.setState({ finished: false });
189         }
190       }
191     }
192   }
193 }