Add current user object that holds user session values instead of standalone getters. Closes #2050

This commit is contained in:
Gabe Kangas 2022-10-10 16:26:09 -07:00
parent d94723bd3a
commit 80a012a3c7
No known key found for this signature in database
GPG key ID: 9A56337728BC81EA
12 changed files with 103 additions and 98 deletions

View file

@ -9,5 +9,6 @@
"linkify", "linkify",
"paypal", "paypal",
"toggleswitch" "toggleswitch"
] ],
"deepscan.enable": true
} }

View file

@ -12,7 +12,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { import {
chatVisibleToggleAtom, chatVisibleToggleAtom,
chatDisplayNameAtom, currentUserAtom,
appStateAtom, appStateAtom,
} from '../../stores/ClientConfigStore'; } from '../../stores/ClientConfigStore';
import styles from './UserDropdown.module.scss'; import styles from './UserDropdown.module.scss';
@ -34,12 +34,19 @@ export type UserDropdownProps = {
}; };
export const UserDropdown: FC<UserDropdownProps> = ({ username: defaultUsername = undefined }) => { export const UserDropdown: FC<UserDropdownProps> = ({ username: defaultUsername = undefined }) => {
const username = defaultUsername || useRecoilValue(chatDisplayNameAtom);
const [showNameChangeModal, setShowNameChangeModal] = useState<boolean>(false); const [showNameChangeModal, setShowNameChangeModal] = useState<boolean>(false);
const [showAuthModal, setShowAuthModal] = useState<boolean>(false); const [showAuthModal, setShowAuthModal] = useState<boolean>(false);
const [chatToggleVisible, setChatToggleVisible] = useRecoilState(chatVisibleToggleAtom); const [chatToggleVisible, setChatToggleVisible] = useRecoilState(chatVisibleToggleAtom);
const appState = useRecoilValue<AppStateOptions>(appStateAtom); const appState = useRecoilValue<AppStateOptions>(appStateAtom);
const currentUser = useRecoilValue(currentUserAtom);
if (!currentUser) {
return null;
}
const { displayName } = currentUser;
const username = defaultUsername || displayName;
const toggleChatVisibility = () => { const toggleChatVisibility = () => {
setChatToggleVisible(!chatToggleVisible); setChatToggleVisible(!chatToggleVisible);
}; };

View file

@ -9,7 +9,7 @@ import IndieAuthIcon from '../../../assets/images/indieauth.png';
import styles from './AuthModal.module.scss'; import styles from './AuthModal.module.scss';
import { import {
chatDisplayNameAtom, currentUserAtom,
chatAuthenticatedAtom, chatAuthenticatedAtom,
accessTokenAtom, accessTokenAtom,
} from '../../stores/ClientConfigStore'; } from '../../stores/ClientConfigStore';
@ -17,10 +17,15 @@ import {
const { TabPane } = Tabs; const { TabPane } = Tabs;
export const AuthModal: FC = () => { export const AuthModal: FC = () => {
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom); const currentUser = useRecoilValue(currentUserAtom);
if (!currentUser) {
return null;
}
const authenticated = useRecoilValue<boolean>(chatAuthenticatedAtom); const authenticated = useRecoilValue<boolean>(chatAuthenticatedAtom);
const accessToken = useRecoilValue<string>(accessTokenAtom); const accessToken = useRecoilValue<string>(accessTokenAtom);
const federationEnabled = true; const federationEnabled = true;
const { displayName } = currentUser;
return ( return (
<div> <div>
@ -41,7 +46,7 @@ export const AuthModal: FC = () => {
> >
<IndieAuthModal <IndieAuthModal
authenticated={authenticated} authenticated={authenticated}
displayName={chatDisplayName} displayName={displayName}
accessToken={accessToken} accessToken={accessToken}
/> />
</TabPane> </TabPane>
@ -56,7 +61,7 @@ export const AuthModal: FC = () => {
> >
<FediAuthModal <FediAuthModal
authenticated={authenticated} authenticated={authenticated}
displayName={chatDisplayName} displayName={displayName}
accessToken={accessToken} accessToken={accessToken}
/> />
</TabPane> </TabPane>

View file

@ -3,11 +3,7 @@ import { useRecoilValue } from 'recoil';
import { Input, Button, Select } from 'antd'; import { Input, Button, Select } from 'antd';
import { MessageType } from '../../../interfaces/socket-events'; import { MessageType } from '../../../interfaces/socket-events';
import WebsocketService from '../../../services/websocket-service'; import WebsocketService from '../../../services/websocket-service';
import { import { websocketServiceAtom, currentUserAtom } from '../../stores/ClientConfigStore';
websocketServiceAtom,
chatDisplayNameAtom,
chatDisplayColorAtom,
} from '../../stores/ClientConfigStore';
const { Option } = Select; const { Option } = Select;
@ -26,10 +22,14 @@ const UserColor: FC<UserColorProps> = ({ color }) => {
}; };
export const NameChangeModal: FC = () => { export const NameChangeModal: FC = () => {
const currentUser = useRecoilValue(currentUserAtom);
if (!currentUser) {
return null;
}
const { displayName, displayColor } = currentUser;
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom); const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom); const [newName, setNewName] = useState<any>(displayName);
const chatDisplayColor = useRecoilValue<number>(chatDisplayColorAtom) || 0;
const [newName, setNewName] = useState<any>(chatDisplayName);
const handleNameChange = () => { const handleNameChange = () => {
const nameChange = { const nameChange = {
@ -39,8 +39,7 @@ export const NameChangeModal: FC = () => {
websocketService.send(nameChange); websocketService.send(nameChange);
}; };
const saveEnabled = const saveEnabled = newName !== displayName && newName !== '' && websocketService?.isConnected();
newName !== chatDisplayName && newName !== '' && websocketService?.isConnected();
const handleColorChange = (color: string) => { const handleColorChange = (color: string) => {
const colorChange = { const colorChange = {
@ -63,7 +62,7 @@ export const NameChangeModal: FC = () => {
placeholder="Your chat display name" placeholder="Your chat display name"
maxLength={30} maxLength={30}
showCount showCount
defaultValue={chatDisplayName} defaultValue={displayName}
/> />
<Button disabled={!saveEnabled} onClick={handleNameChange}> <Button disabled={!saveEnabled} onClick={handleNameChange}>
Change name Change name
@ -73,7 +72,7 @@ export const NameChangeModal: FC = () => {
<Select <Select
style={{ width: 120 }} style={{ width: 120 }}
onChange={handleColorChange} onChange={handleColorChange}
defaultValue={chatDisplayColor.toString()} defaultValue={displayColor.toString()}
getPopupContainer={triggerNode => triggerNode.parentElement} getPopupContainer={triggerNode => triggerNode.parentElement}
> >
{colorOptions.map(e => ( {colorOptions.map(e => (

View file

@ -6,6 +6,7 @@ import ClientConfigService from '../../services/client-config-service';
import ChatService from '../../services/chat-service'; import ChatService from '../../services/chat-service';
import WebsocketService from '../../services/websocket-service'; import WebsocketService from '../../services/websocket-service';
import { ChatMessage } from '../../interfaces/chat-message.model'; import { ChatMessage } from '../../interfaces/chat-message.model';
import { CurrentUser } from '../../interfaces/current-user';
import { ServerStatus, makeEmptyServerStatus } from '../../interfaces/server-status.model'; import { ServerStatus, makeEmptyServerStatus } from '../../interfaces/server-status.model';
import appStateModel, { import appStateModel, {
AppStateEvent, AppStateEvent,
@ -44,31 +45,16 @@ export const clientConfigStateAtom = atom({
default: makeEmptyClientConfig(), default: makeEmptyClientConfig(),
}); });
export const chatDisplayNameAtom = atom<string>({
key: 'chatDisplayName',
default: null,
});
export const chatDisplayColorAtom = atom<number>({
key: 'chatDisplayColor',
default: null,
});
export const chatUserIdAtom = atom<string>({
key: 'chatUserIdAtom',
default: null,
});
export const isChatModeratorAtom = atom<boolean>({
key: 'isModeratorAtom',
default: false,
});
export const accessTokenAtom = atom<string>({ export const accessTokenAtom = atom<string>({
key: 'accessTokenAtom', key: 'accessTokenAtom',
default: null, default: null,
}); });
export const currentUserAtom = atom<CurrentUser>({
key: 'currentUserAtom',
default: null,
});
export const chatMessagesAtom = atom<ChatMessage[]>({ export const chatMessagesAtom = atom<ChatMessage[]>({
key: 'chatMessages', key: 'chatMessages',
default: [] as ChatMessage[], default: [] as ChatMessage[],
@ -126,7 +112,7 @@ export const isChatVisibleSelector = selector({
get: ({ get }) => { get: ({ get }) => {
const state: AppStateOptions = get(appStateAtom); const state: AppStateOptions = get(appStateAtom);
const userVisibleToggle: boolean = get(chatVisibleToggleAtom); const userVisibleToggle: boolean = get(chatVisibleToggleAtom);
const accessToken: String = get(accessTokenAtom); const accessToken: string = get(accessTokenAtom);
return accessToken && state.chatAvailable && userVisibleToggle; return accessToken && state.chatAvailable && userVisibleToggle;
}, },
}); });
@ -135,7 +121,7 @@ export const isChatAvailableSelector = selector({
key: 'isChatAvailableSelector', key: 'isChatAvailableSelector',
get: ({ get }) => { get: ({ get }) => {
const state: AppStateOptions = get(appStateAtom); const state: AppStateOptions = get(appStateAtom);
const accessToken: String = get(accessTokenAtom); const accessToken: string = get(accessTokenAtom);
return accessToken && state.chatAvailable; return accessToken && state.chatAvailable;
}, },
}); });
@ -174,12 +160,8 @@ function mergeMeta(meta) {
export const ClientConfigStore: FC = () => { export const ClientConfigStore: FC = () => {
const [appState, appStateSend, appStateService] = useMachine(appStateModel); const [appState, appStateSend, appStateService] = useMachine(appStateModel);
const [currentUser, setCurrentUser] = useRecoilState(currentUserAtom);
const setChatDisplayName = useSetRecoilState<string>(chatDisplayNameAtom);
const setChatDisplayColor = useSetRecoilState<Number>(chatDisplayColorAtom);
const setChatUserId = useSetRecoilState<string>(chatUserIdAtom);
const setChatAuthenticated = useSetRecoilState<boolean>(chatAuthenticatedAtom); const setChatAuthenticated = useSetRecoilState<boolean>(chatAuthenticatedAtom);
const setIsChatModerator = useSetRecoilState<boolean>(isChatModeratorAtom);
const [clientConfig, setClientConfig] = useRecoilState<ClientConfig>(clientConfigStateAtom); const [clientConfig, setClientConfig] = useRecoilState<ClientConfig>(clientConfigStateAtom);
const setServerStatus = useSetRecoilState<ServerStatus>(serverStatusState); const setServerStatus = useSetRecoilState<ServerStatus>(serverStatusState);
const setClockSkew = useSetRecoilState<Number>(clockSkewAtom); const setClockSkew = useSetRecoilState<Number>(clockSkewAtom);
@ -264,10 +246,13 @@ export const ClientConfigStore: FC = () => {
} }
console.log('setting access token', newAccessToken); console.log('setting access token', newAccessToken);
setCurrentUser({
...currentUser,
displayName: newDisplayName,
displayColor,
});
setAccessToken(newAccessToken); setAccessToken(newAccessToken);
setLocalStorage(ACCESS_TOKEN_KEY, newAccessToken); setLocalStorage(ACCESS_TOKEN_KEY, newAccessToken);
setChatDisplayName(newDisplayName);
setChatDisplayColor(displayColor);
} catch (e) { } catch (e) {
sendEvent(AppStateEvent.Fail); sendEvent(AppStateEvent.Fail);
console.error(`ChatService -> registerUser() ERROR: \n${e}`); console.error(`ChatService -> registerUser() ERROR: \n${e}`);
@ -276,7 +261,7 @@ export const ClientConfigStore: FC = () => {
const resetAndReAuth = () => { const resetAndReAuth = () => {
setLocalStorage(ACCESS_TOKEN_KEY, ''); setLocalStorage(ACCESS_TOKEN_KEY, '');
setAccessToken(''); setAccessToken(null);
handleUserRegistration(); handleUserRegistration();
}; };
@ -299,11 +284,8 @@ export const ClientConfigStore: FC = () => {
case MessageType.CONNECTED_USER_INFO: case MessageType.CONNECTED_USER_INFO:
handleConnectedClientInfoMessage( handleConnectedClientInfoMessage(
message as ConnectedClientInfoEvent, message as ConnectedClientInfoEvent,
setChatDisplayName,
setChatDisplayColor,
setChatUserId,
setIsChatModerator,
setChatAuthenticated, setChatAuthenticated,
setCurrentUser,
); );
setChatMessages(currentState => [...currentState, message as ChatEvent]); setChatMessages(currentState => [...currentState, message as ChatEvent]);
break; break;

View file

@ -2,18 +2,18 @@ import { ConnectedClientInfoEvent } from '../../../interfaces/socket-events';
export function handleConnectedClientInfoMessage( export function handleConnectedClientInfoMessage(
message: ConnectedClientInfoEvent, message: ConnectedClientInfoEvent,
setChatDisplayName: (string) => void,
setChatDisplayColor: (number) => void,
setChatUserId: (number) => void,
setIsChatModerator: (boolean) => void,
setChatAuthenticated: (boolean) => void, setChatAuthenticated: (boolean) => void,
setCurrentUser: (CurrentUser) => void,
) { ) {
const { user } = message; const { user } = message;
const { id, displayName, displayColor, scopes, authenticated } = user; const { id, displayName, displayColor, scopes, authenticated } = user;
setChatDisplayName(displayName);
setChatDisplayColor(displayColor);
setChatUserId(id);
setIsChatModerator(scopes?.includes('MODERATOR'));
setChatAuthenticated(authenticated); setChatAuthenticated(authenticated);
setCurrentUser({
id: id.toString(),
displayName,
displayColor,
isModerator: scopes?.includes('MODERATOR'),
});
} }
export default handleConnectedClientInfoMessage; export default handleConnectedClientInfoMessage;

View file

@ -8,8 +8,7 @@ import { LOCAL_STORAGE_KEYS, getLocalStorage, setLocalStorage } from '../../../u
import { import {
clientConfigStateAtom, clientConfigStateAtom,
chatMessagesAtom, chatMessagesAtom,
chatDisplayNameAtom, currentUserAtom,
chatUserIdAtom,
isChatAvailableSelector, isChatAvailableSelector,
isChatVisibleSelector, isChatVisibleSelector,
appStateAtom, appStateAtom,
@ -134,12 +133,12 @@ export const Content: FC = () => {
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom); const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
const isChatVisible = useRecoilValue<boolean>(isChatVisibleSelector); const isChatVisible = useRecoilValue<boolean>(isChatVisibleSelector);
const isChatAvailable = useRecoilValue<boolean>(isChatAvailableSelector); const isChatAvailable = useRecoilValue<boolean>(isChatAvailableSelector);
const currentUser = useRecoilValue(currentUserAtom);
const [isMobile, setIsMobile] = useRecoilState<boolean | undefined>(isMobileAtom); const [isMobile, setIsMobile] = useRecoilState<boolean | undefined>(isMobileAtom);
const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom); const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom);
const online = useRecoilValue<boolean>(isOnlineSelector); const online = useRecoilValue<boolean>(isOnlineSelector);
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom);
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
const { viewerCount, lastConnectTime, lastDisconnectTime, streamTitle } = const { viewerCount, lastConnectTime, lastDisconnectTime, streamTitle } =
useRecoilValue<ServerStatus>(serverStatusState); useRecoilValue<ServerStatus>(serverStatusState);
const { const {
@ -200,6 +199,11 @@ export const Content: FC = () => {
window.addEventListener('resize', checkIfMobile); window.addEventListener('resize', checkIfMobile);
}, []); }, []);
if (!currentUser) {
return null;
}
const { id: currentUserId, displayName } = currentUser;
const showChat = !chatDisabled && isChatAvailable && isChatVisible; const showChat = !chatDisabled && isChatAvailable && isChatVisible;
return ( return (
@ -261,8 +265,8 @@ export const Content: FC = () => {
socialHandles={socialHandles} socialHandles={socialHandles}
extraPageContent={extraPageContent} extraPageContent={extraPageContent}
messages={messages} messages={messages}
chatDisplayName={chatDisplayName} chatDisplayName={displayName}
chatUserId={chatUserId} chatUserId={currentUserId}
showChat={showChat} showChat={showChat}
/> />
) : ( ) : (

View file

@ -5,26 +5,20 @@ import { ChatMessage } from '../../../interfaces/chat-message.model';
import { ChatContainer } from '../../chat/ChatContainer/ChatContainer'; import { ChatContainer } from '../../chat/ChatContainer/ChatContainer';
import styles from './Sidebar.module.scss'; import styles from './Sidebar.module.scss';
import { import { currentUserAtom, visibleChatMessagesSelector } from '../../stores/ClientConfigStore';
chatDisplayNameAtom,
chatUserIdAtom,
isChatModeratorAtom,
visibleChatMessagesSelector,
} from '../../stores/ClientConfigStore';
export const Sidebar: FC = () => { export const Sidebar: FC = () => {
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom); const currentUser = useRecoilValue(currentUserAtom);
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
const isChatModerator = useRecoilValue<boolean>(isChatModeratorAtom);
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector); const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
const { id, isModerator, displayName } = currentUser;
return ( return (
<Sider className={styles.root} collapsedWidth={0} width={320}> <Sider className={styles.root} collapsedWidth={0} width={320}>
<ChatContainer <ChatContainer
messages={messages} messages={messages}
usernameToHighlight={chatDisplayName} usernameToHighlight={displayName}
chatUserId={chatUserId} chatUserId={id}
isModerator={isChatModerator} isModerator={isModerator}
/> />
</Sider> </Sider>
); );

View file

@ -0,0 +1,6 @@
export interface CurrentUser {
id: string;
displayName: string;
displayColor: number;
isModerator: boolean;
}

View file

@ -3,23 +3,24 @@ import { ChatMessage } from '../../../../interfaces/chat-message.model';
import { ChatContainer } from '../../../../components/chat/ChatContainer/ChatContainer'; import { ChatContainer } from '../../../../components/chat/ChatContainer/ChatContainer';
import { import {
ClientConfigStore, ClientConfigStore,
chatDisplayNameAtom, currentUserAtom,
chatUserIdAtom,
visibleChatMessagesSelector, visibleChatMessagesSelector,
} from '../../../../components/stores/ClientConfigStore'; } from '../../../../components/stores/ClientConfigStore';
export default function ReadOnlyChatEmbed() { export default function ReadOnlyChatEmbed() {
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom); const currentUser = useRecoilValue(currentUserAtom);
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector); const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
if (!currentUser) {
return null;
}
const { id, displayName } = currentUser;
return ( return (
<div> <div>
<ClientConfigStore /> <ClientConfigStore />
<ChatContainer <ChatContainer
messages={messages} messages={messages}
usernameToHighlight={chatDisplayName} usernameToHighlight={displayName}
chatUserId={chatUserId} chatUserId={id}
isModerator={false} isModerator={false}
showInput={false} showInput={false}
height="100vh" height="100vh"

View file

@ -3,32 +3,34 @@ import { ChatMessage } from '../../../../interfaces/chat-message.model';
import { ChatContainer } from '../../../../components/chat/ChatContainer/ChatContainer'; import { ChatContainer } from '../../../../components/chat/ChatContainer/ChatContainer';
import { import {
ClientConfigStore, ClientConfigStore,
chatDisplayNameAtom, currentUserAtom,
chatUserIdAtom,
visibleChatMessagesSelector, visibleChatMessagesSelector,
clientConfigStateAtom, clientConfigStateAtom,
isChatModeratorAtom,
} from '../../../../components/stores/ClientConfigStore'; } from '../../../../components/stores/ClientConfigStore';
import Header from '../../../../components/ui/Header/Header'; import Header from '../../../../components/ui/Header/Header';
import { ClientConfig } from '../../../../interfaces/client-config.model'; import { ClientConfig } from '../../../../interfaces/client-config.model';
export default function ReadWriteChatEmbed() { export default function ReadWriteChatEmbed() {
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom); const currentUser = useRecoilValue(currentUserAtom);
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector); const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom); const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
const isModerator = useRecoilValue<boolean>(isChatModeratorAtom);
const { name, chatDisabled } = clientConfig; const { name, chatDisabled } = clientConfig;
if (!currentUser) {
return null;
}
const { id, displayName, isModerator } = currentUser;
return ( return (
<div> <div>
<ClientConfigStore /> <ClientConfigStore />
<Header name={name} chatAvailable chatDisabled={chatDisabled} /> <Header name={name} chatAvailable chatDisabled={chatDisabled} />
<ChatContainer <ChatContainer
messages={messages} messages={messages}
usernameToHighlight={chatDisplayName} usernameToHighlight={displayName}
chatUserId={chatUserId} chatUserId={id}
isModerator={isModerator} isModerator={isModerator}
showInput showInput
height="80vh" height="80vh"

View file

@ -1,11 +1,11 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react'; import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot, useSetRecoilState } from 'recoil'; import { RecoilRoot, useRecoilState, useSetRecoilState } from 'recoil';
import ReadWritePage from '../pages/embed/chat/readwrite/index'; import ReadWritePage from '../pages/embed/chat/readwrite/index';
import { ChatMessage } from '../interfaces/chat-message.model'; import { ChatMessage } from '../interfaces/chat-message.model';
import { import {
chatMessagesAtom, chatMessagesAtom,
chatDisplayNameAtom, currentUserAtom,
clientConfigStateAtom, clientConfigStateAtom,
} from '../components/stores/ClientConfigStore'; } from '../components/stores/ClientConfigStore';
import { ClientConfig } from '../interfaces/client-config.model'; import { ClientConfig } from '../interfaces/client-config.model';
@ -21,8 +21,8 @@ const testMessages =
const messages: ChatMessage[] = JSON.parse(testMessages); const messages: ChatMessage[] = JSON.parse(testMessages);
const Page = () => { const Page = () => {
const [currentUser, setCurrentUser] = useRecoilState(currentUserAtom);
const setMessages = useSetRecoilState(chatMessagesAtom); const setMessages = useSetRecoilState(chatMessagesAtom);
const setDisplayName = useSetRecoilState(chatDisplayNameAtom);
const setClientConfig = useSetRecoilState<ClientConfig>(clientConfigStateAtom); const setClientConfig = useSetRecoilState<ClientConfig>(clientConfigStateAtom);
const fakeConfig: ClientConfig = { const fakeConfig: ClientConfig = {
@ -45,7 +45,11 @@ const Page = () => {
useEffect(() => { useEffect(() => {
setMessages(messages); setMessages(messages);
setDisplayName('fake-chat-user'); setCurrentUser({
...currentUser,
displayName: 'fake-chat-user',
});
setClientConfig(fakeConfig); setClientConfig(fakeConfig);
}, []); }, []);