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 { ComponentStory, ComponentMeta } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { ActionButton } from './ActionButton';
export default {
@ -14,8 +15,14 @@ export default {
},
} as ComponentMeta<typeof ActionButton>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const Template: ComponentStory<typeof ActionButton> = args => <ActionButton {...args} />;
const itemSelected = a => {
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
export const Example1 = Template.bind({});

View File

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

View File

@ -1,5 +1,6 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { ActionButtonRow } from './ActionButtonRow';
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({});
Example1.args = {
buttons,

View File

@ -34,13 +34,11 @@ import { ServerStatus } from '../../../interfaces/server-status.model';
import { Statusbar } from '../Statusbar/Statusbar';
import { ChatMessage } from '../../../interfaces/chat-message.model';
import { FollowerCollection } from '../followers/FollowerCollection/FollowerCollection';
import { ExternalAction } from '../../../interfaces/external-action';
import { Modal } from '../Modal/Modal';
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),
);
@ -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 = () => {
const appState = useRecoilValue<AppStateOptions>(appStateAtom);
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
@ -194,9 +205,23 @@ export const Content: FC = () => {
const { account: fediverseAccount } = federation;
const { browser: browserNotifications } = notifications;
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 => (
<ActionButton key={action.url} action={action} />
<ActionButton
key={action.url}
action={action}
externalActionSelected={externalActionSelected}
/>
));
const incrementVisitCounter = () => {
@ -232,88 +257,100 @@ export const Content: FC = () => {
incrementVisitCounter();
checkIfMobile();
window.addEventListener('resize', checkIfMobile);
return () => {
window.removeEventListener('resize', checkIfMobile);
};
}, []);
const showChat = !chatDisabled && isChatAvailable && isChatVisible;
return (
<div className={styles.main}>
<Spin wrapperClassName={styles.loadingSpinner} size="large" spinning={appState.appLoading}>
<AntContent className={styles.root}>
<div className={styles.mainSection}>
<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)}
/>
)}
{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
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 className={styles.main}>
<Spin wrapperClassName={styles.loadingSpinner} size="large" spinning={appState.appLoading}>
<AntContent className={styles.root}>
<div className={styles.mainSection}>
<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)}
/>
)}
{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
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>
{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>
{showChat && !isMobile && <Sidebar />}
</AntContent>
</Spin>
{!isMobile && <Footer version={version} />}
</div>
{showChat && !isMobile && <Sidebar />}
</AntContent>
</Spin>
{!isMobile && <Footer version={version} />}
</div>
{externalActionToDisplay && (
<ExternalModal
externalActionToDisplay={externalActionToDisplay}
setExternalActionToDisplay={setExternalActionToDisplay}
/>
)}
</>
);
};
export default Content;