Fix pass at fixing lint issues

Renaud Chaput 2024-06-12 11:35:17 +02:00
parent 9999fdc9fb
commit 7c58b58ad1
No known key found for this signature in database
GPG Key ID: BCFC859D49B46990
15 changed files with 273 additions and 76 deletions

View File

@ -3,8 +3,10 @@ import { Link } from 'react-router-dom';
import { Avatar } from 'mastodon/components/avatar';
import { useAppSelector } from 'mastodon/store';
const AvatarWrapper = ({ accountId }) => {
const account = useAppSelector(state => state.getIn(['accounts', accountId]));
const AvatarWrapper: React.FC<{ accountId: string }> = ({ accountId }) => {
const account = useAppSelector((state) => state.accounts.get(accountId));
if (!account) return null;
return (
<Link to={`/@${account.get('acct')}`} title={`@${account.get('acct')}`}>
@ -13,8 +15,12 @@ const AvatarWrapper = ({ accountId }) => {
);
};
export const AvatarGroup = ({ accountIds }) => (
export const AvatarGroup: React.FC<{ accountIds: string[] }> = ({
accountIds,
}) => (
<div className='notification-group__avatar-group'>
{accountIds.map(accountId => <AvatarWrapper key={accountId} accountId={accountId} />)}
{accountIds.map((accountId) => (
<AvatarWrapper key={accountId} accountId={accountId} />
))}
</div>
);

View File

@ -1,21 +1,37 @@
import { FormattedMessage } from 'react-intl';
import type { List } from 'immutable';
import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react';
import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react';
import { Avatar } from 'mastodon/components/avatar';
import { DisplayName } from 'mastodon/components/display_name';
import { Icon } from 'mastodon/components/icon';
import type { Status } from 'mastodon/models/status';
import { useAppSelector } from 'mastodon/store';
export const EmbeddedStatus = ({ statusId }) => {
const status = useAppSelector(state => state.getIn(['statuses', statusId]));
const account = useAppSelector(state => state.getIn(['accounts', status?.get('account')]));
export const EmbeddedStatus: React.FC<{ statusId: string }> = ({
statusId,
}) => {
const status = useAppSelector(
(state) => state.statuses.get(statusId) as Status | undefined,
);
const account = useAppSelector((state) =>
state.accounts.get(status?.get('account') as string),
);
if (!status) {
return null;
}
const content = { __html: status.get('contentHtml') };
// Assign status attributes to variables with a forced type, as status is not yet properly typed
const contentHtml = status.get('contentHtml') as string;
const poll = status.get('poll');
const mediaAttachmentsSize = (
status.get('media_attachments') as List<unknown>
).size;
const content = { __html: contentHtml };
return (
<div className='notification-group__embedded-status'>
@ -24,12 +40,32 @@ export const EmbeddedStatus = ({ statusId }) => {
<DisplayName account={account} />
</div>
<div className='notification-group__embedded-status__content reply-indicator__content translate' dangerouslySetInnerHTML={content} />
<div
className='notification-group__embedded-status__content reply-indicator__content translate'
dangerouslySetInnerHTML={content}
/>
{(status.get('poll') || status.get('media_attachments').size > 0) && (
{(poll || mediaAttachmentsSize > 0) && (
<div className='notification-group__embedded-status__attachments reply-indicator__attachments'>
{status.get('poll') && <><Icon icon={BarChart4BarsIcon} /><FormattedMessage id='reply_indicator.poll' defaultMessage='Poll' /></>}
{status.get('media_attachments').size > 0 && <><Icon icon={PhotoLibraryIcon} /><FormattedMessage id='reply_indicator.attachments' defaultMessage='{count, plural, one {# attachment} other {# attachments}}' values={{ count: status.get('media_attachments').size }} /></>}
{!!poll && (
<>
<Icon icon={BarChart4BarsIcon} />
<FormattedMessage
id='reply_indicator.poll'
defaultMessage='Poll'
/>
</>
)}
{mediaAttachmentsSize > 0 && (
<>
<Icon icon={PhotoLibraryIcon} />
<FormattedMessage
id='reply_indicator.attachments'
defaultMessage='{count, plural, one {# attachment} other {# attachments}}'
values={{ count: mediaAttachmentsSize }}
/>
</>
)}
</div>
)}
</div>

View File

@ -4,10 +4,22 @@ import { Link } from 'react-router-dom';
import { useAppSelector } from 'mastodon/store';
export const NamesList = ({ accountIds, total }) => {
const lastAccountId = accountIds[0];
const account = useAppSelector(state => state.getIn(['accounts', lastAccountId]));
const displayedName = <Link to={`/@${account.get('acct')}`} title={`@${account.get('acct')}`}><bdi dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></Link>;
export const NamesList: React.FC<{ accountIds: string[]; total: number }> = ({
accountIds,
total,
}) => {
const lastAccountId = accountIds[0] ?? '0';
const account = useAppSelector((state) => state.accounts.get(lastAccountId));
if (!account) return null;
const displayedName = (
<Link to={`/@${account.get('acct')}`} title={`@${account.get('acct')}`}>
<bdi
dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }}
/>
</Link>
);
if (total === 1) {
return displayedName;

View File

@ -8,44 +8,101 @@ import { useAppSelector } from 'mastodon/store';
import { NamesList } from './names_list';
// This needs to be kept in sync with app/models/report.rb
const messages = defineMessages({
other: { id: 'report_notification.categories.other', defaultMessage: 'Other' },
other: {
id: 'report_notification.categories.other',
defaultMessage: 'Other',
},
spam: { id: 'report_notification.categories.spam', defaultMessage: 'Spam' },
legal: { id: 'report_notification.categories.legal', defaultMessage: 'Legal' },
violation: { id: 'report_notification.categories.violation', defaultMessage: 'Rule violation' },
legal: {
id: 'report_notification.categories.legal',
defaultMessage: 'Legal',
},
violation: {
id: 'report_notification.categories.violation',
defaultMessage: 'Rule violation',
},
});
export const NotificationAdminReport: React.FC<{
notification: NotificationGroupAdminReport;
}> = ({ notification, notification: { report } }) => {
const intl = useIntl();
const targetAccount = useAppSelector(state => state.getIn(['accounts', report.target_account.id]));
const account = useAppSelector(state => state.getIn(['accounts', notification.sampleAccountsIds[0]]));
const values = { name: <bdi dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} />, target: <bdi dangerouslySetInnerHTML={{ __html: targetAccount.get('display_name_html') }} />, category: intl.formatMessage(messages[report.category]), count: report.status_ids.length };
const targetAccount = useAppSelector((state) =>
state.getIn(['accounts', report.target_account.id]),
);
const account = useAppSelector((state) =>
state.getIn(['accounts', notification.sampleAccountsIds[0]]),
);
const values = {
name: (
<bdi
dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }}
/>
),
target: (
<bdi
dangerouslySetInnerHTML={{
__html: targetAccount.get('display_name_html'),
}}
/>
),
category: intl.formatMessage(messages[report.category]),
count: report.status_ids.length,
};
let message;
if (report.status_ids.length > 0) {
if (report.category === 'other') {
message = <FormattedMessage id='notification.admin.report_account_other' defaultMessage='{name} reported {count, plural, one {one post} other {# posts}} from {target}' values={values} />;
message = (
<FormattedMessage
id='notification.admin.report_account_other'
defaultMessage='{name} reported {count, plural, one {one post} other {# posts}} from {target}'
values={values}
/>
);
} else {
message = <FormattedMessage id='notification.admin.report_account' defaultMessage='{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}' values={values} />;
message = (
<FormattedMessage
id='notification.admin.report_account'
defaultMessage='{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}'
values={values}
/>
);
}
} else {
if (report.category === 'other') {
message = <FormattedMessage id='notification.admin.report_statuses_other' defaultMessage='{name} reported {target}' values={values} />;
message = (
<FormattedMessage
id='notification.admin.report_statuses_other'
defaultMessage='{name} reported {target}'
values={values}
/>
);
} else {
message = <FormattedMessage id='notification.admin.report_statuses' defaultMessage='{name} reported {target} for {category}' values={values} />;
message = (
<FormattedMessage
id='notification.admin.report_statuses'
defaultMessage='{name} reported {target} for {category}'
values={values}
/>
);
}
}
return (
<a href={`/admin/reports/${report.id}`} target='_blank' rel='noopener noreferrer' className='notification-group notification-group--link notification-group--admin-report focusable' tabIndex='0'>
<div className='notification-group__icon'><Icon id='flag' icon={FlagIcon} /></div>
<a
href={`/admin/reports/${report.id}`}
target='_blank'
rel='noopener noreferrer'
className='notification-group notification-group--link notification-group--admin-report focusable'
tabIndex={0}
>
<div className='notification-group__icon'>
<Icon id='flag' icon={FlagIcon} />
</div>
<div className='notification-group__main'>
<div className='notification-group__main__header'>
@ -55,7 +112,11 @@ export const NotificationAdminReport: React.FC<{
</div>
</div>
{report.comment.length > 0 && <div className='notification-group__embedded-status__content'>{report.comment}</div>}
{report.comment.length > 0 && (
<div className='notification-group__embedded-status__content'>
{report.comment}
</div>
)}
</div>
</a>
);

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
import type { NotificationGroupAdminSignUp } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.admin.sign_up' defaultMessage='{name} signed up' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.admin.sign_up'
defaultMessage='{name} signed up'
values={values}
/>
);
export const NotificationAdminSignUp: React.FC<{
notification: NotificationGroupAdminSignUp;

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
import type { NotificationGroupFavourite } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.favourite' defaultMessage='{name} favorited your status' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.favourite'
defaultMessage='{name} favorited your status'
values={values}
/>
);
export const NotificationFavourite: React.FC<{
notification: NotificationGroupFavourite;

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
import type { NotificationGroupFollow } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.follow'
defaultMessage='{name} followed you'
values={values}
/>
);
export const NotificationFollow: React.FC<{
notification: NotificationGroupFollow;

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
import type { NotificationGroupFollowRequest } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.follow_request' defaultMessage='{name} has requested to follow you' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.follow_request'
defaultMessage='{name} has requested to follow you'
values={values}
/>
);
export const NotificationFollowRequest: React.FC<{
notification: NotificationGroupFollowRequest;

View File

@ -2,14 +2,27 @@ import { useMemo } from 'react';
import { FormattedMessage } from 'react-intl';
import { Icon } from 'mastodon/components/icon';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import { AvatarGroup } from './avatar_group';
import { EmbeddedStatus } from './embedded_status';
import { NamesList } from './names_list';
export const NotificationGroupWithStatus = ({
export type LabelRenderer = (
values: Record<string, React.ReactNode>,
) => JSX.Element;
export const NotificationGroupWithStatus: React.FC<{
icon: IconProp;
statusId?: string;
count: number;
accountIds: string[];
timestamp: string;
labelRenderer: LabelRenderer;
type: string;
}> = ({
icon,
timestamp,
accountIds,
@ -18,12 +31,22 @@ export const NotificationGroupWithStatus = ({
labelRenderer,
type,
}) => {
const label = useMemo(() =>
labelRenderer({ name: <NamesList accountIds={accountIds} total={count} /> }), [labelRenderer, accountIds, count]);
const label = useMemo(
() =>
labelRenderer({
name: <NamesList accountIds={accountIds} total={count} />,
}),
[labelRenderer, accountIds, count],
);
return (
<div className={`notification-group focusable notification-group--${type}`} tabIndex='0'>
<div className='notification-group__icon'><Icon icon={icon} /></div>
<div
className={`notification-group focusable notification-group--${type}`}
tabIndex='0'
>
<div className='notification-group__icon'>
<Icon icon={icon} />
</div>
<div className='notification-group__main'>
<div className='notification-group__main__header'>

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import ReplyIcon from '@/material-icons/400-24px/reply-fill.svg?react';
import type { NotificationGroupMention } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationWithStatus } from './notification_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.mention' defaultMessage='{name} mentioned you' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.mention'
defaultMessage='{name} mentioned you'
values={values}
/>
);
export const NotificationMention: React.FC<{
notification: NotificationGroupMention;

View File

@ -5,8 +5,12 @@ import type { NotificationGroupPoll } from 'mastodon/models/notification_group';
import { NotificationWithStatus } from './notification_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.poll' defaultMessage='A poll you have voted in has ended' />;
const labelRenderer = () => (
<FormattedMessage
id='notification.poll'
defaultMessage='A poll you have voted in has ended'
/>
);
export const NotificationPoll: React.FC<{
notification: NotificationGroupPoll;

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
import type { NotificationGroupReblog } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.reblog'
defaultMessage='{name} boosted your status'
values={values}
/>
);
export const NotificationReblog: React.FC<{
notification: NotificationGroupReblog;

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import NotificationsActiveIcon from '@/material-icons/400-24px/notifications_active-fill.svg?react';
import type { NotificationGroupStatus } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationWithStatus } from './notification_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.status' defaultMessage='{name} just posted' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.status'
defaultMessage='{name} just posted'
values={values}
/>
);
export const NotificationStatus: React.FC<{
notification: NotificationGroupStatus;

View File

@ -3,10 +3,16 @@ import { FormattedMessage } from 'react-intl';
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import type { NotificationGroupUpdate } from 'mastodon/models/notification_group';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationWithStatus } from './notification_with_status';
const labelRenderer = values =>
<FormattedMessage id='notification.update' defaultMessage='{name} edited a post' values={values} />;
const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.update'
defaultMessage='{name} edited a post'
values={values}
/>
);
export const NotificationUpdate: React.FC<{
notification: NotificationGroupUpdate;

View File

@ -1,35 +1,42 @@
import { useMemo } from 'react';
import { FormattedMessage } from 'react-intl';
import { Icon } from 'mastodon/components/icon';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
import Status from 'mastodon/containers/status_container';
import { NamesList } from './names_list';
import type { LabelRenderer } from './notification_group_with_status';
export const NotificationWithStatus = ({
icon,
accountIds,
statusId,
count,
labelRenderer,
type,
}) => {
const label = useMemo(() => labelRenderer({ name: <NamesList accountIds={accountIds} total={count} /> }), [labelRenderer, accountIds, count]);
export const NotificationWithStatus: React.FC<{
type: string;
icon: IconProp;
accountIds: string[];
statusId: string;
count: number;
labelRenderer: LabelRenderer;
}> = ({ icon, accountIds, statusId, count, labelRenderer, type }) => {
const label = useMemo(
() =>
labelRenderer({
name: <NamesList accountIds={accountIds} total={count} />,
}),
[labelRenderer, accountIds, count],
);
return (
<div className={`notification-ungrouped focusable notification-ungrouped--${type}`} tabIndex='0'>
<div
className={`notification-ungrouped focusable notification-ungrouped--${type}`}
tabIndex='0'
>
<div className='notification-ungrouped__header'>
<div className='notification-ungrouped__header__icon'><Icon icon={icon} /></div>
<div className='notification-ungrouped__header__icon'>
<Icon icon={icon} />
</div>
{label}
</div>
<Status
id={statusId}
contextType='notifications'
withDismiss
/>
{/* @ts-expect-error -- <Status> is not yet typed */}
<Status id={statusId} contextType='notifications' withDismiss />
</div>
);
};