]> Untitled Git - lemmy.git/blobdiff - ui/src/components/comment-node.tsx
routes.api: fix get_captcha endpoint (#1135)
[lemmy.git] / ui / src / components / comment-node.tsx
index 49b56629525f61d8ac5651fbcd8e613d1373980a..1992c4fc846bb9c6d4b1b656c5d8cd90aac2eda1 100644 (file)
@@ -3,8 +3,10 @@ import { Link } from 'inferno-router';
 import {
   CommentNode as CommentNodeI,
   CommentLikeForm,
-  CommentForm as CommentFormI,
-  EditUserMentionForm,
+  DeleteCommentForm,
+  RemoveCommentForm,
+  MarkCommentAsReadForm,
+  MarkUserMentionAsReadForm,
   SaveCommentForm,
   BanFromCommunityForm,
   BanUserForm,
@@ -14,10 +16,9 @@ import {
   AddAdminForm,
   TransferCommunityForm,
   TransferSiteForm,
-  BanType,
-  CommentSortType,
   SortType,
-} from '../interfaces';
+} from 'lemmy-js-client';
+import { CommentSortType, BanType } from '../interfaces';
 import { WebSocketService, UserService } from '../services';
 import {
   mdToHtml,
@@ -32,6 +33,7 @@ import { MomentTime } from './moment-time';
 import { CommentForm } from './comment-form';
 import { CommentNodes } from './comment-nodes';
 import { UserListing } from './user-listing';
+import { CommunityLink } from './community-link';
 import { i18n } from '../i18next';
 
 interface CommentNodeState {
@@ -40,6 +42,7 @@ interface CommentNodeState {
   showRemoveDialog: boolean;
   removeReason: string;
   showBanDialog: boolean;
+  removeData: boolean;
   banReason: string;
   banExpires: string;
   banType: BanType;
@@ -61,6 +64,7 @@ interface CommentNodeState {
 
 interface CommentNodeProps {
   node: CommentNodeI;
+  noBorder?: boolean;
   noIndent?: boolean;
   viewOnly?: boolean;
   locked?: boolean;
@@ -83,6 +87,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     showRemoveDialog: false,
     removeReason: null,
     showBanDialog: false,
+    removeData: null,
     banReason: null,
     banExpires: null,
     banType: BanType.Community,
@@ -133,9 +138,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
       >
         <div
           id={`comment-${node.comment.id}`}
-          className={`details comment-node border-top border-light py-2 ${
-            this.isCommentNew ? 'mark' : ''
-          }`}
+          className={`details comment-node py-2 ${
+            !this.props.noBorder ? 'border-top border-light' : ''
+          } ${this.isCommentNew ? 'mark' : ''}`}
           style={
             !this.props.noIndent &&
             this.props.node.comment.parent_id &&
@@ -154,13 +159,16 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                 <UserListing
                   user={{
                     name: node.comment.creator_name,
+                    preferred_username: node.comment.creator_preferred_username,
                     avatar: node.comment.creator_avatar,
                     id: node.comment.creator_id,
                     local: node.comment.creator_local,
                     actor_id: node.comment.creator_actor_id,
+                    published: node.comment.creator_published,
                   }}
                 />
               </span>
+
               {this.isMod && (
                 <div className="badge badge-light d-none d-sm-inline mr-2">
                   {i18n.t('mod')}
@@ -184,13 +192,23 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
               {this.props.showCommunity && (
                 <>
                   <span class="mx-1">{i18n.t('to')}</span>
-                  <Link class="mr-2" to={`/c/${node.comment.community_name}`}>
-                    {node.comment.community_name}
+                  <CommunityLink
+                    community={{
+                      name: node.comment.community_name,
+                      id: node.comment.community_id,
+                      local: node.comment.community_local,
+                      actor_id: node.comment.community_actor_id,
+                      icon: node.comment.community_icon,
+                    }}
+                  />
+                  <span class="mx-2">•</span>
+                  <Link class="mr-2" to={`/post/${node.comment.post_id}`}>
+                    {node.comment.post_name}
                   </Link>
                 </>
               )}
               <button
-                class="btn btn-sm text-muted"
+                class="btn text-muted"
                 onClick={linkEvent(this, this.handleCommentCollapse)}
               >
                 {this.state.collapsed ? (
@@ -206,7 +224,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
               {/* This is an expanding spacer for mobile */}
               <div className="mr-lg-4 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2"></div>
               <button
-                className={`btn btn-sm p-0 unselectable pointer ${this.scoreColor}`}
+                className={`btn p-0 unselectable pointer ${this.scoreColor}`}
                 onClick={linkEvent(node, this.handleCommentUpvote)}
                 data-tippy-content={this.pointsTippy}
               >
@@ -227,6 +245,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                 edit
                 onReplyCancel={this.handleReplyCancel}
                 disabled={this.props.locked}
+                focus
               />
             )}
             {!this.state.showEdit && !this.state.collapsed && (
@@ -457,6 +476,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                                   </button>
                                 ))}
                               {!node.comment.banned_from_community &&
+                                node.comment.creator_local &&
                                 (!this.state.showConfirmAppointAsMod ? (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
@@ -499,6 +519,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                           {/* Community creators and admins can transfer community to another mod */}
                           {(this.amCommunityCreator || this.canAdmin) &&
                             this.isMod &&
+                            node.comment.creator_local &&
                             (!this.state.showConfirmTransferCommunity ? (
                               <button
                                 class="btn btn-link btn-animate text-muted"
@@ -561,6 +582,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                                   </button>
                                 ))}
                               {!node.comment.banned &&
+                                node.comment.creator_local &&
                                 (!this.state.showConfirmAppointAsAdmin ? (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
@@ -603,6 +625,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                           {/* Site Creator can transfer to another admin */}
                           {this.amSiteCreator &&
                             this.isAdmin &&
+                            node.comment.creator_local &&
                             (!this.state.showConfirmTransferSite ? (
                               <button
                                 class="btn btn-link btn-animate text-muted"
@@ -677,6 +700,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                 value={this.state.banReason}
                 onInput={linkEvent(this, this.handleModBanReasonChange)}
               />
+              <div class="form-group">
+                <div class="form-check">
+                  <input
+                    class="form-check-input"
+                    id="mod-ban-remove-data"
+                    type="checkbox"
+                    checked={this.state.removeData}
+                    onChange={linkEvent(this, this.handleModRemoveDataChange)}
+                  />
+                  <label class="form-check-label" htmlFor="mod-ban-remove-data">
+                    {i18n.t('remove_posts_comments')}
+                  </label>
+                </div>
+              </div>
             </div>
             {/* TODO hold off on expires until later */}
             {/* <div class="form-group row"> */}
@@ -695,6 +732,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
             node={node}
             onReplyCancel={this.handleReplyCancel}
             disabled={this.props.locked}
+            focus
           />
         )}
         {node.children && !this.state.collapsed && (
@@ -834,16 +872,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   }
 
   handleDeleteClick(i: CommentNode) {
-    let deleteForm: CommentFormI = {
-      content: i.props.node.comment.content,
+    let deleteForm: DeleteCommentForm = {
       edit_id: i.props.node.comment.id,
-      creator_id: i.props.node.comment.creator_id,
-      post_id: i.props.node.comment.post_id,
-      parent_id: i.props.node.comment.parent_id,
       deleted: !i.props.node.comment.deleted,
       auth: null,
     };
-    WebSocketService.Instance.editComment(deleteForm);
+    WebSocketService.Instance.deleteComment(deleteForm);
   }
 
   handleSaveCommentClick(i: CommentNode) {
@@ -887,7 +921,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
     let form: CommentLikeForm = {
       comment_id: i.comment.id,
-      post_id: i.comment.post_id,
       score: this.state.my_vote,
     };
 
@@ -915,7 +948,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
     let form: CommentLikeForm = {
       comment_id: i.comment.id,
-      post_id: i.comment.post_id,
       score: this.state.my_vote,
     };
 
@@ -934,19 +966,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     i.setState(i.state);
   }
 
+  handleModRemoveDataChange(i: CommentNode, event: any) {
+    i.state.removeData = event.target.checked;
+    i.setState(i.state);
+  }
+
   handleModRemoveSubmit(i: CommentNode) {
     event.preventDefault();
-    let form: CommentFormI = {
-      content: i.props.node.comment.content,
+    let form: RemoveCommentForm = {
       edit_id: i.props.node.comment.id,
-      creator_id: i.props.node.comment.creator_id,
-      post_id: i.props.node.comment.post_id,
-      parent_id: i.props.node.comment.parent_id,
       removed: !i.props.node.comment.removed,
       reason: i.state.removeReason,
       auth: null,
     };
-    WebSocketService.Instance.editComment(form);
+    WebSocketService.Instance.removeComment(form);
 
     i.state.showRemoveDialog = false;
     i.setState(i.state);
@@ -955,22 +988,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   handleMarkRead(i: CommentNode) {
     // if it has a user_mention_id field, then its a mention
     if (i.props.node.comment.user_mention_id) {
-      let form: EditUserMentionForm = {
+      let form: MarkUserMentionAsReadForm = {
         user_mention_id: i.props.node.comment.user_mention_id,
         read: !i.props.node.comment.read,
       };
-      WebSocketService.Instance.editUserMention(form);
+      WebSocketService.Instance.markUserMentionAsRead(form);
     } else {
-      let form: CommentFormI = {
-        content: i.props.node.comment.content,
+      let form: MarkCommentAsReadForm = {
         edit_id: i.props.node.comment.id,
-        creator_id: i.props.node.comment.creator_id,
-        post_id: i.props.node.comment.post_id,
-        parent_id: i.props.node.comment.parent_id,
         read: !i.props.node.comment.read,
         auth: null,
       };
-      WebSocketService.Instance.editComment(form);
+      WebSocketService.Instance.markCommentAsRead(form);
     }
 
     i.state.readLoading = true;
@@ -1015,18 +1044,30 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     event.preventDefault();
 
     if (i.state.banType == BanType.Community) {
+      // If its an unban, restore all their data
+      let ban = !i.props.node.comment.banned_from_community;
+      if (ban == false) {
+        i.state.removeData = false;
+      }
       let form: BanFromCommunityForm = {
         user_id: i.props.node.comment.creator_id,
         community_id: i.props.node.comment.community_id,
-        ban: !i.props.node.comment.banned_from_community,
+        ban,
+        remove_data: i.state.removeData,
         reason: i.state.banReason,
         expires: getUnixTime(i.state.banExpires),
       };
       WebSocketService.Instance.banFromCommunity(form);
     } else {
+      // If its an unban, restore all their data
+      let ban = !i.props.node.comment.banned;
+      if (ban == false) {
+        i.state.removeData = false;
+      }
       let form: BanUserForm = {
         user_id: i.props.node.comment.creator_id,
-        ban: !i.props.node.comment.banned,
+        ban,
+        remove_data: i.state.removeData,
         reason: i.state.banReason,
         expires: getUnixTime(i.state.banExpires),
       };