4 editPrivateMessageReport,
8 import { randomStr } from "@utils/helpers";
9 import { amAdmin } from "@utils/roles";
10 import { RouteDataResponse } from "@utils/types";
11 import classNames from "classnames";
12 import { Component, linkEvent } from "inferno";
14 CommentReportResponse,
18 ListCommentReportsResponse,
20 ListPostReportsResponse,
21 ListPrivateMessageReports,
22 ListPrivateMessageReportsResponse,
25 PrivateMessageReportResponse,
26 PrivateMessageReportView,
29 ResolvePrivateMessageReport,
30 } from "lemmy-js-client";
31 import { fetchLimit } from "../../config";
32 import { InitialFetchRequest } from "../../interfaces";
38 } from "../../services";
39 import { RequestState } from "../../services/HttpService";
40 import { CommentReport } from "../comment/comment-report";
41 import { HtmlTags } from "../common/html-tags";
42 import { Spinner } from "../common/icon";
43 import { Paginator } from "../common/paginator";
44 import { PostReport } from "../post/post-report";
45 import { PrivateMessageReport } from "../private_message/private-message-report";
65 type ReportsData = RouteDataResponse<{
66 commentReportsRes: ListCommentReportsResponse;
67 postReportsRes: ListPostReportsResponse;
68 messageReportsRes: ListPrivateMessageReportsResponse;
74 view: CommentReportView | PostReportView | PrivateMessageReportView;
78 interface ReportsState {
79 commentReportsRes: RequestState<ListCommentReportsResponse>;
80 postReportsRes: RequestState<ListPostReportsResponse>;
81 messageReportsRes: RequestState<ListPrivateMessageReportsResponse>;
82 unreadOrAll: UnreadOrAll;
83 messageType: MessageType;
84 siteRes: GetSiteResponse;
86 isIsomorphic: boolean;
89 export class Reports extends Component<any, ReportsState> {
90 private isoData = setIsoData<ReportsData>(this.context);
91 state: ReportsState = {
92 commentReportsRes: { state: "empty" },
93 postReportsRes: { state: "empty" },
94 messageReportsRes: { state: "empty" },
95 unreadOrAll: UnreadOrAll.Unread,
96 messageType: MessageType.All,
98 siteRes: this.isoData.site_res,
102 constructor(props: any, context: any) {
103 super(props, context);
105 this.handlePageChange = this.handlePageChange.bind(this);
106 this.handleResolveCommentReport =
107 this.handleResolveCommentReport.bind(this);
108 this.handleResolvePostReport = this.handleResolvePostReport.bind(this);
109 this.handleResolvePrivateMessageReport =
110 this.handleResolvePrivateMessageReport.bind(this);
112 // Only fetch the data if coming from another route
113 if (FirstLoadService.isFirstLoad) {
114 const { commentReportsRes, postReportsRes, messageReportsRes } =
115 this.isoData.routeData;
127 messageReportsRes: messageReportsRes,
133 async componentDidMount() {
134 if (!this.state.isIsomorphic) {
135 await this.refetch();
139 get documentTitle(): string {
140 const mui = UserService.Instance.myUserInfo;
142 ? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
144 )} - ${this.state.siteRes.site_view.site.name}`
150 <div className="person-reports container-lg">
151 <div className="row">
152 <div className="col-12">
154 title={this.documentTitle}
155 path={this.context.router.route.match.url}
157 <h1 className="h4 mb-4">{I18NextService.i18n.t("reports")}</h1>
161 page={this.state.page}
162 onChange={this.handlePageChange}
171 switch (this.state.messageType) {
172 case MessageType.All: {
175 case MessageType.CommentReport: {
176 return this.commentReports();
178 case MessageType.PostReport: {
179 return this.postReports();
181 case MessageType.PrivateMessageReport: {
182 return this.privateMessageReports();
191 unreadOrAllRadios() {
192 const radioId = randomStr();
195 <div className="btn-group btn-group-toggle flex-wrap mb-2" role="group">
197 id={`${radioId}-unread`}
199 className="btn-check"
200 value={UnreadOrAll.Unread}
201 checked={this.state.unreadOrAll === UnreadOrAll.Unread}
202 onChange={linkEvent(this, this.handleUnreadOrAllChange)}
205 htmlFor={`${radioId}-unread`}
206 className={classNames("btn btn-outline-secondary pointer", {
207 active: this.state.unreadOrAll === UnreadOrAll.Unread,
210 {I18NextService.i18n.t("unread")}
214 id={`${radioId}-all`}
216 className="btn-check"
217 value={UnreadOrAll.All}
218 checked={this.state.unreadOrAll === UnreadOrAll.All}
219 onChange={linkEvent(this, this.handleUnreadOrAllChange)}
222 htmlFor={`${radioId}-all`}
223 className={classNames("btn btn-outline-secondary pointer", {
224 active: this.state.unreadOrAll === UnreadOrAll.All,
227 {I18NextService.i18n.t("all")}
233 messageTypeRadios() {
234 const radioId = randomStr();
237 <div className="btn-group btn-group-toggle flex-wrap mb-2" role="group">
239 id={`${radioId}-all`}
241 className="btn-check"
242 value={MessageType.All}
243 checked={this.state.messageType === MessageType.All}
244 onChange={linkEvent(this, this.handleMessageTypeChange)}
247 htmlFor={`${radioId}-all`}
248 className={classNames("btn btn-outline-secondary pointer", {
249 active: this.state.messageType === MessageType.All,
252 {I18NextService.i18n.t("all")}
256 id={`${radioId}-comments`}
258 className="btn-check"
259 value={MessageType.CommentReport}
260 checked={this.state.messageType === MessageType.CommentReport}
261 onChange={linkEvent(this, this.handleMessageTypeChange)}
264 htmlFor={`${radioId}-comments`}
265 className={classNames("btn btn-outline-secondary pointer", {
266 active: this.state.messageType === MessageType.CommentReport,
269 {I18NextService.i18n.t("comments")}
273 id={`${radioId}-posts`}
275 className="btn-check"
276 value={MessageType.PostReport}
277 checked={this.state.messageType === MessageType.PostReport}
278 onChange={linkEvent(this, this.handleMessageTypeChange)}
281 htmlFor={`${radioId}-posts`}
282 className={classNames("btn btn-outline-secondary pointer", {
283 active: this.state.messageType === MessageType.PostReport,
286 {I18NextService.i18n.t("posts")}
292 id={`${radioId}-messages`}
294 className="btn-check"
295 value={MessageType.PrivateMessageReport}
297 this.state.messageType === MessageType.PrivateMessageReport
299 onChange={linkEvent(this, this.handleMessageTypeChange)}
302 htmlFor={`${radioId}-messages`}
303 className={classNames("btn btn-outline-secondary pointer", {
305 this.state.messageType === MessageType.PrivateMessageReport,
308 {I18NextService.i18n.t("messages")}
318 <div className="mb-2">
319 <span className="me-3">{this.unreadOrAllRadios()}</span>
320 <span className="me-3">{this.messageTypeRadios()}</span>
325 commentReportToItemType(r: CommentReportView): ItemType {
327 id: r.comment_report.id,
328 type_: MessageEnum.CommentReport,
330 published: r.comment_report.published,
334 postReportToItemType(r: PostReportView): ItemType {
336 id: r.post_report.id,
337 type_: MessageEnum.PostReport,
339 published: r.post_report.published,
343 privateMessageReportToItemType(r: PrivateMessageReportView): ItemType {
345 id: r.private_message_report.id,
346 type_: MessageEnum.PrivateMessageReport,
348 published: r.private_message_report.published,
352 get buildCombined(): ItemType[] {
353 const commentRes = this.state.commentReportsRes;
355 commentRes.state === "success"
356 ? commentRes.data.comment_reports.map(this.commentReportToItemType)
359 const postRes = this.state.postReportsRes;
361 postRes.state === "success"
362 ? postRes.data.post_reports.map(this.postReportToItemType)
364 const pmRes = this.state.messageReportsRes;
365 const privateMessages =
366 pmRes.state === "success"
367 ? pmRes.data.private_message_reports.map(
368 this.privateMessageReportToItemType,
372 return [...comments, ...posts, ...privateMessages].sort((a, b) =>
373 b.published.localeCompare(a.published),
377 renderItemType(i: ItemType) {
379 case MessageEnum.CommentReport:
383 report={i.view as CommentReportView}
384 onResolveReport={this.handleResolveCommentReport}
387 case MessageEnum.PostReport:
391 report={i.view as PostReportView}
392 onResolveReport={this.handleResolvePostReport}
395 case MessageEnum.PrivateMessageReport:
397 <PrivateMessageReport
399 report={i.view as PrivateMessageReportView}
400 onResolveReport={this.handleResolvePrivateMessageReport}
411 {this.buildCombined.map(i => (
414 {this.renderItemType(i)}
422 const res = this.state.commentReportsRes;
431 const reports = res.data.comment_reports;
438 key={cr.comment_report.id}
440 onResolveReport={this.handleResolveCommentReport}
451 const res = this.state.postReportsRes;
460 const reports = res.data.post_reports;
467 key={pr.post_report.id}
469 onResolveReport={this.handleResolvePostReport}
479 privateMessageReports() {
480 const res = this.state.messageReportsRes;
489 const reports = res.data.private_message_reports;
492 {reports.map(pmr => (
495 <PrivateMessageReport
496 key={pmr.private_message_report.id}
498 onResolveReport={this.handleResolvePrivateMessageReport}
508 async handlePageChange(page: number) {
509 this.setState({ page });
510 await this.refetch();
513 async handleUnreadOrAllChange(i: Reports, event: any) {
514 i.setState({ unreadOrAll: Number(event.target.value), page: 1 });
518 async handleMessageTypeChange(i: Reports, event: any) {
519 i.setState({ messageType: Number(event.target.value), page: 1 });
523 static async fetchInitialData({
526 }: InitialFetchRequest): Promise<ReportsData> {
527 const unresolved_only = true;
529 const limit = fetchLimit;
531 const commentReportsForm: ListCommentReports = {
535 auth: auth as string,
538 const postReportsForm: ListPostReports = {
542 auth: auth as string,
545 const data: ReportsData = {
546 commentReportsRes: await client.listCommentReports(commentReportsForm),
547 postReportsRes: await client.listPostReports(postReportsForm),
548 messageReportsRes: { state: "empty" },
552 const privateMessageReportsForm: ListPrivateMessageReports = {
556 auth: auth as string,
559 data.messageReportsRes = await client.listPrivateMessageReports(
560 privateMessageReportsForm,
568 const unresolved_only = this.state.unreadOrAll === UnreadOrAll.Unread;
569 const page = this.state.page;
570 const limit = fetchLimit;
571 const auth = myAuthRequired();
574 commentReportsRes: { state: "loading" },
575 postReportsRes: { state: "loading" },
576 messageReportsRes: { state: "loading" },
582 | ListPrivateMessageReports = {
590 commentReportsRes: await HttpService.client.listCommentReports(form),
591 postReportsRes: await HttpService.client.listPostReports(form),
596 messageReportsRes: await HttpService.client.listPrivateMessageReports(
603 async handleResolveCommentReport(form: ResolveCommentReport) {
604 const res = await HttpService.client.resolveCommentReport(form);
605 this.findAndUpdateCommentReport(res);
608 async handleResolvePostReport(form: ResolvePostReport) {
609 const res = await HttpService.client.resolvePostReport(form);
610 this.findAndUpdatePostReport(res);
613 async handleResolvePrivateMessageReport(form: ResolvePrivateMessageReport) {
614 const res = await HttpService.client.resolvePrivateMessageReport(form);
615 this.findAndUpdatePrivateMessageReport(res);
618 findAndUpdateCommentReport(res: RequestState<CommentReportResponse>) {
620 if (s.commentReportsRes.state === "success" && res.state === "success") {
621 s.commentReportsRes.data.comment_reports = editCommentReport(
622 res.data.comment_report_view,
623 s.commentReportsRes.data.comment_reports,
630 findAndUpdatePostReport(res: RequestState<PostReportResponse>) {
632 if (s.postReportsRes.state === "success" && res.state === "success") {
633 s.postReportsRes.data.post_reports = editPostReport(
634 res.data.post_report_view,
635 s.postReportsRes.data.post_reports,
642 findAndUpdatePrivateMessageReport(
643 res: RequestState<PrivateMessageReportResponse>,
646 if (s.messageReportsRes.state === "success" && res.state === "success") {
647 s.messageReportsRes.data.private_message_reports =
648 editPrivateMessageReport(
649 res.data.private_message_report_view,
650 s.messageReportsRes.data.private_message_reports,