Refactor action buttons callback

This commit is contained in:
Gabe Kangas 2022-10-21 22:24:29 -07:00
parent fadc529a4a
commit 3fbbecc0e8
No known key found for this signature in database
GPG key ID: 9A56337728BC81EA
4 changed files with 147 additions and 113 deletions

View file

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react'; import { ComponentStory, ComponentMeta } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { ActionButton } from './ActionButton'; import { ActionButton } from './ActionButton';
export default { export default {
@ -14,8 +15,14 @@ export default {
}, },
} as ComponentMeta<typeof ActionButton>; } as ComponentMeta<typeof ActionButton>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars const itemSelected = a => {
const Template: ComponentStory<typeof ActionButton> = args => <ActionButton {...args} />; console.log('itemSelected', a);
action(a.title);
};
const Template: ComponentStory<typeof ActionButton> = args => (
<ActionButton externalActionSelected={itemSelected} {...args} />
);
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
export const Example1 = Template.bind({}); export const Example1 = Template.bind({});

View file

@ -1,46 +1,30 @@
import { Button } from 'antd'; import { Button } from 'antd';
import { FC, useState } from 'react'; import { FC } from 'react';
import { Modal } from '../../ui/Modal/Modal';
import { ExternalAction } from '../../../interfaces/external-action'; import { ExternalAction } from '../../../interfaces/external-action';
import styles from './ActionButton.module.scss'; import styles from './ActionButton.module.scss';
export type ActionButtonProps = { export type ActionButtonProps = {
action: ExternalAction; action: ExternalAction;
primary?: boolean; primary?: boolean;
externalActionSelected: (action: ExternalAction) => void;
}; };
export const ActionButton: FC<ActionButtonProps> = ({ export const ActionButton: FC<ActionButtonProps> = ({
action: { url, title, description, icon, color, openExternally }, action,
primary = true, primary = true,
externalActionSelected,
}) => { }) => {
const [showModal, setShowModal] = useState(false); const { title, description, icon, color } = action;
const onButtonClicked = () => {
if (openExternally) {
window.open(url, '_blank');
} else {
setShowModal(true);
}
};
return ( return (
<> <Button
<Button type={primary ? 'primary' : 'default'}
type={primary ? 'primary' : 'default'} className={`${styles.button}`}
className={`${styles.button}`} onClick={() => externalActionSelected(action)}
onClick={onButtonClicked} style={{ backgroundColor: color }}
style={{ backgroundColor: color }} >
> {icon && <img src={icon} className={`${styles.icon}`} alt={description} />}
{icon && <img src={icon} className={`${styles.icon}`} alt={description} />} {title}
{title} </Button>
</Button>
<Modal
title={description || title}
url={url}
open={showModal}
height="80vh"
handleCancel={() => setShowModal(false)}
/>
</>
); );
}; };

View file

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react'; import { ComponentStory, ComponentMeta } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { ActionButtonRow } from './ActionButtonRow'; import { ActionButtonRow } from './ActionButtonRow';
import { ActionButton } from '../ActionButton/ActionButton'; import { ActionButton } from '../ActionButton/ActionButton';
@ -42,7 +43,12 @@ const actions = [
}, },
]; ];
const buttons = actions.map(action => <ActionButton action={action} />); const itemSelected = a => {
console.log('itemSelected', a);
action(a.title);
};
const buttons = actions.map(a => <ActionButton externalActionSelected={itemSelected} action={a} />);
export const Example1 = Template.bind({}); export const Example1 = Template.bind({});
Example1.args = { Example1.args = {
buttons, buttons,

View file

@ -34,13 +34,11 @@ import { ServerStatus } from '../../../interfaces/server-status.model';
import { Statusbar } from '../Statusbar/Statusbar'; import { Statusbar } from '../Statusbar/Statusbar';
import { ChatMessage } from '../../../interfaces/chat-message.model'; import { ChatMessage } from '../../../interfaces/chat-message.model';
import { FollowerCollection } from '../followers/FollowerCollection/FollowerCollection'; import { FollowerCollection } from '../followers/FollowerCollection/FollowerCollection';
import { ExternalAction } from '../../../interfaces/external-action';
import { Modal } from '../Modal/Modal';
const { Content: AntContent } = Layout; const { Content: AntContent } = Layout;
// Lazy loaded components
const Modal = dynamic(() => import('../Modal/Modal').then(mod => mod.Modal));
const BrowserNotifyModal = dynamic(() => const BrowserNotifyModal = dynamic(() =>
import('../../modals/BrowserNotifyModal/BrowserNotifyModal').then(mod => mod.BrowserNotifyModal), import('../../modals/BrowserNotifyModal/BrowserNotifyModal').then(mod => mod.BrowserNotifyModal),
); );
@ -163,6 +161,19 @@ const MobileContent = ({
); );
}; };
const ExternalModal = ({ externalActionToDisplay, setExternalActionToDisplay }) => {
const { title, description, url } = externalActionToDisplay;
return (
<Modal
title={description || title}
url={url}
open={!!externalActionToDisplay}
height="80vh"
handleCancel={() => setExternalActionToDisplay(null)}
/>
);
};
export const Content: FC = () => { export const Content: FC = () => {
const appState = useRecoilValue<AppStateOptions>(appStateAtom); const appState = useRecoilValue<AppStateOptions>(appStateAtom);
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom); const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
@ -194,9 +205,23 @@ export const Content: FC = () => {
const { account: fediverseAccount } = federation; const { account: fediverseAccount } = federation;
const { browser: browserNotifications } = notifications; const { browser: browserNotifications } = notifications;
const { enabled: browserNotificationsEnabled } = browserNotifications; const { enabled: browserNotificationsEnabled } = browserNotifications;
const [externalActionToDisplay, setExternalActionToDisplay] = useState<ExternalAction>(null);
const externalActionSelected = (action: ExternalAction) => {
const { openExternally, url } = action;
if (openExternally) {
window.open(url, '_blank');
} else {
setExternalActionToDisplay(action);
}
};
const externalActionButtons = externalActions.map(action => ( const externalActionButtons = externalActions.map(action => (
<ActionButton key={action.url} action={action} /> <ActionButton
key={action.url}
action={action}
externalActionSelected={externalActionSelected}
/>
)); ));
const incrementVisitCounter = () => { const incrementVisitCounter = () => {
@ -232,88 +257,100 @@ export const Content: FC = () => {
incrementVisitCounter(); incrementVisitCounter();
checkIfMobile(); checkIfMobile();
window.addEventListener('resize', checkIfMobile); window.addEventListener('resize', checkIfMobile);
return () => {
window.removeEventListener('resize', checkIfMobile);
};
}, []); }, []);
const showChat = !chatDisabled && isChatAvailable && isChatVisible; const showChat = !chatDisabled && isChatAvailable && isChatVisible;
return ( return (
<div className={styles.main}> <>
<Spin wrapperClassName={styles.loadingSpinner} size="large" spinning={appState.appLoading}> <div className={styles.main}>
<AntContent className={styles.root}> <Spin wrapperClassName={styles.loadingSpinner} size="large" spinning={appState.appLoading}>
<div className={styles.mainSection}> <AntContent className={styles.root}>
<div className={styles.topSection}> <div className={styles.mainSection}>
{online && <OwncastPlayer source="/hls/stream.m3u8" online={online} />} <div className={styles.topSection}>
{!online && !appState.appLoading && ( {online && <OwncastPlayer source="/hls/stream.m3u8" online={online} />}
<OfflineBanner {!online && !appState.appLoading && (
streamName={name} <OfflineBanner
customText={offlineMessage} streamName={name}
notificationsEnabled={browserNotificationsEnabled} customText={offlineMessage}
fediverseAccount={fediverseAccount} notificationsEnabled={browserNotificationsEnabled}
lastLive={lastDisconnectTime} fediverseAccount={fediverseAccount}
onNotifyClick={() => setShowNotifyPopup(true)} lastLive={lastDisconnectTime}
/> onNotifyClick={() => setShowNotifyPopup(true)}
)} />
{online && ( )}
<Statusbar {online && (
online={online} <Statusbar
lastConnectTime={lastConnectTime} online={online}
lastDisconnectTime={lastDisconnectTime} lastConnectTime={lastConnectTime}
viewerCount={viewerCount} lastDisconnectTime={lastDisconnectTime}
/> viewerCount={viewerCount}
)} />
</div> )}
<div className={styles.midSection}>
<div className={styles.buttonsLogoTitleSection}>
<ActionButtonRow>
{externalActionButtons}
<FollowButton size="small" />
<NotifyReminderPopup
open={showNotifyReminder}
notificationClicked={() => setShowNotifyPopup(true)}
notificationClosed={() => disableNotifyReminderPopup()}
>
<NotifyButton onClick={() => setShowNotifyPopup(true)} />
</NotifyReminderPopup>
</ActionButtonRow>
<Modal
title="Notify"
open={showNotifyPopup}
afterClose={() => disableNotifyReminderPopup()}
handleCancel={() => disableNotifyReminderPopup()}
>
<BrowserNotifyModal />
</Modal>
</div> </div>
<div className={styles.midSection}>
<div className={styles.buttonsLogoTitleSection}>
<ActionButtonRow>
{externalActionButtons}
<FollowButton size="small" />
<NotifyReminderPopup
open={showNotifyReminder}
notificationClicked={() => setShowNotifyPopup(true)}
notificationClosed={() => disableNotifyReminderPopup()}
>
<NotifyButton onClick={() => setShowNotifyPopup(true)} />
</NotifyReminderPopup>
</ActionButtonRow>
<Modal
title="Notify"
open={showNotifyPopup}
afterClose={() => disableNotifyReminderPopup()}
handleCancel={() => disableNotifyReminderPopup()}
>
<BrowserNotifyModal />
</Modal>
</div>
</div>
{isMobile && isChatVisible ? (
<MobileContent
name={name}
streamTitle={streamTitle}
summary={summary}
tags={tags}
socialHandles={socialHandles}
extraPageContent={extraPageContent}
messages={messages}
currentUser={currentUser}
showChat={showChat}
/>
) : (
<DesktopContent
name={name}
streamTitle={streamTitle}
summary={summary}
tags={tags}
socialHandles={socialHandles}
extraPageContent={extraPageContent}
/>
)}
</div> </div>
{isMobile && isChatVisible ? ( {showChat && !isMobile && <Sidebar />}
<MobileContent </AntContent>
name={name} </Spin>
streamTitle={streamTitle} {!isMobile && <Footer version={version} />}
summary={summary} </div>
tags={tags}
socialHandles={socialHandles} {externalActionToDisplay && (
extraPageContent={extraPageContent} <ExternalModal
messages={messages} externalActionToDisplay={externalActionToDisplay}
currentUser={currentUser} setExternalActionToDisplay={setExternalActionToDisplay}
showChat={showChat} />
/> )}
) : ( </>
<DesktopContent
name={name}
streamTitle={streamTitle}
summary={summary}
tags={tags}
socialHandles={socialHandles}
extraPageContent={extraPageContent}
/>
)}
</div>
{showChat && !isMobile && <Sidebar />}
</AntContent>
</Spin>
{!isMobile && <Footer version={version} />}
</div>
); );
}; };
export default Content; export default Content;