From 1830c3c1ef4b1da3758e301858bfca35c3962375 Mon Sep 17 00:00:00 2001 From: Alec Armbruster <35377827+alectrocute@users.noreply.github.com> Date: Mon, 26 Jun 2023 13:44:22 -0400 Subject: [PATCH] add inbox service --- src/shared/components/app/navbar.tsx | 95 ++++---------------- src/shared/components/person/inbox.tsx | 9 +- src/shared/services/InboxService.ts | 116 +++++++++++++++++++++++++ src/shared/services/index.ts | 1 + 4 files changed, 140 insertions(+), 81 deletions(-) create mode 100644 src/shared/services/InboxService.ts diff --git a/src/shared/components/app/navbar.tsx b/src/shared/components/app/navbar.tsx index 11cfb6c6..292f52a6 100644 --- a/src/shared/components/app/navbar.tsx +++ b/src/shared/components/app/navbar.tsx @@ -1,18 +1,12 @@ -import { myAuth, showAvatars } from "@utils/app"; +import { showAvatars } from "@utils/app"; import { isBrowser } from "@utils/browser"; -import { numToSI, poll } from "@utils/helpers"; +import { numToSI } from "@utils/helpers"; import { amAdmin, canCreateCommunity } from "@utils/roles"; import { Component, createRef, linkEvent } from "inferno"; import { NavLink } from "inferno-router"; -import { - GetReportCountResponse, - GetSiteResponse, - GetUnreadCountResponse, - GetUnreadRegistrationApplicationCountResponse, -} from "lemmy-js-client"; -import { donateLemmyUrl, updateUnreadCountsInterval } from "../../config"; -import { I18NextService, UserService } from "../../services"; -import { HttpService, RequestState } from "../../services/HttpService"; +import { GetSiteResponse } from "lemmy-js-client"; +import { donateLemmyUrl } from "../../config"; +import { I18NextService, InboxService, UserService } from "../../services"; import { toast } from "../../toast"; import { Icon } from "../common/icon"; import { PictrsImage } from "../common/pictrs-image"; @@ -22,9 +16,6 @@ interface NavbarProps { } interface NavbarState { - unreadInboxCountRes: RequestState; - unreadReportCountRes: RequestState; - unreadApplicationCountRes: RequestState; onSiteBanner?(url: string): any; } @@ -44,11 +35,6 @@ function handleLogOut(i: Navbar) { } export class Navbar extends Component { - state: NavbarState = { - unreadInboxCountRes: { state: "empty" }, - unreadReportCountRes: { state: "empty" }, - unreadApplicationCountRes: { state: "empty" }, - }; collapseButtonRef = createRef(); mobileMenuRef = createRef(); @@ -58,13 +44,13 @@ export class Navbar extends Component { this.handleOutsideMenuClick = this.handleOutsideMenuClick.bind(this); } - async componentDidMount() { + componentDidMount() { // Subscribe to jwt changes if (isBrowser()) { // On the first load, check the unreads this.requestNotificationPermission(); - this.fetchUnreads(); - this.requestNotificationPermission(); + + InboxService.fetchUnreadCounts(); document.addEventListener("mouseup", this.handleOutsideMenuClick); } @@ -102,7 +88,7 @@ export class Navbar extends Component { to="/inbox" className="p-1 nav-link border-0 nav-messages" title={I18NextService.i18n.t("unread_messages", { - count: Number(this.state.unreadApplicationCountRes.state), + count: Number(this.unreadInboxCount), formattedCount: numToSI(this.unreadInboxCount), })} onMouseUp={linkEvent(this, handleCollapseClick)} @@ -443,67 +429,16 @@ export class Navbar extends Component { return amAdmin() || moderatesS; } - fetchUnreads() { - poll(async () => { - if (window.document.visibilityState !== "hidden") { - const auth = myAuth(); - if (auth) { - this.setState({ - unreadInboxCountRes: await HttpService.client.getUnreadCount({ - auth, - }), - }); - - if (this.moderatesSomething) { - this.setState({ - unreadReportCountRes: await HttpService.client.getReportCount({ - auth, - }), - }); - } - - if (amAdmin()) { - this.setState({ - unreadApplicationCountRes: - await HttpService.client.getUnreadRegistrationApplicationCount({ - auth, - }), - }); - } - } - } - }, updateUnreadCountsInterval); + get unreadInboxCount() { + return InboxService.unreadInboxCount; } - get unreadInboxCount(): number { - if (this.state.unreadInboxCountRes.state == "success") { - const data = this.state.unreadInboxCountRes.data; - return data.replies + data.mentions + data.private_messages; - } else { - return 0; - } + get unreadReportCount() { + return InboxService.unreadReportCount; } - get unreadReportCount(): number { - if (this.state.unreadReportCountRes.state == "success") { - const data = this.state.unreadReportCountRes.data; - return ( - data.post_reports + - data.comment_reports + - (data.private_message_reports ?? 0) - ); - } else { - return 0; - } - } - - get unreadApplicationCount(): number { - if (this.state.unreadApplicationCountRes.state == "success") { - const data = this.state.unreadApplicationCountRes.data; - return data.registration_applications; - } else { - return 0; - } + get unreadApplicationCount() { + return InboxService.unreadApplicationCount; } get currentLocation() { diff --git a/src/shared/components/person/inbox.tsx b/src/shared/components/person/inbox.tsx index 395875be..220dfc21 100644 --- a/src/shared/components/person/inbox.tsx +++ b/src/shared/components/person/inbox.tsx @@ -60,7 +60,12 @@ import { } from "lemmy-js-client"; import { fetchLimit, relTags } from "../../config"; import { CommentViewType, InitialFetchRequest } from "../../interfaces"; -import { FirstLoadService, I18NextService, UserService } from "../../services"; +import { + FirstLoadService, + I18NextService, + InboxService, + UserService, +} from "../../services"; import { HttpService, RequestState } from "../../services/HttpService"; import { toast } from "../../toast"; import { CommentNodes } from "../comment/comment-nodes"; @@ -786,6 +791,8 @@ export class Inbox extends Component { mentionsRes: { state: "empty" }, messagesRes: { state: "empty" }, }); + + InboxService.fetchUnreadCounts(); } } diff --git a/src/shared/services/InboxService.ts b/src/shared/services/InboxService.ts new file mode 100644 index 00000000..c1999c83 --- /dev/null +++ b/src/shared/services/InboxService.ts @@ -0,0 +1,116 @@ +import { myAuth } from "@utils/app"; +import { poll } from "@utils/helpers"; +import { amAdmin } from "@utils/roles"; +import { + GetReportCountResponse, + GetUnreadCountResponse, + GetUnreadRegistrationApplicationCountResponse, +} from "lemmy-js-client"; +import { updateUnreadCountsInterval } from "../config"; +import { HttpService, UserService } from "../services"; +import { RequestState } from "../services/HttpService"; + +export class InboxService { + #unreadInboxCountRes: RequestState; + #unreadReportCountRes: RequestState; + #unreadApplicationCountRes: RequestState; + + static #instance: InboxService; + + private constructor() { + this.#unreadInboxCountRes = { state: "empty" }; + this.#unreadReportCountRes = { state: "empty" }; + this.#unreadApplicationCountRes = { state: "empty" }; + + this.startPoll(); + } + + static get #Instance() { + return this.#instance ?? (this.#instance = new this()); + } + + unreadInboxCount(): number { + if (this.#unreadInboxCountRes.state === "success") { + const { data } = this.#unreadInboxCountRes; + return data.replies + data.mentions + data.private_messages; + } else { + return 0; + } + } + + public static get unreadInboxCount(): number { + return this.#instance.unreadInboxCount(); + } + + unreadReportCount(): number { + if (this.#unreadReportCountRes.state === "success") { + const { data } = this.#unreadReportCountRes; + return ( + data.post_reports + + data.comment_reports + + (data.private_message_reports ?? 0) + ); + } else { + return 0; + } + } + + public static get unreadReportCount(): number { + return this.#instance.unreadReportCount(); + } + + unreadApplicationCount(): number { + if (this.#unreadApplicationCountRes.state === "success") { + return this.#unreadApplicationCountRes.data.registration_applications; + } else { + return 0; + } + } + + public static get unreadApplicationCount(): number { + return this.#instance.unreadApplicationCount(); + } + + get isModerator(): boolean { + const mods = UserService.Instance.myUserInfo?.moderates; + const moderates = (mods && mods.length > 0) || false; + return amAdmin() || moderates; + } + + startPoll() { + poll(async () => { + if (window.document.visibilityState === "hidden") { + return; + } + + this.fetchUnreadCounts(); + }, updateUnreadCountsInterval); + } + + async fetchUnreadCounts() { + const auth = myAuth(); + + if (auth) { + this.#unreadInboxCountRes = await HttpService.client.getUnreadCount({ + auth, + }); + + if (this.isModerator) { + this.#unreadReportCountRes = await HttpService.client.getReportCount({ + auth, + }); + } + + if (amAdmin()) { + this.#unreadApplicationCountRes = + await HttpService.client.getUnreadRegistrationApplicationCount({ + auth, + }); + } + } + } + + public static fetchUnreadCounts() { + this.#Instance.fetchUnreadCounts(); + } +} diff --git a/src/shared/services/index.ts b/src/shared/services/index.ts index 620293c4..b3591daa 100644 --- a/src/shared/services/index.ts +++ b/src/shared/services/index.ts @@ -3,4 +3,5 @@ export { HistoryService } from "./HistoryService"; export { HomeCacheService } from "./HomeCacheService"; export { HttpService } from "./HttpService"; export { I18NextService } from "./I18NextService"; +export { InboxService } from "./InboxService"; export { UserService } from "./UserService";