Add follow+notify to actions menu and refactor how those modals are displayed. Closes #2247
This commit is contained in:
@@ -41,3 +41,22 @@ export const Example = Template.bind({});
|
|||||||
Example.args = {
|
Example.args = {
|
||||||
actions,
|
actions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ShowFollowExample = Template.bind({});
|
||||||
|
ShowFollowExample.args = {
|
||||||
|
actions,
|
||||||
|
showFollowItem: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ShowNotifyExample = Template.bind({});
|
||||||
|
ShowNotifyExample.args = {
|
||||||
|
actions,
|
||||||
|
showNotifyItem: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ShowNotifyAndFollowExample = Template.bind({});
|
||||||
|
ShowNotifyAndFollowExample.args = {
|
||||||
|
actions,
|
||||||
|
showNotifyItem: true,
|
||||||
|
showFollowItem: true,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,19 +1,38 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Button, Dropdown, Menu } from 'antd';
|
import { Button, Dropdown, Menu } from 'antd';
|
||||||
import { EllipsisOutlined } from '@ant-design/icons';
|
import { EllipsisOutlined, HeartOutlined, BellOutlined } from '@ant-design/icons';
|
||||||
import styles from './ActionButtonMenu.module.scss';
|
import styles from './ActionButtonMenu.module.scss';
|
||||||
import { ExternalAction } from '../../../interfaces/external-action';
|
import { ExternalAction } from '../../../interfaces/external-action';
|
||||||
|
|
||||||
|
const NOTIFY_KEY = 'notify';
|
||||||
|
const FOLLOW_KEY = 'follow';
|
||||||
|
|
||||||
export type ActionButtonMenuProps = {
|
export type ActionButtonMenuProps = {
|
||||||
actions: ExternalAction[];
|
actions: ExternalAction[];
|
||||||
|
showFollowItem?: boolean;
|
||||||
|
showNotifyItem?: boolean;
|
||||||
externalActionSelected: (action: ExternalAction) => void;
|
externalActionSelected: (action: ExternalAction) => void;
|
||||||
|
notifyItemSelected: () => void;
|
||||||
|
followItemSelected: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActionButtonMenu: FC<ActionButtonMenuProps> = ({
|
export const ActionButtonMenu: FC<ActionButtonMenuProps> = ({
|
||||||
actions,
|
actions,
|
||||||
externalActionSelected,
|
externalActionSelected,
|
||||||
|
notifyItemSelected,
|
||||||
|
followItemSelected,
|
||||||
|
showFollowItem,
|
||||||
|
showNotifyItem,
|
||||||
}) => {
|
}) => {
|
||||||
const onMenuClick = a => {
|
const onMenuClick = a => {
|
||||||
|
if (a.key === NOTIFY_KEY) {
|
||||||
|
notifyItemSelected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (a.key === FOLLOW_KEY) {
|
||||||
|
followItemSelected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const action = actions.find(x => x.url === a.key);
|
const action = actions.find(x => x.url === a.key);
|
||||||
externalActionSelected(action);
|
externalActionSelected(action);
|
||||||
};
|
};
|
||||||
@@ -28,6 +47,29 @@ export const ActionButtonMenu: FC<ActionButtonMenuProps> = ({
|
|||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (showFollowItem) {
|
||||||
|
items.unshift({
|
||||||
|
key: FOLLOW_KEY,
|
||||||
|
label: (
|
||||||
|
<span className={styles.item}>
|
||||||
|
<HeartOutlined className={styles.icon} /> Follow this stream
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showNotifyItem) {
|
||||||
|
items.unshift({
|
||||||
|
key: NOTIFY_KEY,
|
||||||
|
label: (
|
||||||
|
<span className={styles.item}>
|
||||||
|
<BellOutlined className={styles.icon} />
|
||||||
|
Notify when live
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const menu = <Menu items={items} onClick={onMenuClick} />;
|
const menu = <Menu items={items} onClick={onMenuClick} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,40 +1,22 @@
|
|||||||
import { Button, ButtonProps } from 'antd';
|
import { Button, ButtonProps } from 'antd';
|
||||||
import { HeartFilled } from '@ant-design/icons';
|
import { HeartFilled } from '@ant-design/icons';
|
||||||
import { FC, useState } from 'react';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { FC } from 'react';
|
||||||
import { Modal } from '../ui/Modal/Modal';
|
|
||||||
import { FollowModal } from '../modals/FollowModal/FollowModal';
|
|
||||||
import styles from './ActionButton/ActionButton.module.scss';
|
import styles from './ActionButton/ActionButton.module.scss';
|
||||||
import { clientConfigStateAtom } from '../stores/ClientConfigStore';
|
|
||||||
import { ClientConfig } from '../../interfaces/client-config.model';
|
|
||||||
|
|
||||||
export type FollowButtonProps = ButtonProps;
|
export type FollowButtonProps = ButtonProps & {
|
||||||
|
onClick?: () => void;
|
||||||
export const FollowButton: FC<FollowButtonProps> = props => {
|
props?: ButtonProps;
|
||||||
const [showModal, setShowModal] = useState(false);
|
|
||||||
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
|
|
||||||
const { name, federation } = clientConfig;
|
|
||||||
const { account } = federation;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
{...props}
|
|
||||||
type="primary"
|
|
||||||
className={styles.button}
|
|
||||||
icon={<HeartFilled />}
|
|
||||||
onClick={() => setShowModal(true)}
|
|
||||||
>
|
|
||||||
Follow
|
|
||||||
</Button>
|
|
||||||
<Modal
|
|
||||||
title={`Follow ${name}`}
|
|
||||||
open={showModal}
|
|
||||||
handleCancel={() => setShowModal(false)}
|
|
||||||
width="550px"
|
|
||||||
>
|
|
||||||
<FollowModal account={account} name={name} handleClose={() => setShowModal(false)} />
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const FollowButton: FC<FollowButtonProps> = ({ onClick, props }) => (
|
||||||
|
<Button
|
||||||
|
{...props}
|
||||||
|
type="primary"
|
||||||
|
className={styles.button}
|
||||||
|
icon={<HeartFilled />}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
Follow
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { FollowerCollection } from '../followers/FollowerCollection/FollowerColl
|
|||||||
import { ExternalAction } from '../../../interfaces/external-action';
|
import { ExternalAction } from '../../../interfaces/external-action';
|
||||||
import { Modal } from '../Modal/Modal';
|
import { Modal } from '../Modal/Modal';
|
||||||
import { ActionButtonMenu } from '../../action-buttons/ActionButtonMenu/ActionButtonMenu';
|
import { ActionButtonMenu } from '../../action-buttons/ActionButtonMenu/ActionButtonMenu';
|
||||||
|
import { FollowModal } from '../../modals/FollowModal/FollowModal';
|
||||||
|
|
||||||
const { Content: AntContent } = Layout;
|
const { Content: AntContent } = Layout;
|
||||||
|
|
||||||
@@ -116,6 +117,8 @@ const MobileContent = ({
|
|||||||
showChat,
|
showChat,
|
||||||
actions,
|
actions,
|
||||||
setExternalActionToDisplay,
|
setExternalActionToDisplay,
|
||||||
|
setShowNotifyPopup,
|
||||||
|
setShowFollowModal,
|
||||||
}) => {
|
}) => {
|
||||||
if (!currentUser) {
|
if (!currentUser) {
|
||||||
return null;
|
return null;
|
||||||
@@ -160,7 +163,14 @@ const MobileContent = ({
|
|||||||
const replacementTabBar = (props, DefaultTabBar) => (
|
const replacementTabBar = (props, DefaultTabBar) => (
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}>
|
||||||
<DefaultTabBar {...props} style={{ width: '85%' }} />
|
<DefaultTabBar {...props} style={{ width: '85%' }} />
|
||||||
<ActionButtonMenu actions={actions} externalActionSelected={setExternalActionToDisplay} />
|
<ActionButtonMenu
|
||||||
|
showFollowItem
|
||||||
|
showNotifyItem
|
||||||
|
actions={actions}
|
||||||
|
externalActionSelected={setExternalActionToDisplay}
|
||||||
|
notifyItemSelected={() => setShowNotifyPopup(true)}
|
||||||
|
followItemSelected={() => setShowFollowModal(true)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -211,7 +221,8 @@ export const Content: FC = () => {
|
|||||||
notifications,
|
notifications,
|
||||||
} = clientConfig;
|
} = clientConfig;
|
||||||
const [showNotifyReminder, setShowNotifyReminder] = useState(false);
|
const [showNotifyReminder, setShowNotifyReminder] = useState(false);
|
||||||
const [showNotifyPopup, setShowNotifyPopup] = useState(false);
|
const [showNotifyModal, setShowNotifyModal] = useState(false);
|
||||||
|
const [showFollowModal, setShowFollowModal] = useState(false);
|
||||||
const { account: fediverseAccount } = federation;
|
const { account: fediverseAccount } = federation;
|
||||||
const { browser: browserNotifications } = notifications;
|
const { browser: browserNotifications } = notifications;
|
||||||
const { enabled: browserNotificationsEnabled } = browserNotifications;
|
const { enabled: browserNotificationsEnabled } = browserNotifications;
|
||||||
@@ -248,7 +259,7 @@ export const Content: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const disableNotifyReminderPopup = () => {
|
const disableNotifyReminderPopup = () => {
|
||||||
setShowNotifyPopup(false);
|
setShowNotifyModal(false);
|
||||||
setShowNotifyReminder(false);
|
setShowNotifyReminder(false);
|
||||||
setLocalStorage(LOCAL_STORAGE_KEYS.hasDisplayedNotificationModal, true);
|
setLocalStorage(LOCAL_STORAGE_KEYS.hasDisplayedNotificationModal, true);
|
||||||
};
|
};
|
||||||
@@ -289,7 +300,7 @@ export const Content: FC = () => {
|
|||||||
notificationsEnabled={browserNotificationsEnabled}
|
notificationsEnabled={browserNotificationsEnabled}
|
||||||
fediverseAccount={fediverseAccount}
|
fediverseAccount={fediverseAccount}
|
||||||
lastLive={lastDisconnectTime}
|
lastLive={lastDisconnectTime}
|
||||||
onNotifyClick={() => setShowNotifyPopup(true)}
|
onNotifyClick={() => setShowNotifyModal(true)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{online && (
|
{online && (
|
||||||
@@ -306,20 +317,20 @@ export const Content: FC = () => {
|
|||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<ActionButtonRow>
|
<ActionButtonRow>
|
||||||
{externalActionButtons}
|
{externalActionButtons}
|
||||||
<FollowButton size="small" />
|
<FollowButton size="small" onClick={() => setShowFollowModal(true)} />
|
||||||
<NotifyReminderPopup
|
<NotifyReminderPopup
|
||||||
open={showNotifyReminder}
|
open={showNotifyReminder}
|
||||||
notificationClicked={() => setShowNotifyPopup(true)}
|
notificationClicked={() => setShowNotifyModal(true)}
|
||||||
notificationClosed={() => disableNotifyReminderPopup()}
|
notificationClosed={() => disableNotifyReminderPopup()}
|
||||||
>
|
>
|
||||||
<NotifyButton onClick={() => setShowNotifyPopup(true)} />
|
<NotifyButton onClick={() => setShowNotifyModal(true)} />
|
||||||
</NotifyReminderPopup>
|
</NotifyReminderPopup>
|
||||||
</ActionButtonRow>
|
</ActionButtonRow>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title="Notify"
|
title="Notify"
|
||||||
open={showNotifyPopup}
|
open={showNotifyModal}
|
||||||
afterClose={() => disableNotifyReminderPopup()}
|
afterClose={() => disableNotifyReminderPopup()}
|
||||||
handleCancel={() => disableNotifyReminderPopup()}
|
handleCancel={() => disableNotifyReminderPopup()}
|
||||||
>
|
>
|
||||||
@@ -340,6 +351,8 @@ export const Content: FC = () => {
|
|||||||
showChat={showChat}
|
showChat={showChat}
|
||||||
actions={externalActions}
|
actions={externalActions}
|
||||||
setExternalActionToDisplay={externalActionSelected}
|
setExternalActionToDisplay={externalActionSelected}
|
||||||
|
setShowNotifyPopup={setShowNotifyModal}
|
||||||
|
setShowFollowModal={setShowFollowModal}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DesktopContent
|
<DesktopContent
|
||||||
@@ -357,13 +370,24 @@ export const Content: FC = () => {
|
|||||||
</Spin>
|
</Spin>
|
||||||
{!isMobile && false && <Footer version={version} />}
|
{!isMobile && false && <Footer version={version} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{externalActionToDisplay && (
|
{externalActionToDisplay && (
|
||||||
<ExternalModal
|
<ExternalModal
|
||||||
externalActionToDisplay={externalActionToDisplay}
|
externalActionToDisplay={externalActionToDisplay}
|
||||||
setExternalActionToDisplay={setExternalActionToDisplay}
|
setExternalActionToDisplay={setExternalActionToDisplay}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<Modal
|
||||||
|
title={`Follow ${name}`}
|
||||||
|
open={showFollowModal}
|
||||||
|
handleCancel={() => setShowFollowModal(false)}
|
||||||
|
width="550px"
|
||||||
|
>
|
||||||
|
<FollowModal
|
||||||
|
account={fediverseAccount}
|
||||||
|
name={name}
|
||||||
|
handleClose={() => setShowFollowModal(false)}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user