]> Untitled Git - lemmy.git/commitdiff
Adding comment loading indicator. #519
authorDessalines <tyhou13@gmx.com>
Sun, 8 Mar 2020 22:47:27 +0000 (18:47 -0400)
committerDessalines <tyhou13@gmx.com>
Sun, 8 Mar 2020 22:47:27 +0000 (18:47 -0400)
ui/src/components/comment-form.tsx

index f3009d341a8293acac27ea1beb0b3de268feb02b..6a50459247878fb1a48f705bc0f7bbec603f167a 100644 (file)
@@ -1,8 +1,13 @@
 import { Component, linkEvent } from 'inferno';
+import { Subscription } from 'rxjs';
+import { retryWhen, delay, take } from 'rxjs/operators';
 import { Prompt } from 'inferno-router';
 import {
   CommentNode as CommentNodeI,
   CommentForm as CommentFormI,
+  WebSocketJsonResponse,
+  UserOperation,
+  CommentResponse,
 } from '../interfaces';
 import {
   capitalizeFirstLetter,
@@ -11,6 +16,7 @@ import {
   markdownHelpUrl,
   toast,
   setupTribute,
+  wsJsonToRes,
 } from '../utils';
 import { WebSocketService, UserService } from '../services';
 import autosize from 'autosize';
@@ -29,12 +35,15 @@ interface CommentFormState {
   commentForm: CommentFormI;
   buttonTitle: string;
   previewMode: boolean;
+  loading: boolean;
   imageLoading: boolean;
 }
 
 export class CommentForm extends Component<CommentFormProps, CommentFormState> {
-  private id = `comment-form-${randomStr()}`;
+  private id = `comment-textarea-${randomStr()}`;
+  private formId = `comment-form-${randomStr()}`;
   private tribute: Tribute;
+  private subscription: Subscription;
   private emptyState: CommentFormState = {
     commentForm: {
       auth: null,
@@ -52,6 +61,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
       ? capitalizeFirstLetter(i18n.t('edit'))
       : capitalizeFirstLetter(i18n.t('reply')),
     previewMode: false,
+    loading: false,
     imageLoading: false,
   };
 
@@ -72,6 +82,14 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
         this.state.commentForm.parent_id = this.props.node.comment.id;
       }
     }
+
+    this.subscription = WebSocketService.Instance.subject
+      .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
+      .subscribe(
+        msg => this.parseMessage(msg),
+        err => console.error(err),
+        () => console.log('complete')
+      );
   }
 
   componentDidMount() {
@@ -85,6 +103,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
     });
   }
 
+  componentWillUnmount() {
+    this.subscription.unsubscribe();
+  }
+
   render() {
     return (
       <div class="mb-3">
@@ -92,7 +114,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
           when={this.state.commentForm.content}
           message={i18n.t('block_leaving')}
         />
-        <form onSubmit={linkEvent(this, this.handleCommentSubmit)}>
+        <form
+          id={this.formId}
+          onSubmit={linkEvent(this, this.handleCommentSubmit)}
+        >
           <div class="form-group row">
             <div className={`col-sm-12`}>
               <textarea
@@ -123,7 +148,13 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
                 class="btn btn-sm btn-secondary mr-2"
                 disabled={this.props.disabled}
               >
-                {this.state.buttonTitle}
+                {this.state.loading ? (
+                  <svg class="icon icon-spinner spin">
+                    <use xlinkHref="#icon-spinner"></use>
+                  </svg>
+                ) : (
+                  <span>{this.state.buttonTitle}</span>
+                )}
               </button>
               {this.state.commentForm.content && (
                 <button
@@ -185,6 +216,19 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
     );
   }
 
+  handleFinished() {
+    this.state.previewMode = false;
+    this.state.loading = false;
+    this.state.commentForm.content = '';
+    let form: any = document.getElementById(this.formId);
+    form.reset();
+    if (this.props.node) {
+      this.props.onReplyCancel();
+    }
+    autosize.update(document.querySelector('textarea'));
+    this.setState(this.state);
+  }
+
   handleCommentSubmit(i: CommentForm, event: any) {
     event.preventDefault();
     if (i.props.edit) {
@@ -193,15 +237,8 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
       WebSocketService.Instance.createComment(i.state.commentForm);
     }
 
-    i.state.previewMode = false;
-    i.state.commentForm.content = undefined;
-    event.target.reset();
+    i.state.loading = true;
     i.setState(i.state);
-    if (i.props.node) {
-      i.props.onReplyCancel();
-    }
-
-    autosize.update(document.querySelector('textarea'));
   }
 
   handleCommentContentChange(i: CommentForm, event: any) {
@@ -256,7 +293,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
         i.state.commentForm.content = content;
         i.state.imageLoading = false;
         i.setState(i.state);
-        var textarea: any = document.getElementById(i.id);
+        let textarea: any = document.getElementById(i.id);
         autosize.update(textarea);
       })
       .catch(error => {
@@ -265,4 +302,23 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
         toast(error, 'danger');
       });
   }
+
+  parseMessage(msg: WebSocketJsonResponse) {
+    let res = wsJsonToRes(msg);
+
+    // Only do the showing and hiding if logged in
+    if (UserService.Instance.user) {
+      if (res.op == UserOperation.CreateComment) {
+        let data = res.data as CommentResponse;
+        if (data.comment.creator_id == UserService.Instance.user.id) {
+          this.handleFinished();
+        }
+      } else if (res.op == UserOperation.EditComment) {
+        let data = res.data as CommentResponse;
+        if (data.comment.creator_id == UserService.Instance.user.id) {
+          this.handleFinished();
+        }
+      }
+    }
+  }
 }