Fixed glaring bugs when switching between guilds
This commit is contained in:
parent
fa10c8a7a9
commit
e35187b877
@ -2,4 +2,4 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
};
|
||||
|
2363
package-lock.json
generated
2363
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,18 +13,19 @@ export interface TokenRowProps {
|
||||
url: string;
|
||||
guild: CombinedGuild;
|
||||
guildMeta: GuildMetadata;
|
||||
guildMetaGuild: CombinedGuild;
|
||||
token: Token;
|
||||
}
|
||||
|
||||
const TokenRow: FC<TokenRowProps> = (props: TokenRowProps) => {
|
||||
const { guild, guildMeta, token } = props;
|
||||
const { guild, guildMeta, guildMetaGuild, token } = props;
|
||||
|
||||
const [ guildSocketConfigs ] = useOneTimeAsyncAction(
|
||||
async () => await guild.fetchSocketConfigs(),
|
||||
null,
|
||||
[ guild ]
|
||||
);
|
||||
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta.iconResourceId);
|
||||
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta.iconResourceId, guildMetaGuild);
|
||||
|
||||
const [ revoke ] = useAsyncVoidCallback(async () => {
|
||||
await guild.requestDoRevokeToken(token.token);
|
||||
@ -51,7 +52,7 @@ const TokenRow: FC<TokenRowProps> = (props: TokenRowProps) => {
|
||||
|
||||
const userText = (token.member instanceof Member ? 'Used by ' + token.member.displayName : token.member?.id) ?? 'Unused Token';
|
||||
return (
|
||||
<div key={token.token} className="token-row">
|
||||
<div key={guild.id + token.token} className="token-row">
|
||||
<div className="user-token">
|
||||
<div className="user">{userText}</div>
|
||||
<div className="token">{token.token}</div>
|
||||
|
@ -7,13 +7,14 @@ import ContextMenu from './components/context-menu';
|
||||
export interface ConnectionInfoContextMenuProps {
|
||||
guild: CombinedGuild;
|
||||
selfMember: Member;
|
||||
selfMemberGuild: CombinedGuild;
|
||||
relativeToRef: RefObject<HTMLElement>;
|
||||
close: () => void;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const ConnectionInfoContextMenu: FC<ConnectionInfoContextMenuProps> = (props: ConnectionInfoContextMenuProps) => {
|
||||
const { guild, selfMember, relativeToRef, close, setOverlay } = props;
|
||||
const { guild, selfMember, selfMemberGuild, relativeToRef, close, setOverlay } = props;
|
||||
|
||||
const setSelfStatus = useCallback(async (status: string) => {
|
||||
if (selfMember.status !== status) {
|
||||
@ -35,8 +36,8 @@ const ConnectionInfoContextMenu: FC<ConnectionInfoContextMenuProps> = (props: Co
|
||||
|
||||
const openPersonalize = useCallback(() => {
|
||||
close();
|
||||
setOverlay(<PersonalizeOverlay guild={guild} selfMember={selfMember} close={() => setOverlay(null)} />);
|
||||
}, [ guild, selfMember, close ]);
|
||||
setOverlay(<PersonalizeOverlay guild={guild} selfMember={selfMember} selfMemberGuild={selfMemberGuild} close={() => setOverlay(null)} />);
|
||||
}, [ guild, selfMember, selfMemberGuild, close ]);
|
||||
|
||||
const alignment = useMemo(() => {
|
||||
return { bottom: 'top', centerX: 'centerX' }
|
||||
|
@ -11,17 +11,18 @@ export interface GuildTitleContextMenuProps {
|
||||
relativeToRef: RefObject<HTMLElement>;
|
||||
guild: CombinedGuild;
|
||||
guildMeta: GuildMetadata;
|
||||
guildMetaGuild: CombinedGuild;
|
||||
selfMember: Member;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const GuildTitleContextMenu: FC<GuildTitleContextMenuProps> = (props: GuildTitleContextMenuProps) => {
|
||||
const { close, relativeToRef, guild, guildMeta, selfMember, setOverlay } = props;
|
||||
const { close, relativeToRef, guild, guildMeta, guildMetaGuild, selfMember, setOverlay } = props;
|
||||
|
||||
const openGuildSettings = useCallback(() => {
|
||||
close();
|
||||
setOverlay(<GuildSettingsOverlay guild={guild} guildMeta={guildMeta} close={() => setOverlay(null)} />);
|
||||
}, [ guild, guildMeta, close ]);
|
||||
setOverlay(<GuildSettingsOverlay guild={guild} guildMeta={guildMeta} guildMetaGuild={guildMetaGuild} close={() => setOverlay(null)} />);
|
||||
}, [ guild, guildMeta, guildMetaGuild, close ]);
|
||||
|
||||
const openCreateChannel = useCallback(() => {
|
||||
close();
|
||||
|
@ -7,32 +7,32 @@ import React, { FC, useEffect, useMemo, useState } from 'react';
|
||||
import CombinedGuild from '../../guild-combined';
|
||||
import Display from '../components/display';
|
||||
import InvitePreview from '../components/invite-preview';
|
||||
import { Token } from '../../data-types';
|
||||
import { GuildMetadata, Token } from '../../data-types';
|
||||
import { useAsyncSubmitButton } from '../require/react-helper';
|
||||
import { Duration } from 'moment';
|
||||
import moment from 'moment';
|
||||
import DropdownInput from '../components/input-dropdown';
|
||||
import Button from '../components/button';
|
||||
import { useTokensSubscription, useGuildMetadataSubscription, useSoftImageSrcResourceSubscription } from '../require/guild-subscriptions';
|
||||
import { useTokensSubscription, useSoftImageSrcResourceSubscription } from '../require/guild-subscriptions';
|
||||
import TokenRow from '../components/token-row';
|
||||
|
||||
|
||||
export interface GuildInvitesDisplayProps {
|
||||
guild: CombinedGuild;
|
||||
guildMeta: GuildMetadata;
|
||||
guildMetaGuild: CombinedGuild;
|
||||
}
|
||||
const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDisplayProps) => {
|
||||
const { guild } = props;
|
||||
const { guild, guildMeta, guildMetaGuild } = props;
|
||||
|
||||
const url = 'https://localhost:3030'; // TODO: this will likely be a dropdown list at some point
|
||||
|
||||
const [ fetchRetryCallable, tokens, tokensGuild, tokensError ] = useTokensSubscription(guild);
|
||||
|
||||
const [ guildMeta, guildMetaGuild, guildMetaError ] = useGuildMetadataSubscription(guild);
|
||||
|
||||
const [ expiresFromNow, setExpiresFromNow ] = useState<Duration | null>(moment.duration(1, 'day'));
|
||||
const [ expiresFromNowText, setExpiresFromNowText ] = useState<string>('1 day');
|
||||
|
||||
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta?.iconResourceId ?? null);
|
||||
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta?.iconResourceId ?? null, guildMetaGuild);
|
||||
|
||||
useEffect(() => {
|
||||
if (expiresFromNowText === 'never') {
|
||||
@ -59,10 +59,9 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
|
||||
);
|
||||
|
||||
const errorMessage = useMemo(() => {
|
||||
if (guildMetaError) return 'Unable to load guild metadata';
|
||||
if (createTokenFailMessage) return createTokenFailMessage;
|
||||
return null;
|
||||
}, [ guildMetaError ]);
|
||||
}, [ createTokenFailMessage ]);
|
||||
|
||||
const tokenElements = useMemo(() => {
|
||||
if (tokensError) {
|
||||
@ -72,7 +71,7 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
|
||||
if (!guildMeta) {
|
||||
return <div className="no-guild-meta">No Guild Metadata</div>;
|
||||
}
|
||||
return tokens?.map((token: Token) => <TokenRow key={token.token} url={url} guild={guild} token={token} guildMeta={guildMeta} />);
|
||||
return tokens?.map((token: Token) => <TokenRow key={guild.id + token.token} url={url} guild={guild} token={token} guildMeta={guildMeta} guildMetaGuild={guildMetaGuild} />);
|
||||
}, [ url, guild, tokens, tokensError ]);
|
||||
|
||||
return (
|
||||
|
@ -10,17 +10,19 @@ import CombinedGuild from '../../guild-combined';
|
||||
import Display from '../components/display';
|
||||
import TextInput from '../components/input-text';
|
||||
import ImageEditInput from '../components/input-image-edit';
|
||||
import { useGuildMetadataSubscription, useResourceSubscription } from '../require/guild-subscriptions';
|
||||
import { useResourceSubscription } from '../require/guild-subscriptions';
|
||||
import { GuildMetadata } from '../../data-types';
|
||||
|
||||
export interface GuildOverviewDisplayProps {
|
||||
guild: CombinedGuild;
|
||||
guildMeta: GuildMetadata;
|
||||
guildMetaGuild: CombinedGuild;
|
||||
}
|
||||
const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOverviewDisplayProps) => {
|
||||
const { guild } = props;
|
||||
const { guild, guildMeta, guildMetaGuild } = props;
|
||||
|
||||
// TODO: Use the one from guild.tsx (for both of these?)
|
||||
const [ guildMeta, guildMetaGuild, guildMetaError ] = useGuildMetadataSubscription(guild);
|
||||
const [ iconResource, iconResourceGuild, iconResourceError ] = useResourceSubscription(guild, guildMeta?.iconResourceId ?? null);
|
||||
const [ iconResource, iconResourceGuild, iconResourceError ] = useResourceSubscription(guild, guildMeta?.iconResourceId ?? null, guildMetaGuild);
|
||||
|
||||
const [ savedName, setSavedName ] = useState<string | null>(null);
|
||||
const [ savedIconBuff, setSavedIconBuff ] = useState<Buffer | null>(null);
|
||||
@ -56,12 +58,11 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
|
||||
}, [ name, savedName, iconBuff, savedIconBuff ]);
|
||||
|
||||
const errorMessage = useMemo(() => {
|
||||
if (guildMetaError) return 'Unable to load guild metadata';
|
||||
if (iconResourceError) return 'Unable to load icon';
|
||||
if (!iconInputValid && iconInputMessage) return iconInputMessage;
|
||||
if (!nameInputValid && nameInputMessage) return nameInputMessage;
|
||||
return null;
|
||||
}, [ guildMetaError, iconResourceError, iconInputValid, iconInputMessage, nameInputValid, nameInputMessage ]);
|
||||
}, [ iconResourceError, iconInputValid, iconInputMessage, nameInputValid, nameInputMessage ]);
|
||||
|
||||
const infoMessage = useMemo(() => {
|
||||
if (iconInputValid && iconInputMessage) return iconInputMessage;
|
||||
|
@ -31,7 +31,7 @@ const ChannelList: FC<ChannelListProps> = (props: ChannelListProps) => {
|
||||
}
|
||||
return channels.map((channel: Channel) => (
|
||||
<ChannelElement
|
||||
key={channel.id} guild={guild}
|
||||
key={guild.id + channel.id} guild={guild}
|
||||
selfMember={selfMember}
|
||||
channel={channel} activeChannel={activeChannel}
|
||||
setActiveChannel={() => { setActiveChannel(channel); }}
|
||||
|
@ -24,7 +24,7 @@ const GuildListElement: FC<GuildListElementProps> = (props: GuildListElementProp
|
||||
// TODO: handle metadata error
|
||||
const [ guildMeta, guildMetaGuild, guildMetaError ] = useGuildMetadataSubscription(guild);
|
||||
const [ selfMember ] = useSelfMemberSubscription(guild);
|
||||
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta?.iconResourceId ?? null);
|
||||
const [ iconSrc ] = useSoftImageSrcResourceSubscription(guild, guildMeta?.iconResourceId ?? null, guildMetaGuild);
|
||||
|
||||
const [ contextHover, mouseEnterCallable, mouseLeaveCallable ] = useContextHover(() => {
|
||||
if (!guildMeta) return null;
|
||||
|
@ -1,4 +1,9 @@
|
||||
import React, { FC, useMemo } from 'react';
|
||||
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 React, { FC, useMemo, useEffect } from 'react';
|
||||
import { Member } from '../../../data-types';
|
||||
import CombinedGuild from '../../../guild-combined';
|
||||
import { useSoftImageSrcResourceSubscription } from '../../require/guild-subscriptions';
|
||||
@ -14,12 +19,13 @@ export interface DummyMember {
|
||||
export interface MemberProps {
|
||||
guild: CombinedGuild;
|
||||
member: Member | DummyMember;
|
||||
memberGuild: CombinedGuild | null;
|
||||
}
|
||||
|
||||
const MemberElement: FC<MemberProps> = (props: MemberProps) => {
|
||||
const { guild, member } = props;
|
||||
const { guild, member, memberGuild } = props;
|
||||
|
||||
const [ avatarSrc ] = useSoftImageSrcResourceSubscription(guild, member.avatarResourceId);
|
||||
const [ avatarSrc ] = useSoftImageSrcResourceSubscription(guild, member.avatarResourceId, memberGuild);
|
||||
|
||||
const nameStyle = useMemo(() => member.roleColor ? { color: member.roleColor } : {}, [ member.roleColor ]);
|
||||
|
||||
@ -37,4 +43,4 @@ const MemberElement: FC<MemberProps> = (props: MemberProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
export default MemberElement;
|
||||
export default MemberElement;
|
||||
|
@ -46,14 +46,15 @@ interface PreviewImageElementProps {
|
||||
resourcePreviewId: string;
|
||||
resourceId: string;
|
||||
resourceName: string;
|
||||
resourceIdGuild: CombinedGuild;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const PreviewImageElement: FC<PreviewImageElementProps> = (props: PreviewImageElementProps) => {
|
||||
const { guild, previewWidth, previewHeight, resourcePreviewId, resourceId, resourceName, setOverlay } = props;
|
||||
const { guild, previewWidth, previewHeight, resourcePreviewId, resourceId, resourceName, resourceIdGuild, setOverlay } = props;
|
||||
|
||||
// TODO: Handle resourceError
|
||||
const [ previewImgSrc, previewResource, previewResourceGuild, previewResourceError ] = useSoftImageSrcResourceSubscription(guild, resourcePreviewId);
|
||||
const [ previewImgSrc, previewResource, previewResourceGuild, previewResourceError ] = useSoftImageSrcResourceSubscription(guild, resourcePreviewId, resourceIdGuild);
|
||||
|
||||
const [ contextMenu, onContextMenu ] = useContextClickContextMenu((alignment: IAlignment, relativeToPos: { x: number, y: number }, close: () => void) => {
|
||||
if (!previewResource) return null;
|
||||
@ -66,7 +67,7 @@ const PreviewImageElement: FC<PreviewImageElementProps> = (props: PreviewImageEl
|
||||
}, [ previewResource, resourceName ]);
|
||||
|
||||
const openImageOverlay = useCallback(() => {
|
||||
setOverlay(<ImageOverlay guild={guild} resourceId={resourceId} resourceName={resourceName} close={() => setOverlay(null)} />);
|
||||
setOverlay(<ImageOverlay guild={guild} resourceId={resourceId} resourceName={resourceName} resourceIdGuild={resourceIdGuild} close={() => setOverlay(null)} />);
|
||||
}, [ guild, resourceId, resourceName ]);
|
||||
|
||||
return (
|
||||
@ -84,11 +85,12 @@ export interface MessageElementProps {
|
||||
guild: CombinedGuild;
|
||||
message: Message;
|
||||
prevMessage: Message | null;
|
||||
messageGuild: CombinedGuild;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const MessageElement: FC<MessageElementProps> = (props: MessageElementProps) => {
|
||||
const { guild, message, prevMessage, setOverlay } = props;
|
||||
const { guild, message, prevMessage, messageGuild, setOverlay } = props;
|
||||
|
||||
const className = useMemo(() => {
|
||||
return message.isContinued(prevMessage) ? 'message-react continued' : 'message-react';
|
||||
@ -142,6 +144,7 @@ const MessageElement: FC<MessageElementProps> = (props: MessageElementProps) =>
|
||||
previewWidth={message.previewWidth} previewHeight={message.previewHeight}
|
||||
resourcePreviewId={message.resourcePreviewId}
|
||||
resourceId={message.resourceId}
|
||||
resourceIdGuild={messageGuild}
|
||||
resourceName={message.resourceName ?? 'unknown.unk'}
|
||||
setOverlay={setOverlay}
|
||||
/>
|
||||
|
@ -6,22 +6,23 @@ import MemberElement from './components/member-element';
|
||||
export interface MemberListProps {
|
||||
guild: CombinedGuild;
|
||||
members: Member[] | null;
|
||||
membersGuild: CombinedGuild | null;
|
||||
membersFetchError: unknown | null;
|
||||
}
|
||||
|
||||
const MemberList: FC<MemberListProps> = (props: MemberListProps) => {
|
||||
const { guild, members, membersFetchError } = props;
|
||||
const { guild, members, membersGuild, membersFetchError } = props;
|
||||
|
||||
const memberElements = useMemo(() => {
|
||||
if (membersFetchError) {
|
||||
// TODO: Try Again
|
||||
return <div className="members-failed">Unable to load members</div>
|
||||
}
|
||||
if (!members) {
|
||||
if (!members || !membersGuild) {
|
||||
return <div className="members-loading">Loading members...</div>
|
||||
}
|
||||
return members?.map((member: Member) => <MemberElement key={member.id} guild={guild} member={member} />);
|
||||
}, [ guild, members, membersFetchError ]);
|
||||
return members?.map((member: Member) => <MemberElement key={guild.id + member.id} guild={guild} member={member} memberGuild={membersGuild} />);
|
||||
}, [ guild, members, membersGuild, membersFetchError ]);
|
||||
|
||||
return (
|
||||
<div className="member-list">
|
||||
@ -30,4 +31,4 @@ const MemberList: FC<MemberListProps> = (props: MemberListProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default MemberList;
|
||||
export default MemberList;
|
||||
|
@ -13,11 +13,12 @@ import { useMessagesScrollingSubscription } from '../require/guild-subscriptions
|
||||
interface MessageListProps {
|
||||
guild: CombinedGuild;
|
||||
channel: Channel;
|
||||
channelGuild: CombinedGuild;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const MessageList: FC<MessageListProps> = (props: MessageListProps) => {
|
||||
const { guild, channel, setOverlay } = props;
|
||||
const { guild, channel, channelGuild, setOverlay } = props;
|
||||
|
||||
const [
|
||||
fetchRetryCallable,
|
||||
@ -30,19 +31,19 @@ const MessageList: FC<MessageListProps> = (props: MessageListProps) => {
|
||||
messagesFetchError,
|
||||
messagesFetchAboveError,
|
||||
messagesFetchBelowError
|
||||
] = useMessagesScrollingSubscription(guild, channel);
|
||||
] = useMessagesScrollingSubscription(guild, channel, channelGuild);
|
||||
|
||||
const messageElements = useMemo(() => {
|
||||
const result = [];
|
||||
if (messages) {
|
||||
if (messages && messagesGuild) {
|
||||
for (let i = 0; i < messages.length; ++i) {
|
||||
const prevMessage = messages[i - 1] ?? null;
|
||||
const message = messages[i] as Message;
|
||||
result.push(<MessageElement key={message.id} guild={guild} message={message} prevMessage={prevMessage} setOverlay={setOverlay} />);
|
||||
result.push(<MessageElement key={guild.id + message.id} guild={guild} message={message} prevMessage={prevMessage} messageGuild={messagesGuild} setOverlay={setOverlay} />);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, [ messages ]);
|
||||
}, [ messages, messagesGuild ]);
|
||||
|
||||
return (
|
||||
<div className="message-list">
|
||||
|
@ -14,10 +14,11 @@ import Overlay from '../components/overlay';
|
||||
export interface GuildSettingsOverlayProps {
|
||||
guild: CombinedGuild;
|
||||
guildMeta: GuildMetadata;
|
||||
guildMetaGuild: CombinedGuild;
|
||||
close: () => void;
|
||||
}
|
||||
const GuildSettingsOverlay: FC<GuildSettingsOverlayProps> = (props: GuildSettingsOverlayProps) => {
|
||||
const { guild, guildMeta, close } = props;
|
||||
const { guild, guildMeta, guildMetaGuild, close } = props;
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -25,9 +26,9 @@ const GuildSettingsOverlay: FC<GuildSettingsOverlayProps> = (props: GuildSetting
|
||||
const [ display, setDisplay ] = useState<JSX.Element>();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedId === 'overview') setDisplay(<GuildOverviewDisplay guild={guild} />);
|
||||
if (selectedId === 'overview') setDisplay(<GuildOverviewDisplay guild={guild} guildMeta={guildMeta} guildMetaGuild={guildMetaGuild} />);
|
||||
//if (selectedId === 'roles' ) setDisplay(<GuildOverviewDisplay guild={guild} guildMeta={guildMeta} />);
|
||||
if (selectedId === 'invites' ) setDisplay(<GuildInvitesDisplay guild={guild} />);
|
||||
if (selectedId === 'invites' ) setDisplay(<GuildInvitesDisplay guild={guild} guildMeta={guildMeta} guildMetaGuild={guildMetaGuild} />);
|
||||
}, [ selectedId ]);
|
||||
|
||||
return (
|
||||
|
@ -13,18 +13,19 @@ import Overlay from '../components/overlay';
|
||||
import { useSoftImageSrcResourceSubscription } from '../require/guild-subscriptions';
|
||||
|
||||
export interface ImageOverlayProps {
|
||||
guild: CombinedGuild
|
||||
resourceId: string,
|
||||
resourceName: string,
|
||||
guild: CombinedGuild;
|
||||
resourceId: string;
|
||||
resourceName: string;
|
||||
resourceIdGuild: CombinedGuild;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
const ImageOverlay: FC<ImageOverlayProps> = (props: ImageOverlayProps) => {
|
||||
const { guild, resourceId, resourceName, close } = props;
|
||||
const { guild, resourceId, resourceName, resourceIdGuild, close } = props;
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [ imgSrc, resource, resourceGuild, resourceError ] = useSoftImageSrcResourceSubscription(guild, resourceId);
|
||||
const [ imgSrc, resource, resourceGuild, resourceError ] = useSoftImageSrcResourceSubscription(guild, resourceId, resourceIdGuild);
|
||||
|
||||
const [ contextMenu, onContextMenu ] = useContextClickContextMenu((alignment: IAlignment, relativeToPos: { x: number, y: number }, close: () => void) => {
|
||||
if (!resource) return null;
|
||||
|
@ -18,14 +18,15 @@ import { useResourceSubscription } from '../require/guild-subscriptions';
|
||||
export interface PersonalizeOverlayProps {
|
||||
guild: CombinedGuild;
|
||||
selfMember: Member;
|
||||
selfMemberGuild: CombinedGuild;
|
||||
close: () => void;
|
||||
}
|
||||
const PersonalizeOverlay: FC<PersonalizeOverlayProps> = (props: PersonalizeOverlayProps) => {
|
||||
const { guild, selfMember, close } = props;
|
||||
const { guild, selfMember, selfMemberGuild, close } = props;
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [ avatarResource, avatarResourceGuild, avatarResourceError ] = useResourceSubscription(guild, selfMember.avatarResourceId)
|
||||
const [ avatarResource, avatarResourceGuild, avatarResourceError ] = useResourceSubscription(guild, selfMember.avatarResourceId, selfMemberGuild);
|
||||
|
||||
const displayNameInputRef = createRef<HTMLInputElement>();
|
||||
|
||||
|
@ -234,6 +234,7 @@ function useMultipleGuildSubscription<
|
||||
|
||||
const onFetch = useCallback((fetchValue: T[] | null, fetchValueGuild: CombinedGuild) => {
|
||||
if (fetchValue) fetchValue.sort(sortFunc);
|
||||
/* LOG.debug('onFetch', { valueType: (fetchValue?.length && (fetchValue[0] as T).constructor.name) ?? 'null', guild: fetchValueGuild.id }); */
|
||||
setValue(fetchValue);
|
||||
setValueGuild(fetchValueGuild);
|
||||
setFetchError(null);
|
||||
@ -488,6 +489,7 @@ function useMultipleGuildSubscriptionScrolling<
|
||||
if (fetchValue.length >= maxFetchElements) hasMoreAbove = true;
|
||||
fetchValue = fetchValue.slice(Math.max(fetchValue.length - maxElements)).sort(sortFunc);
|
||||
}
|
||||
//LOG.debug('Got items: ', { fetchValueLength: fetchValue?.length ?? '<empty>' })
|
||||
setFetchResult({ hasMoreAbove, hasMoreBelow: false });
|
||||
setValue(fetchValue);
|
||||
setValueGuild(fetchValueGuild);
|
||||
@ -630,12 +632,15 @@ export function useGuildMetadataSubscription(guild: CombinedGuild) {
|
||||
}, fetchMetadataFunc);
|
||||
}
|
||||
|
||||
export function useResourceSubscription(guild: CombinedGuild, resourceId: string | null) {
|
||||
export function useResourceSubscription(guild: CombinedGuild, resourceId: string | null, resourceIdGuild: CombinedGuild | null) {
|
||||
const fetchResourceFunc = useCallback(async () => {
|
||||
// TODO: This function isn't working for the members list
|
||||
//LOG.silly('fetching resource for subscription (resourceId: ' + resourceId + ')');
|
||||
if (resourceId === null) return null;
|
||||
if (resourceIdGuild === null) return null;
|
||||
if (resourceIdGuild !== guild) return null;
|
||||
return await guild.fetchResource(resourceId);
|
||||
}, [ guild, resourceId ]);
|
||||
}, [ guild, resourceIdGuild, resourceId ]);
|
||||
return useSingleGuildSubscription<Resource, 'update-resource', 'conflict-resource'>(guild, {
|
||||
updatedEventName: 'update-resource',
|
||||
updatedEventArgsMap: (resource: Resource) => resource,
|
||||
@ -644,11 +649,17 @@ export function useResourceSubscription(guild: CombinedGuild, resourceId: string
|
||||
}, fetchResourceFunc);
|
||||
}
|
||||
|
||||
export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null): [ imgSrc: string, resource: Resource | null, resourceGuild: CombinedGuild | null, fetchError: unknown | null ] {
|
||||
const [ resource, resourceGuild, fetchError ] = useResourceSubscription(guild, resourceId);
|
||||
export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null, resourceIdGuild: CombinedGuild | null): [
|
||||
imgSrc: string,
|
||||
resource: Resource | null,
|
||||
resourceGuild: CombinedGuild | null,
|
||||
fetchError: unknown | null
|
||||
] {
|
||||
const [ resource, resourceGuild, fetchError ] = useResourceSubscription(guild, resourceId, resourceIdGuild);
|
||||
|
||||
const [ imgSrc ] = useOneTimeAsyncAction(
|
||||
async () => {
|
||||
//LOG.debug(`Fetching soft imgSrc for g#${guild.id} r#${resource?.id ?? '<null>'}`, { fetchError });
|
||||
if (fetchError) return './img/error.png';
|
||||
if (!resource) return './img/loading.svg';
|
||||
return await ElementsUtil.getImageSrcFromBufferFailSoftly(resource.data);
|
||||
@ -732,18 +743,24 @@ export function useTokensSubscription(guild: CombinedGuild) {
|
||||
}, fetchTokensFunc);
|
||||
}
|
||||
|
||||
export function useMessagesScrollingSubscription(guild: CombinedGuild, channel: Channel) {
|
||||
export function useMessagesScrollingSubscription(guild: CombinedGuild, channel: Channel, channelGuild: CombinedGuild) {
|
||||
const maxFetchElements = Globals.MESSAGES_PER_REQUEST;
|
||||
const maxElements = Globals.MAX_CURRENT_MESSAGES;
|
||||
const fetchMessagesFunc = useCallback(async () => {
|
||||
if (guild !== channelGuild) {
|
||||
LOG.debug('not loading messages from guild differences');
|
||||
return [];
|
||||
}
|
||||
return await guild.fetchMessagesRecent(channel.id, maxFetchElements);
|
||||
}, [ guild, channel.id, maxFetchElements ]);
|
||||
}, [ guild, channelGuild, channel.id, maxFetchElements ]);
|
||||
const fetchAboveFunc = useCallback(async (reference: Message) => {
|
||||
if (guild !== channelGuild) return [];
|
||||
return await guild.fetchMessagesBefore(channel.id, reference.id, maxFetchElements);
|
||||
}, [ guild, channel.id, maxFetchElements ]);
|
||||
}, [ guild, channelGuild, channel.id, maxFetchElements ]);
|
||||
const fetchBelowFunc = useCallback(async (reference: Message) => {
|
||||
if (guild !== channelGuild) return [];
|
||||
return await guild.fetchMessagesAfter(channel.id, reference.id, maxFetchElements);
|
||||
}, [ guild, channel.id, maxFetchElements ]);
|
||||
}, [ guild, channelGuild, channel.id, maxFetchElements ]);
|
||||
return useMultipleGuildSubscriptionScrolling(
|
||||
guild, {
|
||||
newEventName: 'new-messages',
|
||||
|
@ -13,11 +13,12 @@ import { useContextMenu } from '../require/react-helper';
|
||||
export interface ConnectionInfoProps {
|
||||
guild: CombinedGuild;
|
||||
selfMember: Member | null;
|
||||
selfMemberGuild: CombinedGuild | null;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const ConnectionInfo: FC<ConnectionInfoProps> = (props: ConnectionInfoProps) => {
|
||||
const { guild, selfMember, setOverlay } = props;
|
||||
const { guild, selfMember, selfMemberGuild, setOverlay } = props;
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -35,10 +36,10 @@ const ConnectionInfo: FC<ConnectionInfoProps> = (props: ConnectionInfoProps) =>
|
||||
}, [ selfMember ]);
|
||||
|
||||
const [ contextMenu, toggleContextMenu ] = useContextMenu((close: () => void) => {
|
||||
if (!selfMember) return null;
|
||||
if (!selfMember || !selfMemberGuild) return null;
|
||||
return (
|
||||
<ConnectionInfoContextMenu
|
||||
guild={guild} selfMember={selfMember} relativeToRef={rootRef}
|
||||
guild={guild} selfMember={selfMember} selfMemberGuild={selfMemberGuild} relativeToRef={rootRef}
|
||||
close={close} setOverlay={setOverlay}
|
||||
/>
|
||||
);
|
||||
@ -46,7 +47,7 @@ const ConnectionInfo: FC<ConnectionInfoProps> = (props: ConnectionInfoProps) =>
|
||||
|
||||
return (
|
||||
<div ref={rootRef} className="connection-info">
|
||||
<div onClick={toggleContextMenu}><MemberElement guild={guild} member={displayMember} /></div>
|
||||
<div onClick={toggleContextMenu}><MemberElement guild={guild} member={displayMember} memberGuild={selfMemberGuild} /></div>
|
||||
{contextMenu}
|
||||
</div>
|
||||
);
|
||||
|
@ -7,12 +7,14 @@ import { useContextMenu } from '../require/react-helper';
|
||||
export interface GuildTitleProps {
|
||||
guild: CombinedGuild;
|
||||
guildMeta: GuildMetadata | null;
|
||||
guildMetaGuild: CombinedGuild | null;
|
||||
selfMember: Member | null;
|
||||
selfMemberGuild: CombinedGuild | null;
|
||||
setOverlay: Dispatch<SetStateAction<ReactNode>>;
|
||||
}
|
||||
|
||||
const GuildTitle: FC<GuildTitleProps> = (props: GuildTitleProps) => {
|
||||
const { guild, guildMeta, selfMember, setOverlay } = props;
|
||||
const { guild, guildMeta, guildMetaGuild, selfMember, selfMemberGuild, setOverlay } = props;
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -27,16 +29,16 @@ const GuildTitle: FC<GuildTitleProps> = (props: GuildTitleProps) => {
|
||||
}, [ selfMember ]);
|
||||
|
||||
const [ contextMenu, toggleContextMenu ] = useContextMenu((close: () => void) => {
|
||||
if (!guildMeta) return null;
|
||||
if (!selfMember) return null;
|
||||
if (!guildMeta || !guildMetaGuild) return null;
|
||||
if (!selfMember || !selfMemberGuild) return null;
|
||||
return (
|
||||
<GuildTitleContextMenu
|
||||
relativeToRef={rootRef} close={close}
|
||||
guild={guild} guildMeta={guildMeta} selfMember={selfMember}
|
||||
guild={guild} guildMeta={guildMeta} guildMetaGuild={guildMetaGuild} selfMember={selfMember}
|
||||
setOverlay={setOverlay}
|
||||
/>
|
||||
);
|
||||
}, [ guild, guildMeta, selfMember, rootRef ]);
|
||||
}, [ guild, guildMeta, guildMetaGuild, selfMember, selfMemberGuild, rootRef ]);
|
||||
|
||||
const nameStyle = useMemo(() => {
|
||||
if (hasContextMenu) {
|
||||
|
@ -1,3 +1,8 @@
|
||||
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 React, { Dispatch, FC, ReactNode, SetStateAction, useEffect, useState } from 'react';
|
||||
import { Channel } from '../../data-types';
|
||||
import CombinedGuild from '../../guild-combined';
|
||||
@ -27,8 +32,8 @@ const GuildElement: FC<GuildElementProps> = (props: GuildElementProps) => {
|
||||
const [ guildMeta, guildMetaGuild, guildMetaFetchError ] = useGuildMetadataSubscription(guild);
|
||||
const [ membersRetry, members, membersGuild, membersFetchError ] = useMembersSubscription(guild);
|
||||
const [ channelsRetry, channels, channelsGuild, channelsFetchError ] = useChannelsSubscription(guild);
|
||||
|
||||
const [ activeChannel, setActiveChannel ] = useState<Channel | null>(null);
|
||||
const [ activeChannelGuild, setActiveChannelGuild ] = useState<CombinedGuild | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveChannel(null);
|
||||
@ -37,36 +42,41 @@ const GuildElement: FC<GuildElementProps> = (props: GuildElementProps) => {
|
||||
useEffect(() => {
|
||||
if (activeChannel === null) {
|
||||
// initial active channel is the first one in the list
|
||||
if (channels && channels.length > 0) {
|
||||
if (channels && channelsGuild && channels.length > 0) {
|
||||
setActiveChannel(channels[0] as Channel);
|
||||
setActiveChannelGuild(channelsGuild);
|
||||
//LOG.debug('Active channel guild enabled', { channel: channels[0]?.id, channelsGuild: channelsGuild?.id });
|
||||
}
|
||||
} else if (channels && activeChannel) {
|
||||
} else if (channels && channelsGuild && activeChannel) {
|
||||
// in the active channel was updated
|
||||
setActiveChannel(channels.find(channel => channel.id === activeChannel.id) ?? null);
|
||||
const newActiveChannel = channels.find(channel => channel.id === activeChannel.id) ?? null
|
||||
setActiveChannel(newActiveChannel);
|
||||
setActiveChannelGuild(channelsGuild);
|
||||
//LOG.debug('Active channel was updated...', { channel: newActiveChannel?.id, channelsGuild: channelsGuild?.id });
|
||||
}
|
||||
}, [ channels, activeChannel ]);
|
||||
}, [ channels, channelsGuild, activeChannel ]);
|
||||
|
||||
return (
|
||||
<div className="guild-react">
|
||||
<div className="guild-sidebar">
|
||||
<GuildTitle guild={guild} selfMember={selfMember} guildMeta={guildMeta} setOverlay={setOverlay} />
|
||||
<GuildTitle guild={guild} selfMember={selfMember} selfMemberGuild={selfMemberGuild} guildMeta={guildMeta} guildMetaGuild={guildMetaGuild} setOverlay={setOverlay} />
|
||||
<ChannelList
|
||||
guild={guild} selfMember={selfMember}
|
||||
channels={channels} channelsFetchError={channelsFetchError}
|
||||
activeChannel={activeChannel} setActiveChannel={setActiveChannel}
|
||||
setOverlay={setOverlay}
|
||||
/>
|
||||
<ConnectionInfo guild={guild} selfMember={selfMember} setOverlay={setOverlay} />
|
||||
<ConnectionInfo guild={guild} selfMember={selfMember} selfMemberGuild={selfMemberGuild} setOverlay={setOverlay} />
|
||||
</div>
|
||||
<div className="guild-channel">
|
||||
<ChannelTitle channel={activeChannel} />
|
||||
<div className="guild-channel-content">
|
||||
<div className="guild-channel-feed-wrapper">
|
||||
{activeChannel && <MessageList guild={guild} channel={activeChannel} setOverlay={setOverlay} />}
|
||||
{activeChannel && <SendMessage guild={guild} channel={activeChannel} />}
|
||||
{activeChannel && activeChannelGuild && <MessageList guild={guild} channel={activeChannel} channelGuild={activeChannelGuild} setOverlay={setOverlay} />}
|
||||
{activeChannel && activeChannelGuild && <SendMessage guild={guild} channel={activeChannel} />}
|
||||
</div>
|
||||
<div className="member-list-wrapper">
|
||||
<MemberList guild={guild} members={members} membersFetchError={membersFetchError} />
|
||||
<MemberList guild={guild} members={members} membersGuild={membersGuild} membersFetchError={membersFetchError} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user