Files
mastodon/app/javascript/flavours/glitch/features/annual_report/index.tsx
diondiondion 5a66331003 [Glitch] Update Wrapstodon design
Port 9d81561bb2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-09 18:27:14 +01:00

124 lines
3.8 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react';
import type { FC } from 'react';
import { defineMessage, FormattedMessage, useIntl } from 'react-intl';
import { useLocation } from 'react-router';
import classNames from 'classnames/bind';
import { closeModal } from '@/flavours/glitch/actions/modal';
import { IconButton } from '@/flavours/glitch/components/icon_button';
import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator';
import { me } from '@/flavours/glitch/initial_state';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import { Archetype } from './archetype';
import { Followers } from './followers';
import { HighlightedPost } from './highlighted_post';
import styles from './index.module.scss';
import { MostUsedHashtag } from './most_used_hashtag';
import { NewPosts } from './new_posts';
const moduleClassNames = classNames.bind(styles);
export const shareMessage = defineMessage({
id: 'annual_report.summary.share_message',
defaultMessage: 'I got the {archetype} archetype!',
});
// Share = false when using the embedded version of the report.
export const AnnualReport: FC<{ context?: 'modal' | 'standalone' }> = ({
context = 'standalone',
}) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const report = useAppSelector((state) => state.annualReport.report);
const account = useAppSelector((state) => {
if (me) {
return state.accounts.get(me);
}
if (report?.schema_version === 2) {
return state.accounts.get(report.account_id);
}
return undefined;
});
const close = useCallback(() => {
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
}, [dispatch]);
// Close modal when navigating away from within
const { pathname } = useLocation();
const [initialPathname] = useState(pathname);
useEffect(() => {
if (pathname !== initialPathname) {
close();
}
}, [pathname, initialPathname, close]);
if (!report) {
return <LoadingIndicator />;
}
const newPostCount = report.data.time_series.reduce(
(sum, item) => sum + item.statuses,
0,
);
const newFollowerCount = report.data.time_series.reduce(
(sum, item) => sum + item.followers,
0,
);
const topHashtag = report.data.top_hashtags[0];
return (
<div className={moduleClassNames(styles.wrapper, 'theme-dark')}>
<div className={styles.header}>
<h1>
<FormattedMessage
id='annual_report.summary.title'
defaultMessage='Wrapstodon {year}'
values={{ year: report.year }}
/>
</h1>
{account && <p>@{account.acct}</p>}
{context === 'modal' && (
<IconButton
title={intl.formatMessage({
id: 'annual_report.summary.close',
defaultMessage: 'Close',
})}
className={styles.closeButton}
icon='close'
iconComponent={CloseIcon}
onClick={close}
/>
)}
</div>
<div className={styles.stack}>
<HighlightedPost data={report.data.top_statuses} />
<div
className={moduleClassNames(styles.statsGrid, {
noHashtag: !topHashtag,
onlyHashtag: !(newFollowerCount && newPostCount),
singleNumber: !!newFollowerCount !== !!newPostCount,
})}
>
{!!newFollowerCount && <Followers count={newFollowerCount} />}
{!!newPostCount && <NewPosts count={newPostCount} />}
{topHashtag && <MostUsedHashtag hashtag={topHashtag} />}
</div>
<Archetype
report={report}
account={account}
canShare={context === 'modal'}
/>
</div>
</div>
);
};