From 352c0e880c95ad1075973a66daad3ceeb78fde41 Mon Sep 17 00:00:00 2001
From: Paul <paulmakles@gmail.com>
Date: Thu, 24 Jun 2021 13:07:55 +0100
Subject: [PATCH] Context Menus: Add "mark as unread" back. Servers: Fix
 various issues relating to voice channels.

---
 package.json                                     |  3 ++-
 src/components/navigation/items/ButtonItem.tsx   |  4 ++--
 src/components/navigation/left/ServerSidebar.tsx |  2 +-
 src/context/revoltjs/events.ts                   | 16 ++++++++++++++++
 src/context/revoltjs/hooks.ts                    | 14 ++++++++------
 src/lib/ContextMenus.tsx                         | 16 +++++++---------
 yarn.lock                                        |  8 ++++----
 7 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/package.json b/package.json
index 7077cd3..b623553 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
     "detect-browser": "^5.2.0",
     "eslint": "^7.28.0",
     "eslint-config-preact": "^1.1.4",
+    "eventemitter3": "^4.0.7",
     "highlight.js": "^11.0.1",
     "idb": "^6.1.2",
     "localforage": "^1.9.0",
@@ -76,7 +77,7 @@
     "react-scroll": "^1.8.2",
     "react-tippy": "^1.4.0",
     "redux": "^4.1.0",
-    "revolt.js": "4.3.2",
+    "revolt.js": "4.3.2-patch.1",
     "rimraf": "^3.0.2",
     "sass": "^1.35.1",
     "shade-blend-color": "^1.0.0",
diff --git a/src/components/navigation/items/ButtonItem.tsx b/src/components/navigation/items/ButtonItem.tsx
index 4f5064e..31c29fb 100644
--- a/src/components/navigation/items/ButtonItem.tsx
+++ b/src/components/navigation/items/ButtonItem.tsx
@@ -82,7 +82,7 @@ export function UserButton({ active, alert, alertCount, user, context, channel }
 }
 
 type ChannelProps = CommonProps & {
-    channel: Channels.Channel,
+    channel: Channels.Channel & { unread?: string },
     user?: Users.User
     compact?: boolean
 }
@@ -101,7 +101,7 @@ export function ChannelButton({ active, alert, alertCount, channel, user, compac
             data-active={active}
             data-alert={typeof alert === 'string'}
             className={classNames(styles.item, { [styles.compact]: compact })}
-            onContextMenu={attachContextMenu('Menu', { channel: channel._id })}>
+            onContextMenu={attachContextMenu('Menu', { channel: channel._id, unread: typeof channel.unread !== 'undefined' })}>
             <div className={styles.avatar}>
                 <ChannelIcon target={channel} size={compact ? 24 : 32} />
             </div>
diff --git a/src/components/navigation/left/ServerSidebar.tsx b/src/components/navigation/left/ServerSidebar.tsx
index b84bb69..03f175c 100644
--- a/src/components/navigation/left/ServerSidebar.tsx
+++ b/src/components/navigation/left/ServerSidebar.tsx
@@ -47,7 +47,7 @@ function ServerSidebar(props: Props & WithDispatcher) {
     if (!server) return <Redirect to="/" />;
 
     const channels = (useChannels(server.channels, ctx)
-        .filter(entry => typeof entry !== 'undefined') as Readonly<Channels.TextChannel>[])
+        .filter(entry => typeof entry !== 'undefined') as Readonly<Channels.TextChannel | Channels.VoiceChannel>[])
         .map(x => mapChannelWithUnread(x, props.unreads));
     
     const channel = channels.find(x => x?._id === channel_id);
diff --git a/src/context/revoltjs/events.ts b/src/context/revoltjs/events.ts
index b97375f..21472bd 100644
--- a/src/context/revoltjs/events.ts
+++ b/src/context/revoltjs/events.ts
@@ -104,6 +104,16 @@ export function registerEvents({
         client.addListener(listener, (listenerFunc as any)[listener]);
     }
 
+    function logMutation(target: string, key: string) {
+        console.log('(o) Object mutated', target, '\nChanged:', key);
+    }
+
+    if (import.meta.env.DEV) {
+        client.users.addListener('mutation', logMutation);
+        client.servers.addListener('mutation', logMutation);
+        client.channels.addListener('mutation', logMutation);
+    }
+
     const online = () => {
         if (operations.ready()) {
             setStatus(ClientStatus.RECONNECTING);
@@ -128,6 +138,12 @@ export function registerEvents({
             client.removeListener(listener, (listenerFunc as any)[listener]);
         }
 
+        if (import.meta.env.DEV) {
+            client.users.removeListener('mutation', logMutation);
+            client.servers.removeListener('mutation', logMutation);
+            client.channels.removeListener('mutation', logMutation);
+        }
+
         window.removeEventListener("online", online);
         window.removeEventListener("offline", offline);
     };
diff --git a/src/context/revoltjs/hooks.ts b/src/context/revoltjs/hooks.ts
index e5e25a8..a6ca792 100644
--- a/src/context/revoltjs/hooks.ts
+++ b/src/context/revoltjs/hooks.ts
@@ -11,7 +11,7 @@ export interface HookContext {
 export function useForceUpdate(context?: HookContext): HookContext {
     const client = useContext(AppContext);
     if (context) return context;
-    const H = useState(undefined);
+    /*const H = useState(undefined);
     var updateState: (_: undefined) => void;
     if (Array.isArray(H)) {
         let [, u] = H;
@@ -20,14 +20,16 @@ export function useForceUpdate(context?: HookContext): HookContext {
         console.warn('Failed to construct using useState.');
         console.warn(H);
         updateState = ()=>{};
-    }
-    return { client, forceUpdate: useCallback(() => updateState(undefined), []) };
+    }*/
+
+    const [, updateState] = useState(0);
+    return { client, forceUpdate: () => updateState(Math.random()) };
 }
 
 function useObject(type: string, id?: string | string[], context?: HookContext) {
     const ctx = useForceUpdate(context);
 
-    function mutation(target: string) {
+    function update(target: any) {
         if (typeof id === 'string' ? target === id :
             Array.isArray(id) ? id.includes(target) : true) {
             ctx.forceUpdate();
@@ -36,8 +38,8 @@ function useObject(type: string, id?: string | string[], context?: HookContext)
 
     const map = (ctx.client as any)[type];
     useEffect(() => {
-        map.addListener("update", mutation);
-        return () => map.removeListener("update", mutation);
+        map.addListener("update", update);
+        return () => map.removeListener("update", update);
     }, [id]);
 
     return typeof id === 'string' ? map.get(id)
diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx
index 4867ee1..358ed93 100644
--- a/src/lib/ContextMenus.tsx
+++ b/src/lib/ContextMenus.tsx
@@ -62,9 +62,9 @@ type Action =
     | { action: "set_status" }
     | { action: "clear_status" }
     | { action: "create_channel"; target: Servers.Server }
-    | { action: "create_invite"; target: Channels.GroupChannel | Channels.TextChannel }
+    | { action: "create_invite"; target: Channels.GroupChannel | Channels.TextChannel | Channels.VoiceChannel }
     | { action: "leave_group"; target: Channels.GroupChannel }
-    | { action: "delete_channel"; target: Channels.TextChannel }
+    | { action: "delete_channel"; target: Channels.TextChannel | Channels.VoiceChannel }
     | { action: "close_dm"; target: Channels.DirectMessageChannel }
     | { action: "leave_server"; target: Servers.Server }
     | { action: "delete_server"; target: Servers.Server }
@@ -374,20 +374,17 @@ function ContextMenus(props: WithDispatcher) {
                     const targetChannel = channel ?? contextualChannel;
 
                     const user = useUser(uid, forceUpdate);
-                    const server = useServer(targetChannel?.channel_type === 'TextChannel' ? targetChannel.server : sid, forceUpdate);
+                    const serverChannel = targetChannel && (targetChannel.channel_type === 'TextChannel' || targetChannel.channel_type === 'VoiceChannel') ? targetChannel : undefined;
+                    const server = useServer(serverChannel ? serverChannel.server : sid, forceUpdate);
 
                     const channelPermissions = targetChannel ? useChannelPermission(targetChannel._id, forceUpdate) : 0;
                     const serverPermissions = server ? useServerPermission(server._id, forceUpdate) : (
-                        targetChannel?.channel_type === 'TextChannel' ? useServerPermission(targetChannel.server, forceUpdate) : 0
+                        serverChannel ? useServerPermission(serverChannel.server, forceUpdate) : 0
                     );
                     const userPermissions = user ? useUserPermission(user._id, forceUpdate) : 0;
 
                     if (channel && unread) {
-                        generateAction(
-                            { action: "mark_as_read", channel },
-                            undefined,
-                            true
-                        );
+                        generateAction({ action: "mark_as_read", channel });
                     }
 
                     if (contextualChannel) {
@@ -580,6 +577,7 @@ function ContextMenus(props: WithDispatcher) {
                                     generateAction({ action: "close_dm", target: channel });
                                     break;
                                 case 'TextChannel':
+                                case 'VoiceChannel':
                                     // ! FIXME: add permission for invites
                                     generateAction({ action: "create_invite", target: channel });
 
diff --git a/yarn.lock b/yarn.lock
index 2284252..182a627 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3412,10 +3412,10 @@ reusify@^1.0.4:
   resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-revolt.js@4.3.2:
-  version "4.3.2"
-  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.2.tgz#2e613ff1d918d77266e9c777e226bfbddd5a9b87"
-  integrity sha512-JyD3fRaory3Rhy/sAWcvHjLb/CluJRZap2Di2ZFFf9uiRJBgLNlClS/3RkBLAcQqx4KVx7Ua3WbKq1/dU6x7dQ==
+revolt.js@4.3.2-patch.1:
+  version "4.3.2-patch.1"
+  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.2-patch.1.tgz#0c4190f0a640951636c6f2577c9298418b06917f"
+  integrity sha512-XAu2JeYc2+OFLM56WktGT/4tAyvjibmNL5oGc5pPZEjl0DnoIxPE96CZPe+35ZCX9bEiuoX378Fwfmfe3uN7sw==
   dependencies:
     "@insertish/mutable" "1.1.0"
     axios "^0.19.2"
-- 
GitLab