owncast/web/components/ui/Content/Content.tsx

291 lines
9.5 KiB
TypeScript
Raw Normal View History

import { useRecoilState, useRecoilValue } from 'recoil';
import { Layout, Tabs, Spin } from 'antd';
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
import { FC, useEffect, useState } from 'react';
2022-09-10 22:08:22 +03:00
import classNames from 'classnames';
import dynamic from 'next/dynamic';
import { LOCAL_STORAGE_KEYS, getLocalStorage, setLocalStorage } from '../../../utils/localStorage';
2022-05-04 00:17:05 +03:00
import {
clientConfigStateAtom,
2022-09-10 22:08:22 +03:00
chatMessagesAtom,
currentUserAtom,
2022-09-11 06:03:58 +03:00
isChatAvailableSelector,
isChatVisibleSelector,
appStateAtom,
isOnlineSelector,
isMobileAtom,
serverStatusState,
2022-05-04 00:17:05 +03:00
} from '../../stores/ClientConfigStore';
import { ClientConfig } from '../../../interfaces/client-config.model';
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
import { CustomPageContent } from '../CustomPageContent/CustomPageContent';
import { OwncastPlayer } from '../../video/OwncastPlayer/OwncastPlayer';
import styles from './Content.module.scss';
import { Sidebar } from '../Sidebar/Sidebar';
import { Footer } from '../Footer/Footer';
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
import { ActionButtonRow } from '../../action-buttons/ActionButtonRow/ActionButtonRow';
import { ActionButton } from '../../action-buttons/ActionButton/ActionButton';
import { OfflineBanner } from '../OfflineBanner/OfflineBanner';
import { AppStateOptions } from '../../stores/application-state';
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
import { FollowButton } from '../../action-buttons/FollowButton';
import { NotifyButton } from '../../action-buttons/NotifyButton';
import { ContentHeader } from '../../common/ContentHeader/ContentHeader';
import { ServerStatus } from '../../../interfaces/server-status.model';
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
import { Statusbar } from '../Statusbar/Statusbar';
2022-09-10 22:08:22 +03:00
import { ChatMessage } from '../../../interfaces/chat-message.model';
const { TabPane } = Tabs;
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
const { Content: AntContent } = Layout;
// Lazy loaded components
const Modal = dynamic(() => import('../Modal/Modal').then(mod => mod.Modal));
const BrowserNotifyModal = dynamic(() =>
import('../../modals/BrowserNotifyModal/BrowserNotifyModal').then(mod => mod.BrowserNotifyModal),
);
const NotifyReminderPopup = dynamic(() =>
import('../NotifyReminderPopup/NotifyReminderPopup').then(mod => mod.NotifyReminderPopup),
);
const FollowerCollection = dynamic(() =>
import('../followers/FollowerCollection/FollowerCollection').then(mod => mod.FollowerCollection),
);
// We only need to load the chat container here if we're in mobile or narrow
// windows, so lazy loading it makes sense.
const ChatContainer = dynamic(() =>
import('../../chat/ChatContainer/ChatContainer').then(mod => mod.ChatContainer),
);
2022-09-10 22:08:22 +03:00
const DesktopContent = ({ name, streamTitle, summary, tags, socialHandles, extraPageContent }) => (
<>
<div className={styles.lowerHalf}>
<ContentHeader
name={name}
title={streamTitle}
summary={summary}
tags={tags}
links={socialHandles}
logo="/logo"
/>
</div>
<div className={styles.lowerSection}>
<Tabs defaultActiveKey="0">
<TabPane tab="About" key="2">
<CustomPageContent content={extraPageContent} />
</TabPane>
<TabPane tab="Followers" key="3">
<FollowerCollection name={name} />
2022-09-10 22:08:22 +03:00
</TabPane>
</Tabs>
</div>
</>
);
const MobileContent = ({
name,
streamTitle,
summary,
tags,
socialHandles,
extraPageContent,
messages,
chatDisplayName,
chatUserId,
2022-09-11 06:03:58 +03:00
showChat,
2022-09-10 22:08:22 +03:00
}) => (
<div className={classNames(styles.lowerSectionMobile)}>
<Tabs defaultActiveKey="0">
2022-09-11 06:03:58 +03:00
{showChat && (
<TabPane tab="Chat" key="1">
<ChatContainer
messages={messages}
usernameToHighlight={chatDisplayName}
chatUserId={chatUserId}
isModerator={false}
height="40vh"
/>
</TabPane>
)}
2022-09-10 22:08:22 +03:00
<TabPane tab="About" key="2">
<ContentHeader
name={name}
title={streamTitle}
summary={summary}
tags={tags}
links={socialHandles}
logo="/logo"
/>
<CustomPageContent content={extraPageContent} />
</TabPane>
<TabPane tab="Followers" key="3">
<FollowerCollection name={name} />
2022-09-10 22:08:22 +03:00
</TabPane>
</Tabs>
</div>
);
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
export const Content: FC = () => {
const appState = useRecoilValue<AppStateOptions>(appStateAtom);
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
const isChatVisible = useRecoilValue<boolean>(isChatVisibleSelector);
2022-09-11 06:03:58 +03:00
const isChatAvailable = useRecoilValue<boolean>(isChatAvailableSelector);
const currentUser = useRecoilValue(currentUserAtom);
2022-09-11 06:03:58 +03:00
const [isMobile, setIsMobile] = useRecoilState<boolean | undefined>(isMobileAtom);
2022-09-10 22:08:22 +03:00
const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom);
const online = useRecoilValue<boolean>(isOnlineSelector);
2022-08-17 03:49:21 +03:00
const { viewerCount, lastConnectTime, lastDisconnectTime, streamTitle } =
useRecoilValue<ServerStatus>(serverStatusState);
2022-08-17 03:49:21 +03:00
const {
extraPageContent,
version,
name,
summary,
socialHandles,
tags,
externalActions,
offlineMessage,
2022-09-11 06:03:58 +03:00
chatDisabled,
federation,
notifications,
2022-08-17 03:49:21 +03:00
} = clientConfig;
const [showNotifyReminder, setShowNotifyReminder] = useState(false);
const [showNotifyPopup, setShowNotifyPopup] = useState(false);
const { account: fediverseAccount } = federation;
const { browser: browserNotifications } = notifications;
const { enabled: browserNotificationsEnabled } = browserNotifications;
2022-05-08 02:13:06 +03:00
const externalActionButtons = externalActions.map(action => (
<ActionButton key={action.url} action={action} />
));
const incrementVisitCounter = () => {
let visits = parseInt(getLocalStorage(LOCAL_STORAGE_KEYS.userVisitCount), 10);
if (Number.isNaN(visits)) {
visits = 0;
}
setLocalStorage(LOCAL_STORAGE_KEYS.userVisitCount, visits + 1);
if (visits > 2 && !getLocalStorage(LOCAL_STORAGE_KEYS.hasDisplayedNotificationModal)) {
setShowNotifyReminder(true);
}
};
const disableNotifyReminderPopup = () => {
setShowNotifyPopup(false);
setShowNotifyReminder(false);
setLocalStorage(LOCAL_STORAGE_KEYS.hasDisplayedNotificationModal, true);
};
const checkIfMobile = () => {
const w = window.innerWidth;
if (isMobile === undefined) {
if (w <= 768) setIsMobile(true);
else setIsMobile(false);
}
if (!isMobile && w <= 768) setIsMobile(true);
if (isMobile && w > 768) setIsMobile(false);
};
useEffect(() => {
incrementVisitCounter();
checkIfMobile();
window.addEventListener('resize', checkIfMobile);
}, []);
if (!currentUser) {
return null;
}
const { id: currentUserId, displayName } = currentUser;
2022-09-11 06:03:58 +03:00
const showChat = !chatDisabled && isChatAvailable && isChatVisible;
return (
2022-08-30 09:33:30 +03:00
<div>
<Spin className={styles.loadingSpinner} size="large" spinning={appState.appLoading}>
<AntContent className={styles.root}>
<div className={styles.leftContent}>
<div className={styles.topSection}>
{online && <OwncastPlayer source="/hls/stream.m3u8" online={online} />}
{!online && !appState.appLoading && (
<OfflineBanner
streamName={name}
customText={offlineMessage}
notificationsEnabled={browserNotificationsEnabled}
fediverseAccount={fediverseAccount}
lastLive={lastDisconnectTime}
onNotifyClick={() => setShowNotifyPopup(true)}
/>
)}
2022-10-09 04:53:41 +03:00
{online && (
<Statusbar
online={online}
lastConnectTime={lastConnectTime}
lastDisconnectTime={lastDisconnectTime}
viewerCount={viewerCount}
/>
)}
</div>
<div className={styles.midSection}>
<div className={styles.buttonsLogoTitleSection}>
<ActionButtonRow>
{externalActionButtons}
<FollowButton size="small" />
<NotifyReminderPopup
visible={showNotifyReminder}
notificationClicked={() => setShowNotifyPopup(true)}
notificationClosed={() => disableNotifyReminderPopup()}
>
<NotifyButton onClick={() => setShowNotifyPopup(true)} />
</NotifyReminderPopup>
</ActionButtonRow>
<Modal
title="Notify"
visible={showNotifyPopup}
afterClose={() => disableNotifyReminderPopup()}
handleCancel={() => disableNotifyReminderPopup()}
2022-08-30 09:33:30 +03:00
>
<BrowserNotifyModal />
</Modal>
</div>
2022-08-30 09:33:30 +03:00
</div>
{isMobile && isChatVisible ? (
<MobileContent
name={name}
streamTitle={streamTitle}
summary={summary}
tags={tags}
socialHandles={socialHandles}
extraPageContent={extraPageContent}
messages={messages}
chatDisplayName={displayName}
chatUserId={currentUserId}
2022-09-11 06:03:58 +03:00
showChat={showChat}
/>
) : (
<DesktopContent
name={name}
streamTitle={streamTitle}
summary={summary}
tags={tags}
socialHandles={socialHandles}
extraPageContent={extraPageContent}
/>
)}
2022-08-30 09:33:30 +03:00
</div>
2022-09-11 06:03:58 +03:00
{showChat && !isMobile && <Sidebar />}
</AntContent>
2022-09-11 06:03:58 +03:00
{(!isMobile || !showChat) && <Footer version={version} />}
</Spin>
2022-08-30 09:33:30 +03:00
</div>
);
reafctor: normalize component formatting (#2082) * refactor: move/rename BanUserButton file * refactor: move/rename Chart file * refactor: update generic component filenames to PascalCase * refactor: update config component filenames to PascalCase * refactor: update AdminLayout component filename to PascalCase * refactor: update/move VideoJS component * chore(eslint): disable bad react/require-default-props rule * refactor: normalize ActionButton component * refactor: normalize ActionButtonRow component * refactor: normalize FollowButton component * refactor: normalize NotifyButton component * refactor: normalize ChatActionMessage component * refactor: normalize ChatContainer component * refactor: normalize ChatJoinMessage component * refactor: normalize ChatModerationActionMenu component * refactor: normalize ChatModerationDetailsModal component * refactor: normalize ChatModeratorNotification component * refactor: normalize ChatSocialMessage component * refactor: normalize ChatSystemMessage component * refactor: normalize ChatTextField component * refactor: normalize ChatUserBadge component * refactor: normalize ChatUserMessage component * refactor: normalize ContentHeader component * refactor: normalize OwncastLogo component * refactor: normalize UserDropdown component * chore(eslint): modify react/function-component-definition rule * refactor: normalize CodecSelector component * refactor: update a bunch of functional components using eslint * refactor: update a bunch of functional components using eslint, pt2 * refactor: update a bunch of functional components using eslint, pt3 * refactor: replace all component->component default imports with named imports * refactor: replace all component-stories->component default imports with named imports * refactor: remove default exports from most components * chore(eslint): add eslint config files for the components and pages dirs * fix: use-before-define error in ChatContainer * Fix ChatContainer import * Only process .tsx files in Next builds Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2022-09-07 10:00:28 +03:00
};
export default Content;