271 lines
6.8 KiB
TypeScript
271 lines
6.8 KiB
TypeScript
import { useCallback, useMemo } from 'react';
|
||
import type { FC } from 'react';
|
||
|
||
import { defineMessage, FormattedMessage, useIntl } from 'react-intl';
|
||
|
||
import AnniversaryImage from '@/images/anniversary.svg?react';
|
||
import { focusCompose, resetCompose } from '@/mastodon/actions/compose';
|
||
import { closeModal } from '@/mastodon/actions/modal';
|
||
import { Button } from '@/mastodon/components/button';
|
||
import { DisplayNameSimple } from '@/mastodon/components/display_name/simple';
|
||
import { FormattedDateWrapper } from '@/mastodon/components/formatted_date';
|
||
import { IconButton } from '@/mastodon/components/icon_button';
|
||
import { ModalShell, ModalShellBody } from '@/mastodon/components/modal_shell';
|
||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
||
import {
|
||
createAppSelector,
|
||
useAppDispatch,
|
||
useAppSelector,
|
||
} from '@/mastodon/store';
|
||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||
|
||
import classes from './styles.module.scss';
|
||
|
||
const closeMessage = defineMessage({
|
||
id: 'lightbox.close',
|
||
defaultMessage: 'Close',
|
||
});
|
||
|
||
const selectServerName = createAppSelector(
|
||
[
|
||
(state) => state.accounts,
|
||
(_, accountId: string) => accountId,
|
||
(state) => state.server.server.item?.domain,
|
||
],
|
||
(accounts, accountId, serverDomain) => {
|
||
const acct = accounts.getIn([accountId, 'acct']) as string | undefined;
|
||
if (!acct) {
|
||
return undefined;
|
||
}
|
||
|
||
const domain = acct.split('@').at(1);
|
||
if (domain) {
|
||
return domain;
|
||
}
|
||
|
||
return serverDomain;
|
||
},
|
||
);
|
||
|
||
export const AccountJoinModal: FC<{
|
||
accountId: string;
|
||
onClose: () => void;
|
||
}> = ({ accountId, onClose }) => {
|
||
const intl = useIntl();
|
||
const account = useAccount(accountId);
|
||
const currentId = useCurrentAccountId();
|
||
const isMe = accountId === currentId;
|
||
|
||
const createdAtStr = account?.created_at;
|
||
const anniversary = useMemo(() => {
|
||
if (!createdAtStr) {
|
||
return null;
|
||
}
|
||
const now = new Date();
|
||
const createdAt = new Date(createdAtStr);
|
||
if (
|
||
now.getMonth() === createdAt.getMonth() &&
|
||
now.getDate() === createdAt.getDate()
|
||
) {
|
||
return now.getFullYear() - createdAt.getFullYear();
|
||
}
|
||
return null;
|
||
}, [createdAtStr]);
|
||
|
||
const domain = useAppSelector((state) => selectServerName(state, accountId));
|
||
|
||
const dispatch = useAppDispatch();
|
||
const handle = account?.acct;
|
||
const handleShare = useCallback(() => {
|
||
if (anniversary === null) {
|
||
return;
|
||
}
|
||
|
||
let shareText = '#Fediversary';
|
||
if (anniversary === 0) {
|
||
shareText = isMe ? '#firstday' : '#welcome';
|
||
}
|
||
|
||
if (!isMe && handle) {
|
||
shareText = `@${handle} ${shareText}`;
|
||
}
|
||
|
||
dispatch(resetCompose());
|
||
dispatch(focusCompose(`\n\n${shareText}`, true));
|
||
dispatch(closeModal({ modalType: 'ACCOUNT_JOIN_DATE', ignoreFocus: true }));
|
||
}, [anniversary, handle, dispatch, isMe]);
|
||
|
||
return (
|
||
<ModalShell as='div' className={classes.joinShell}>
|
||
<ModalShellBody className={classes.joinWrapper}>
|
||
<AccountAnniversaryImage anniversary={anniversary} />
|
||
|
||
<div>
|
||
<AccountJoinMessage
|
||
name={<DisplayNameSimple account={account} />}
|
||
isMe={isMe}
|
||
serverName={domain}
|
||
anniversary={anniversary}
|
||
/>
|
||
<h1>
|
||
<FormattedDateWrapper
|
||
value={account?.created_at}
|
||
month='short'
|
||
day='numeric'
|
||
year='numeric'
|
||
/>
|
||
</h1>
|
||
</div>
|
||
|
||
<AccountAnniversaryShare
|
||
anniversary={anniversary}
|
||
onShare={handleShare}
|
||
isMe={isMe}
|
||
/>
|
||
|
||
<IconButton
|
||
iconComponent={CloseIcon}
|
||
icon='times'
|
||
onClick={onClose}
|
||
title={intl.formatMessage(closeMessage)}
|
||
className={classes.joinClose}
|
||
/>
|
||
</ModalShellBody>
|
||
</ModalShell>
|
||
);
|
||
};
|
||
|
||
const AccountJoinMessage: FC<{
|
||
name: React.JSX.Element;
|
||
isMe: boolean;
|
||
serverName?: string;
|
||
anniversary: number | null;
|
||
}> = ({ name, isMe, serverName, anniversary }) => {
|
||
if (anniversary === 0) {
|
||
if (isMe) {
|
||
return (
|
||
<FormattedMessage
|
||
id='account.join_modal.me_today'
|
||
defaultMessage='It’s your first day on {server}!'
|
||
tagName='p'
|
||
values={{
|
||
server: serverName,
|
||
}}
|
||
/>
|
||
);
|
||
}
|
||
return (
|
||
<FormattedMessage
|
||
id='account.join_modal.other_today'
|
||
defaultMessage='It’s {name}’s first day on {server}!'
|
||
tagName='p'
|
||
values={{
|
||
name,
|
||
server: serverName,
|
||
}}
|
||
/>
|
||
);
|
||
}
|
||
|
||
if (isMe) {
|
||
if (anniversary !== null && anniversary > 0) {
|
||
return (
|
||
<FormattedMessage
|
||
id='account.join_modal.me_anniversary'
|
||
defaultMessage='Happy Fediversary! You joined {server} on'
|
||
tagName='p'
|
||
values={{
|
||
server: serverName,
|
||
}}
|
||
/>
|
||
);
|
||
}
|
||
return (
|
||
<FormattedMessage
|
||
id='account.join_modal.me'
|
||
defaultMessage='You joined {server} on'
|
||
tagName='p'
|
||
values={{
|
||
server: serverName,
|
||
}}
|
||
/>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<FormattedMessage
|
||
id='account.join_modal.other'
|
||
defaultMessage='{name} joined {server} on'
|
||
tagName='p'
|
||
values={{
|
||
name,
|
||
server: serverName,
|
||
}}
|
||
/>
|
||
);
|
||
};
|
||
|
||
const AccountAnniversaryImage: FC<{ anniversary: number | null }> = ({
|
||
anniversary,
|
||
}) => {
|
||
if (anniversary === null) {
|
||
return null;
|
||
}
|
||
|
||
return (
|
||
<div className={classes.joinBanner}>
|
||
<AnniversaryImage role='presentation' />
|
||
<h2>{anniversary || 1}</h2>
|
||
{anniversary === 0 && (
|
||
<FormattedMessage
|
||
id='account.join_modal.day'
|
||
defaultMessage='Day'
|
||
tagName='h3'
|
||
/>
|
||
)}
|
||
{anniversary > 0 && (
|
||
<FormattedMessage
|
||
id='account.join_modal.years'
|
||
defaultMessage='{number, plural, one {year} other {years}}'
|
||
values={{ number: anniversary }}
|
||
tagName='h3'
|
||
/>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
const AccountAnniversaryShare: FC<{
|
||
anniversary: number | null;
|
||
onShare: () => void;
|
||
isMe: boolean;
|
||
}> = ({ anniversary, onShare, isMe }) => {
|
||
if (anniversary === null) {
|
||
return null;
|
||
}
|
||
|
||
return (
|
||
<Button onClick={onShare}>
|
||
{anniversary === 0 && isMe && (
|
||
<FormattedMessage
|
||
id='account.join_modal.share.intro'
|
||
defaultMessage='Share an intro post'
|
||
/>
|
||
)}
|
||
{anniversary === 0 && !isMe && (
|
||
<FormattedMessage
|
||
id='account.join_modal.share.welcome'
|
||
defaultMessage='Share a welcome post'
|
||
/>
|
||
)}
|
||
{anniversary > 0 && (
|
||
<FormattedMessage
|
||
id='account.join_modal.share.celebrate'
|
||
defaultMessage='Share a celebratory post'
|
||
/>
|
||
)}
|
||
</Button>
|
||
);
|
||
};
|