diff --git a/web/components/common/UserDropdown/UserDropdown.tsx b/web/components/common/UserDropdown/UserDropdown.tsx index b271c2d65..28391a1fe 100644 --- a/web/components/common/UserDropdown/UserDropdown.tsx +++ b/web/components/common/UserDropdown/UserDropdown.tsx @@ -1,19 +1,19 @@ import { Menu, Dropdown, Button, Space } from 'antd'; import { DownOutlined } from '@ant-design/icons'; -import { useRecoilState } from 'recoil'; -import { chatVisibilityAtom } from '../../stores/ClientConfigStore'; +import { useRecoilState, useRecoilValue } from 'recoil'; +import { chatVisibilityAtom, chatDisplayNameAtom } from '../../stores/ClientConfigStore'; import { ChatState, ChatVisibilityState } from '../../../interfaces/application-state'; import s from './UserDropdown.module.scss'; interface Props { - username: string; + username?: string; chatState: ChatState; } -export default function UserDropdown({ username = 'test-user', chatState }: Props) { - const chatEnabled = chatState !== ChatState.NotAvailable; +export default function UserDropdown({ username: defaultUsername, chatState }: Props) { const [chatVisibility, setChatVisibility] = useRecoilState(chatVisibilityAtom); + const username = defaultUsername || useRecoilValue(chatDisplayNameAtom); const toggleChatVisibility = () => { if (chatVisibility === ChatVisibilityState.Hidden) { @@ -27,7 +27,7 @@ export default function UserDropdown({ username = 'test-user', chatState }: Prop Change name Authenticate - {chatEnabled && ( + {chatState === ChatState.Available && ( toggleChatVisibility()}> Toggle chat @@ -48,3 +48,7 @@ export default function UserDropdown({ username = 'test-user', chatState }: Prop ); } + +UserDropdown.defaultProps = { + username: undefined, +}; diff --git a/web/components/layouts/Main.tsx b/web/components/layouts/Main.tsx index fe25c8a0c..79c1aa13b 100644 --- a/web/components/layouts/Main.tsx +++ b/web/components/layouts/Main.tsx @@ -1,6 +1,5 @@ import { Layout } from 'antd'; import { useRecoilValue } from 'recoil'; -import { ServerStatusStore } from '../stores/ServerStatusStore'; import { ClientConfigStore, clientConfigStateAtom } from '../stores/ClientConfigStore'; import { Content, Header } from '../ui'; import { ClientConfig } from '../../interfaces/client-config.model'; @@ -11,7 +10,6 @@ function Main() { return ( <> -
diff --git a/web/components/stores/ClientConfigStore.tsx b/web/components/stores/ClientConfigStore.tsx index e7765c031..9073d8d04 100644 --- a/web/components/stores/ClientConfigStore.tsx +++ b/web/components/stores/ClientConfigStore.tsx @@ -1,11 +1,13 @@ /* eslint-disable no-case-declarations */ -import { useEffect, useLayoutEffect } from 'react'; +import { useEffect } from 'react'; import { atom, useRecoilState, useSetRecoilState } from 'recoil'; import { makeEmptyClientConfig, ClientConfig } from '../../interfaces/client-config.model'; import ClientConfigService from '../../services/client-config-service'; import ChatService from '../../services/chat-service'; import WebsocketService from '../../services/websocket-service'; import { ChatMessage } from '../../interfaces/chat-message.model'; +import { ServerStatus, makeEmptyServerStatus } from '../../interfaces/server-status.model'; + import { AppState, ChatState, @@ -22,6 +24,14 @@ import { } from '../../interfaces/socket-events'; import handleConnectedClientInfoMessage from './eventhandlers/connectedclientinfo'; import handleChatMessage from './eventhandlers/handleChatMessage'; +import ServerStatusService from '../../services/status-service'; + +// Server status is what gets updated such as viewer count, durations, +// stream title, online/offline state, etc. +export const serverStatusState = atom({ + key: 'serverStatusState', + default: makeEmptyServerStatus(), +}); // The config that comes from the API. export const clientConfigStateAtom = atom({ @@ -71,6 +81,7 @@ export const websocketServiceAtom = atom({ export function ClientConfigStore() { const setClientConfig = useSetRecoilState(clientConfigStateAtom); + const setServerStatus = useSetRecoilState(serverStatusState); const setChatVisibility = useSetRecoilState(chatVisibilityAtom); const setChatState = useSetRecoilState(chatStateAtom); const [chatMessages, setChatMessages] = useRecoilState(chatMessagesAtom); @@ -90,6 +101,22 @@ export function ClientConfigStore() { } }; + const updateServerStatus = async () => { + try { + const status = await ServerStatusService.getStatus(); + setServerStatus(status); + if (status.online) { + setAppState(AppState.Online); + } else { + setAppState(AppState.Offline); + } + return status; + } catch (error) { + console.error(`serverStatusState -> getStatus() ERROR: \n${error}`); + return null; + } + }; + const handleUserRegistration = async (optionalDisplayName?: string) => { try { setAppState(AppState.Registering); @@ -140,7 +167,6 @@ export function ClientConfigStore() { } catch (error) { console.error(`ChatService -> startChat() ERROR: \n${error}`); } - setChatState(ChatState.Available); }; useEffect(() => { @@ -148,7 +174,14 @@ export function ClientConfigStore() { handleUserRegistration(); }, []); - useLayoutEffect(() => { + useEffect(() => { + setInterval(() => { + updateServerStatus(); + }, 5000); + updateServerStatus(); + }, []); + + useEffect(() => { if (!accessToken) { return; } @@ -159,6 +192,7 @@ export function ClientConfigStore() { useEffect(() => { const updatedChatState = getChatState(appState); + console.log('updatedChatState', updatedChatState); setChatState(updatedChatState); const updatedChatVisibility = getChatVisibilityState(appState); console.log( diff --git a/web/components/stores/ServerStatusStore.tsx b/web/components/stores/ServerStatusStore.tsx deleted file mode 100644 index 93cf493f8..000000000 --- a/web/components/stores/ServerStatusStore.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { useEffect } from 'react'; -import { atom, useRecoilState } from 'recoil'; -import { ServerStatus, makeEmptyServerStatus } from '../../interfaces/server-status.model'; -import ServerStatusService from '../../services/status-service'; - -export const serverStatusState = atom({ - key: 'serverStatusState', - default: makeEmptyServerStatus(), -}); - -export function ServerStatusStore() { - const [, setServerStatus] = useRecoilState(serverStatusState); - - const updateServerStatus = async () => { - try { - const status = await ServerStatusService.getStatus(); - setServerStatus(status); - return status; - } catch (error) { - console.error(`serverStatusState -> getStatus() ERROR: \n${error}`); - return null; - } - }; - - useEffect(() => { - setInterval(() => { - updateServerStatus(); - }, 5000); - updateServerStatus(); - }, []); - - return null; -} diff --git a/web/components/ui/Content/Content.tsx b/web/components/ui/Content/Content.tsx index 376b8ddd2..206ea0b85 100644 --- a/web/components/ui/Content/Content.tsx +++ b/web/components/ui/Content/Content.tsx @@ -5,8 +5,8 @@ import { clientConfigStateAtom, chatMessagesAtom, chatStateAtom, + serverStatusState, } from '../../stores/ClientConfigStore'; -import { serverStatusState } from '../../stores/ServerStatusStore'; import { ClientConfig } from '../../../interfaces/client-config.model'; import CustomPageContent from '../../CustomPageContent'; import OwncastPlayer from '../../video/OwncastPlayer'; @@ -30,7 +30,7 @@ const { Content } = Layout; export default function ContentComponent() { const status = useRecoilValue(serverStatusState); const clientConfig = useRecoilValue(clientConfigStateAtom); - const chatOpen = useRecoilValue(chatVisibilityAtom); + const chatVisibility = useRecoilValue(chatVisibilityAtom); const messages = useRecoilValue(chatMessagesAtom); const chatState = useRecoilValue(chatStateAtom); @@ -41,6 +41,9 @@ export default function ContentComponent() { const total = 0; + const isShowingChatColumn = + chatState === ChatState.Available && chatVisibility === ChatVisibilityState.Visible; + // This is example content. It should be removed. const externalActions = [ { @@ -58,7 +61,7 @@ export default function ContentComponent() { )); return ( - +
Follow +
@@ -82,16 +86,17 @@ export default function ContentComponent() { - {chatOpen && ( + {chatVisibility && (
)} +
- {chatOpen && } + {isShowingChatColumn && }
); } diff --git a/web/components/ui/Footer/Footer.tsx b/web/components/ui/Footer/Footer.tsx index 3280573bf..7a53889c5 100644 --- a/web/components/ui/Footer/Footer.tsx +++ b/web/components/ui/Footer/Footer.tsx @@ -9,5 +9,5 @@ interface Props { export default function FooterComponent(props: Props) { const { version } = props; - return
Footer: Owncast {version}
; + return
Owncast {version}
; } diff --git a/web/components/ui/Header/Header.tsx b/web/components/ui/Header/Header.tsx index 0b5c1efb9..c9ca0f857 100644 --- a/web/components/ui/Header/Header.tsx +++ b/web/components/ui/Header/Header.tsx @@ -1,6 +1,8 @@ import { Layout } from 'antd'; +import { useRecoilValue } from 'recoil'; import { ChatState } from '../../../interfaces/application-state'; import { OwncastLogo, UserDropdown } from '../../common'; +import { chatStateAtom } from '../../stores/ClientConfigStore'; import s from './Header.module.scss'; const { Header } = Layout; @@ -10,13 +12,15 @@ interface Props { } export default function HeaderComponent({ name = 'Your stream title' }: Props) { + const chatState = useRecoilValue(chatStateAtom); + return (
{name}
- +
); } diff --git a/web/components/ui/Modal/Modal.tsx b/web/components/ui/Modal/Modal.tsx index 002866e7a..6e43a0b6e 100644 --- a/web/components/ui/Modal/Modal.tsx +++ b/web/components/ui/Modal/Modal.tsx @@ -21,7 +21,6 @@ export default function Modal(props: Props) { height: '80vh', }; - console.log(url); const iframe = url && (