From 0571c065bd5594b5583244a2bd49c6640fb0e59c Mon Sep 17 00:00:00 2001
From: Paul <paulmakles@gmail.com>
Date: Thu, 29 Jul 2021 16:55:07 +0100
Subject: [PATCH] Remove remaining references to useUser(s). Add Channel
 object.

---
 src/components/common/messaging/Message.tsx   |   1 -
 .../common/messaging/SystemMessage.tsx        |   1 -
 .../messaging/attachments/MessageReply.tsx    |   9 +-
 .../common/messaging/bars/ReplyBar.tsx        |   2 -
 .../common/messaging/bars/TypingIndicator.tsx |   1 -
 .../navigation/left/HomeSidebar.tsx           |   6 +-
 .../navigation/right/MemberSidebar.tsx        |   1 -
 .../intermediate/popovers/UserProfile.tsx     |   1 -
 src/context/revoltjs/hooks.ts                 |  12 --
 src/mobx/index.ts                             | 114 +++++++++++++++++-
 src/pages/Open.tsx                            |  24 ++--
 src/pages/settings/server/Invites.tsx         |   7 +-
 src/pages/settings/server/Members.tsx         |   1 -
 13 files changed, 126 insertions(+), 54 deletions(-)

diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx
index a7a92d3..54099c6 100644
--- a/src/components/common/messaging/Message.tsx
+++ b/src/components/common/messaging/Message.tsx
@@ -9,7 +9,6 @@ import { QueuedMessage } from "../../../redux/reducers/queue";
 
 import { useIntermediate } from "../../../context/intermediate/Intermediate";
 import { AppContext } from "../../../context/revoltjs/RevoltClient";
-import { useUser } from "../../../context/revoltjs/hooks";
 import { MessageObject } from "../../../context/revoltjs/util";
 
 import Overline from "../../ui/Overline";
diff --git a/src/components/common/messaging/SystemMessage.tsx b/src/components/common/messaging/SystemMessage.tsx
index 59051ba..19c5325 100644
--- a/src/components/common/messaging/SystemMessage.tsx
+++ b/src/components/common/messaging/SystemMessage.tsx
@@ -8,7 +8,6 @@ import { TextReact } from "../../../lib/i18n";
 import { User } from "../../../mobx";
 import { useData } from "../../../mobx/State";
 
-import { useForceUpdate, useUser } from "../../../context/revoltjs/hooks";
 import { MessageObject } from "../../../context/revoltjs/util";
 
 import UserShort from "../user/UserShort";
diff --git a/src/components/common/messaging/attachments/MessageReply.tsx b/src/components/common/messaging/attachments/MessageReply.tsx
index b849e3d..dcf3517 100644
--- a/src/components/common/messaging/attachments/MessageReply.tsx
+++ b/src/components/common/messaging/attachments/MessageReply.tsx
@@ -13,7 +13,7 @@ import { useRenderState } from "../../../../lib/renderer/Singleton";
 
 import { useData } from "../../../../mobx/State";
 
-import { useForceUpdate, useUser } from "../../../../context/revoltjs/hooks";
+import { useClient } from "../../../../context/revoltjs/RevoltClient";
 import { mapMessage, MessageObject } from "../../../../context/revoltjs/util";
 
 import Markdown from "../../../markdown/Markdown";
@@ -124,7 +124,7 @@ export const ReplyBase = styled.div<{
 `;
 
 export const MessageReply = observer(({ index, channel, id }: Props) => {
-    const ctx = useForceUpdate();
+    const client = useClient();
     const view = useRenderState(channel);
     if (view?.type !== "RENDER") return null;
 
@@ -138,7 +138,7 @@ export const MessageReply = observer(({ index, channel, id }: Props) => {
         if (m) {
             setMessage(m);
         } else {
-            ctx.client.channels
+            client.channels
                 .fetchMessage(channel, id)
                 .then((m) => setMessage(mapMessage(m)));
         }
@@ -178,8 +178,7 @@ export const MessageReply = observer(({ index, channel, id }: Props) => {
                             <div
                                 className="content"
                                 onClick={() => {
-                                    const obj =
-                                        ctx.client.channels.get(channel);
+                                    const obj = client.channels.get(channel);
                                     if (obj?.channel_type === "TextChannel") {
                                         history.push(
                                             `/server/${obj.server}/channel/${obj._id}/${message._id}`,
diff --git a/src/components/common/messaging/bars/ReplyBar.tsx b/src/components/common/messaging/bars/ReplyBar.tsx
index 5de6906..a6b282d 100644
--- a/src/components/common/messaging/bars/ReplyBar.tsx
+++ b/src/components/common/messaging/bars/ReplyBar.tsx
@@ -17,8 +17,6 @@ import { useRenderState } from "../../../../lib/renderer/Singleton";
 import { useData } from "../../../../mobx/State";
 import { Reply } from "../../../../redux/reducers/queue";
 
-import { useUsers } from "../../../../context/revoltjs/hooks";
-
 import IconButton from "../../../ui/IconButton";
 
 import Markdown from "../../../markdown/Markdown";
diff --git a/src/components/common/messaging/bars/TypingIndicator.tsx b/src/components/common/messaging/bars/TypingIndicator.tsx
index 8c2fe0b..816b7fc 100644
--- a/src/components/common/messaging/bars/TypingIndicator.tsx
+++ b/src/components/common/messaging/bars/TypingIndicator.tsx
@@ -15,7 +15,6 @@ import {
     AppContext,
     useClient,
 } from "../../../../context/revoltjs/RevoltClient";
-import { useUsers } from "../../../../context/revoltjs/hooks";
 
 import { Username } from "../../user/UserShort";
 
diff --git a/src/components/navigation/left/HomeSidebar.tsx b/src/components/navigation/left/HomeSidebar.tsx
index b120313..e22d35b 100644
--- a/src/components/navigation/left/HomeSidebar.tsx
+++ b/src/components/navigation/left/HomeSidebar.tsx
@@ -23,11 +23,7 @@ import { Unreads } from "../../../redux/reducers/unreads";
 
 import { useIntermediate } from "../../../context/intermediate/Intermediate";
 import { AppContext } from "../../../context/revoltjs/RevoltClient";
-import {
-    useDMs,
-    useForceUpdate,
-    useUsers,
-} from "../../../context/revoltjs/hooks";
+import { useDMs, useForceUpdate } from "../../../context/revoltjs/hooks";
 
 import Category from "../../ui/Category";
 import placeholderSVG from "../items/placeholder.svg";
diff --git a/src/components/navigation/right/MemberSidebar.tsx b/src/components/navigation/right/MemberSidebar.tsx
index 8beac5b..23d6555 100644
--- a/src/components/navigation/right/MemberSidebar.tsx
+++ b/src/components/navigation/right/MemberSidebar.tsx
@@ -21,7 +21,6 @@ import {
     HookContext,
     useChannel,
     useForceUpdate,
-    useUsers,
 } from "../../../context/revoltjs/hooks";
 
 import CollapsibleSection from "../../common/CollapsibleSection";
diff --git a/src/context/intermediate/popovers/UserProfile.tsx b/src/context/intermediate/popovers/UserProfile.tsx
index c321b9f..0e0105d 100644
--- a/src/context/intermediate/popovers/UserProfile.tsx
+++ b/src/context/intermediate/popovers/UserProfile.tsx
@@ -31,7 +31,6 @@ import {
     useChannels,
     useForceUpdate,
     useUserPermission,
-    useUsers,
 } from "../../revoltjs/hooks";
 import { useIntermediate } from "../Intermediate";
 
diff --git a/src/context/revoltjs/hooks.ts b/src/context/revoltjs/hooks.ts
index e693ccf..e5ea687 100644
--- a/src/context/revoltjs/hooks.ts
+++ b/src/context/revoltjs/hooks.ts
@@ -77,18 +77,6 @@ function useObject(
         : map.toArray();
 }
 
-export function useUser(id?: string, context?: HookContext) {
-    if (typeof id === "undefined") return;
-    return useObject("users", id, context) as Readonly<Users.User> | undefined;
-}
-
-export function useUsers(ids?: string[], context?: HookContext) {
-    return useObject("users", ids, context) as (
-        | Readonly<Users.User>
-        | undefined
-    )[];
-}
-
 export function useChannel(id?: string, context?: HookContext) {
     if (typeof id === "undefined") return;
     return useObject("channels", id, context) as
diff --git a/src/mobx/index.ts b/src/mobx/index.ts
index d878cd1..fdc1ae4 100644
--- a/src/mobx/index.ts
+++ b/src/mobx/index.ts
@@ -9,8 +9,8 @@ import {
     action,
     extendObservable,
 } from "mobx";
-import { Attachment, Users } from "revolt.js/dist/api/objects";
-import { RemoveUserField } from "revolt.js/dist/api/routes";
+import { Attachment, Channels, Users } from "revolt.js/dist/api/objects";
+import { RemoveChannelField, RemoveUserField } from "revolt.js/dist/api/routes";
 import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
 
 type Nullable<T> = T | null;
@@ -42,7 +42,7 @@ export class User {
     }
 
     @action update(data: Partial<Users.User>, clear?: RemoveUserField) {
-        const apply = (key: keyof Users.User) => {
+        const apply = (key: string) => {
             // This code has been tested.
             // @ts-expect-error
             if (data[key] && !isEqual(this[key], data[key])) {
@@ -62,6 +62,7 @@ export class User {
             }
         }
 
+        apply("username");
         apply("avatar");
         apply("badges");
         apply("status");
@@ -70,8 +71,110 @@ export class User {
     }
 }
 
+export class Channel {
+    _id: string;
+    type: Channels.Channel["channel_type"];
+
+    // Direct Message
+    active: Nullable<boolean> = null;
+
+    // Group
+    owner: Nullable<string> = null;
+
+    // Server
+    server: Nullable<string> = null;
+
+    // Permissions
+    permissions: Nullable<number> = null;
+    default_permissions: Nullable<number> = null;
+    role_permissions: Nullable<{ [key: string]: number }> = null;
+
+    // Common
+    name: Nullable<string> = null;
+    icon: Nullable<Attachment> = null;
+    description: Nullable<string> = null;
+    recipients: Nullable<string[]> = null;
+    last_message: Nullable<string | Channels.LastMessage> = null;
+
+    constructor(data: Channels.Channel) {
+        this._id = data._id;
+        this.type = data.channel_type;
+
+        switch (data.channel_type) {
+            case "DirectMessage": {
+                this.active = toNullable(data.active);
+                this.recipients = toNullable(data.recipients);
+                this.last_message = toNullable(data.last_message);
+                break;
+            }
+            case "Group": {
+                this.recipients = toNullable(data.recipients);
+                this.name = toNullable(data.name);
+                this.owner = toNullable(data.owner);
+                this.description = toNullable(data.description);
+                this.last_message = toNullable(data.last_message);
+                this.icon = toNullable(data.icon);
+                this.permissions = toNullable(data.permissions);
+                break;
+            }
+            case "TextChannel":
+            case "VoiceChannel": {
+                this.server = toNullable(data.server);
+                this.name = toNullable(data.name);
+                this.description = toNullable(data.description);
+                this.icon = toNullable(data.icon);
+                this.default_permissions = toNullable(data.default_permissions);
+                this.role_permissions = toNullable(data.role_permissions);
+
+                if (data.channel_type === "TextChannel") {
+                    this.last_message = toNullable(data.last_message);
+                }
+
+                break;
+            }
+        }
+
+        makeAutoObservable(this);
+    }
+
+    @action update(
+        data: Partial<Channels.Channel>,
+        clear?: RemoveChannelField,
+    ) {
+        const apply = (key: string) => {
+            // This code has been tested.
+            // @ts-expect-error
+            if (data[key] && !isEqual(this[key], data[key])) {
+                // @ts-expect-error
+                this[key] = data[key];
+            }
+        };
+
+        switch (clear) {
+            case "Description":
+                this.description = null;
+                break;
+            case "Icon":
+                this.icon = null;
+                break;
+        }
+
+        apply("active");
+        apply("owner");
+        apply("permissions");
+        apply("default_permissions");
+        apply("role_permissions");
+        apply("name");
+        apply("icon");
+        apply("description");
+        apply("recipients");
+        apply("last_message");
+    }
+}
+
 export class DataStore {
     @observable users = new Map<string, User>();
+    @observable channels = new Map<string, Channel>();
 
     constructor() {
         makeAutoObservable(this);
@@ -84,6 +187,11 @@ export class DataStore {
                 for (let user of packet.users) {
                     this.users.set(user._id, new User(user));
                 }
+
+                for (let channel of packet.channels) {
+                    this.channels.set(channel._id, new Channel(channel));
+                }
+
                 break;
             }
             case "UserUpdate": {
diff --git a/src/pages/Open.tsx b/src/pages/Open.tsx
index 6a36e24..ddeb98b 100644
--- a/src/pages/Open.tsx
+++ b/src/pages/Open.tsx
@@ -9,11 +9,6 @@ import {
     ClientStatus,
     StatusContext,
 } from "../context/revoltjs/RevoltClient";
-import {
-    useChannels,
-    useForceUpdate,
-    useUser,
-} from "../context/revoltjs/hooks";
 
 import Header from "../components/ui/Header";
 
@@ -32,13 +27,9 @@ export default function Open() {
         );
     }
 
-    const ctx = useForceUpdate();
-    const channels = useChannels(undefined, ctx);
-    const user = useUser(id, ctx);
-
     useEffect(() => {
         if (id === "saved") {
-            for (const channel of channels) {
+            for (const channel of client.channels.toArray()) {
                 if (channel?.channel_type === "SavedMessages") {
                     history.push(`/channel/${channel._id}`);
                     return;
@@ -53,12 +44,15 @@ export default function Open() {
             return;
         }
 
+        let user = client.users.get(id);
         if (user) {
-            const channel: string | undefined = channels.find(
-                (channel) =>
-                    channel?.channel_type === "DirectMessage" &&
-                    channel.recipients.includes(id),
-            )?._id;
+            const channel: string | undefined = client.channels
+                .toArray()
+                .find(
+                    (channel) =>
+                        channel?.channel_type === "DirectMessage" &&
+                        channel.recipients.includes(id),
+                )?._id;
 
             if (channel) {
                 history.push(`/channel/${channel}`);
diff --git a/src/pages/settings/server/Invites.tsx b/src/pages/settings/server/Invites.tsx
index e77bf3b..1708d85 100644
--- a/src/pages/settings/server/Invites.tsx
+++ b/src/pages/settings/server/Invites.tsx
@@ -9,11 +9,7 @@ import { useEffect, useState } from "preact/hooks";
 import { useData } from "../../../mobx/State";
 
 import { useClient } from "../../../context/revoltjs/RevoltClient";
-import {
-    useChannels,
-    useForceUpdate,
-    useUsers,
-} from "../../../context/revoltjs/hooks";
+import { useChannels, useForceUpdate } from "../../../context/revoltjs/hooks";
 import { getChannelName } from "../../../context/revoltjs/util";
 
 import UserIcon from "../../../components/common/user/UserIcon";
@@ -34,7 +30,6 @@ export const Invites = observer(({ server }: Props) => {
     const channels = useChannels(invites?.map((x) => x.channel) ?? [], ctx);
 
     const store = useData();
-    const client = useClient();
     const users = invites?.map((invite) => store.users.get(invite.creator));
 
     useEffect(() => {
diff --git a/src/pages/settings/server/Members.tsx b/src/pages/settings/server/Members.tsx
index 24528cb..69f3aa9 100644
--- a/src/pages/settings/server/Members.tsx
+++ b/src/pages/settings/server/Members.tsx
@@ -10,7 +10,6 @@ import { useEffect, useState } from "preact/hooks";
 import { useData } from "../../../mobx/State";
 
 import { useClient } from "../../../context/revoltjs/RevoltClient";
-import { useForceUpdate, useUsers } from "../../../context/revoltjs/hooks";
 
 import UserIcon from "../../../components/common/user/UserIcon";
 import Button from "../../../components/ui/Button";
-- 
GitLab