mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-28 13:47:23 +00:00
[Glitch] Wrapstodon: Allow dismissing banner
Port 10f232ca08 to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
@@ -1,38 +1,60 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { fn } from 'storybook/test';
|
||||
import { action } from 'storybook/actions';
|
||||
|
||||
import type { AnyFunction, OmitValueType } from '@/flavours/glitch/utils/types';
|
||||
|
||||
import type { AnnualReportAnnouncementProps } from '.';
|
||||
import { AnnualReportAnnouncement } from '.';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/AnnualReportAnnouncement',
|
||||
component: AnnualReportAnnouncement,
|
||||
args: {
|
||||
hasData: false,
|
||||
isLoading: false,
|
||||
year: '2025',
|
||||
onRequestBuild: fn(),
|
||||
onOpen: fn(),
|
||||
type Props = OmitValueType<
|
||||
// We can't use the name 'state' here because it's reserved for overriding Redux state.
|
||||
Omit<AnnualReportAnnouncementProps, 'state'> & {
|
||||
reportState: AnnualReportAnnouncementProps['state'];
|
||||
},
|
||||
} satisfies Meta<typeof AnnualReportAnnouncement>;
|
||||
AnyFunction // Remove any functions, as they can't meaningfully be controlled in Storybook.
|
||||
>;
|
||||
|
||||
const meta = {
|
||||
title: 'Components/AnnualReport/Announcement',
|
||||
args: {
|
||||
reportState: 'eligible',
|
||||
year: '2025',
|
||||
},
|
||||
argTypes: {
|
||||
reportState: {
|
||||
control: {
|
||||
type: 'select',
|
||||
},
|
||||
options: ['eligible', 'generating', 'available'],
|
||||
},
|
||||
},
|
||||
render({ reportState, ...args }: Props) {
|
||||
return (
|
||||
<AnnualReportAnnouncement
|
||||
state={reportState}
|
||||
{...args}
|
||||
onDismiss={action('dismissed announcement')}
|
||||
onOpen={action('opened report modal')}
|
||||
onRequestBuild={action('requested build')}
|
||||
/>
|
||||
);
|
||||
},
|
||||
} satisfies Meta<Props>;
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: (args) => <AnnualReportAnnouncement {...args} />,
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Loading: Story = {
|
||||
args: {
|
||||
isLoading: true,
|
||||
reportState: 'generating',
|
||||
},
|
||||
render: Default.render,
|
||||
};
|
||||
|
||||
export const WithData: Story = {
|
||||
args: {
|
||||
hasData: true,
|
||||
reportState: 'available',
|
||||
},
|
||||
render: Default.render,
|
||||
};
|
||||
|
||||
@@ -2,33 +2,36 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import type { ApiAnnualReportState } from '@/flavours/glitch/api/annual_report';
|
||||
import { Button } from '@/flavours/glitch/components/button';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
export const AnnualReportAnnouncement: React.FC<{
|
||||
export interface AnnualReportAnnouncementProps {
|
||||
year: string;
|
||||
hasData: boolean;
|
||||
isLoading: boolean;
|
||||
state: Exclude<ApiAnnualReportState, 'ineligible'>;
|
||||
onRequestBuild: () => void;
|
||||
onOpen: () => void;
|
||||
}> = ({ year, hasData, isLoading, onRequestBuild, onOpen }) => {
|
||||
onDismiss: () => void;
|
||||
}
|
||||
|
||||
export const AnnualReportAnnouncement: React.FC<
|
||||
AnnualReportAnnouncementProps
|
||||
> = ({ year, state, onRequestBuild, onOpen, onDismiss }) => {
|
||||
return (
|
||||
<div className={classNames('theme-dark', styles.wrapper)}>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.title'
|
||||
defaultMessage='Wrapstodon {year} has arrived'
|
||||
values={{ year }}
|
||||
/>
|
||||
</h2>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.description'
|
||||
defaultMessage='Discover more about your engagement on Mastodon over the past year.'
|
||||
/>
|
||||
</p>
|
||||
{hasData ? (
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.title'
|
||||
defaultMessage='Wrapstodon {year} has arrived'
|
||||
values={{ year }}
|
||||
tagName='h2'
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.description'
|
||||
defaultMessage='Discover more about your engagement on Mastodon over the past year.'
|
||||
tagName='p'
|
||||
/>
|
||||
{state === 'available' ? (
|
||||
<Button onClick={onOpen}>
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.action_view'
|
||||
@@ -36,13 +39,21 @@ export const AnnualReportAnnouncement: React.FC<{
|
||||
/>
|
||||
</Button>
|
||||
) : (
|
||||
<Button loading={isLoading} onClick={onRequestBuild}>
|
||||
<Button loading={state === 'generating'} onClick={onRequestBuild}>
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.action_build'
|
||||
defaultMessage='Build my Wrapstodon'
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
{state === 'eligible' && (
|
||||
<Button onClick={onDismiss} plain className={styles.closeButton}>
|
||||
<FormattedMessage
|
||||
id='annual_report.announcement.action_dismiss'
|
||||
defaultMessage='No thanks'
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
radial-gradient(at 16% 95%, #1e948299 0, transparent 50%)
|
||||
var(--color-bg-primary);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
position: relative;
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
@@ -26,4 +27,11 @@
|
||||
p {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
margin-inline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useCallback } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { openModal } from '@/flavours/glitch/actions/modal';
|
||||
import { useDismissible } from '@/flavours/glitch/hooks/useDismissible';
|
||||
import {
|
||||
generateReport,
|
||||
selectWrapstodonYear,
|
||||
@@ -19,21 +20,26 @@ export const AnnualReportTimeline: FC = () => {
|
||||
void dispatch(generateReport());
|
||||
}, [dispatch]);
|
||||
|
||||
const { wasDismissed, dismiss } = useDismissible(
|
||||
`annual_report_announcement_${year}`,
|
||||
);
|
||||
|
||||
const handleOpen = useCallback(() => {
|
||||
dispatch(openModal({ modalType: 'ANNUAL_REPORT', modalProps: {} }));
|
||||
}, [dispatch]);
|
||||
dismiss();
|
||||
}, [dismiss, dispatch]);
|
||||
|
||||
if (!year || !state || state === 'ineligible') {
|
||||
if (!year || wasDismissed || !state || state === 'ineligible') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnnualReportAnnouncement
|
||||
year={year.toString()}
|
||||
hasData={state === 'available'}
|
||||
isLoading={state === 'generating'}
|
||||
state={state}
|
||||
onRequestBuild={handleBuildRequest}
|
||||
onOpen={handleOpen}
|
||||
onDismiss={dismiss}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export const CriticalUpdateBanner = () => (
|
||||
<div className='warning-banner'>
|
||||
<div className='warning-banner__message'>
|
||||
<h1>
|
||||
import { criticalUpdatesPending } from '@/flavours/glitch/initial_state';
|
||||
|
||||
export const CriticalUpdateBanner: FC = () => {
|
||||
if (!criticalUpdatesPending) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className='warning-banner'>
|
||||
<div className='warning-banner__message'>
|
||||
<FormattedMessage
|
||||
id='home.pending_critical_update.title'
|
||||
defaultMessage='Critical security update available!'
|
||||
tagName='h1'
|
||||
/>
|
||||
</h1>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='home.pending_critical_update.body'
|
||||
defaultMessage='Please update your Mastodon server as soon as possible!'
|
||||
/>{' '}
|
||||
<a href='/admin/software_updates'>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='home.pending_critical_update.link'
|
||||
defaultMessage='See updates'
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
id='home.pending_critical_update.body'
|
||||
defaultMessage='Please update your Mastodon server as soon as possible!'
|
||||
/>{' '}
|
||||
<a href='/admin/software_updates'>
|
||||
<FormattedMessage
|
||||
id='home.pending_critical_update.link'
|
||||
defaultMessage='See updates'
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,7 +15,6 @@ import { fetchAnnouncements, toggleShowAnnouncements } from 'flavours/glitch/act
|
||||
import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge';
|
||||
import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator';
|
||||
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
||||
import { criticalUpdatesPending } from 'flavours/glitch/initial_state';
|
||||
import { withBreakpoint } from 'flavours/glitch/features/ui/hooks/useBreakpoint';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
@@ -27,6 +26,7 @@ import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import { ColumnSettings } from './components/column_settings';
|
||||
import { CriticalUpdateBanner } from './components/critical_update_banner';
|
||||
import { Announcements } from './components/announcements';
|
||||
import { AnnualReportTimeline } from '../annual_report/timeline';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.home', defaultMessage: 'Home' },
|
||||
@@ -129,7 +129,10 @@ class HomeTimeline extends PureComponent {
|
||||
const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements, matchesBreakpoint } = this.props;
|
||||
const pinned = !!columnId;
|
||||
const { signedIn } = this.props.identity;
|
||||
const banners = [];
|
||||
const banners = [
|
||||
<CriticalUpdateBanner key='critical-update-banner' />,
|
||||
<AnnualReportTimeline key='annual-report' />
|
||||
];
|
||||
|
||||
let announcementsButton;
|
||||
|
||||
@@ -147,10 +150,6 @@ class HomeTimeline extends PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
if (criticalUpdatesPending) {
|
||||
banners.push(<CriticalUpdateBanner key='critical-update-banner' />);
|
||||
}
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
|
||||
Reference in New Issue
Block a user