From e0814f109615d108513db63bb97cc45d9700702f Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Thu, 27 Jan 2022 00:40:29 -0600 Subject: [PATCH] Guild list in Recoil! I'm liking it already. Quite a bit nicer than passing state all over the place. --- .../webapp/elements/components/overlay.tsx | 2 +- .../contexts/context-menu-connection-info.tsx | 2 +- .../contexts/context-menu-guild-title.tsx | 2 +- .../lists/components/channel-element.tsx | 2 +- .../lists/components/guild-list-element.tsx | 41 ++--- .../lists/components/message-element.tsx | 2 +- .../webapp/elements/lists/guild-list.tsx | 27 ++-- .../elements/overlays/overlay-add-guild.tsx | 17 ++- .../elements/overlays/overlay-channel.tsx | 2 +- .../elements/overlays/overlay-personalize.tsx | 2 +- .../webapp/elements/{ => require}/atoms.ts | 24 ++- .../elements/require/setup-guild-recoil.ts | 142 ++++++++++++++++++ src/client/webapp/elements/root.tsx | 11 +- .../sections/guild-list-container.tsx | 26 +--- .../elements/sections/guilds-manager.tsx | 34 +---- 15 files changed, 230 insertions(+), 106 deletions(-) rename src/client/webapp/elements/{ => require}/atoms.ts (78%) create mode 100644 src/client/webapp/elements/require/setup-guild-recoil.ts diff --git a/src/client/webapp/elements/components/overlay.tsx b/src/client/webapp/elements/components/overlay.tsx index 316114d..e3c92be 100644 --- a/src/client/webapp/elements/components/overlay.tsx +++ b/src/client/webapp/elements/components/overlay.tsx @@ -5,7 +5,7 @@ const LOG = Logger.create(__filename, electronConsole); import React, { FC, ReactNode, RefObject, useCallback, useEffect } from "react"; import { useActionWhenEscapeOrClickedOrContextOutsideEffect } from '../require/react-helper'; -import { overlayState } from '../atoms'; +import { overlayState } from '../require/atoms'; import { useSetRecoilState } from 'recoil'; interface OverlayProps { diff --git a/src/client/webapp/elements/contexts/context-menu-connection-info.tsx b/src/client/webapp/elements/contexts/context-menu-connection-info.tsx index fc9cd71..0d66585 100644 --- a/src/client/webapp/elements/contexts/context-menu-connection-info.tsx +++ b/src/client/webapp/elements/contexts/context-menu-connection-info.tsx @@ -2,7 +2,7 @@ import React, { FC, ReactNode, RefObject, useCallback, useMemo } from 'react'; import { useSetRecoilState } from 'recoil'; import { Member } from '../../data-types'; import CombinedGuild from '../../guild-combined'; -import { overlayState } from '../atoms'; +import { overlayState } from '../require/atoms'; import PersonalizeOverlay from '../overlays/overlay-personalize'; import { SubscriptionResult } from '../require/guild-subscriptions'; import ContextMenu from './components/context-menu'; diff --git a/src/client/webapp/elements/contexts/context-menu-guild-title.tsx b/src/client/webapp/elements/contexts/context-menu-guild-title.tsx index 87d22a5..c7a9879 100644 --- a/src/client/webapp/elements/contexts/context-menu-guild-title.tsx +++ b/src/client/webapp/elements/contexts/context-menu-guild-title.tsx @@ -2,7 +2,7 @@ import React, { FC, ReactNode, RefObject, useCallback, useMemo } from 'react'; import { useSetRecoilState } from 'recoil'; import { GuildMetadata, Member } from '../../data-types'; import CombinedGuild from '../../guild-combined'; -import { overlayState } from '../atoms'; +import { overlayState } from '../require/atoms'; import ChannelOverlay from '../overlays/overlay-channel'; import GuildSettingsOverlay from '../overlays/overlay-guild-settings'; import BaseElements from '../require/base-elements'; diff --git a/src/client/webapp/elements/lists/components/channel-element.tsx b/src/client/webapp/elements/lists/components/channel-element.tsx index ca681bf..0e5d44a 100644 --- a/src/client/webapp/elements/lists/components/channel-element.tsx +++ b/src/client/webapp/elements/lists/components/channel-element.tsx @@ -10,7 +10,7 @@ import ChannelOverlay from '../../overlays/overlay-channel'; import BaseElements from '../../require/base-elements'; import { useContextHover } from '../../require/react-helper'; import BasicHover, { BasicHoverSide } from '../../contexts/context-hover-basic'; -import { overlayState } from '../../atoms'; +import { overlayState } from '../../require/atoms'; import { useSetRecoilState } from 'recoil'; export interface ChannelElementProps { diff --git a/src/client/webapp/elements/lists/components/guild-list-element.tsx b/src/client/webapp/elements/lists/components/guild-list-element.tsx index 0dd335b..9c3e4c3 100644 --- a/src/client/webapp/elements/lists/components/guild-list-element.tsx +++ b/src/client/webapp/elements/lists/components/guild-list-element.tsx @@ -1,41 +1,42 @@ import React, { FC, useCallback, useMemo, useRef } from 'react'; -import CombinedGuild from '../../../guild-combined'; -import GuildsManager from '../../../guilds-manager'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { GuildMetadata } from '../../../data-types'; import ContextMenu from '../../contexts/components/context-menu'; import BasicHover, { BasicHoverSide } from '../../contexts/context-hover-basic'; +import { guildsManagerState, GuildWithErrorableValue, selectedGuildIdState, selectedGuildState } from '../../require/atoms'; import BaseElements from '../../require/base-elements'; import { IAlignment } from '../../require/elements-util'; -import { useGuildMetadataSubscription, useSelfMemberSubscription, useSoftImageSrcResourceSubscription } from '../../require/guild-subscriptions'; +import { useSelfMemberSubscription, useSoftImageSrcResourceSubscription } from '../../require/guild-subscriptions'; import { useContextClickContextMenu, useContextHover } from '../../require/react-helper'; export interface GuildListElementProps { - guildsManager: GuildsManager; - guild: CombinedGuild; - activeGuild: CombinedGuild | null; - setSelfActiveGuild: () => void; + guildWithMeta: GuildWithErrorableValue, } const GuildListElement: FC = (props: GuildListElementProps) => { - const { guildsManager, guild, activeGuild, setSelfActiveGuild } = props; + const { guildWithMeta: { guild, value: guildMeta, valueError: _guildMetaError } } = props; const rootRef = useRef(null); - // TODO: state higher up + const guildsManager = useRecoilValue(guildsManagerState); + const selectedGuild = useRecoilValue(selectedGuildState); + const setSelectedGuildId = useSetRecoilState(selectedGuildIdState); + + // TODO: more state higher up // TODO: handle metadata error - const [ guildMetaResult, guildMetaError ] = useGuildMetadataSubscription(guild); const [ selfMemberResult ] = useSelfMemberSubscription(guild); - const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMetaResult?.value.iconResourceId ?? null, guildMetaResult?.guild ?? null); + const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta?.iconResourceId ?? null, guild); const [ contextHover, mouseEnterCallable, mouseLeaveCallable ] = useContextHover(() => { - if (!guildMetaResult) return null; + if (!guildMeta) return null; if (!selfMemberResult || !selfMemberResult.value) return null; const nameStyle = selfMemberResult.value.roleColor ? { color: selfMemberResult.value.roleColor } : {}; return ( - +
{BaseElements.TAB_LEFT}
-
{guildMetaResult.value.name}
+
{guildMeta.name}
{selfMemberResult.value.displayName}
@@ -44,9 +45,10 @@ const GuildListElement: FC = (props: GuildListElementProp
) - }, [ guildMetaResult, selfMemberResult ]); + }, [ guildMeta, selfMemberResult ]); const leaveGuildCallable = useCallback(async () => { + if (!guildsManager) return; guild.disconnect(); await guildsManager.removeGuild(guild); }, [ guildsManager, guild ]) @@ -63,9 +65,14 @@ const GuildListElement: FC = (props: GuildListElementProp ) }, [ leaveGuildCallable ]); + + const setSelfActiveGuild = useCallback(() => { + setSelectedGuildId(guild.id); + }, [ guild ]); + const className = useMemo(() => { - return activeGuild && guild.id === activeGuild.id ? 'guild active' : 'guild'; - }, [ guild, activeGuild ]); + return selectedGuild && guild.id === selectedGuild.id ? 'guild active' : 'guild'; + }, [ guild, selectedGuild ]); return (
diff --git a/src/client/webapp/elements/lists/components/message-element.tsx b/src/client/webapp/elements/lists/components/message-element.tsx index 387a899..8798289 100644 --- a/src/client/webapp/elements/lists/components/message-element.tsx +++ b/src/client/webapp/elements/lists/components/message-element.tsx @@ -3,7 +3,7 @@ import React, { FC, ReactNode, useCallback, useMemo } from 'react'; import { useSetRecoilState } from 'recoil'; import { Member, Message } from '../../../data-types'; import CombinedGuild from '../../../guild-combined'; -import { overlayState } from '../../atoms'; +import { overlayState } from '../../require/atoms'; import ImageContextMenu from '../../contexts/context-menu-image'; import ImageOverlay from '../../overlays/overlay-image'; import ElementsUtil, { IAlignment } from '../../require/elements-util'; diff --git a/src/client/webapp/elements/lists/guild-list.tsx b/src/client/webapp/elements/lists/guild-list.tsx index 70ce47d..ac595c7 100644 --- a/src/client/webapp/elements/lists/guild-list.tsx +++ b/src/client/webapp/elements/lists/guild-list.tsx @@ -1,27 +1,20 @@ -import React, { Dispatch, FC, SetStateAction, useMemo } from 'react'; -import CombinedGuild from '../../guild-combined'; -import GuildsManager from '../../guilds-manager'; +import React, { FC, useMemo } from 'react'; +import { useRecoilValue } from 'recoil'; +import { GuildMetadata } from '../../data-types'; +import { guildsState, GuildWithErrorableValue } from '../require/atoms'; import GuildListElement from './components/guild-list-element'; -export interface GuildListProps { - guildsManager: GuildsManager; - guilds: CombinedGuild[]; - activeGuild: CombinedGuild | null; - setActiveGuild: Dispatch>; -} - -const GuildList: FC = (props: GuildListProps) => { - const { guildsManager, guilds, activeGuild, setActiveGuild } = props; +const GuildList: FC = () => { + const guildsWithMeta = useRecoilValue(guildsState); const guildElements = useMemo(() => { - return guilds.map((guild: CombinedGuild) => ( + if (!guildsWithMeta) return null; + return guildsWithMeta.map((guildWithMeta: GuildWithErrorableValue) => ( { setActiveGuild(guild); } } + guildWithMeta={guildWithMeta} key={guildWithMeta.guild.id} /> )); - }, [ guildsManager, guilds, activeGuild ]); + }, [ guildsWithMeta ]); return (
diff --git a/src/client/webapp/elements/overlays/overlay-add-guild.tsx b/src/client/webapp/elements/overlays/overlay-add-guild.tsx index 77db25d..aece1bd 100644 --- a/src/client/webapp/elements/overlays/overlay-add-guild.tsx +++ b/src/client/webapp/elements/overlays/overlay-add-guild.tsx @@ -3,8 +3,7 @@ const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); -import React, { Dispatch, FC, ReactNode, SetStateAction, useEffect, useMemo, useRef, useState } from 'react'; -import GuildsManager from '../../guilds-manager'; +import React, { FC, ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import moment from 'moment'; import TextInput from '../components/input-text'; import ImageEditInput from '../components/input-image-edit'; @@ -17,8 +16,8 @@ import { useAsyncSubmitButton, useOneTimeAsyncAction } from '../require/react-he import * as fs from 'fs/promises'; import Button from '../components/button'; import Overlay from '../components/overlay'; -import { useSetRecoilState } from 'recoil'; -import { overlayState } from '../atoms'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { guildsManagerState, overlayState, selectedGuildIdState } from '../require/atoms'; export interface IAddGuildData { name: string, @@ -52,13 +51,14 @@ function getExampleAvatarPath(): string { } export interface AddGuildOverlayProps { - guildsManager: GuildsManager; addGuildData: IAddGuildData; - setActiveGuild: Dispatch>; } const AddGuildOverlay: FC = (props: AddGuildOverlayProps) => { - const { guildsManager, addGuildData, setActiveGuild } = props; + const { addGuildData } = props; + + const guildsManager = useRecoilValue(guildsManagerState); + const setSelectedGuildId = useSetRecoilState(selectedGuildIdState); const rootRef = useRef(null); const setOverlay = useSetRecoilState(overlayState); @@ -97,6 +97,7 @@ const AddGuildOverlay: FC = (props: AddGuildOverlayProps) const [ submitFunc, submitButtonText, submitButtonShaking, _, submitFailMessage ] = useAsyncSubmitButton( async () => { + if (!guildsManager) return { result: null, errorMessage: null }; if (validationErrorMessage || !avatarBuff) return { result: null, errorMessage: 'Validation failed' }; if (expired) return { result: null, errorMessage: 'Token expired' }; @@ -108,7 +109,7 @@ const AddGuildOverlay: FC = (props: AddGuildOverlayProps) return { result: null, errorMessage: (e as Error).message ?? 'Error adding new guild' }; } - setActiveGuild(newGuild); + setSelectedGuildId(newGuild.id); setOverlay(null); return { result: newGuild, errorMessage: null }; diff --git a/src/client/webapp/elements/overlays/overlay-channel.tsx b/src/client/webapp/elements/overlays/overlay-channel.tsx index 15f26fc..47d2115 100644 --- a/src/client/webapp/elements/overlays/overlay-channel.tsx +++ b/src/client/webapp/elements/overlays/overlay-channel.tsx @@ -14,7 +14,7 @@ import { useAsyncSubmitButton } from '../require/react-helper'; import Button from '../components/button'; import Overlay from '../components/overlay'; import { useSetRecoilState } from 'recoil'; -import { overlayState } from '../atoms'; +import { overlayState } from '../require/atoms'; export interface ChannelOverlayProps { guild: CombinedGuild; diff --git a/src/client/webapp/elements/overlays/overlay-personalize.tsx b/src/client/webapp/elements/overlays/overlay-personalize.tsx index c6a44c4..ec2a03d 100644 --- a/src/client/webapp/elements/overlays/overlay-personalize.tsx +++ b/src/client/webapp/elements/overlays/overlay-personalize.tsx @@ -15,7 +15,7 @@ import Button from '../components/button'; import Overlay from '../components/overlay'; import { SubscriptionResult, useResourceSubscription } from '../require/guild-subscriptions'; import { useSetRecoilState } from 'recoil'; -import { overlayState } from '../atoms'; +import { overlayState } from '../require/atoms'; export interface PersonalizeOverlayProps { guild: CombinedGuild; diff --git a/src/client/webapp/elements/atoms.ts b/src/client/webapp/elements/require/atoms.ts similarity index 78% rename from src/client/webapp/elements/atoms.ts rename to src/client/webapp/elements/require/atoms.ts index e5266e8..c5c8756 100644 --- a/src/client/webapp/elements/atoms.ts +++ b/src/client/webapp/elements/require/atoms.ts @@ -1,7 +1,8 @@ import { ReactNode } from 'react'; -import { atom, selector } from 'recoil'; -import { Channel, GuildMetadata, Member, Message } from '../data-types'; -import CombinedGuild from '../guild-combined'; +import { atom, DefaultValue, selector } from 'recoil'; +import { Channel, GuildMetadata, Member, Message } from '../../data-types'; +import CombinedGuild from '../../guild-combined'; +import GuildsManager from '../../guilds-manager'; export interface GuildWithValue { guild: CombinedGuild; @@ -25,9 +26,18 @@ export const overlayState = atom({ default: null }); +export const guildsManagerState = atom({ + key: 'guildsManagerState', + default: null, + // Allow mutability so that we can have changes to internal guild stuff + // We will still listen to new/update/delete/conflict events to maintain the UI's state + dangerouslyAllowMutability: true +}) + export const guildsState = atom[] | null>({ key: 'guildsState', - default: null + default: null, + dangerouslyAllowMutability: true }); export const selectedGuildIdState = atom({ @@ -45,7 +55,8 @@ export const selectedGuildWithMetaState = selector guildWithMeta.guild.id === guildId) ?? null; - } + }, + dangerouslyAllowMutability: true }); export const selectedGuildState = selector({ @@ -55,7 +66,8 @@ export const selectedGuildState = selector({ if (guildWithMeta === null) return null; return guildWithMeta.guild; - } + }, + dangerouslyAllowMutability: true }); export const selectedGuildMembersState = atom | null>({ diff --git a/src/client/webapp/elements/require/setup-guild-recoil.ts b/src/client/webapp/elements/require/setup-guild-recoil.ts new file mode 100644 index 0000000..363a08c --- /dev/null +++ b/src/client/webapp/elements/require/setup-guild-recoil.ts @@ -0,0 +1,142 @@ +import * as electronRemote from '@electron/remote'; +const electronConsole = electronRemote.getGlobal('console') as Console; +import Logger from '../../../../logger/logger'; +const LOG = Logger.create(__filename, electronConsole); + +import { useCallback, useEffect, useRef } from "react"; +import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; +import { GuildMetadata } from "../../data-types"; +import GuildsManager from "../../guilds-manager"; +import { guildsManagerState, guildsState, GuildWithErrorableValue, selectedGuildIdState, selectedGuildState } from "./atoms"; +import { useIsMountedRef } from "./react-helper"; +import CombinedGuild from '../../guild-combined'; +import { AutoVerifierChangesType } from '../../auto-verifier'; + + +/** Manages the guildsManager to ensure that guildsState is up to date with a list of guilds + * and that the guilds attempt to fetch their corresponding guildMetas + * This class it a bit more complicated since it has to fetch/listen to guild metadata changes on many guilds at once */ +function useManagedGuildsManager(guildsManager: GuildsManager) { + const isMounted = useIsMountedRef(); + const metadataInProgress = useRef>(new Set()); + const [ guildsWithMeta, setGuildsWithMeta ] = useRecoilState(guildsState); + + // Update the guild list + // If new guilds are added, add them with null metadata + const onChange = useCallback(() => { + const guilds = guildsManager.guilds; + setGuildsWithMeta((prevGuildsWithMeta) => { + if (!prevGuildsWithMeta) { + return guilds.map(guild => ({ guild, value: null, valueError: null })); + } else { + const newGuilds = guilds.filter(guild => !prevGuildsWithMeta.find(guildWithMeta => guildWithMeta.guild.id === guild.id)); + const newGuildsWithMeta = prevGuildsWithMeta + .filter(guildWithMeta => guilds.find(guild => guildWithMeta.guild.id === guild.id)) // Remove old guilds + .concat(newGuilds.map(guild => ({ guild, value: null, valueError: null }))); // Add new guilds + return newGuildsWithMeta; + } + }); + }, [ guildsManager, setGuildsWithMeta ]); + + // Listen for changes to the guild manager + useEffect(() => { + // Set initial guilds + onChange(); + + // Listen for updates + guildsManager.on('update-guilds', onChange); + return () => { + guildsManager.off('update-guilds', onChange); + } + }, [ guildsManager, onChange ]); + + + const setGuildWithMeta = useCallback((guildId: number, newGuildWithMeta: GuildWithErrorableValue) => { + setGuildsWithMeta(prevGuildsWithMeta => { + if (!prevGuildsWithMeta) return null; + return prevGuildsWithMeta.map(guildWithMeta => guildWithMeta.guild.id === guildId ? newGuildWithMeta : guildWithMeta); + }); + }, [ setGuildsWithMeta ]); + + useEffect(() => { + if (guildsWithMeta === null) return; + + // Load guild metadatas + for (const { guild, value, valueError } of guildsWithMeta) { + // Only fetch if the value has not been fetched yet and we are not currently fetching it. + if (!metadataInProgress.current.has(guild.id) && value === null && valueError === null) { + (async () => { + metadataInProgress.current.add(guild.id); + try { + const guildMeta = await guild.fetchMetadata(); + if (!isMounted.current) return; + setGuildWithMeta(guild.id, { guild, value: guildMeta, valueError: null }); + } catch (e: unknown) { + LOG.error(`error fetching metadata for g#${guild.id}`, e); + if (!isMounted.current) return; + setGuildWithMeta(guild.id, { guild, value: null, valueError: e }); + } + metadataInProgress.current.delete(guild.id); + })(); + } + } + }, [ guildsWithMeta, setGuildWithMeta ]); + + // Listen for changes to the guild metadata + useEffect(() => { + if (guildsWithMeta === null) return; + + // Listen for changes to metadata + function handleUpdateOrConflict(guild: CombinedGuild, guildMeta: GuildMetadata) { + setGuildWithMeta(guild.id, { guild, value: guildMeta, valueError: null }); + } + const callbacks = new Map void, + conflictCallback: (changesType: AutoVerifierChangesType, oldGuildMeta: GuildMetadata, guildMeta: GuildMetadata) => void + }>(); + + for (const { guild } of guildsWithMeta) { + const updateCallback = (guildMeta: GuildMetadata) => handleUpdateOrConflict(guild, guildMeta); + const conflictCallback = (_changesType: AutoVerifierChangesType, _oldGuildMeta: GuildMetadata, guildMeta: GuildMetadata) => handleUpdateOrConflict(guild, guildMeta); + guild.on('update-metadata', updateCallback); + guild.on('conflict-metadata', conflictCallback); + callbacks.set(guild, { updateCallback, conflictCallback }); + } + + return () => { + for (const { guild } of guildsWithMeta) { + const { updateCallback, conflictCallback } = callbacks.get(guild) as { + updateCallback: (guildMeta: GuildMetadata) => void, + conflictCallback: (changesType: AutoVerifierChangesType, oldGuildMeta: GuildMetadata, guildMeta: GuildMetadata) => void + }; + guild.off('update-metadata', updateCallback); + guild.off('conflict-metadata', conflictCallback); + } + } + }, [ guildsWithMeta ]); + + //useEffect(() => { + // LOG.debug(`guildsWithMeta: `, { guildsWithMeta }); + //}, [ guildsWithMeta ]); +} + +// Entrypoint for recoil setup with guilds +export function useGuildsManagerWithRecoil(guildsManager: GuildsManager): void { + const setGuildsManager = useSetRecoilState(guildsManagerState); + const guilds = useRecoilValue(guildsState); + const [ selectedGuildId, setSelectedGuildId ] = useRecoilState(selectedGuildIdState); + + // Set the guilds manager atom + useEffect(() => { setGuildsManager(guildsManager); }, [ guildsManager, setGuildsManager ]); + + // Manage the guilds within the manager (adds them to the guilds atom and automatically loads and updates their metadata) + useManagedGuildsManager(guildsManager); + + // Make sure that the first guild is set to the active guild once we get some guilds + useEffect(() => { + if (guilds && guilds.length > 0 && selectedGuildId === null) { + setSelectedGuildId((guilds[0] as GuildWithErrorableValue).guild.id); + } + }); +} + diff --git a/src/client/webapp/elements/root.tsx b/src/client/webapp/elements/root.tsx index 9c43649..fa5d837 100644 --- a/src/client/webapp/elements/root.tsx +++ b/src/client/webapp/elements/root.tsx @@ -1,7 +1,8 @@ import React, { FC, ReactNode } from 'react'; -import { useRecoilState } from 'recoil'; +import { useRecoilValue } from 'recoil'; import GuildsManager from '../guilds-manager'; -import { overlayState } from './atoms'; +import { overlayState } from './require/atoms'; +import { useGuildsManagerWithRecoil } from './require/setup-guild-recoil'; import GuildsManagerElement from './sections/guilds-manager'; import TitleBar from './sections/title-bar'; @@ -12,12 +13,14 @@ export interface RootElementProps { const RootElement: FC = (props: RootElementProps) => { const { guildsManager } = props; - const [ overlay, setOverlay ] = useRecoilState(overlayState); + const overlay = useRecoilValue(overlayState); + + useGuildsManagerWithRecoil(guildsManager); return (
- +
{overlay}
); diff --git a/src/client/webapp/elements/sections/guild-list-container.tsx b/src/client/webapp/elements/sections/guild-list-container.tsx index dd12f24..ad50397 100644 --- a/src/client/webapp/elements/sections/guild-list-container.tsx +++ b/src/client/webapp/elements/sections/guild-list-container.tsx @@ -3,9 +3,7 @@ const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); -import React, { Dispatch, FC, ReactNode, SetStateAction, useRef } from 'react'; -import CombinedGuild from '../../guild-combined'; -import GuildsManager from '../../guilds-manager'; +import React, { FC, ReactNode, useRef } from 'react'; import GuildList from '../lists/guild-list'; import { useAsyncVoidCallback, useContextHover } from '../require/react-helper'; import fs from 'fs/promises'; @@ -13,19 +11,10 @@ import AddGuildOverlay from '../overlays/overlay-add-guild'; import ErrorMessageOverlay from '../overlays/overlay-error-message'; import BasicHover, { BasicHoverSide } from '../contexts/context-hover-basic'; import BaseElements from '../require/base-elements'; -import { overlayState } from '../atoms'; +import { overlayState } from '../require/atoms'; import { useSetRecoilState } from 'recoil'; -export interface GuildListContainerProps { - guildsManager: GuildsManager; - guilds: CombinedGuild[]; - activeGuild: CombinedGuild | null; - setActiveGuild: Dispatch>; -} - -const GuildListContainer: FC = (props: GuildListContainerProps) => { - const { guildsManager, guilds, activeGuild, setActiveGuild } = props; - +const GuildListContainer: FC = () => { const addGuildRef = useRef(null); const setOverlay = useSetRecoilState(overlayState); @@ -71,16 +60,13 @@ const GuildListContainer: FC = (props: GuildListContain LOG.debug('bad guild data:', { addGuildData, fileText }); setOverlay(); } else { - setOverlay(); + setOverlay(); } - }, [ guildsManager ]); + }, []); return (
- +
= (props: GuildsManagerElementProps) => { - const { guildsManager } = props; - - const [ guilds ] = useGuildListSubscription(guildsManager); - const [ activeGuild, setActiveGuild ] = useState(null); - - useEffect(() => { - if (activeGuild === null) { - // initial active channel is the first one in the list - if (guilds && guilds.length > 0) { - setActiveGuild(guilds[0] as CombinedGuild); - } - } - }, [ guilds, activeGuild ]); +const GuildsManagerElement: FC = () => { + const selectedGuild = useRecoilValue(selectedGuildState); return (
- - {activeGuild && } + + {selectedGuild && }
); }