]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/person/reports.tsx
Merge branch 'main' into route-data-refactor
[lemmy-ui.git] / src / shared / components / person / reports.tsx
index 51b41c92800e4ea78241bab4069e1b3a67d03b9f..fb8e8b831870bacc68daada998c165759753ed69 100644 (file)
@@ -13,28 +13,24 @@ import {
   PostReportView,
   PrivateMessageReportResponse,
   PrivateMessageReportView,
-  UserOperation,
-  wsJsonToRes,
-  wsUserOp,
+  ResolveCommentReport,
+  ResolvePostReport,
+  ResolvePrivateMessageReport,
 } from "lemmy-js-client";
-import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { InitialFetchRequest } from "../../interfaces";
-import { UserService, WebSocketService } from "../../services";
+import { HttpService, UserService } from "../../services";
+import { FirstLoadService } from "../../services/FirstLoadService";
+import { RequestState } from "../../services/HttpService";
 import {
-  WithPromiseKeys,
+  RouteDataResponse,
   amAdmin,
+  editCommentReport,
+  editPostReport,
+  editPrivateMessageReport,
   fetchLimit,
-  isBrowser,
-  myAuth,
+  myAuthRequired,
   setIsoData,
-  setupTippy,
-  toast,
-  updateCommentReportRes,
-  updatePostReportRes,
-  updatePrivateMessageReportRes,
-  wsClient,
-  wsSubscribe,
 } from "../../utils";
 import { CommentReport } from "../comment/comment-report";
 import { HtmlTags } from "../common/html-tags";
@@ -61,11 +57,11 @@ enum MessageEnum {
   PrivateMessageReport,
 }
 
-interface ReportsData {
+type ReportsData = RouteDataResponse<{
   commentReportsResponse: ListCommentReportsResponse;
   postReportsResponse: ListPostReportsResponse;
   privateMessageReportsResponse?: ListPrivateMessageReportsResponse;
-}
+}>;
 
 type ItemType = {
   id: number;
@@ -75,70 +71,71 @@ type ItemType = {
 };
 
 interface ReportsState {
-  listCommentReportsResponse?: ListCommentReportsResponse;
-  listPostReportsResponse?: ListPostReportsResponse;
-  listPrivateMessageReportsResponse?: ListPrivateMessageReportsResponse;
+  commentReportsRes: RequestState<ListCommentReportsResponse>;
+  postReportsRes: RequestState<ListPostReportsResponse>;
+  messageReportsRes: RequestState<ListPrivateMessageReportsResponse>;
   unreadOrAll: UnreadOrAll;
   messageType: MessageType;
-  combined: ItemType[];
   siteRes: GetSiteResponse;
   page: number;
-  loading: boolean;
+  isIsomorphic: boolean;
 }
 
 export class Reports extends Component<any, ReportsState> {
   private isoData = setIsoData<ReportsData>(this.context);
-  private subscription?: Subscription;
   state: ReportsState = {
+    commentReportsRes: { state: "empty" },
+    postReportsRes: { state: "empty" },
+    messageReportsRes: { state: "empty" },
     unreadOrAll: UnreadOrAll.Unread,
     messageType: MessageType.All,
-    combined: [],
     page: 1,
     siteRes: this.isoData.site_res,
-    loading: true,
+    isIsomorphic: false,
   };
 
   constructor(props: any, context: any) {
     super(props, context);
 
     this.handlePageChange = this.handlePageChange.bind(this);
-
-    this.parseMessage = this.parseMessage.bind(this);
-    this.subscription = wsSubscribe(this.parseMessage);
+    this.handleResolveCommentReport =
+      this.handleResolveCommentReport.bind(this);
+    this.handleResolvePostReport = this.handleResolvePostReport.bind(this);
+    this.handleResolvePrivateMessageReport =
+      this.handleResolvePrivateMessageReport.bind(this);
 
     // Only fetch the data if coming from another route
-    if (this.isoData.path === this.context.router.route.match.url) {
+    if (FirstLoadService.isFirstLoad) {
       const {
-        commentReportsResponse,
-        postReportsResponse,
-        privateMessageReportsResponse,
+        commentReportsResponse: commentReportsRes,
+        postReportsResponse: postReportsRes,
+        privateMessageReportsResponse: messageReportsRes,
       } = this.isoData.routeData;
 
       this.state = {
         ...this.state,
-        listCommentReportsResponse: commentReportsResponse,
-        listPostReportsResponse: postReportsResponse,
-        listPrivateMessageReportsResponse: privateMessageReportsResponse,
+        commentReportsRes,
+        postReportsRes,
+        isIsomorphic: true,
       };
 
-      this.state = {
-        ...this.state,
-        combined: this.buildCombined(),
-        loading: false,
-      };
-    } else {
-      this.refetch();
+      if (amAdmin()) {
+        this.state = {
+          ...this.state,
+          messageReportsRes: messageReportsRes ?? { state: "empty" },
+        };
+      }
     }
   }
 
-  componentWillUnmount() {
-    if (isBrowser()) {
-      this.subscription?.unsubscribe();
+  async componentDidMount() {
+    if (!this.state.isIsomorphic) {
+      await this.refetch();
     }
   }
 
   get documentTitle(): string {
-    let mui = UserService.Instance.myUserInfo;
+    const mui = UserService.Instance.myUserInfo;
     return mui
       ? `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
           this.state.siteRes.site_view.site.name
@@ -149,37 +146,46 @@ export class Reports extends Component<any, ReportsState> {
   render() {
     return (
       <div className="container-lg">
-        {this.state.loading ? (
-          <h5>
-            <Spinner large />
-          </h5>
-        ) : (
-          <div className="row">
-            <div className="col-12">
-              <HtmlTags
-                title={this.documentTitle}
-                path={this.context.router.route.match.url}
-              />
-              <h5 className="mb-2">{i18n.t("reports")}</h5>
-              {this.selects()}
-              {this.state.messageType == MessageType.All && this.all()}
-              {this.state.messageType == MessageType.CommentReport &&
-                this.commentReports()}
-              {this.state.messageType == MessageType.PostReport &&
-                this.postReports()}
-              {this.state.messageType == MessageType.PrivateMessageReport &&
-                this.privateMessageReports()}
-              <Paginator
-                page={this.state.page}
-                onChange={this.handlePageChange}
-              />
-            </div>
+        <div className="row">
+          <div className="col-12">
+            <HtmlTags
+              title={this.documentTitle}
+              path={this.context.router.route.match.url}
+            />
+            <h5 className="mb-2">{i18n.t("reports")}</h5>
+            {this.selects()}
+            {this.section}
+            <Paginator
+              page={this.state.page}
+              onChange={this.handlePageChange}
+            />
           </div>
-        )}
+        </div>
       </div>
     );
   }
 
+  get section() {
+    switch (this.state.messageType) {
+      case MessageType.All: {
+        return this.all();
+      }
+      case MessageType.CommentReport: {
+        return this.commentReports();
+      }
+      case MessageType.PostReport: {
+        return this.postReports();
+      }
+      case MessageType.PrivateMessageReport: {
+        return this.privateMessageReports();
+      }
+
+      default: {
+        return null;
+      }
+    }
+  }
+
   unreadOrAllRadios() {
     return (
       <div className="btn-group btn-group-toggle flex-wrap mb-2">
@@ -315,23 +321,25 @@ export class Reports extends Component<any, ReportsState> {
     };
   }
 
-  buildCombined(): ItemType[] {
-    // let comments: ItemType[] = this.state.listCommentReportsResponse
-    //   .map(r => r.comment_reports)
-    //   .unwrapOr([])
-    //   .map(r => this.commentReportToItemType(r));
-    let comments =
-      this.state.listCommentReportsResponse?.comment_reports.map(
-        this.commentReportToItemType
-      ) ?? [];
-    let posts =
-      this.state.listPostReportsResponse?.post_reports.map(
-        this.postReportToItemType
-      ) ?? [];
-    let privateMessages =
-      this.state.listPrivateMessageReportsResponse?.private_message_reports.map(
-        this.privateMessageReportToItemType
-      ) ?? [];
+  get buildCombined(): ItemType[] {
+    const commentRes = this.state.commentReportsRes;
+    const comments =
+      commentRes.state == "success"
+        ? commentRes.data.comment_reports.map(this.commentReportToItemType)
+        : [];
+
+    const postRes = this.state.postReportsRes;
+    const posts =
+      postRes.state == "success"
+        ? postRes.data.post_reports.map(this.postReportToItemType)
+        : [];
+    const pmRes = this.state.messageReportsRes;
+    const privateMessages =
+      pmRes.state == "success"
+        ? pmRes.data.private_message_reports.map(
+            this.privateMessageReportToItemType
+          )
+        : [];
 
     return [...comments, ...posts, ...privateMessages].sort((a, b) =>
       b.published.localeCompare(a.published)
@@ -342,15 +350,26 @@ export class Reports extends Component<any, ReportsState> {
     switch (i.type_) {
       case MessageEnum.CommentReport:
         return (
-          <CommentReport key={i.id} report={i.view as CommentReportView} />
+          <CommentReport
+            key={i.id}
+            report={i.view as CommentReportView}
+            onResolveReport={this.handleResolveCommentReport}
+          />
         );
       case MessageEnum.PostReport:
-        return <PostReport key={i.id} report={i.view as PostReportView} />;
+        return (
+          <PostReport
+            key={i.id}
+            report={i.view as PostReportView}
+            onResolveReport={this.handleResolvePostReport}
+          />
+        );
       case MessageEnum.PrivateMessageReport:
         return (
           <PrivateMessageReport
             key={i.id}
             report={i.view as PrivateMessageReportView}
+            onResolveReport={this.handleResolvePrivateMessageReport}
           />
         );
       default:
@@ -361,7 +380,7 @@ export class Reports extends Component<any, ReportsState> {
   all() {
     return (
       <div>
-        {this.state.combined.map(i => (
+        {this.buildCombined.map(i => (
           <>
             <hr />
             {this.renderItemType(i)}
@@ -372,76 +391,111 @@ export class Reports extends Component<any, ReportsState> {
   }
 
   commentReports() {
-    let reports = this.state.listCommentReportsResponse?.comment_reports;
-    return (
-      reports && (
-        <div>
-          {reports.map(cr => (
-            <>
-              <hr />
-              <CommentReport key={cr.comment_report.id} report={cr} />
-            </>
-          ))}
-        </div>
-      )
-    );
+    const res = this.state.commentReportsRes;
+    switch (res.state) {
+      case "loading":
+        return (
+          <h5>
+            <Spinner large />
+          </h5>
+        );
+      case "success": {
+        const reports = res.data.comment_reports;
+        return (
+          <div>
+            {reports.map(cr => (
+              <>
+                <hr />
+                <CommentReport
+                  key={cr.comment_report.id}
+                  report={cr}
+                  onResolveReport={this.handleResolveCommentReport}
+                />
+              </>
+            ))}
+          </div>
+        );
+      }
+    }
   }
 
   postReports() {
-    let reports = this.state.listPostReportsResponse?.post_reports;
-    return (
-      reports && (
-        <div>
-          {reports.map(pr => (
-            <>
-              <hr />
-              <PostReport key={pr.post_report.id} report={pr} />
-            </>
-          ))}
-        </div>
-      )
-    );
+    const res = this.state.postReportsRes;
+    switch (res.state) {
+      case "loading":
+        return (
+          <h5>
+            <Spinner large />
+          </h5>
+        );
+      case "success": {
+        const reports = res.data.post_reports;
+        return (
+          <div>
+            {reports.map(pr => (
+              <>
+                <hr />
+                <PostReport
+                  key={pr.post_report.id}
+                  report={pr}
+                  onResolveReport={this.handleResolvePostReport}
+                />
+              </>
+            ))}
+          </div>
+        );
+      }
+    }
   }
 
   privateMessageReports() {
-    let reports =
-      this.state.listPrivateMessageReportsResponse?.private_message_reports;
-    return (
-      reports && (
-        <div>
-          {reports.map(pmr => (
-            <>
-              <hr />
-              <PrivateMessageReport
-                key={pmr.private_message_report.id}
-                report={pmr}
-              />
-            </>
-          ))}
-        </div>
-      )
-    );
+    const res = this.state.messageReportsRes;
+    switch (res.state) {
+      case "loading":
+        return (
+          <h5>
+            <Spinner large />
+          </h5>
+        );
+      case "success": {
+        const reports = res.data.private_message_reports;
+        return (
+          <div>
+            {reports.map(pmr => (
+              <>
+                <hr />
+                <PrivateMessageReport
+                  key={pmr.private_message_report.id}
+                  report={pmr}
+                  onResolveReport={this.handleResolvePrivateMessageReport}
+                />
+              </>
+            ))}
+          </div>
+        );
+      }
+    }
   }
 
-  handlePageChange(page: number) {
+  async handlePageChange(page: number) {
     this.setState({ page });
-    this.refetch();
+    await this.refetch();
   }
 
-  handleUnreadOrAllChange(i: Reports, event: any) {
+  async handleUnreadOrAllChange(i: Reports, event: any) {
     i.setState({ unreadOrAll: Number(event.target.value), page: 1 });
-    i.refetch();
+    await i.refetch();
   }
 
-  handleMessageTypeChange(i: Reports, event: any) {
+  async handleMessageTypeChange(i: Reports, event: any) {
     i.setState({ messageType: Number(event.target.value), page: 1 });
-    i.refetch();
+    await i.refetch();
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     auth,
     client,
-  }: InitialFetchRequest): WithPromiseKeys<ReportsData> {
+  }: InitialFetchRequest): Promise<ReportsData> {
     const unresolved_only = true;
     const page = 1;
     const limit = fetchLimit;
@@ -460,9 +514,11 @@ export class Reports extends Component<any, ReportsState> {
       auth: auth as string,
     };
 
-    const data: WithPromiseKeys<ReportsData> = {
-      commentReportsResponse: client.listCommentReports(commentReportsForm),
-      postReportsResponse: client.listPostReports(postReportsForm),
+    const data: ReportsData = {
+      commentReportsResponse: await client.listCommentReports(
+        commentReportsForm
+      ),
+      postReportsResponse: await client.listPostReports(postReportsForm),
     };
 
     if (amAdmin()) {
@@ -473,123 +529,100 @@ export class Reports extends Component<any, ReportsState> {
         auth: auth as string,
       };
 
-      data.privateMessageReportsResponse = client.listPrivateMessageReports(
-        privateMessageReportsForm
-      );
+      data.privateMessageReportsResponse =
+        await client.listPrivateMessageReports(privateMessageReportsForm);
     }
 
     return data;
   }
 
-  refetch() {
-    const unresolved_only = this.state.unreadOrAll === UnreadOrAll.Unread;
+  async refetch() {
+    const unresolved_only = this.state.unreadOrAll == UnreadOrAll.Unread;
     const page = this.state.page;
     const limit = fetchLimit;
-    const auth = myAuth();
+    const auth = myAuthRequired();
+
+    this.setState({
+      commentReportsRes: { state: "loading" },
+      postReportsRes: { state: "loading" },
+      messageReportsRes: { state: "loading" },
+    });
+
+    const form:
+      | ListCommentReports
+      | ListPostReports
+      | ListPrivateMessageReports = {
+      unresolved_only,
+      page,
+      limit,
+      auth,
+    };
 
-    if (auth) {
-      const commentReportsForm: ListCommentReports = {
-        unresolved_only,
-        page,
-        limit,
-        auth,
-      };
+    this.setState({
+      commentReportsRes: await HttpService.client.listCommentReports(form),
+      postReportsRes: await HttpService.client.listPostReports(form),
+    });
 
-      WebSocketService.Instance.send(
-        wsClient.listCommentReports(commentReportsForm)
-      );
+    if (amAdmin()) {
+      this.setState({
+        messageReportsRes: await HttpService.client.listPrivateMessageReports(
+          form
+        ),
+      });
+    }
+  }
 
-      const postReportsForm: ListPostReports = {
-        unresolved_only,
-        page,
-        limit,
-        auth,
-      };
+  async handleResolveCommentReport(form: ResolveCommentReport) {
+    const res = await HttpService.client.resolveCommentReport(form);
+    this.findAndUpdateCommentReport(res);
+  }
 
-      WebSocketService.Instance.send(wsClient.listPostReports(postReportsForm));
+  async handleResolvePostReport(form: ResolvePostReport) {
+    const res = await HttpService.client.resolvePostReport(form);
+    this.findAndUpdatePostReport(res);
+  }
 
-      if (amAdmin()) {
-        const privateMessageReportsForm: ListPrivateMessageReports = {
-          unresolved_only,
-          page,
-          limit,
-          auth,
-        };
-        WebSocketService.Instance.send(
-          wsClient.listPrivateMessageReports(privateMessageReportsForm)
+  async handleResolvePrivateMessageReport(form: ResolvePrivateMessageReport) {
+    const res = await HttpService.client.resolvePrivateMessageReport(form);
+    this.findAndUpdatePrivateMessageReport(res);
+  }
+
+  findAndUpdateCommentReport(res: RequestState<CommentReportResponse>) {
+    this.setState(s => {
+      if (s.commentReportsRes.state == "success" && res.state == "success") {
+        s.commentReportsRes.data.comment_reports = editCommentReport(
+          res.data.comment_report_view,
+          s.commentReportsRes.data.comment_reports
         );
       }
-    }
+      return s;
+    });
   }
 
-  parseMessage(msg: any) {
-    let op = wsUserOp(msg);
-    console.log(msg);
-    if (msg.error) {
-      toast(i18n.t(msg.error), "danger");
-      return;
-    } else if (msg.reconnect) {
-      this.refetch();
-    } else if (op == UserOperation.ListCommentReports) {
-      let data = wsJsonToRes<ListCommentReportsResponse>(msg);
-      this.setState({ listCommentReportsResponse: data });
-      this.setState({ combined: this.buildCombined(), loading: false });
-      // this.sendUnreadCount();
-      window.scrollTo(0, 0);
-      setupTippy();
-    } else if (op == UserOperation.ListPostReports) {
-      let data = wsJsonToRes<ListPostReportsResponse>(msg);
-      this.setState({ listPostReportsResponse: data });
-      this.setState({ combined: this.buildCombined(), loading: false });
-      // this.sendUnreadCount();
-      window.scrollTo(0, 0);
-      setupTippy();
-    } else if (op == UserOperation.ListPrivateMessageReports) {
-      let data = wsJsonToRes<ListPrivateMessageReportsResponse>(msg);
-      this.setState({ listPrivateMessageReportsResponse: data });
-      this.setState({ combined: this.buildCombined(), loading: false });
-      // this.sendUnreadCount();
-      window.scrollTo(0, 0);
-      setupTippy();
-    } else if (op == UserOperation.ResolvePostReport) {
-      let data = wsJsonToRes<PostReportResponse>(msg);
-      updatePostReportRes(
-        data.post_report_view,
-        this.state.listPostReportsResponse?.post_reports
-      );
-      let urcs = UserService.Instance.unreadReportCountSub;
-      if (data.post_report_view.post_report.resolved) {
-        urcs.next(urcs.getValue() - 1);
-      } else {
-        urcs.next(urcs.getValue() + 1);
-      }
-      this.setState(this.state);
-    } else if (op == UserOperation.ResolveCommentReport) {
-      let data = wsJsonToRes<CommentReportResponse>(msg);
-      updateCommentReportRes(
-        data.comment_report_view,
-        this.state.listCommentReportsResponse?.comment_reports
-      );
-      let urcs = UserService.Instance.unreadReportCountSub;
-      if (data.comment_report_view.comment_report.resolved) {
-        urcs.next(urcs.getValue() - 1);
-      } else {
-        urcs.next(urcs.getValue() + 1);
+  findAndUpdatePostReport(res: RequestState<PostReportResponse>) {
+    this.setState(s => {
+      if (s.postReportsRes.state == "success" && res.state == "success") {
+        s.postReportsRes.data.post_reports = editPostReport(
+          res.data.post_report_view,
+          s.postReportsRes.data.post_reports
+        );
       }
-      this.setState(this.state);
-    } else if (op == UserOperation.ResolvePrivateMessageReport) {
-      let data = wsJsonToRes<PrivateMessageReportResponse>(msg);
-      updatePrivateMessageReportRes(
-        data.private_message_report_view,
-        this.state.listPrivateMessageReportsResponse?.private_message_reports
-      );
-      let urcs = UserService.Instance.unreadReportCountSub;
-      if (data.private_message_report_view.private_message_report.resolved) {
-        urcs.next(urcs.getValue() - 1);
-      } else {
-        urcs.next(urcs.getValue() + 1);
+      return s;
+    });
+  }
+
+  findAndUpdatePrivateMessageReport(
+    res: RequestState<PrivateMessageReportResponse>
+  ) {
+    this.setState(s => {
+      if (s.messageReportsRes.state == "success" && res.state == "success") {
+        s.messageReportsRes.data.private_message_reports =
+          editPrivateMessageReport(
+            res.data.private_message_report_view,
+            s.messageReportsRes.data.private_message_reports
+          );
       }
-      this.setState(this.state);
-    }
+      return s;
+    });
   }
 }