]> Untitled Git - lemmy.git/blobdiff - ui/src/components/post-listing.tsx
routes.api: fix get_captcha endpoint (#1135)
[lemmy.git] / ui / src / components / post-listing.tsx
index 418fe7b486a6c64e301b16f536091a43c23d77ee..fa4bf391177359df89f823244b21e72c6a925c5e 100644 (file)
@@ -4,18 +4,21 @@ import { WebSocketService, UserService } from '../services';
 import {
   Post,
   CreatePostLikeForm,
-  PostForm as PostFormI,
+  DeletePostForm,
+  RemovePostForm,
+  LockPostForm,
+  StickyPostForm,
   SavePostForm,
   CommunityUser,
   UserView,
-  BanType,
   BanFromCommunityForm,
   BanUserForm,
   AddModToCommunityForm,
   AddAdminForm,
   TransferSiteForm,
   TransferCommunityForm,
-} from '../interfaces';
+} from 'lemmy-js-client';
+import { BanType } from '../interfaces';
 import { MomentTime } from './moment-time';
 import { PostForm } from './post-form';
 import { IFramelyCard } from './iframely-card';
@@ -33,7 +36,6 @@ import {
   setupTippy,
   hostname,
   previewLines,
-  toast,
 } from '../utils';
 import { i18n } from '../i18next';
 
@@ -42,6 +44,7 @@ interface PostListingState {
   showRemoveDialog: boolean;
   removeReason: string;
   showBanDialog: boolean;
+  removeData: boolean;
   banReason: string;
   banExpires: string;
   banType: BanType;
@@ -72,6 +75,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     showRemoveDialog: false,
     removeReason: null,
     showBanDialog: false,
+    removeData: null,
     banReason: null,
     banExpires: null,
     banType: BanType.Community,
@@ -101,6 +105,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     this.state.upvotes = nextProps.post.upvotes;
     this.state.downvotes = nextProps.post.downvotes;
     this.state.score = nextProps.post.score;
+    if (this.props.post.id !== nextProps.post.id) {
+      this.state.imageExpanded = false;
+    }
     this.setState(this.state);
   }
 
@@ -158,7 +165,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     return (
       <img
         className={`img-fluid thumbnail rounded ${
-          (post.nsfw || post.community_nsfw) && 'img-blur'
+          post.nsfw || post.community_nsfw ? 'img-blur' : ''
         }`}
         src={src}
       />
@@ -185,8 +192,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
 
     if (isImage(post.url)) {
       return (
-        <span
-          class="text-body pointer"
+        <div
+          class="float-right text-body pointer d-inline-block position-relative"
           data-tippy-content={i18n.t('expand_here')}
           onClick={linkEvent(this, this.handleImageExpandClick)}
         >
@@ -194,12 +201,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
           <svg class="icon mini-overlay">
             <use xlinkHref="#icon-image"></use>
           </svg>
-        </span>
+        </div>
       );
     } else if (post.thumbnail_url) {
       return (
         <a
-          className="text-body"
+          class="float-right text-body d-inline-block position-relative"
           href={post.url}
           target="_blank"
           rel="noopener"
@@ -235,9 +242,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
             title={post.url}
             rel="noopener"
           >
-            <svg class="icon thumbnail">
-              <use xlinkHref="#icon-external-link"></use>
-            </svg>
+            <div class="thumbnail rounded bg-light d-flex justify-content-center">
+              <svg class="icon d-flex align-items-center">
+                <use xlinkHref="#icon-external-link"></use>
+              </svg>
+            </div>
           </a>
         );
       }
@@ -248,698 +257,794 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
           to={`/post/${post.id}`}
           title={i18n.t('comments')}
         >
-          <svg class="icon thumbnail">
-            <use xlinkHref="#icon-message-square"></use>
-          </svg>
+          <div class="thumbnail rounded bg-light d-flex justify-content-center">
+            <svg class="icon d-flex align-items-center">
+              <use xlinkHref="#icon-message-square"></use>
+            </svg>
+          </div>
         </Link>
       );
     }
   }
 
-  listing() {
+  createdLine() {
     let post = this.props.post;
     return (
-      <div class="row">
-        <div className={`vote-bar col-1 pr-0 small text-center`}>
+      <ul class="list-inline mb-1 text-muted small">
+        <li className="list-inline-item">
+          <UserListing
+            user={{
+              name: post.creator_name,
+              preferred_username: post.creator_preferred_username,
+              avatar: post.creator_avatar,
+              id: post.creator_id,
+              local: post.creator_local,
+              actor_id: post.creator_actor_id,
+              published: post.creator_published,
+            }}
+          />
+
+          {this.isMod && (
+            <span className="mx-1 badge badge-light">{i18n.t('mod')}</span>
+          )}
+          {this.isAdmin && (
+            <span className="mx-1 badge badge-light">{i18n.t('admin')}</span>
+          )}
+          {(post.banned_from_community || post.banned) && (
+            <span className="mx-1 badge badge-danger">{i18n.t('banned')}</span>
+          )}
+          {this.props.showCommunity && (
+            <span>
+              <span class="mx-1"> {i18n.t('to')} </span>
+              <CommunityLink
+                community={{
+                  name: post.community_name,
+                  id: post.community_id,
+                  local: post.community_local,
+                  actor_id: post.community_actor_id,
+                  icon: post.community_icon,
+                }}
+              />
+            </span>
+          )}
+        </li>
+        <li className="list-inline-item">•</li>
+        {post.url && !(hostname(post.url) == window.location.hostname) && (
+          <>
+            <li className="list-inline-item">
+              <a
+                className="text-muted font-italic"
+                href={post.url}
+                target="_blank"
+                title={post.url}
+                rel="noopener"
+              >
+                {hostname(post.url)}
+              </a>
+            </li>
+            <li className="list-inline-item">•</li>
+          </>
+        )}
+        <li className="list-inline-item">
+          <span>
+            <MomentTime data={post} />
+          </span>
+        </li>
+        {post.body && (
+          <>
+            <li className="list-inline-item">•</li>
+            <li className="list-inline-item">
+              {/* Using a link with tippy doesn't work on touch devices unfortunately */}
+              <Link
+                className="text-muted"
+                data-tippy-content={md.render(previewLines(post.body))}
+                data-tippy-allowHtml={true}
+                to={`/post/${post.id}`}
+              >
+                <svg class="mr-1 icon icon-inline">
+                  <use xlinkHref="#icon-book-open"></use>
+                </svg>
+              </Link>
+            </li>
+          </>
+        )}
+      </ul>
+    );
+  }
+
+  voteBar() {
+    return (
+      <div className={`vote-bar col-1 pr-0 small text-center`}>
+        <button
+          className={`btn-animate btn btn-link p-0 ${
+            this.state.my_vote == 1 ? 'text-info' : 'text-muted'
+          }`}
+          onClick={linkEvent(this, this.handlePostLike)}
+          data-tippy-content={i18n.t('upvote')}
+        >
+          <svg class="icon upvote">
+            <use xlinkHref="#icon-arrow-up1"></use>
+          </svg>
+        </button>
+        <div
+          class={`unselectable pointer font-weight-bold text-muted px-1`}
+          data-tippy-content={this.pointsTippy}
+        >
+          {this.state.score}
+        </div>
+        {this.props.enableDownvotes && (
           <button
             className={`btn-animate btn btn-link p-0 ${
-              this.state.my_vote == 1 ? 'text-info' : 'text-muted'
+              this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
             }`}
-            onClick={linkEvent(this, this.handlePostLike)}
-            data-tippy-content={i18n.t('upvote')}
+            onClick={linkEvent(this, this.handlePostDisLike)}
+            data-tippy-content={i18n.t('downvote')}
           >
-            <svg class="icon upvote">
-              <use xlinkHref="#icon-arrow-up1"></use>
+            <svg class="icon downvote">
+              <use xlinkHref="#icon-arrow-down1"></use>
             </svg>
           </button>
-          <div
-            class={`unselectable pointer font-weight-bold text-muted px-1`}
-            data-tippy-content={this.pointsTippy}
-          >
-            {this.state.score}
-          </div>
-          {this.props.enableDownvotes && (
-            <button
-              className={`btn-animate btn btn-link p-0 ${
-                this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
-              }`}
-              onClick={linkEvent(this, this.handlePostDisLike)}
-              data-tippy-content={i18n.t('downvote')}
+        )}
+      </div>
+    );
+  }
+
+  postTitleLine() {
+    let post = this.props.post;
+    return (
+      <div className="post-title overflow-hidden">
+        <h5>
+          {this.props.showBody && post.url ? (
+            <a
+              className={!post.stickied ? 'text-body' : 'text-primary'}
+              href={post.url}
+              target="_blank"
+              title={post.url}
+              rel="noopener"
+            >
+              {post.name}
+            </a>
+          ) : (
+            <Link
+              className={!post.stickied ? 'text-body' : 'text-primary'}
+              to={`/post/${post.id}`}
+              title={i18n.t('comments')}
+            >
+              {post.name}
+            </Link>
+          )}
+          {(isImage(post.url) || this.props.post.thumbnail_url) && (
+            <>
+              {!this.state.imageExpanded ? (
+                <span
+                  class="text-monospace unselectable pointer ml-2 text-muted small"
+                  data-tippy-content={i18n.t('expand_here')}
+                  onClick={linkEvent(this, this.handleImageExpandClick)}
+                >
+                  <svg class="icon icon-inline">
+                    <use xlinkHref="#icon-plus-square"></use>
+                  </svg>
+                </span>
+              ) : (
+                <span>
+                  <span
+                    class="text-monospace unselectable pointer ml-2 text-muted small"
+                    onClick={linkEvent(this, this.handleImageExpandClick)}
+                  >
+                    <svg class="icon icon-inline">
+                      <use xlinkHref="#icon-minus-square"></use>
+                    </svg>
+                  </span>
+                  <div>
+                    <span
+                      class="pointer"
+                      onClick={linkEvent(this, this.handleImageExpandClick)}
+                    >
+                      <img
+                        class="img-fluid img-expanded"
+                        src={this.getImage()}
+                      />
+                    </span>
+                  </div>
+                </span>
+              )}
+            </>
+          )}
+          {post.removed && (
+            <small className="ml-2 text-muted font-italic">
+              {i18n.t('removed')}
+            </small>
+          )}
+          {post.deleted && (
+            <small
+              className="unselectable pointer ml-2 text-muted font-italic"
+              data-tippy-content={i18n.t('deleted')}
             >
-              <svg class="icon downvote">
-                <use xlinkHref="#icon-arrow-down1"></use>
+              <svg class={`icon icon-inline text-danger`}>
+                <use xlinkHref="#icon-trash"></use>
               </svg>
-            </button>
+            </small>
           )}
-        </div>
-        {!this.state.imageExpanded && (
-          <div class="col-3 col-sm-2 pr-0 mt-1">
-            <div class="position-relative">{this.thumbnail()}</div>
-          </div>
+          {post.locked && (
+            <small
+              className="unselectable pointer ml-2 text-muted font-italic"
+              data-tippy-content={i18n.t('locked')}
+            >
+              <svg class={`icon icon-inline text-danger`}>
+                <use xlinkHref="#icon-lock"></use>
+              </svg>
+            </small>
+          )}
+          {post.stickied && (
+            <small
+              className="unselectable pointer ml-2 text-muted font-italic"
+              data-tippy-content={i18n.t('stickied')}
+            >
+              <svg class={`icon icon-inline text-primary`}>
+                <use xlinkHref="#icon-pin"></use>
+              </svg>
+            </small>
+          )}
+          {post.nsfw && (
+            <small className="ml-2 text-muted font-italic">
+              {i18n.t('nsfw')}
+            </small>
+          )}
+        </h5>
+      </div>
+    );
+  }
+
+  commentsLine(showVotes: boolean = false) {
+    let post = this.props.post;
+    return (
+      <ul class="d-flex align-items-center list-inline mb-1 text-muted small">
+        <li className="list-inline-item">
+          <Link
+            className="text-muted"
+            title={i18n.t('number_of_comments', {
+              count: post.number_of_comments,
+            })}
+            to={`/post/${post.id}`}
+          >
+            <svg class="mr-1 icon icon-inline">
+              <use xlinkHref="#icon-message-square"></use>
+            </svg>
+            {i18n.t('number_of_comments', {
+              count: post.number_of_comments,
+            })}
+          </Link>
+        </li>
+        {(showVotes || this.state.upvotes !== this.state.score) && (
+          <>
+            <span
+              class="unselectable pointer ml-3"
+              data-tippy-content={this.pointsTippy}
+            >
+              <li className="list-inline-item">
+                <a
+                  className={`btn-animate btn btn-link p-0 ${
+                    this.state.my_vote == 1 ? 'text-info' : 'text-muted'
+                  }`}
+                  onClick={linkEvent(this, this.handlePostLike)}
+                >
+                  <svg class="small icon icon-inline mx-1">
+                    <use xlinkHref="#icon-arrow-up1"></use>
+                  </svg>
+                  {this.state.upvotes}
+                </a>
+              </li>
+              <li className="list-inline-item">
+                <a
+                  className={`btn-animate btn btn-link p-0 ${
+                    this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
+                  }`}
+                  onClick={linkEvent(this, this.handlePostDisLike)}
+                >
+                  <svg class="small icon icon-inline mx-1">
+                    <use xlinkHref="#icon-arrow-down1"></use>
+                  </svg>
+                  {this.state.downvotes}
+                </a>
+              </li>
+            </span>
+          </>
         )}
-        <div
-          class={`${this.state.imageExpanded ? 'col-12' : 'col-8 col-sm-9'}`}
-        >
-          <div class="row">
-            <div className="col-12">
-              <div className="post-title">
-                <h5 className="mb-0 d-inline">
-                  {this.props.showBody && post.url ? (
-                    <a
-                      className="text-body"
-                      href={post.url}
-                      target="_blank"
-                      title={post.url}
-                      rel="noopener"
-                    >
-                      {post.name}
-                    </a>
-                  ) : (
-                    <Link
-                      className="text-body"
-                      to={`/post/${post.id}`}
-                      title={i18n.t('comments')}
-                    >
-                      {post.name}
-                    </Link>
-                  )}
-                </h5>
-                {post.url && !(hostname(post.url) == window.location.hostname) && (
-                  <small class="d-inline-block">
-                    <a
-                      className="ml-2 text-muted font-italic"
-                      href={post.url}
-                      target="_blank"
-                      title={post.url}
-                      rel="noopener"
-                    >
-                      {hostname(post.url)}
-                      <svg class="ml-1 icon icon-inline">
-                        <use xlinkHref="#icon-external-link"></use>
-                      </svg>
-                    </a>
-                  </small>
-                )}
-                {(isImage(post.url) || this.props.post.thumbnail_url) && (
-                  <>
-                    {!this.state.imageExpanded ? (
-                      <span
-                        class="text-monospace unselectable pointer ml-2 text-muted small"
-                        data-tippy-content={i18n.t('expand_here')}
-                        onClick={linkEvent(this, this.handleImageExpandClick)}
-                      >
-                        <svg class="icon icon-inline">
-                          <use xlinkHref="#icon-plus-square"></use>
-                        </svg>
-                      </span>
-                    ) : (
-                      <span>
-                        <span
-                          class="text-monospace unselectable pointer ml-2 text-muted small"
-                          onClick={linkEvent(this, this.handleImageExpandClick)}
-                        >
-                          <svg class="icon icon-inline">
-                            <use xlinkHref="#icon-minus-square"></use>
-                          </svg>
-                        </span>
-                        <div>
-                          <span
-                            class="pointer"
-                            onClick={linkEvent(
-                              this,
-                              this.handleImageExpandClick
-                            )}
-                          >
-                            <img
-                              class="img-fluid img-expanded"
-                              src={this.getImage()}
-                            />
-                          </span>
-                        </div>
-                      </span>
-                    )}
-                  </>
-                )}
-                {post.removed && (
-                  <small className="ml-2 text-muted font-italic">
-                    {i18n.t('removed')}
-                  </small>
-                )}
-                {post.deleted && (
-                  <small
-                    className="unselectable pointer ml-2 text-muted font-italic"
-                    data-tippy-content={i18n.t('deleted')}
+      </ul>
+    );
+  }
+
+  duplicatesLine() {
+    return (
+      this.props.post.duplicates && (
+        <ul class="list-inline mb-1 small text-muted">
+          <>
+            <li className="list-inline-item mr-2">
+              {i18n.t('cross_posted_to')}
+            </li>
+            {this.props.post.duplicates.map(post => (
+              <li className="list-inline-item mr-2">
+                <Link to={`/post/${post.id}`}>{post.community_name}</Link>
+              </li>
+            ))}
+          </>
+        </ul>
+      )
+    );
+  }
+
+  postActions() {
+    let post = this.props.post;
+    return (
+      <ul class="list-inline mb-1 text-muted font-weight-bold">
+        {UserService.Instance.user && (
+          <>
+            {this.props.showBody && (
+              <>
+                <li className="list-inline-item">
+                  <button
+                    class="btn btn-link btn-animate text-muted"
+                    onClick={linkEvent(this, this.handleSavePostClick)}
+                    data-tippy-content={
+                      post.saved ? i18n.t('unsave') : i18n.t('save')
+                    }
                   >
-                    <svg class={`icon icon-inline text-danger`}>
-                      <use xlinkHref="#icon-trash"></use>
+                    <svg
+                      class={`icon icon-inline ${post.saved && 'text-warning'}`}
+                    >
+                      <use xlinkHref="#icon-star"></use>
                     </svg>
-                  </small>
-                )}
-                {post.locked && (
-                  <small
-                    className="unselectable pointer ml-2 text-muted font-italic"
-                    data-tippy-content={i18n.t('locked')}
+                  </button>
+                </li>
+                <li className="list-inline-item">
+                  <Link
+                    class="btn btn-link btn-animate text-muted"
+                    to={`/create_post${this.crossPostParams}`}
+                    title={i18n.t('cross_post')}
                   >
-                    <svg class={`icon icon-inline text-danger`}>
-                      <use xlinkHref="#icon-lock"></use>
+                    <svg class="icon icon-inline">
+                      <use xlinkHref="#icon-copy"></use>
                     </svg>
-                  </small>
-                )}
-                {post.stickied && (
-                  <small
-                    className="unselectable pointer ml-2 text-muted font-italic"
-                    data-tippy-content={i18n.t('stickied')}
+                  </Link>
+                </li>
+              </>
+            )}
+            {this.myPost && this.props.showBody && (
+              <>
+                <li className="list-inline-item">
+                  <button
+                    class="btn btn-link btn-animate text-muted"
+                    onClick={linkEvent(this, this.handleEditClick)}
+                    data-tippy-content={i18n.t('edit')}
                   >
-                    <svg class={`icon icon-inline text-success`}>
-                      <use xlinkHref="#icon-pin"></use>
+                    <svg class="icon icon-inline">
+                      <use xlinkHref="#icon-edit"></use>
                     </svg>
-                  </small>
-                )}
-                {post.nsfw && (
-                  <small className="ml-2 text-muted font-italic">
-                    {i18n.t('nsfw')}
-                  </small>
-                )}
-              </div>
-            </div>
-          </div>
-          <div class="row">
-            <div className="details col-12">
-              <ul class="list-inline mb-0 text-muted small">
-                <li className="list-inline-item">
-                  <span>{i18n.t('by')} </span>
-                  <UserListing
-                    user={{
-                      name: post.creator_name,
-                      avatar: post.creator_avatar,
-                      id: post.creator_id,
-                      local: post.creator_local,
-                      actor_id: post.creator_actor_id,
-                      published: post.creator_published,
-                    }}
-                  />
-
-                  {this.isMod && (
-                    <span className="mx-1 badge badge-light">
-                      {i18n.t('mod')}
-                    </span>
-                  )}
-                  {this.isAdmin && (
-                    <span className="mx-1 badge badge-light">
-                      {i18n.t('admin')}
-                    </span>
-                  )}
-                  {(post.banned_from_community || post.banned) && (
-                    <span className="mx-1 badge badge-danger">
-                      {i18n.t('banned')}
-                    </span>
-                  )}
-                  {this.props.showCommunity && (
-                    <span>
-                      <span> {i18n.t('to')} </span>
-                      <CommunityLink
-                        community={{
-                          name: post.community_name,
-                          id: post.community_id,
-                          local: post.community_local,
-                          actor_id: post.community_actor_id,
-                        }}
-                      />
-                    </span>
-                  )}
+                  </button>
                 </li>
-                <li className="list-inline-item">•</li>
                 <li className="list-inline-item">
-                  <span>
-                    <MomentTime data={post} />
-                  </span>
+                  <button
+                    class="btn btn-link btn-animate text-muted"
+                    onClick={linkEvent(this, this.handleDeleteClick)}
+                    data-tippy-content={
+                      !post.deleted ? i18n.t('delete') : i18n.t('restore')
+                    }
+                  >
+                    <svg
+                      class={`icon icon-inline ${
+                        post.deleted && 'text-danger'
+                      }`}
+                    >
+                      <use xlinkHref="#icon-trash"></use>
+                    </svg>
+                  </button>
                 </li>
-                {post.body && (
+              </>
+            )}
+
+            {!this.state.showAdvanced && this.props.showBody ? (
+              <li className="list-inline-item">
+                <button
+                  class="btn btn-link btn-animate text-muted"
+                  onClick={linkEvent(this, this.handleShowAdvanced)}
+                  data-tippy-content={i18n.t('more')}
+                >
+                  <svg class="icon icon-inline">
+                    <use xlinkHref="#icon-more-vertical"></use>
+                  </svg>
+                </button>
+              </li>
+            ) : (
+              <>
+                {this.props.showBody && post.body && (
+                  <li className="list-inline-item">
+                    <button
+                      class="btn btn-link btn-animate text-muted"
+                      onClick={linkEvent(this, this.handleViewSource)}
+                      data-tippy-content={i18n.t('view_source')}
+                    >
+                      <svg
+                        class={`icon icon-inline ${
+                          this.state.viewSource && 'text-success'
+                        }`}
+                      >
+                        <use xlinkHref="#icon-file-text"></use>
+                      </svg>
+                    </button>
+                  </li>
+                )}
+                {this.canModOnSelf && (
                   <>
-                    <li className="list-inline-item">•</li>
                     <li className="list-inline-item">
-                      {/* Using a link with tippy doesn't work on touch devices unfortunately */}
-                      <Link
-                        className="text-muted"
-                        data-tippy-content={md.render(previewLines(post.body))}
-                        data-tippy-allowHtml={true}
-                        to={`/post/${post.id}`}
+                      <button
+                        class="btn btn-link btn-animate text-muted"
+                        onClick={linkEvent(this, this.handleModLock)}
+                        data-tippy-content={
+                          post.locked ? i18n.t('unlock') : i18n.t('lock')
+                        }
+                      >
+                        <svg
+                          class={`icon icon-inline ${
+                            post.locked && 'text-danger'
+                          }`}
+                        >
+                          <use xlinkHref="#icon-lock"></use>
+                        </svg>
+                      </button>
+                    </li>
+                    <li className="list-inline-item">
+                      <button
+                        class="btn btn-link btn-animate text-muted"
+                        onClick={linkEvent(this, this.handleModSticky)}
+                        data-tippy-content={
+                          post.stickied ? i18n.t('unsticky') : i18n.t('sticky')
+                        }
                       >
-                        <svg class="mr-1 icon icon-inline">
-                          <use xlinkHref="#icon-book-open"></use>
+                        <svg
+                          class={`icon icon-inline ${
+                            post.stickied && 'text-success'
+                          }`}
+                        >
+                          <use xlinkHref="#icon-pin"></use>
                         </svg>
-                      </Link>
+                      </button>
                     </li>
                   </>
                 )}
-                <li className="list-inline-item">•</li>
-                {this.state.upvotes !== this.state.score && (
+                {/* Mods can ban from community, and appoint as mods to community */}
+                {(this.canMod || this.canAdmin) && (
+                  <li className="list-inline-item">
+                    {!post.removed ? (
+                      <span
+                        class="pointer"
+                        onClick={linkEvent(this, this.handleModRemoveShow)}
+                      >
+                        {i18n.t('remove')}
+                      </span>
+                    ) : (
+                      <span
+                        class="pointer"
+                        onClick={linkEvent(this, this.handleModRemoveSubmit)}
+                      >
+                        {i18n.t('restore')}
+                      </span>
+                    )}
+                  </li>
+                )}
+                {this.canMod && (
                   <>
-                    <span
-                      class="unselectable pointer mr-2"
-                      data-tippy-content={this.pointsTippy}
-                    >
+                    {!this.isMod && (
                       <li className="list-inline-item">
-                        <span className="text-muted">
-                          <svg class="small icon icon-inline mr-1">
-                            <use xlinkHref="#icon-arrow-up"></use>
-                          </svg>
-                          {this.state.upvotes}
-                        </span>
+                        {!post.banned_from_community ? (
+                          <span
+                            class="pointer"
+                            onClick={linkEvent(
+                              this,
+                              this.handleModBanFromCommunityShow
+                            )}
+                          >
+                            {i18n.t('ban')}
+                          </span>
+                        ) : (
+                          <span
+                            class="pointer"
+                            onClick={linkEvent(
+                              this,
+                              this.handleModBanFromCommunitySubmit
+                            )}
+                          >
+                            {i18n.t('unban')}
+                          </span>
+                        )}
                       </li>
+                    )}
+                    {!post.banned_from_community && post.creator_local && (
                       <li className="list-inline-item">
-                        <span className="text-muted">
-                          <svg class="small icon icon-inline mr-1">
-                            <use xlinkHref="#icon-arrow-down"></use>
-                          </svg>
-                          {this.state.downvotes}
+                        <span
+                          class="pointer"
+                          onClick={linkEvent(
+                            this,
+                            this.handleAddModToCommunity
+                          )}
+                        >
+                          {this.isMod
+                            ? i18n.t('remove_as_mod')
+                            : i18n.t('appoint_as_mod')}
                         </span>
                       </li>
-                    </span>
-                    <li className="list-inline-item">•</li>
+                    )}
                   </>
                 )}
-                <li className="list-inline-item">
-                  <Link
-                    className="text-muted"
-                    title={i18n.t('number_of_comments', {
-                      count: post.number_of_comments,
-                    })}
-                    to={`/post/${post.id}`}
-                  >
-                    <svg class="mr-1 icon icon-inline">
-                      <use xlinkHref="#icon-message-square"></use>
-                    </svg>
-                    {post.number_of_comments}
-                  </Link>
-                </li>
-              </ul>
-              {this.props.post.duplicates && (
-                <ul class="list-inline mb-1 small text-muted">
-                  <>
-                    <li className="list-inline-item mr-2">
-                      {i18n.t('cross_posted_to')}
-                    </li>
-                    {this.props.post.duplicates.map(post => (
-                      <li className="list-inline-item mr-2">
-                        <Link to={`/post/${post.id}`}>
-                          {post.community_name}
-                        </Link>
-                      </li>
-                    ))}
-                  </>
-                </ul>
-              )}
-              <ul class="list-inline mb-1 text-muted font-weight-bold">
-                {UserService.Instance.user && (
-                  <>
-                    {this.props.showBody && (
-                      <>
-                        <li className="list-inline-item">
-                          <button
-                            class="btn btn-sm btn-link btn-animate text-muted"
-                            onClick={linkEvent(this, this.handleSavePostClick)}
-                            data-tippy-content={
-                              post.saved ? i18n.t('unsave') : i18n.t('save')
-                            }
+                {/* Community creators and admins can transfer community to another mod */}
+                {(this.amCommunityCreator || this.canAdmin) &&
+                  this.isMod &&
+                  post.creator_local && (
+                    <li className="list-inline-item">
+                      {!this.state.showConfirmTransferCommunity ? (
+                        <span
+                          class="pointer"
+                          onClick={linkEvent(
+                            this,
+                            this.handleShowConfirmTransferCommunity
+                          )}
+                        >
+                          {i18n.t('transfer_community')}
+                        </span>
+                      ) : (
+                        <>
+                          <span class="d-inline-block mr-1">
+                            {i18n.t('are_you_sure')}
+                          </span>
+                          <span
+                            class="pointer d-inline-block mr-1"
+                            onClick={linkEvent(
+                              this,
+                              this.handleTransferCommunity
+                            )}
                           >
-                            <svg
-                              class={`icon icon-inline ${
-                                post.saved && 'text-warning'
-                              }`}
-                            >
-                              <use xlinkHref="#icon-star"></use>
-                            </svg>
-                          </button>
-                        </li>
-                        <li className="list-inline-item">
-                          <Link
-                            class="btn btn-sm btn-link btn-animate text-muted"
-                            to={`/create_post${this.crossPostParams}`}
-                            title={i18n.t('cross_post')}
+                            {i18n.t('yes')}
+                          </span>
+                          <span
+                            class="pointer d-inline-block"
+                            onClick={linkEvent(
+                              this,
+                              this.handleCancelShowConfirmTransferCommunity
+                            )}
                           >
-                            <svg class="icon icon-inline">
-                              <use xlinkHref="#icon-copy"></use>
-                            </svg>
-                          </Link>
-                        </li>
-                      </>
-                    )}
-                    {this.myPost && this.props.showBody && (
-                      <>
-                        <li className="list-inline-item">
-                          <button
-                            class="btn btn-sm btn-link btn-animate text-muted"
-                            onClick={linkEvent(this, this.handleEditClick)}
-                            data-tippy-content={i18n.t('edit')}
+                            {i18n.t('no')}
+                          </span>
+                        </>
+                      )}
+                    </li>
+                  )}
+                {/* Admins can ban from all, and appoint other admins */}
+                {this.canAdmin && (
+                  <>
+                    {!this.isAdmin && (
+                      <li className="list-inline-item">
+                        {!post.banned ? (
+                          <span
+                            class="pointer"
+                            onClick={linkEvent(this, this.handleModBanShow)}
                           >
-                            <svg class="icon icon-inline">
-                              <use xlinkHref="#icon-edit"></use>
-                            </svg>
-                          </button>
-                        </li>
-                        <li className="list-inline-item">
-                          <button
-                            class="btn btn-sm btn-link btn-animate text-muted"
-                            onClick={linkEvent(this, this.handleDeleteClick)}
-                            data-tippy-content={
-                              !post.deleted
-                                ? i18n.t('delete')
-                                : i18n.t('restore')
-                            }
+                            {i18n.t('ban_from_site')}
+                          </span>
+                        ) : (
+                          <span
+                            class="pointer"
+                            onClick={linkEvent(this, this.handleModBanSubmit)}
                           >
-                            <svg
-                              class={`icon icon-inline ${
-                                post.deleted && 'text-danger'
-                              }`}
-                            >
-                              <use xlinkHref="#icon-trash"></use>
-                            </svg>
-                          </button>
-                        </li>
-                      </>
+                            {i18n.t('unban_from_site')}
+                          </span>
+                        )}
+                      </li>
                     )}
-
-                    {!this.state.showAdvanced && this.props.showBody ? (
+                    {!post.banned && post.creator_local && (
                       <li className="list-inline-item">
-                        <button
-                          class="btn btn-sm btn-link btn-animate text-muted"
-                          onClick={linkEvent(this, this.handleShowAdvanced)}
-                          data-tippy-content={i18n.t('more')}
+                        <span
+                          class="pointer"
+                          onClick={linkEvent(this, this.handleAddAdmin)}
                         >
-                          <svg class="icon icon-inline">
-                            <use xlinkHref="#icon-more-vertical"></use>
-                          </svg>
-                        </button>
+                          {this.isAdmin
+                            ? i18n.t('remove_as_admin')
+                            : i18n.t('appoint_as_admin')}
+                        </span>
                       </li>
+                    )}
+                  </>
+                )}
+                {/* Site Creator can transfer to another admin */}
+                {this.amSiteCreator && this.isAdmin && (
+                  <li className="list-inline-item">
+                    {!this.state.showConfirmTransferSite ? (
+                      <span
+                        class="pointer"
+                        onClick={linkEvent(
+                          this,
+                          this.handleShowConfirmTransferSite
+                        )}
+                      >
+                        {i18n.t('transfer_site')}
+                      </span>
                     ) : (
                       <>
-                        {this.props.showBody && post.body && (
-                          <li className="list-inline-item">
-                            <button
-                              class="btn btn-sm btn-link btn-animate text-muted"
-                              onClick={linkEvent(this, this.handleViewSource)}
-                              data-tippy-content={i18n.t('view_source')}
-                            >
-                              <svg
-                                class={`icon icon-inline ${
-                                  this.state.viewSource && 'text-success'
-                                }`}
-                              >
-                                <use xlinkHref="#icon-file-text"></use>
-                              </svg>
-                            </button>
-                          </li>
-                        )}
-                        {this.canModOnSelf && (
-                          <>
-                            <li className="list-inline-item">
-                              <button
-                                class="btn btn-sm btn-link btn-animate text-muted"
-                                onClick={linkEvent(this, this.handleModLock)}
-                                data-tippy-content={
-                                  post.locked
-                                    ? i18n.t('unlock')
-                                    : i18n.t('lock')
-                                }
-                              >
-                                <svg
-                                  class={`icon icon-inline ${
-                                    post.locked && 'text-danger'
-                                  }`}
-                                >
-                                  <use xlinkHref="#icon-lock"></use>
-                                </svg>
-                              </button>
-                            </li>
-                            <li className="list-inline-item">
-                              <button
-                                class="btn btn-sm btn-link btn-animate text-muted"
-                                onClick={linkEvent(this, this.handleModSticky)}
-                                data-tippy-content={
-                                  post.stickied
-                                    ? i18n.t('unsticky')
-                                    : i18n.t('sticky')
-                                }
-                              >
-                                <svg
-                                  class={`icon icon-inline ${
-                                    post.stickied && 'text-success'
-                                  }`}
-                                >
-                                  <use xlinkHref="#icon-pin"></use>
-                                </svg>
-                              </button>
-                            </li>
-                          </>
-                        )}
-                        {/* Mods can ban from community, and appoint as mods to community */}
-                        {(this.canMod || this.canAdmin) && (
-                          <li className="list-inline-item">
-                            {!post.removed ? (
-                              <span
-                                class="pointer"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleModRemoveShow
-                                )}
-                              >
-                                {i18n.t('remove')}
-                              </span>
-                            ) : (
-                              <span
-                                class="pointer"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleModRemoveSubmit
-                                )}
-                              >
-                                {i18n.t('restore')}
-                              </span>
-                            )}
-                          </li>
-                        )}
-                        {this.canMod && (
-                          <>
-                            {!this.isMod && (
-                              <li className="list-inline-item">
-                                {!post.banned_from_community ? (
-                                  <span
-                                    class="pointer"
-                                    onClick={linkEvent(
-                                      this,
-                                      this.handleModBanFromCommunityShow
-                                    )}
-                                  >
-                                    {i18n.t('ban')}
-                                  </span>
-                                ) : (
-                                  <span
-                                    class="pointer"
-                                    onClick={linkEvent(
-                                      this,
-                                      this.handleModBanFromCommunitySubmit
-                                    )}
-                                  >
-                                    {i18n.t('unban')}
-                                  </span>
-                                )}
-                              </li>
-                            )}
-                            {!post.banned_from_community && (
-                              <li className="list-inline-item">
-                                <span
-                                  class="pointer"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleAddModToCommunity
-                                  )}
-                                >
-                                  {this.isMod
-                                    ? i18n.t('remove_as_mod')
-                                    : i18n.t('appoint_as_mod')}
-                                </span>
-                              </li>
-                            )}
-                          </>
-                        )}
-                        {/* Community creators and admins can transfer community to another mod */}
-                        {(this.amCommunityCreator || this.canAdmin) &&
-                          this.isMod && (
-                            <li className="list-inline-item">
-                              {!this.state.showConfirmTransferCommunity ? (
-                                <span
-                                  class="pointer"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleShowConfirmTransferCommunity
-                                  )}
-                                >
-                                  {i18n.t('transfer_community')}
-                                </span>
-                              ) : (
-                                <>
-                                  <span class="d-inline-block mr-1">
-                                    {i18n.t('are_you_sure')}
-                                  </span>
-                                  <span
-                                    class="pointer d-inline-block mr-1"
-                                    onClick={linkEvent(
-                                      this,
-                                      this.handleTransferCommunity
-                                    )}
-                                  >
-                                    {i18n.t('yes')}
-                                  </span>
-                                  <span
-                                    class="pointer d-inline-block"
-                                    onClick={linkEvent(
-                                      this,
-                                      this
-                                        .handleCancelShowConfirmTransferCommunity
-                                    )}
-                                  >
-                                    {i18n.t('no')}
-                                  </span>
-                                </>
-                              )}
-                            </li>
+                        <span class="d-inline-block mr-1">
+                          {i18n.t('are_you_sure')}
+                        </span>
+                        <span
+                          class="pointer d-inline-block mr-1"
+                          onClick={linkEvent(this, this.handleTransferSite)}
+                        >
+                          {i18n.t('yes')}
+                        </span>
+                        <span
+                          class="pointer d-inline-block"
+                          onClick={linkEvent(
+                            this,
+                            this.handleCancelShowConfirmTransferSite
                           )}
-                        {/* Admins can ban from all, and appoint other admins */}
-                        {this.canAdmin && (
-                          <>
-                            {!this.isAdmin && (
-                              <li className="list-inline-item">
-                                {!post.banned ? (
-                                  <span
-                                    class="pointer"
-                                    onClick={linkEvent(
-                                      this,
-                                      this.handleModBanShow
-                                    )}
-                                  >
-                                    {i18n.t('ban_from_site')}
-                                  </span>
-                                ) : (
-                                  <span
-                                    class="pointer"
-                                    onClick={linkEvent(
-                                      this,
-                                      this.handleModBanSubmit
-                                    )}
-                                  >
-                                    {i18n.t('unban_from_site')}
-                                  </span>
-                                )}
-                              </li>
-                            )}
-                            {!post.banned && (
-                              <li className="list-inline-item">
-                                <span
-                                  class="pointer"
-                                  onClick={linkEvent(this, this.handleAddAdmin)}
-                                >
-                                  {this.isAdmin
-                                    ? i18n.t('remove_as_admin')
-                                    : i18n.t('appoint_as_admin')}
-                                </span>
-                              </li>
-                            )}
-                          </>
-                        )}
-                        {/* Site Creator can transfer to another admin */}
-                        {this.amSiteCreator && this.isAdmin && (
-                          <li className="list-inline-item">
-                            {!this.state.showConfirmTransferSite ? (
-                              <span
-                                class="pointer"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleShowConfirmTransferSite
-                                )}
-                              >
-                                {i18n.t('transfer_site')}
-                              </span>
-                            ) : (
-                              <>
-                                <span class="d-inline-block mr-1">
-                                  {i18n.t('are_you_sure')}
-                                </span>
-                                <span
-                                  class="pointer d-inline-block mr-1"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleTransferSite
-                                  )}
-                                >
-                                  {i18n.t('yes')}
-                                </span>
-                                <span
-                                  class="pointer d-inline-block"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleCancelShowConfirmTransferSite
-                                  )}
-                                >
-                                  {i18n.t('no')}
-                                </span>
-                              </>
-                            )}
-                          </li>
-                        )}
+                        >
+                          {i18n.t('no')}
+                        </span>
                       </>
                     )}
-                  </>
+                  </li>
                 )}
-              </ul>
-              {this.state.showRemoveDialog && (
-                <form
-                  class="form-inline"
-                  onSubmit={linkEvent(this, this.handleModRemoveSubmit)}
-                >
+              </>
+            )}
+          </>
+        )}
+      </ul>
+    );
+  }
+
+  removeAndBanDialogs() {
+    let post = this.props.post;
+    return (
+      <>
+        {this.state.showRemoveDialog && (
+          <form
+            class="form-inline"
+            onSubmit={linkEvent(this, this.handleModRemoveSubmit)}
+          >
+            <input
+              type="text"
+              class="form-control mr-2"
+              placeholder={i18n.t('reason')}
+              value={this.state.removeReason}
+              onInput={linkEvent(this, this.handleModRemoveReasonChange)}
+            />
+            <button type="submit" class="btn btn-secondary">
+              {i18n.t('remove_post')}
+            </button>
+          </form>
+        )}
+        {this.state.showBanDialog && (
+          <form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
+            <div class="form-group row">
+              <label class="col-form-label" htmlFor="post-listing-reason">
+                {i18n.t('reason')}
+              </label>
+              <input
+                type="text"
+                id="post-listing-reason"
+                class="form-control mr-2"
+                placeholder={i18n.t('reason')}
+                value={this.state.banReason}
+                onInput={linkEvent(this, this.handleModBanReasonChange)}
+              />
+              <div class="form-group">
+                <div class="form-check">
                   <input
-                    type="text"
-                    class="form-control mr-2"
-                    placeholder={i18n.t('reason')}
-                    value={this.state.removeReason}
-                    onInput={linkEvent(this, this.handleModRemoveReasonChange)}
+                    class="form-check-input"
+                    id="mod-ban-remove-data"
+                    type="checkbox"
+                    checked={this.state.removeData}
+                    onChange={linkEvent(this, this.handleModRemoveDataChange)}
                   />
-                  <button type="submit" class="btn btn-secondary">
-                    {i18n.t('remove_post')}
-                  </button>
-                </form>
-              )}
-              {this.state.showBanDialog && (
-                <form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
-                  <div class="form-group row">
-                    <label class="col-form-label" htmlFor="post-listing-reason">
-                      {i18n.t('reason')}
-                    </label>
-                    <input
-                      type="text"
-                      id="post-listing-reason"
-                      class="form-control mr-2"
-                      placeholder={i18n.t('reason')}
-                      value={this.state.banReason}
-                      onInput={linkEvent(this, this.handleModBanReasonChange)}
-                    />
-                  </div>
-                  {/* TODO hold off on expires until later */}
-                  {/* <div class="form-group row"> */}
-                  {/*   <label class="col-form-label">Expires</label> */}
-                  {/*   <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
-                  {/* </div> */}
-                  <div class="form-group row">
-                    <button type="submit" class="btn btn-secondary">
-                      {i18n.t('ban')} {post.creator_name}
-                    </button>
-                  </div>
-                </form>
-              )}
+                  <label class="form-check-label" htmlFor="mod-ban-remove-data">
+                    {i18n.t('remove_posts_comments')}
+                  </label>
+                </div>
+              </div>
             </div>
-          </div>
+            {/* TODO hold off on expires until later */}
+            {/* <div class="form-group row"> */}
+            {/*   <label class="col-form-label">Expires</label> */}
+            {/*   <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
+            {/* </div> */}
+            <div class="form-group row">
+              <button type="submit" class="btn btn-secondary">
+                {i18n.t('ban')} {post.creator_name}
+              </button>
+            </div>
+          </form>
+        )}
+      </>
+    );
+  }
+
+  mobileThumbnail() {
+    return this.props.post.thumbnail_url || isImage(this.props.post.url) ? (
+      <div class="row">
+        <div className={`${this.state.imageExpanded ? 'col-12' : 'col-8'}`}>
+          {this.postTitleLine()}
+        </div>
+        <div class="col-4">
+          {/* Post body prev or thumbnail */}
+          {!this.state.imageExpanded && this.thumbnail()}
         </div>
       </div>
+    ) : (
+      this.postTitleLine()
+    );
+  }
+
+  showMobilePreview() {
+    return (
+      this.props.post.body &&
+      !this.props.showBody && (
+        <div
+          className="md-div mb-1"
+          dangerouslySetInnerHTML={{
+            __html: md.render(previewLines(this.props.post.body)),
+          }}
+        />
+      )
+    );
+  }
+
+  listing() {
+    return (
+      <>
+        {/* The mobile view*/}
+        <div class="d-block d-sm-none">
+          <div class="row">
+            <div class="col-12">
+              {this.createdLine()}
+
+              {/* If it has a thumbnail, do a right aligned thumbnail */}
+              {this.mobileThumbnail()}
+
+              {/* Show a preview of the post body */}
+              {this.showMobilePreview()}
+
+              {this.commentsLine(true)}
+              {this.duplicatesLine()}
+              {this.postActions()}
+              {this.removeAndBanDialogs()}
+            </div>
+          </div>
+        </div>
+
+        {/* The larger view*/}
+        <div class="d-none d-sm-block">
+          <div class="row">
+            {this.voteBar()}
+            {!this.state.imageExpanded && (
+              <div class="col-sm-2 pr-0">
+                <div class="">{this.thumbnail()}</div>
+              </div>
+            )}
+            <div
+              class={`${
+                this.state.imageExpanded ? 'col-12' : 'col-12 col-sm-9'
+              }`}
+            >
+              <div class="row">
+                <div className="col-12">
+                  {this.postTitleLine()}
+                  {this.createdLine()}
+                  {this.commentsLine()}
+                  {this.duplicatesLine()}
+                  {this.postActions()}
+                  {this.removeAndBanDialogs()}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </>
     );
   }
 
@@ -1111,18 +1216,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   handleDeleteClick(i: PostListing) {
-    let deleteForm: PostFormI = {
-      body: i.props.post.body,
-      community_id: i.props.post.community_id,
-      name: i.props.post.name,
-      url: i.props.post.url,
+    let deleteForm: DeletePostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
       deleted: !i.props.post.deleted,
-      nsfw: i.props.post.nsfw,
       auth: null,
     };
-    WebSocketService.Instance.editPost(deleteForm);
+    WebSocketService.Instance.deletePost(deleteForm);
   }
 
   handleSavePostClick(i: PostListing) {
@@ -1140,7 +1239,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     let post = this.props.post;
 
     if (post.url) {
-      params += `&url=${post.url}`;
+      params += `&url=${encodeURIComponent(post.url)}`;
     }
     if (this.props.post.body) {
       params += `&body=${this.props.post.body}`;
@@ -1158,48 +1257,41 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     i.setState(i.state);
   }
 
+  handleModRemoveDataChange(i: PostListing, event: any) {
+    i.state.removeData = event.target.checked;
+    i.setState(i.state);
+  }
+
   handleModRemoveSubmit(i: PostListing) {
     event.preventDefault();
-    let form: PostFormI = {
-      name: i.props.post.name,
-      community_id: i.props.post.community_id,
+    let form: RemovePostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
       removed: !i.props.post.removed,
       reason: i.state.removeReason,
-      nsfw: i.props.post.nsfw,
       auth: null,
     };
-    WebSocketService.Instance.editPost(form);
+    WebSocketService.Instance.removePost(form);
 
     i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
 
   handleModLock(i: PostListing) {
-    let form: PostFormI = {
-      name: i.props.post.name,
-      community_id: i.props.post.community_id,
+    let form: LockPostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
-      nsfw: i.props.post.nsfw,
       locked: !i.props.post.locked,
       auth: null,
     };
-    WebSocketService.Instance.editPost(form);
+    WebSocketService.Instance.lockPost(form);
   }
 
   handleModSticky(i: PostListing) {
-    let form: PostFormI = {
-      name: i.props.post.name,
-      community_id: i.props.post.community_id,
+    let form: StickyPostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
-      nsfw: i.props.post.nsfw,
       stickied: !i.props.post.stickied,
       auth: null,
     };
-    WebSocketService.Instance.editPost(form);
+    WebSocketService.Instance.stickyPost(form);
   }
 
   handleModBanFromCommunityShow(i: PostListing) {
@@ -1240,18 +1332,30 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     event.preventDefault();
 
     if (i.state.banType == BanType.Community) {
+      // If its an unban, restore all their data
+      let ban = !i.props.post.banned_from_community;
+      if (ban == false) {
+        i.state.removeData = false;
+      }
       let form: BanFromCommunityForm = {
         user_id: i.props.post.creator_id,
         community_id: i.props.post.community_id,
-        ban: !i.props.post.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.post.banned;
+      if (ban == false) {
+        i.state.removeData = false;
+      }
       let form: BanUserForm = {
         user_id: i.props.post.creator_id,
-        ban: !i.props.post.banned,
+        ban,
+        remove_data: i.state.removeData,
         reason: i.state.banReason,
         expires: getUnixTime(i.state.banExpires),
       };