[Glitch] Show mute end date in badge

Port 7a4945c0d3ed3550e1a22e53c03c6de646d62aec to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Echo 2026-02-05 21:01:28 +01:00 committed by Claire
parent 8f58c42ca3
commit 351b8a719f
5 changed files with 73 additions and 20 deletions

View File

@ -8,8 +8,9 @@ export interface ApiRelationshipJSON {
following: boolean; following: boolean;
id: string; id: string;
languages: string[] | null; languages: string[] | null;
muting_notifications: boolean;
muting: boolean; muting: boolean;
muting_notifications: boolean;
muting_expires_at: string | null;
note: string; note: string;
notifying: boolean; notifying: boolean;
requested_by: boolean; requested_by: boolean;

View File

@ -8,7 +8,7 @@ const meta = {
component: badges.Badge, component: badges.Badge,
title: 'Components/Badge', title: 'Components/Badge',
args: { args: {
label: 'Example', label: undefined,
}, },
} satisfies Meta<typeof badges.Badge>; } satisfies Meta<typeof badges.Badge>;
@ -16,16 +16,22 @@ export default meta;
type Story = StoryObj<typeof meta>; type Story = StoryObj<typeof meta>;
export const Default: Story = {}; export const Default: Story = {
args: {
label: 'Example',
},
};
export const Domain: Story = { export const Domain: Story = {
args: { args: {
...Default.args,
domain: 'example.com', domain: 'example.com',
}, },
}; };
export const CustomIcon: Story = { export const CustomIcon: Story = {
args: { args: {
...Default.args,
icon: <CelebrationIcon />, icon: <CelebrationIcon />,
}, },
}; };
@ -57,6 +63,13 @@ export const Muted: Story = {
}, },
}; };
export const MutedWithDate: Story = {
render(args) {
const futureDate = new Date(new Date().getFullYear(), 11, 31).toISOString();
return <badges.MutedBadge {...args} expiresAt={futureDate} />;
},
};
export const Blocked: Story = { export const Blocked: Story = {
render(args) { render(args) {
return <badges.BlockedBadge {...args} />; return <badges.BlockedBadge {...args} />;

View File

@ -1,6 +1,6 @@
import type { FC, ReactNode } from 'react'; import type { FC, ReactNode } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
@ -36,21 +36,25 @@ export const Badge: FC<BadgeProps> = ({
</div> </div>
); );
export const AdminBadge: FC<Partial<BadgeProps>> = (props) => ( export const AdminBadge: FC<Partial<BadgeProps>> = ({ label, ...props }) => (
<Badge <Badge
icon={<AdminIcon />} icon={<AdminIcon />}
label={ label={
<FormattedMessage id='account.badges.admin' defaultMessage='Admin' /> label ?? (
<FormattedMessage id='account.badges.admin' defaultMessage='Admin' />
)
} }
{...props} {...props}
/> />
); );
export const GroupBadge: FC<Partial<BadgeProps>> = (props) => ( export const GroupBadge: FC<Partial<BadgeProps>> = ({ label, ...props }) => (
<Badge <Badge
icon={<GroupsIcon />} icon={<GroupsIcon />}
label={ label={
<FormattedMessage id='account.badges.group' defaultMessage='Group' /> label ?? (
<FormattedMessage id='account.badges.group' defaultMessage='Group' />
)
} }
{...props} {...props}
/> />
@ -66,21 +70,54 @@ export const AutomatedBadge: FC<{ className?: string }> = ({ className }) => (
/> />
); );
export const MutedBadge: FC<Partial<BadgeProps>> = (props) => ( export const MutedBadge: FC<
<Badge Partial<BadgeProps> & { expiresAt?: string | null }
icon={<VolumeOffIcon />} > = ({ expiresAt, label, ...props }) => {
label={ // Format the date, only showing the year if it's different from the current year.
<FormattedMessage id='account.badges.muted' defaultMessage='Muted' /> const intl = useIntl();
} let formattedDate: string | null = null;
{...props} if (expiresAt) {
/> const expiresDate = new Date(expiresAt);
); const isCurrentYear =
expiresDate.getFullYear() === new Date().getFullYear();
formattedDate = intl.formatDate(expiresDate, {
month: 'short',
day: 'numeric',
...(isCurrentYear ? {} : { year: 'numeric' }),
});
}
return (
<Badge
icon={<VolumeOffIcon />}
label={
label ??
(formattedDate ? (
<FormattedMessage
id='account.badges.muted_until'
defaultMessage='Muted until {until}'
values={{
until: formattedDate,
}}
/>
) : (
<FormattedMessage id='account.badges.muted' defaultMessage='Muted' />
))
}
{...props}
/>
);
};
export const BlockedBadge: FC<Partial<BadgeProps>> = (props) => ( export const BlockedBadge: FC<Partial<BadgeProps>> = ({ label, ...props }) => (
<Badge <Badge
icon={<BlockIcon />} icon={<BlockIcon />}
label={ label={
<FormattedMessage id='account.badges.blocked' defaultMessage='Blocked' /> label ?? (
<FormattedMessage
id='account.badges.blocked'
defaultMessage='Blocked'
/>
)
} }
{...props} {...props}
/> />

View File

@ -106,6 +106,7 @@ export const AccountBadges: FC<{ accountId: string }> = ({ accountId }) => {
<MutedBadge <MutedBadge
key='muted-badge' key='muted-badge'
className={classNames(className, classes.badgeMuted)} className={classNames(className, classes.badgeMuted)}
expiresAt={relationship.muting_expires_at}
/>, />,
); );
} }

View File

@ -15,8 +15,9 @@ const RelationshipFactory = Record<RelationshipShape>({
following: false, following: false,
id: '', id: '',
languages: null, languages: null,
muting_notifications: false,
muting: false, muting: false,
muting_notifications: false,
muting_expires_at: null,
note: '', note: '',
notifying: false, notifying: false,
requested_by: false, requested_by: false,