Use Recoil State for Guild Metadata

This commit is contained in:
Michael Peters 2022-01-27 21:46:40 -06:00
parent e0814f1096
commit 245637bed6
10 changed files with 83 additions and 93 deletions

View File

@ -1,42 +1,44 @@
import moment from 'moment'; import moment from 'moment';
import React, { FC } from 'react'; import React, { FC } from 'react';
import { GuildMetadata, Member, Token } from '../../data-types'; import { useRecoilValue } from 'recoil';
import CombinedGuild from '../../guild-combined'; import { Member, Token } from '../../data-types';
import Util from '../../util'; import Util from '../../util';
import { IAddGuildData } from '../overlays/overlay-add-guild'; import { IAddGuildData } from '../overlays/overlay-add-guild';
import { selectedGuildWithMetaState } from '../require/atoms';
import BaseElements from '../require/base-elements'; import BaseElements from '../require/base-elements';
import { SubscriptionResult, useSoftImageSrcResourceSubscription } from '../require/guild-subscriptions'; import { useSoftImageSrcResourceSubscription } from '../require/guild-subscriptions';
import { useAsyncVoidCallback, useDownloadButton, useOneTimeAsyncAction } from '../require/react-helper'; import { useAsyncVoidCallback, useDownloadButton, useOneTimeAsyncAction } from '../require/react-helper';
import Button, { ButtonColorType } from './button'; import Button, { ButtonColorType } from './button';
export interface TokenRowProps { export interface TokenRowProps {
url: string; url: string;
guild: CombinedGuild;
guildMetaResult: SubscriptionResult<GuildMetadata>;
token: Token; token: Token;
} }
const TokenRow: FC<TokenRowProps> = (props: TokenRowProps) => { const TokenRow: FC<TokenRowProps> = (props: TokenRowProps) => {
const { guild, guildMetaResult, token } = props; const { token } = props;
const guildWithMeta = useRecoilValue(selectedGuildWithMetaState);
if (guildWithMeta === null || guildWithMeta.value === null) return null;
const [ guildSocketConfigs ] = useOneTimeAsyncAction( const [ guildSocketConfigs ] = useOneTimeAsyncAction(
async () => await guild.fetchSocketConfigs(), async () => await guildWithMeta.guild.fetchSocketConfigs(),
null, null,
[ guild ] [ guildWithMeta.guild ]
); );
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMetaResult.value.iconResourceId, guildMetaResult.guild); const [ iconSrc ] = useSoftImageSrcResourceSubscription(guildWithMeta.guild, guildWithMeta.value.iconResourceId, guildWithMeta.guild);
const [ revoke ] = useAsyncVoidCallback(async () => { const [ revoke ] = useAsyncVoidCallback(async () => {
await guild.requestDoRevokeToken(token.token); await guildWithMeta.guild.requestDoRevokeToken(token.token);
}, [ guild, token ]); }, [ guildWithMeta.guild, token ]);
const [ downloadFunc, downloadText, downloadShaking ] = useDownloadButton( const [ downloadFunc, downloadText, downloadShaking ] = useDownloadButton(
guildMetaResult.value.name + '.cordis', guildWithMeta.value.name + '.cordis',
async () => { async () => {
if (guildSocketConfigs === null) return null; if (guildSocketConfigs === null) return null;
if (guildWithMeta === null || guildWithMeta.value === null) return null;
const guildSocketConfig = Util.randomChoice(guildSocketConfigs); const guildSocketConfig = Util.randomChoice(guildSocketConfigs);
const addGuildData: IAddGuildData = { const addGuildData: IAddGuildData = {
name: guildMetaResult.value.name, name: guildWithMeta.value.name,
url: guildSocketConfig.url, url: guildSocketConfig.url,
cert: guildSocketConfig.cert, cert: guildSocketConfig.cert,
token: token.token, token: token.token,
@ -46,12 +48,12 @@ const TokenRow: FC<TokenRowProps> = (props: TokenRowProps) => {
const json = JSON.stringify(addGuildData); const json = JSON.stringify(addGuildData);
return Buffer.from(json); return Buffer.from(json);
}, },
[ guildSocketConfigs, guildMetaResult, token, iconSrc ] [ guildSocketConfigs, guildWithMeta, token, iconSrc ]
); );
const userText = (token.member instanceof Member ? 'Used by ' + token.member.displayName : token.member?.id) ?? 'Unused Token'; const userText = (token.member instanceof Member ? 'Used by ' + token.member.displayName : token.member?.id) ?? 'Unused Token';
return ( return (
<div key={guild.id + token.token} className="token-row"> <div key={guildWithMeta.guild.id + token.token} className="token-row">
<div className="user-token"> <div className="user-token">
<div className="user">{userText}</div> <div className="user">{userText}</div>
<div className="token">{token.token}</div> <div className="token">{token.token}</div>

View File

@ -1,36 +1,32 @@
import React, { FC, ReactNode, RefObject, useCallback, useMemo } from 'react'; import React, { FC, ReactNode, RefObject, useCallback, useMemo } from 'react';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { GuildMetadata, Member } from '../../data-types'; import { Member } from '../../data-types';
import CombinedGuild from '../../guild-combined';
import { overlayState } from '../require/atoms'; import { overlayState } from '../require/atoms';
import ChannelOverlay from '../overlays/overlay-channel'; import ChannelOverlay from '../overlays/overlay-channel';
import GuildSettingsOverlay from '../overlays/overlay-guild-settings'; import GuildSettingsOverlay from '../overlays/overlay-guild-settings';
import BaseElements from '../require/base-elements'; import BaseElements from '../require/base-elements';
import { SubscriptionResult } from '../require/guild-subscriptions';
import ContextMenu from './components/context-menu'; import ContextMenu from './components/context-menu';
export interface GuildTitleContextMenuProps { export interface GuildTitleContextMenuProps {
close: () => void; close: () => void;
relativeToRef: RefObject<HTMLElement>; relativeToRef: RefObject<HTMLElement>;
guild: CombinedGuild;
guildMetaResult: SubscriptionResult<GuildMetadata>;
selfMember: Member; selfMember: Member;
} }
const GuildTitleContextMenu: FC<GuildTitleContextMenuProps> = (props: GuildTitleContextMenuProps) => { const GuildTitleContextMenu: FC<GuildTitleContextMenuProps> = (props: GuildTitleContextMenuProps) => {
const { close, relativeToRef, guild, guildMetaResult, selfMember } = props; const { close, relativeToRef, selfMember } = props;
const setOverlay = useSetRecoilState<ReactNode>(overlayState); const setOverlay = useSetRecoilState<ReactNode>(overlayState);
const openGuildSettings = useCallback(() => { const openGuildSettings = useCallback(() => {
close(); close();
setOverlay(<GuildSettingsOverlay guild={guild} guildMetaResult={guildMetaResult} />); setOverlay(<GuildSettingsOverlay />);
}, [ guild, guildMetaResult, close ]); }, [ close ]);
const openCreateChannel = useCallback(() => { const openCreateChannel = useCallback(() => {
close(); close();
setOverlay(<ChannelOverlay guild={guild} />); setOverlay(<ChannelOverlay />);
}, [ guild, close ]); }, [ close ]);
const guildSettingsElement = useMemo(() => { const guildSettingsElement = useMemo(() => {
if (!selfMember.privileges.includes('modify_profile')) return null; if (!selfMember.privileges.includes('modify_profile')) return null;
@ -59,7 +55,7 @@ const GuildTitleContextMenu: FC<GuildTitleContextMenuProps> = (props: GuildTitle
}, []); }, []);
return ( return (
<ContextMenu alignment={alignment} close={close} relativeToRef={relativeToRef} realignDeps={[ guild, guildMetaResult, selfMember ]}> <ContextMenu alignment={alignment} close={close} relativeToRef={relativeToRef} realignDeps={[ selfMember ]}>
<div className="guild-title-context-menu"> <div className="guild-title-context-menu">
{guildSettingsElement} {guildSettingsElement}
{createChannelElement} {createChannelElement}

View File

@ -4,34 +4,31 @@ import Logger from '../../../../logger/logger';
const LOG = Logger.create(__filename, electronConsole); const LOG = Logger.create(__filename, electronConsole);
import React, { FC, useEffect, useMemo, useState } from 'react'; import React, { FC, useEffect, useMemo, useState } from 'react';
import CombinedGuild from '../../guild-combined';
import Display from '../components/display'; import Display from '../components/display';
import InvitePreview from '../components/invite-preview'; import InvitePreview from '../components/invite-preview';
import { GuildMetadata, Token } from '../../data-types'; import { Token } from '../../data-types';
import { useAsyncSubmitButton } from '../require/react-helper'; import { useAsyncSubmitButton } from '../require/react-helper';
import { Duration } from 'moment'; import { Duration } from 'moment';
import moment from 'moment'; import moment from 'moment';
import DropdownInput from '../components/input-dropdown'; import DropdownInput from '../components/input-dropdown';
import Button from '../components/button'; import Button from '../components/button';
import { useTokensSubscription, useSoftImageSrcResourceSubscription, SubscriptionResult } from '../require/guild-subscriptions'; import { useTokensSubscription, useSoftImageSrcResourceSubscription } from '../require/guild-subscriptions';
import TokenRow from '../components/token-row'; import TokenRow from '../components/token-row';
import { useRecoilValue } from 'recoil';
import { selectedGuildWithMetaState } from '../require/atoms';
const GuildInvitesDisplay: FC = () => {
export interface GuildInvitesDisplayProps { const guildWithMeta = useRecoilValue(selectedGuildWithMetaState);
guild: CombinedGuild; if (guildWithMeta === null || guildWithMeta.value === null) return null;
guildMetaResult: SubscriptionResult<GuildMetadata>;
}
const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDisplayProps) => {
const { guild, guildMetaResult } = props;
const url = 'https://localhost:3030'; // TODO: this will likely be a dropdown list at some point const url = 'https://localhost:3030'; // TODO: this will likely be a dropdown list at some point
const [ _fetchRetryCallable, tokensResult, tokensError ] = useTokensSubscription(guild); const [ _fetchRetryCallable, tokensResult, tokensError ] = useTokensSubscription(guildWithMeta.guild);
const [ expiresFromNow, setExpiresFromNow ] = useState<Duration | null>(moment.duration(1, 'day')); const [ expiresFromNow, setExpiresFromNow ] = useState<Duration | null>(moment.duration(1, 'day'));
const [ expiresFromNowText, setExpiresFromNowText ] = useState<string>('1 day'); const [ expiresFromNowText, setExpiresFromNowText ] = useState<string>('1 day');
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMetaResult.value.iconResourceId ?? null, guildMetaResult.guild); const [ iconSrc ] = useSoftImageSrcResourceSubscription(guildWithMeta.guild, guildWithMeta.value.iconResourceId ?? null, guildWithMeta.guild);
useEffect(() => { useEffect(() => {
if (expiresFromNowText === 'never') { if (expiresFromNowText === 'never') {
@ -46,14 +43,14 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
const [ createTokenFunc, tokenButtonText, tokenButtonShaking, _, createTokenFailMessage ] = useAsyncSubmitButton( const [ createTokenFunc, tokenButtonText, tokenButtonShaking, _, createTokenFailMessage ] = useAsyncSubmitButton(
async () => { async () => {
try { try {
const createdToken = await guild.requestDoCreateToken(expiresFromNowText === 'never' ? null : expiresFromNowText) const createdToken = await guildWithMeta.guild.requestDoCreateToken(expiresFromNowText === 'never' ? null : expiresFromNowText)
return { result: createdToken, errorMessage: null }; return { result: createdToken, errorMessage: null };
} catch (e: unknown) { } catch (e: unknown) {
LOG.error('error creating token', e); LOG.error('error creating token', e);
return { result: null, errorMessage: 'Error creating token' }; return { result: null, errorMessage: 'Error creating token' };
} }
}, },
[ guild, expiresFromNowText ], [ guildWithMeta, expiresFromNowText ],
{ start: 'Create Token', done: 'Create Another Token' } { start: 'Create Token', done: 'Create Another Token' }
); );
@ -67,11 +64,11 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
// TODO: Try Again // TODO: Try Again
return <div className="tokens-failed">Unable to load tokens</div>; return <div className="tokens-failed">Unable to load tokens</div>;
} }
if (!guildMetaResult) { if (!guildWithMeta?.value) {
return <div className="no-guild-meta">No Guild Metadata</div>; return <div className="no-guild-meta">No Guild Metadata</div>;
} }
return tokensResult?.value?.map((token: Token) => <TokenRow key={guild.id + token.token} url={url} guild={guild} token={token} guildMetaResult={guildMetaResult} />); return tokensResult?.value?.map((token: Token) => <TokenRow key={guildWithMeta.guild.id + token.token} url={url} token={token} />);
}, [ url, guild, tokensResult, tokensError ]); }, [ url, guildWithMeta, tokensResult, tokensError ]);
return ( return (
<Display <Display
@ -91,7 +88,7 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
<div><Button shaking={tokenButtonShaking} onClick={createTokenFunc}>{tokenButtonText}</Button></div> <div><Button shaking={tokenButtonShaking} onClick={createTokenFunc}>{tokenButtonText}</Button></div>
</div> </div>
<InvitePreview <InvitePreview
name={guildMetaResult.value.name ?? ''} iconSrc={iconSrc} name={guildWithMeta.value.name} iconSrc={iconSrc}
url={url} expiresFromNow={expiresFromNow} url={url} expiresFromNow={expiresFromNow}
/> />
</div> </div>

View File

@ -6,22 +6,20 @@ const LOG = Logger.create(__filename, electronConsole);
import React, { Dispatch, FC, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react'; import React, { Dispatch, FC, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react';
import Globals from '../../globals'; import Globals from '../../globals';
import CombinedGuild from '../../guild-combined';
import Display from '../components/display'; import Display from '../components/display';
import TextInput from '../components/input-text'; import TextInput from '../components/input-text';
import ImageEditInput from '../components/input-image-edit'; import ImageEditInput from '../components/input-image-edit';
import { SubscriptionResult, useResourceSubscription } from '../require/guild-subscriptions'; import { useResourceSubscription } from '../require/guild-subscriptions';
import { GuildMetadata } from '../../data-types'; import { useRecoilValue } from 'recoil';
import { selectedGuildWithMetaState } from '../require/atoms';
export interface GuildOverviewDisplayProps { const GuildOverviewDisplay: FC = () => {
guild: CombinedGuild; const guildWithMeta = useRecoilValue(selectedGuildWithMetaState);
guildMetaResult: SubscriptionResult<GuildMetadata>;
} if (guildWithMeta === null || guildWithMeta.value === null) return null;
const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOverviewDisplayProps) => {
const { guild, guildMetaResult } = props;
// TODO: Use the one from guild.tsx (for both of these?) // TODO: Use the one from guild.tsx (for both of these?)
const [ iconResourceResult, iconResourceError ] = useResourceSubscription(guild, guildMetaResult.value.iconResourceId, guildMetaResult.guild); const [ iconResourceResult, iconResourceError ] = useResourceSubscription(guildWithMeta.guild, guildWithMeta.value.iconResourceId, guildWithMeta.guild);
const [ savedName, setSavedName ] = useState<string | null>(null); const [ savedName, setSavedName ] = useState<string | null>(null);
const [ savedIconBuff, setSavedIconBuff ] = useState<Buffer | null>(null); const [ savedIconBuff, setSavedIconBuff ] = useState<Buffer | null>(null);
@ -39,11 +37,10 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
const [ iconInputMessage, setIconInputMessage ] = useState<string | null>(null); const [ iconInputMessage, setIconInputMessage ] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
if (guildMetaResult) { if (guildWithMeta === null || guildWithMeta.value === null) return;
if (name === savedName) setName(guildMetaResult.value.name); if (name === savedName) setName(guildWithMeta.value.name);
setSavedName(guildMetaResult.value.name); setSavedName(guildWithMeta.value.name);
} }, [ guildWithMeta ]);
}, [ guildMetaResult ]);
useEffect(() => { useEffect(() => {
if (iconResourceResult && iconResourceResult.value) { if (iconResourceResult && iconResourceResult.value) {
@ -84,7 +81,7 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
if (name !== savedName) { if (name !== savedName) {
// Save name // Save name
try { try {
await guild.requestSetGuildName(name); await guildWithMeta.guild.requestSetGuildName(name);
setSavedName(name); setSavedName(name);
} catch (e: unknown) { } catch (e: unknown) {
LOG.error('error setting guild name', e); LOG.error('error setting guild name', e);
@ -98,7 +95,7 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
// Save icon // Save icon
try { try {
LOG.debug('saving icon'); LOG.debug('saving icon');
await guild.requestSetGuildIcon(iconBuff); await guildWithMeta.guild.requestSetGuildIcon(iconBuff);
setSavedIconBuff(iconBuff); setSavedIconBuff(iconBuff);
} catch (e: unknown) { } catch (e: unknown) {
LOG.error('error setting guild icon', e); LOG.error('error setting guild icon', e);

View File

@ -49,7 +49,7 @@ const ChannelElement: FC<ChannelElementProps> = (props: ChannelElementProps) =>
}, [ modifyRef, channel ]); }, [ modifyRef, channel ]);
const launchModify = useCallback(() => { const launchModify = useCallback(() => {
setOverlay(<ChannelOverlay guild={guild} channel={channel} />); setOverlay(<ChannelOverlay channel={channel} />);
}, [ guild, channel ]); }, [ guild, channel ]);
return ( return (

View File

@ -4,7 +4,6 @@ import Logger from '../../../../logger/logger';
const LOG = Logger.create(__filename, electronConsole); const LOG = Logger.create(__filename, electronConsole);
import React, { FC, ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import React, { FC, ReactNode, useEffect, useMemo, useRef, useState } from 'react';
import CombinedGuild from '../../guild-combined';
import BaseElements from '../require/base-elements'; import BaseElements from '../require/base-elements';
import TextInput from '../components/input-text'; import TextInput from '../components/input-text';
import SubmitOverlayLower from '../components/submit-overlay-lower'; import SubmitOverlayLower from '../components/submit-overlay-lower';
@ -13,15 +12,17 @@ import { Channel } from '../../data-types';
import { useAsyncSubmitButton } from '../require/react-helper'; import { useAsyncSubmitButton } from '../require/react-helper';
import Button from '../components/button'; import Button from '../components/button';
import Overlay from '../components/overlay'; import Overlay from '../components/overlay';
import { useSetRecoilState } from 'recoil'; import { useRecoilValue, useSetRecoilState } from 'recoil';
import { overlayState } from '../require/atoms'; import { overlayState, selectedGuildState } from '../require/atoms';
export interface ChannelOverlayProps { export interface ChannelOverlayProps {
guild: CombinedGuild; channel?: Channel; // If this is undefined, this is an add-channel overlay
channel?: Channel;
} }
const ChannelOverlay: FC<ChannelOverlayProps> = (props: ChannelOverlayProps) => { const ChannelOverlay: FC<ChannelOverlayProps> = (props: ChannelOverlayProps) => {
const { guild, channel } = props; const { channel } = props;
const guild = useRecoilValue(selectedGuildState);
if (guild === null) return null;
const rootRef = useRef<HTMLDivElement>(null); const rootRef = useRef<HTMLDivElement>(null);
const nameInputRef = useRef<HTMLInputElement>(null); const nameInputRef = useRef<HTMLInputElement>(null);

View File

@ -1,18 +1,15 @@
import React, { FC, useEffect, useRef, useState } from "react"; import React, { FC, useEffect, useRef, useState } from "react";
import CombinedGuild from "../../guild-combined";
import ChoicesControl from "../components/control-choices"; import ChoicesControl from "../components/control-choices";
import GuildInvitesDisplay from "../displays/display-guild-invites"; import GuildInvitesDisplay from "../displays/display-guild-invites";
import GuildOverviewDisplay from "../displays/display-guild-overview"; import GuildOverviewDisplay from "../displays/display-guild-overview";
import { GuildMetadata } from '../../data-types';
import Overlay from '../components/overlay'; import Overlay from '../components/overlay';
import { SubscriptionResult } from '../require/guild-subscriptions'; import { useRecoilValue } from "recoil";
import { selectedGuildWithMetaState } from "../require/atoms";
export interface GuildSettingsOverlayProps { const GuildSettingsOverlay: FC = () => {
guild: CombinedGuild; const guildWithMeta = useRecoilValue(selectedGuildWithMetaState);
guildMetaResult: SubscriptionResult<GuildMetadata>;
} if (guildWithMeta === null || guildWithMeta.value === null) return null;
const GuildSettingsOverlay: FC<GuildSettingsOverlayProps> = (props: GuildSettingsOverlayProps) => {
const { guild, guildMetaResult } = props;
const rootRef = useRef<HTMLDivElement>(null); const rootRef = useRef<HTMLDivElement>(null);
@ -20,15 +17,15 @@ const GuildSettingsOverlay: FC<GuildSettingsOverlayProps> = (props: GuildSetting
const [ display, setDisplay ] = useState<JSX.Element>(); const [ display, setDisplay ] = useState<JSX.Element>();
useEffect(() => { useEffect(() => {
if (selectedId === 'overview') setDisplay(<GuildOverviewDisplay guild={guild} guildMetaResult={guildMetaResult} />); if (selectedId === 'overview') setDisplay(<GuildOverviewDisplay />);
//if (selectedId === 'roles' ) setDisplay(<GuildOverviewDisplay guild={guild} guildMeta={guildMeta} />); //if (selectedId === 'roles' ) setDisplay(<GuildOverviewDisplay guild={guild} guildMeta={guildMeta} />);
if (selectedId === 'invites' ) setDisplay(<GuildInvitesDisplay guild={guild} guildMetaResult={guildMetaResult} />); if (selectedId === 'invites' ) setDisplay(<GuildInvitesDisplay />);
}, [ selectedId ]); }, [ selectedId ]);
return ( return (
<Overlay childRootRef={rootRef}> <Overlay childRootRef={rootRef}>
<div ref={rootRef} className="content display-swapper guild-settings"> <div ref={rootRef} className="content display-swapper guild-settings">
<ChoicesControl title={guildMetaResult.value.name} selectedId={selectedId} setSelectedId={setSelectedId} choices={[ <ChoicesControl title={guildWithMeta.value.name ?? 'unknown guild'} selectedId={selectedId} setSelectedId={setSelectedId} choices={[
{ id: 'overview', display: 'Overview' }, { id: 'overview', display: 'Overview' },
{ id: 'roles', display: 'Roles' }, { id: 'roles', display: 'Roles' },
{ id: 'invites', display: 'Invites' }, { id: 'invites', display: 'Invites' },

View File

@ -703,13 +703,14 @@ function useMultipleGuildSubscriptionScrolling<
} }
/** /**
* @deprecated
* @param guild The guild to load from * @param guild The guild to load from
* @returns [ * @returns [
* guildMetaResult: The guild's metadata * guildMetaResult: The guild's metadata
* fetchError: Any error from fetching * fetchError: Any error from fetching
* ] * ]
*/ */
export function useGuildMetadataSubscription(guild: CombinedGuild) { function useGuildMetadataSubscription(guild: CombinedGuild) {
const fetchMetadataFunc = useCallback(async () => { const fetchMetadataFunc = useCallback(async () => {
//LOG.silly('fetching metadata for subscription'); //LOG.silly('fetching metadata for subscription');
return await guild.fetchMetadata(); return await guild.fetchMetadata();

View File

@ -1,18 +1,19 @@
import React, { FC, useMemo, useRef } from 'react'; import React, { FC, useMemo, useRef } from 'react';
import { GuildMetadata, Member } from '../../data-types'; import { useRecoilValue } from 'recoil';
import CombinedGuild from '../../guild-combined'; import { Member } from '../../data-types';
import GuildTitleContextMenu from '../contexts/context-menu-guild-title'; import GuildTitleContextMenu from '../contexts/context-menu-guild-title';
import { selectedGuildWithMetaState } from '../require/atoms';
import { isNonNullAndHasValue, SubscriptionResult } from '../require/guild-subscriptions'; import { isNonNullAndHasValue, SubscriptionResult } from '../require/guild-subscriptions';
import { useContextMenu } from '../require/react-helper'; import { useContextMenu } from '../require/react-helper';
export interface GuildTitleProps { export interface GuildTitleProps {
guild: CombinedGuild;
guildMetaResult: SubscriptionResult<GuildMetadata | null> | null;
selfMemberResult: SubscriptionResult<Member | null> | null; selfMemberResult: SubscriptionResult<Member | null> | null;
} }
const GuildTitle: FC<GuildTitleProps> = (props: GuildTitleProps) => { const GuildTitle: FC<GuildTitleProps> = (props: GuildTitleProps) => {
const { guild, guildMetaResult, selfMemberResult } = props; const { selfMemberResult } = props;
const guildWithMeta = useRecoilValue(selectedGuildWithMetaState)
const rootRef = useRef<HTMLDivElement>(null); const rootRef = useRef<HTMLDivElement>(null);
@ -25,16 +26,15 @@ const GuildTitle: FC<GuildTitleProps> = (props: GuildTitleProps) => {
}, [ selfMemberResult ]); }, [ selfMemberResult ]);
const [ contextMenu, toggleContextMenu ] = useContextMenu((close: () => void) => { const [ contextMenu, toggleContextMenu ] = useContextMenu((close: () => void) => {
if (!isNonNullAndHasValue(guildMetaResult)) return null;
if (!isNonNullAndHasValue(selfMemberResult)) return null; if (!isNonNullAndHasValue(selfMemberResult)) return null;
return ( return (
<GuildTitleContextMenu <GuildTitleContextMenu
relativeToRef={rootRef} close={close} relativeToRef={rootRef} close={close}
guild={guild} guildMetaResult={guildMetaResult} selfMember={selfMemberResult.value} selfMember={selfMemberResult.value}
/> />
); );
}, [ guild, guildMetaResult, selfMemberResult, rootRef ]); }, [ selfMemberResult, rootRef ]);
const nameStyle = useMemo(() => { const nameStyle = useMemo(() => {
if (hasContextMenu) { if (hasContextMenu) {
@ -47,7 +47,7 @@ const GuildTitle: FC<GuildTitleProps> = (props: GuildTitleProps) => {
return ( return (
<div className="guild-title" ref={rootRef}> <div className="guild-title" ref={rootRef}>
<div className="guild-name-container" style={nameStyle} onClick={hasContextMenu ? toggleContextMenu : undefined}> <div className="guild-name-container" style={nameStyle} onClick={hasContextMenu ? toggleContextMenu : undefined}>
<span className="guild-name">{guildMetaResult?.value?.name ?? null}</span> <span className="guild-name">{guildWithMeta?.value?.name ?? null}</span>
</div> </div>
{contextMenu} {contextMenu}
</div> </div>

View File

@ -9,7 +9,7 @@ import CombinedGuild from '../../guild-combined';
import ChannelList from '../lists/channel-list'; import ChannelList from '../lists/channel-list';
import MemberList from '../lists/member-list'; import MemberList from '../lists/member-list';
import MessageList from '../lists/message-list'; import MessageList from '../lists/message-list';
import { useSelfMemberSubscription, useGuildMetadataSubscription, useMembersSubscription, useChannelsSubscription } from '../require/guild-subscriptions'; import { useSelfMemberSubscription, useMembersSubscription, useChannelsSubscription } from '../require/guild-subscriptions';
import ChannelTitle from './channel-title'; import ChannelTitle from './channel-title';
import ConnectionInfo from './connection-info'; import ConnectionInfo from './connection-info';
import GuildTitle from './guild-title'; import GuildTitle from './guild-title';
@ -28,7 +28,6 @@ const GuildElement: FC<GuildElementProps> = (props: GuildElementProps) => {
// TODO: React jump messages to bottom when the current user sent a message // TODO: React jump messages to bottom when the current user sent a message
const [ selfMemberResult ] = useSelfMemberSubscription(guild); const [ selfMemberResult ] = useSelfMemberSubscription(guild);
const [ guildMetaResult, guildMetaFetchError ] = useGuildMetadataSubscription(guild);
const [ membersRetry, membersResult, membersFetchError ] = useMembersSubscription(guild); const [ membersRetry, membersResult, membersFetchError ] = useMembersSubscription(guild);
const [ channelsRetry, channelsResult, channelsFetchError ] = useChannelsSubscription(guild); const [ channelsRetry, channelsResult, channelsFetchError ] = useChannelsSubscription(guild);
@ -83,7 +82,7 @@ const GuildElement: FC<GuildElementProps> = (props: GuildElementProps) => {
return ( return (
<div className="guild-react"> <div className="guild-react">
<div className="guild-sidebar"> <div className="guild-sidebar">
<GuildTitle guild={guild} selfMemberResult={selfMemberResult} guildMetaResult={guildMetaResult} /> <GuildTitle selfMemberResult={selfMemberResult} />
<ChannelList <ChannelList
guild={guild} selfMember={selfMemberResult?.value ?? null} guild={guild} selfMember={selfMemberResult?.value ?? null}
channels={channelsResult?.value ?? null} channelsFetchError={channelsFetchError} channels={channelsResult?.value ?? null} channelsFetchError={channelsFetchError}