]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/modlog.tsx
Add community name to featured post action in Modlog (#1891)
[lemmy-ui.git] / src / shared / components / modlog.tsx
index 8972f98546004f9f5d32d711219158d2564f2c69..ca1cb3326b2cfef3a2ca454d00d071d454e72abc 100644 (file)
@@ -1,3 +1,21 @@
+import {
+  fetchUsers,
+  getUpdatedSearchId,
+  myAuth,
+  personToChoice,
+  setIsoData,
+} from "@utils/app";
+import {
+  debounce,
+  formatPastDate,
+  getIdFromString,
+  getPageFromString,
+  getQueryParams,
+  getQueryString,
+} from "@utils/helpers";
+import { amAdmin, amMod } from "@utils/roles";
+import type { QueryParams } from "@utils/types";
+import { Choice, RouteDataResponse } from "@utils/types";
 import { NoOptionI18nKeys } from "i18next";
 import { Component, linkEvent } from "inferno";
 import { T } from "inferno-i18next-dess";
@@ -8,7 +26,6 @@ import {
   AdminPurgeCommunityView,
   AdminPurgePersonView,
   AdminPurgePostView,
-  CommunityModeratorView,
   GetCommunity,
   GetCommunityResponse,
   GetModlog,
@@ -21,42 +38,17 @@ import {
   ModBanView,
   ModFeaturePostView,
   ModLockPostView,
-  ModlogActionType,
   ModRemoveCommentView,
   ModRemoveCommunityView,
   ModRemovePostView,
   ModTransferCommunityView,
-  PersonSafe,
-  UserOperation,
-  wsJsonToRes,
-  wsUserOp,
+  ModlogActionType,
+  Person,
 } from "lemmy-js-client";
-import moment from "moment";
-import { Subscription } from "rxjs";
-import { i18n } from "../i18next";
+import { fetchLimit } from "../config";
 import { InitialFetchRequest } from "../interfaces";
-import { WebSocketService } from "../services";
-import {
-  amAdmin,
-  amMod,
-  Choice,
-  debounce,
-  fetchLimit,
-  fetchUsers,
-  getIdFromString,
-  getPageFromString,
-  getQueryParams,
-  getQueryString,
-  getUpdatedSearchId,
-  isBrowser,
-  myAuth,
-  personToChoice,
-  QueryParams,
-  setIsoData,
-  toast,
-  wsClient,
-  wsSubscribe,
-} from "../utils";
+import { FirstLoadService, I18NextService } from "../services";
+import { HttpService, RequestState } from "../services/HttpService";
 import { HtmlTags } from "./common/html-tags";
 import { Icon, Spinner } from "./common/icon";
 import { MomentTime } from "./common/moment-time";
@@ -83,10 +75,17 @@ type View =
   | AdminPurgePostView
   | AdminPurgeCommentView;
 
+type ModlogData = RouteDataResponse<{
+  res: GetModlogResponse;
+  communityRes: GetCommunityResponse;
+  modUserResponse: GetPersonDetailsResponse;
+  userResponse: GetPersonDetailsResponse;
+}>;
+
 interface ModlogType {
   id: number;
   type_: ModlogActionType;
-  moderator?: PersonSafe;
+  moderator?: Person;
   view: View;
   when_: string;
 }
@@ -100,10 +99,8 @@ const getModlogQueryParams = () =>
   });
 
 interface ModlogState {
-  res?: GetModlogResponse;
-  communityMods?: CommunityModeratorView[];
-  communityName?: string;
-  loadingModlog: boolean;
+  res: RequestState<GetModlogResponse>;
+  communityRes: RequestState<GetCommunityResponse>;
   loadingModSearch: boolean;
   loadingUserSearch: boolean;
   modSearchOptions: Choice[];
@@ -117,17 +114,16 @@ interface ModlogProps {
   actionType: ModlogActionType;
 }
 
-const getActionFromString = (action?: string) =>
-  action
-    ? ModlogActionType[action] ?? ModlogActionType.All
-    : ModlogActionType.All;
+function getActionFromString(action?: string): ModlogActionType {
+  return action !== undefined ? (action as ModlogActionType) : "All";
+}
 
 const getModlogActionMapper =
   (
     actionType: ModlogActionType,
     getAction: (view: View) => { id: number; when_: string }
   ) =>
-  (view: View & { moderator?: PersonSafe; admin?: PersonSafe }): ModlogType => {
+  (view: View & { moderator?: Person; admin?: Person }): ModlogType => {
     const { id, when_ } = getAction(view);
 
     return {
@@ -158,14 +154,14 @@ function buildCombined({
   const combined = removed_posts
     .map(
       getModlogActionMapper(
-        ModlogActionType.ModRemovePost,
+        "ModRemovePost",
         ({ mod_remove_post }: ModRemovePostView) => mod_remove_post
       )
     )
     .concat(
       locked_posts.map(
         getModlogActionMapper(
-          ModlogActionType.ModLockPost,
+          "ModLockPost",
           ({ mod_lock_post }: ModLockPostView) => mod_lock_post
         )
       )
@@ -173,7 +169,7 @@ function buildCombined({
     .concat(
       featured_posts.map(
         getModlogActionMapper(
-          ModlogActionType.ModFeaturePost,
+          "ModFeaturePost",
           ({ mod_feature_post }: ModFeaturePostView) => mod_feature_post
         )
       )
@@ -181,7 +177,7 @@ function buildCombined({
     .concat(
       removed_comments.map(
         getModlogActionMapper(
-          ModlogActionType.ModRemoveComment,
+          "ModRemoveComment",
           ({ mod_remove_comment }: ModRemoveCommentView) => mod_remove_comment
         )
       )
@@ -189,7 +185,7 @@ function buildCombined({
     .concat(
       removed_communities.map(
         getModlogActionMapper(
-          ModlogActionType.ModRemoveCommunity,
+          "ModRemoveCommunity",
           ({ mod_remove_community }: ModRemoveCommunityView) =>
             mod_remove_community
         )
@@ -198,7 +194,7 @@ function buildCombined({
     .concat(
       banned_from_community.map(
         getModlogActionMapper(
-          ModlogActionType.ModBanFromCommunity,
+          "ModBanFromCommunity",
           ({ mod_ban_from_community }: ModBanFromCommunityView) =>
             mod_ban_from_community
         )
@@ -207,7 +203,7 @@ function buildCombined({
     .concat(
       added_to_community.map(
         getModlogActionMapper(
-          ModlogActionType.ModAddCommunity,
+          "ModAddCommunity",
           ({ mod_add_community }: ModAddCommunityView) => mod_add_community
         )
       )
@@ -215,7 +211,7 @@ function buildCombined({
     .concat(
       transferred_to_community.map(
         getModlogActionMapper(
-          ModlogActionType.ModTransferCommunity,
+          "ModTransferCommunity",
           ({ mod_transfer_community }: ModTransferCommunityView) =>
             mod_transfer_community
         )
@@ -223,24 +219,18 @@ function buildCombined({
     )
     .concat(
       added.map(
-        getModlogActionMapper(
-          ModlogActionType.ModAdd,
-          ({ mod_add }: ModAddView) => mod_add
-        )
+        getModlogActionMapper("ModAdd", ({ mod_add }: ModAddView) => mod_add)
       )
     )
     .concat(
       banned.map(
-        getModlogActionMapper(
-          ModlogActionType.ModBan,
-          ({ mod_ban }: ModBanView) => mod_ban
-        )
+        getModlogActionMapper("ModBan", ({ mod_ban }: ModBanView) => mod_ban)
       )
     )
     .concat(
       admin_purged_persons.map(
         getModlogActionMapper(
-          ModlogActionType.AdminPurgePerson,
+          "AdminPurgePerson",
           ({ admin_purge_person }: AdminPurgePersonView) => admin_purge_person
         )
       )
@@ -248,7 +238,7 @@ function buildCombined({
     .concat(
       admin_purged_communities.map(
         getModlogActionMapper(
-          ModlogActionType.AdminPurgeCommunity,
+          "AdminPurgeCommunity",
           ({ admin_purge_community }: AdminPurgeCommunityView) =>
             admin_purge_community
         )
@@ -257,7 +247,7 @@ function buildCombined({
     .concat(
       admin_purged_posts.map(
         getModlogActionMapper(
-          ModlogActionType.AdminPurgePost,
+          "AdminPurgePost",
           ({ admin_purge_post }: AdminPurgePostView) => admin_purge_post
         )
       )
@@ -265,7 +255,7 @@ function buildCombined({
     .concat(
       admin_purged_comments.map(
         getModlogActionMapper(
-          ModlogActionType.AdminPurgeComment,
+          "AdminPurgeComment",
           ({ admin_purge_comment }: AdminPurgeCommentView) =>
             admin_purge_comment
         )
@@ -280,7 +270,7 @@ function buildCombined({
 
 function renderModlogType({ type_, view }: ModlogType) {
   switch (type_) {
-    case ModlogActionType.ModRemovePost: {
+    case "ModRemovePost": {
       const mrpv = view as ModRemovePostView;
       const {
         mod_remove_post: { reason, removed },
@@ -302,7 +292,7 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.ModLockPost: {
+    case "ModLockPost": {
       const {
         mod_lock_post: { locked },
         post: { id, name },
@@ -318,10 +308,11 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.ModFeaturePost: {
+    case "ModFeaturePost": {
       const {
         mod_feature_post: { featured, is_featured_community },
         post: { id, name },
+        community,
       } = view as ModFeaturePostView;
 
       return (
@@ -330,11 +321,16 @@ function renderModlogType({ type_, view }: ModlogType) {
           <span>
             Post <Link to={`/post/${id}`}>{name}</Link>
           </span>
-          <span>{is_featured_community ? " In Community" : " In Local"}</span>
+          <span>
+            {is_featured_community
+              ? " in community "
+              : " in Local, from community "}
+          </span>
+          <CommunityLink community={community} />
         </>
       );
     }
-    case ModlogActionType.ModRemoveComment: {
+    case "ModRemoveComment": {
       const mrc = view as ModRemoveCommentView;
       const {
         mod_remove_comment: { reason, removed },
@@ -361,7 +357,7 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.ModRemoveCommunity: {
+    case "ModRemoveCommunity": {
       const mrco = view as ModRemoveCommunityView;
       const {
         mod_remove_community: { reason, expires, removed },
@@ -381,14 +377,14 @@ function renderModlogType({ type_, view }: ModlogType) {
           )}
           {expires && (
             <span>
-              <div>expires: {moment.utc(expires).fromNow()}</div>
+              <div>expires: {formatPastDate(expires)}</div>
             </span>
           )}
         </>
       );
     }
 
-    case ModlogActionType.ModBanFromCommunity: {
+    case "ModBanFromCommunity": {
       const mbfc = view as ModBanFromCommunityView;
       const {
         mod_ban_from_community: { reason, expires, banned },
@@ -413,14 +409,14 @@ function renderModlogType({ type_, view }: ModlogType) {
           )}
           {expires && (
             <span>
-              <div>expires: {moment.utc(expires).fromNow()}</div>
+              <div>expires: {formatPastDate(expires)}</div>
             </span>
           )}
         </>
       );
     }
 
-    case ModlogActionType.ModAddCommunity: {
+    case "ModAddCommunity": {
       const {
         mod_add_community: { removed },
         modded_person,
@@ -441,16 +437,12 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.ModTransferCommunity: {
-      const {
-        mod_transfer_community: { removed },
-        community,
-        modded_person,
-      } = view as ModTransferCommunityView;
+    case "ModTransferCommunity": {
+      const { community, modded_person } = view as ModTransferCommunityView;
 
       return (
         <>
-          <span>{removed ? "Removed " : "Transferred "}</span>
+          <span>Transferred</span>
           <span>
             <CommunityLink community={community} />
           </span>
@@ -462,7 +454,7 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.ModBan: {
+    case "ModBan": {
       const {
         mod_ban: { reason, expires, banned },
         banned_person,
@@ -481,14 +473,14 @@ function renderModlogType({ type_, view }: ModlogType) {
           )}
           {expires && (
             <span>
-              <div>expires: {moment.utc(expires).fromNow()}</div>
+              <div>expires: {formatPastDate(expires)}</div>
             </span>
           )}
         </>
       );
     }
 
-    case ModlogActionType.ModAdd: {
+    case "ModAdd": {
       const {
         mod_add: { removed },
         modded_person,
@@ -504,7 +496,7 @@ function renderModlogType({ type_, view }: ModlogType) {
         </>
       );
     }
-    case ModlogActionType.AdminPurgePerson: {
+    case "AdminPurgePerson": {
       const {
         admin_purge_person: { reason },
       } = view as AdminPurgePersonView;
@@ -521,7 +513,7 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.AdminPurgeCommunity: {
+    case "AdminPurgeCommunity": {
       const {
         admin_purge_community: { reason },
       } = view as AdminPurgeCommunityView;
@@ -538,7 +530,7 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.AdminPurgePost: {
+    case "AdminPurgePost": {
       const {
         admin_purge_post: { reason },
         community,
@@ -546,7 +538,7 @@ function renderModlogType({ type_, view }: ModlogType) {
 
       return (
         <>
-          <span>Purged a Post from from </span>
+          <span>Purged a Post from </span>
           <CommunityLink community={community} />
           {reason && (
             <span>
@@ -557,7 +549,7 @@ function renderModlogType({ type_, view }: ModlogType) {
       );
     }
 
-    case ModlogActionType.AdminPurgeComment: {
+    case "AdminPurgeComment": {
       const {
         admin_purge_comment: { reason },
         post: { id, name },
@@ -597,16 +589,16 @@ const Filter = ({
   options: Choice[];
   loading: boolean;
 }) => (
-  <div className="col-sm-6 form-group">
-    <label className="col-form-label" htmlFor={`filter-${filterType}`}>
-      {i18n.t(`filter_by_${filterType}` as NoOptionI18nKeys)}
+  <div className="col-sm-6 mb-3">
+    <label className="mb-2" htmlFor={`filter-${filterType}`}>
+      {I18NextService.i18n.t(`filter_by_${filterType}` as NoOptionI18nKeys)}
     </label>
     <SearchableSelect
       id={`filter-${filterType}`}
       value={value ?? 0}
       options={[
         {
-          label: i18n.t("all"),
+          label: I18NextService.i18n.t("all"),
           value: "0",
         },
       ].concat(options)}
@@ -640,8 +632,8 @@ async function createNewOptions({
 
   if (text.length > 0) {
     newOptions.push(
-      ...(await fetchUsers(text)).users
-        .slice(0, fetchLimit)
+      ...(await fetchUsers(text))
+        .slice(0, Number(fetchLimit))
         .map<Choice>(personToChoice)
     );
   }
@@ -653,11 +645,11 @@ export class Modlog extends Component<
   RouteComponentProps<{ communityId?: string }>,
   ModlogState
 > {
-  private isoData = setIsoData(this.context);
-  private subscription?: Subscription;
+  private isoData = setIsoData<ModlogData>(this.context);
 
   state: ModlogState = {
-    loadingModlog: true,
+    res: { state: "empty" },
+    communityRes: { state: "empty" },
     loadingModSearch: false,
     loadingUserSearch: false,
     userSearchOptions: [],
@@ -673,58 +665,40 @@ export class Modlog extends Component<
     this.handleUserChange = this.handleUserChange.bind(this);
     this.handleModChange = this.handleModChange.bind(this);
 
-    this.parseMessage = this.parseMessage.bind(this);
-    this.subscription = wsSubscribe(this.parseMessage);
-
     // Only fetch the data if coming from another route
-    if (this.isoData.path === this.context.router.route.match.url) {
-      this.state = {
-        ...this.state,
-        res: this.isoData.routeData[0] as GetModlogResponse,
-      };
+    if (FirstLoadService.isFirstLoad) {
+      const { res, communityRes, modUserResponse, userResponse } =
+        this.isoData.routeData;
 
-      const communityRes: GetCommunityResponse | undefined =
-        this.isoData.routeData[1];
-
-      // Getting the moderators
       this.state = {
         ...this.state,
-        communityMods: communityRes?.moderators,
+        res,
+        communityRes,
       };
 
-      const filteredModRes: GetPersonDetailsResponse | undefined =
-        this.isoData.routeData[2];
-      if (filteredModRes) {
+      if (modUserResponse.state === "success") {
         this.state = {
           ...this.state,
-          modSearchOptions: [personToChoice(filteredModRes.person_view)],
+          modSearchOptions: [personToChoice(modUserResponse.data.person_view)],
         };
       }
 
-      const filteredUserRes: GetPersonDetailsResponse | undefined =
-        this.isoData.routeData[3];
-      if (filteredUserRes) {
+      if (userResponse.state === "success") {
         this.state = {
           ...this.state,
-          userSearchOptions: [personToChoice(filteredUserRes.person_view)],
+          userSearchOptions: [personToChoice(userResponse.data.person_view)],
         };
       }
-
-      this.state = { ...this.state, loadingModlog: false };
-    } else {
-      this.refetch();
     }
   }
 
-  componentWillUnmount() {
-    if (isBrowser()) {
-      this.subscription?.unsubscribe();
-    }
+  async componentDidMount() {
+    await this.refetch();
   }
 
   get combined() {
     const res = this.state.res;
-    const combined = res ? buildCombined(res) : [];
+    const combined = res.state == "success" ? buildCombined(res.data) : [];
 
     return (
       <tbody>
@@ -748,16 +722,19 @@ export class Modlog extends Component<
   }
 
   get amAdminOrMod(): boolean {
-    return amAdmin() || amMod(this.state.communityMods);
+    const amMod_ =
+      this.state.communityRes.state == "success" &&
+      amMod(this.state.communityRes.data.moderators);
+    return amAdmin() || amMod_;
   }
 
-  modOrAdminText(person?: PersonSafe): string {
+  modOrAdminText(person?: Person): string {
     return person &&
       this.isoData.site_res.admins.some(
         ({ person: { id } }) => id === person.id
       )
-      ? i18n.t("admin")
-      : i18n.t("mod");
+      ? I18NextService.i18n.t("admin")
+      : I18NextService.i18n.t("mod");
   }
 
   get documentTitle(): string {
@@ -766,133 +743,133 @@ export class Modlog extends Component<
 
   render() {
     const {
-      communityName,
-      loadingModlog,
       loadingModSearch,
       loadingUserSearch,
       userSearchOptions,
       modSearchOptions,
     } = this.state;
-    const { actionType, page, modId, userId } = getModlogQueryParams();
+    const { actionType, modId, userId } = getModlogQueryParams();
 
     return (
-      <div className="container-lg">
+      <div className="modlog container-lg">
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
         />
 
-        <div>
-          <div
-            className="alert alert-warning text-sm-start text-xs-center"
-            role="alert"
-          >
-            <Icon
-              icon="alert-triangle"
-              inline
-              classes="mr-sm-2 mx-auto d-sm-inline d-block"
-            />
-            <T i18nKey="modlog_content_warning" class="d-inline">
-              #<strong>#</strong>#
-            </T>
-          </div>
+        <h1 className="h4 mb-4">{I18NextService.i18n.t("modlog")}</h1>
+
+        <div
+          className="alert alert-warning text-sm-start text-xs-center"
+          role="alert"
+        >
+          <Icon
+            icon="alert-triangle"
+            inline
+            classes="me-sm-2 mx-auto d-sm-inline d-block"
+          />
+          <T i18nKey="modlog_content_warning" class="d-inline">
+            #<strong>#</strong>#
+          </T>
+        </div>
+        {this.state.communityRes.state === "success" && (
           <h5>
-            {communityName && (
-              <Link className="text-body" to={`/c/${communityName}`}>
-                /c/{communityName}{" "}
-              </Link>
-            )}
-            <span>{i18n.t("modlog")}</span>
+            <Link
+              className="text-body"
+              to={`/c/${this.state.communityRes.data.community_view.community.name}`}
+            >
+              /c/{this.state.communityRes.data.community_view.community.name}{" "}
+            </Link>
+            <span>{I18NextService.i18n.t("modlog")}</span>
           </h5>
-          <div className="form-row">
+        )}
+        <div className="row mb-2">
+          <div className="col-sm-6">
             <select
               value={actionType}
               onChange={linkEvent(this, this.handleFilterActionChange)}
-              className="custom-select col-sm-6"
+              className="form-select"
               aria-label="action"
             >
               <option disabled aria-hidden="true">
-                {i18n.t("filter_by_action")}
-              </option>
-              <option value={ModlogActionType.All}>{i18n.t("all")}</option>
-              <option value={ModlogActionType.ModRemovePost}>
-                Removing Posts
+                {I18NextService.i18n.t("filter_by_action")}
               </option>
-              <option value={ModlogActionType.ModLockPost}>
-                Locking Posts
-              </option>
-              <option value={ModlogActionType.ModFeaturePost}>
-                Featuring Posts
-              </option>
-              <option value={ModlogActionType.ModRemoveComment}>
-                Removing Comments
-              </option>
-              <option value={ModlogActionType.ModRemoveCommunity}>
-                Removing Communities
-              </option>
-              <option value={ModlogActionType.ModBanFromCommunity}>
+              <option value={"All"}>{I18NextService.i18n.t("all")}</option>
+              <option value={"ModRemovePost"}>Removing Posts</option>
+              <option value={"ModLockPost"}>Locking Posts</option>
+              <option value={"ModFeaturePost"}>Featuring Posts</option>
+              <option value={"ModRemoveComment"}>Removing Comments</option>
+              <option value={"ModRemoveCommunity"}>Removing Communities</option>
+              <option value={"ModBanFromCommunity"}>
                 Banning From Communities
               </option>
-              <option value={ModlogActionType.ModAddCommunity}>
-                Adding Mod to Community
-              </option>
-              <option value={ModlogActionType.ModTransferCommunity}>
+              <option value={"ModAddCommunity"}>Adding Mod to Community</option>
+              <option value={"ModTransferCommunity"}>
                 Transferring Communities
               </option>
-              <option value={ModlogActionType.ModAdd}>
-                Adding Mod to Site
-              </option>
-              <option value={ModlogActionType.ModBan}>Banning From Site</option>
+              <option value={"ModAdd"}>Adding Mod to Site</option>
+              <option value={"ModBan"}>Banning From Site</option>
             </select>
           </div>
-          <div className="form-row mb-2">
+        </div>
+        <div className="row mb-2">
+          <Filter
+            filterType="user"
+            onChange={this.handleUserChange}
+            onSearch={this.handleSearchUsers}
+            value={userId}
+            options={userSearchOptions}
+            loading={loadingUserSearch}
+          />
+          {!this.isoData.site_res.site_view.local_site
+            .hide_modlog_mod_names && (
             <Filter
-              filterType="user"
-              onChange={this.handleUserChange}
-              onSearch={this.handleSearchUsers}
-              value={userId}
-              options={userSearchOptions}
-              loading={loadingUserSearch}
+              filterType="mod"
+              onChange={this.handleModChange}
+              onSearch={this.handleSearchMods}
+              value={modId}
+              options={modSearchOptions}
+              loading={loadingModSearch}
             />
-            {!this.isoData.site_res.site_view.local_site
-              .hide_modlog_mod_names && (
-              <Filter
-                filterType="mod"
-                onChange={this.handleModChange}
-                onSearch={this.handleSearchMods}
-                value={modId}
-                options={modSearchOptions}
-                loading={loadingModSearch}
-              />
-            )}
-          </div>
-          <div className="table-responsive">
-            {loadingModlog ? (
-              <h5>
-                <Spinner large />
-              </h5>
-            ) : (
-              <table id="modlog_table" className="table table-sm table-hover">
-                <thead className="pointer">
-                  <tr>
-                    <th> {i18n.t("time")}</th>
-                    <th>{i18n.t("mod")}</th>
-                    <th>{i18n.t("action")}</th>
-                  </tr>
-                </thead>
-                {this.combined}
-              </table>
-            )}
-            <Paginator page={page} onChange={this.handlePageChange} />
-          </div>
+          )}
         </div>
+        {this.renderModlogTable()}
       </div>
     );
   }
 
+  renderModlogTable() {
+    switch (this.state.res.state) {
+      case "loading":
+        return (
+          <h5>
+            <Spinner large />
+          </h5>
+        );
+      case "success": {
+        const page = getModlogQueryParams().page;
+        return (
+          <div className="table-responsive">
+            <table id="modlog_table" className="table table-sm table-hover">
+              <thead className="pointer">
+                <tr>
+                  <th> {I18NextService.i18n.t("time")}</th>
+                  <th>{I18NextService.i18n.t("mod")}</th>
+                  <th>{I18NextService.i18n.t("action")}</th>
+                </tr>
+              </thead>
+              {this.combined}
+            </table>
+            <Paginator page={page} onChange={this.handlePageChange} />
+          </div>
+        );
+      }
+    }
+  }
+
   handleFilterActionChange(i: Modlog, event: any) {
     i.updateUrl({
-      actionType: ModlogActionType[event.target.value],
+      actionType: event.target.value as ModlogActionType,
       page: 1,
     });
   }
@@ -943,7 +920,7 @@ export class Modlog extends Component<
     });
   });
 
-  updateUrl({ actionType, modId, page, userId }: Partial<ModlogProps>) {
+  async updateUrl({ actionType, modId, page, userId }: Partial<ModlogProps>) {
     const {
       page: urlPage,
       actionType: urlActionType,
@@ -966,54 +943,50 @@ export class Modlog extends Component<
       )}`
     );
 
-    this.setState({
-      loadingModlog: true,
-      res: undefined,
-    });
-
-    this.refetch();
+    await this.refetch();
   }
 
-  refetch() {
-    const auth = myAuth(false);
+  async refetch() {
+    const auth = myAuth();
     const { actionType, page, modId, userId } = getModlogQueryParams();
     const { communityId: urlCommunityId } = this.props.match.params;
     const communityId = getIdFromString(urlCommunityId);
 
-    const modlogForm: GetModlog = {
-      community_id: communityId,
-      page,
-      limit: fetchLimit,
-      type_: actionType,
-      other_person_id: userId ?? undefined,
-      mod_person_id: !this.isoData.site_res.site_view.local_site
-        .hide_modlog_mod_names
-        ? modId ?? undefined
-        : undefined,
-      auth,
-    };
-
-    WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
-
-    if (communityId) {
-      const communityForm: GetCommunity = {
-        id: communityId,
+    this.setState({ res: { state: "loading" } });
+    this.setState({
+      res: await HttpService.client.getModlog({
+        community_id: communityId,
+        page,
+        limit: fetchLimit,
+        type_: actionType,
+        other_person_id: userId ?? undefined,
+        mod_person_id: !this.isoData.site_res.site_view.local_site
+          .hide_modlog_mod_names
+          ? modId ?? undefined
+          : undefined,
         auth,
-      };
+      }),
+    });
 
-      WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
+    if (communityId) {
+      this.setState({ communityRes: { state: "loading" } });
+      this.setState({
+        communityRes: await HttpService.client.getCommunity({
+          id: communityId,
+          auth,
+        }),
+      });
     }
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     path,
     query: { modId: urlModId, page, userId: urlUserId, actionType },
     auth,
     site,
-  }: InitialFetchRequest<QueryParams<ModlogProps>>): Promise<any>[] {
+  }: InitialFetchRequest<QueryParams<ModlogProps>>): Promise<ModlogData> {
     const pathSplit = path.split("/");
-    const promises: Promise<any>[] = [];
     const communityId = getIdFromString(pathSplit[2]);
     const modId = !site.site_view.local_site.hide_modlog_mod_names
       ? getIdFromString(urlModId)
@@ -1030,74 +1003,50 @@ export class Modlog extends Component<
       auth,
     };
 
-    promises.push(client.getModlog(modlogForm));
+    let communityResponse: RequestState<GetCommunityResponse> = {
+      state: "empty",
+    };
 
     if (communityId) {
       const communityForm: GetCommunity = {
         id: communityId,
         auth,
       };
-      promises.push(client.getCommunity(communityForm));
-    } else {
-      promises.push(Promise.resolve());
+
+      communityResponse = await client.getCommunity(communityForm);
     }
 
+    let modUserResponse: RequestState<GetPersonDetailsResponse> = {
+      state: "empty",
+    };
+
     if (modId) {
       const getPersonForm: GetPersonDetails = {
         person_id: modId,
         auth,
       };
 
-      promises.push(client.getPersonDetails(getPersonForm));
-    } else {
-      promises.push(Promise.resolve());
+      modUserResponse = await client.getPersonDetails(getPersonForm);
     }
 
+    let userResponse: RequestState<GetPersonDetailsResponse> = {
+      state: "empty",
+    };
+
     if (userId) {
       const getPersonForm: GetPersonDetails = {
         person_id: userId,
         auth,
       };
 
-      promises.push(client.getPersonDetails(getPersonForm));
-    } else {
-      promises.push(Promise.resolve());
+      userResponse = await client.getPersonDetails(getPersonForm);
     }
 
-    return promises;
-  }
-
-  parseMessage(msg: any) {
-    const op = wsUserOp(msg);
-    console.log(msg);
-
-    if (msg.error) {
-      toast(i18n.t(msg.error), "danger");
-    } else {
-      switch (op) {
-        case UserOperation.GetModlog: {
-          const res = wsJsonToRes<GetModlogResponse>(msg);
-          window.scrollTo(0, 0);
-          this.setState({ res, loadingModlog: false });
-
-          break;
-        }
-
-        case UserOperation.GetCommunity: {
-          const {
-            moderators,
-            community_view: {
-              community: { name },
-            },
-          } = wsJsonToRes<GetCommunityResponse>(msg);
-          this.setState({
-            communityMods: moderators,
-            communityName: name,
-          });
-
-          break;
-        }
-      }
-    }
+    return {
+      res: await client.getModlog(modlogForm),
+      communityRes: communityResponse,
+      modUserResponse,
+      userResponse,
+    };
   }
 }