Skip to content

Commit

Permalink
Add option to ignore filtered notifications to the web interface (mas…
Browse files Browse the repository at this point in the history
  • Loading branch information
ClearlyClaire authored Aug 9, 2024
1 parent 8a5b57f commit 1701575
Show file tree
Hide file tree
Showing 14 changed files with 403 additions and 44 deletions.
4 changes: 2 additions & 2 deletions app/javascript/mastodon/api/notification_policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { apiRequestGet, apiRequestPut } from 'mastodon/api';
import type { NotificationPolicyJSON } from 'mastodon/api_types/notification_policies';

export const apiGetNotificationPolicy = () =>
apiRequestGet<NotificationPolicyJSON>('/v1/notifications/policy');
apiRequestGet<NotificationPolicyJSON>('/v2/notifications/policy');

export const apiUpdateNotificationsPolicy = (
policy: Partial<NotificationPolicyJSON>,
) => apiRequestPut<NotificationPolicyJSON>('/v1/notifications/policy', policy);
) => apiRequestPut<NotificationPolicyJSON>('/v2/notifications/policy', policy);
11 changes: 7 additions & 4 deletions app/javascript/mastodon/api_types/notification_policies.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// See app/serializers/rest/notification_policy_serializer.rb

export type NotificationPolicyValue = 'accept' | 'filter' | 'drop';

export interface NotificationPolicyJSON {
filter_not_following: boolean;
filter_not_followers: boolean;
filter_new_accounts: boolean;
filter_private_mentions: boolean;
for_not_following: NotificationPolicyValue;
for_not_followers: NotificationPolicyValue;
for_new_accounts: NotificationPolicyValue;
for_private_mentions: NotificationPolicyValue;
for_limited_accounts: NotificationPolicyValue;
summary: {
pending_requests_count: number;
pending_notifications_count: number;
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/components/dropdown_selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const listenerOptions = supportsPassiveEvents
? { passive: true, capture: true }
: true;

interface SelectItem {
export interface SelectItem {
value: string;
icon?: string;
iconComponent?: IconProp;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,73 +1,127 @@
import { useCallback } from 'react';

import { FormattedMessage } from 'react-intl';
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';

import { openModal } from 'mastodon/actions/modal';
import { updateNotificationsPolicy } from 'mastodon/actions/notification_policies';
import type { AppDispatch } from 'mastodon/store';
import { useAppSelector, useAppDispatch } from 'mastodon/store';

import { CheckboxWithLabel } from './checkbox_with_label';

// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => {};
import { SelectWithLabel } from './select_with_label';

const messages = defineMessages({
accept: { id: 'notifications.policy.accept', defaultMessage: 'Accept' },
accept_hint: {
id: 'notifications.policy.accept_hint',
defaultMessage: 'Show in notifications',
},
filter: { id: 'notifications.policy.filter', defaultMessage: 'Filter' },
filter_hint: {
id: 'notifications.policy.filter_hint',
defaultMessage: 'Send to filtered notifications inbox',
},
drop: { id: 'notifications.policy.drop', defaultMessage: 'Ignore' },
drop_hint: {
id: 'notifications.policy.drop_hint',
defaultMessage: 'Send to the void, never to be seen again',
},
});

// TODO: change the following when we change the API
const changeFilter = (
dispatch: AppDispatch,
filterType: string,
value: string,
) => {
if (value === 'drop') {
dispatch(
openModal({
modalType: 'IGNORE_NOTIFICATIONS',
modalProps: { filterType },
}),
);
} else {
void dispatch(updateNotificationsPolicy({ [filterType]: value }));
}
};

export const PolicyControls: React.FC = () => {
const intl = useIntl();
const dispatch = useAppDispatch();

const notificationPolicy = useAppSelector(
(state) => state.notificationPolicy,
);

const handleFilterNotFollowing = useCallback(
(checked: boolean) => {
void dispatch(
updateNotificationsPolicy({ filter_not_following: checked }),
);
(value: string) => {
changeFilter(dispatch, 'for_not_following', value);
},
[dispatch],
);

const handleFilterNotFollowers = useCallback(
(checked: boolean) => {
void dispatch(
updateNotificationsPolicy({ filter_not_followers: checked }),
);
(value: string) => {
changeFilter(dispatch, 'for_not_followers', value);
},
[dispatch],
);

const handleFilterNewAccounts = useCallback(
(checked: boolean) => {
void dispatch(
updateNotificationsPolicy({ filter_new_accounts: checked }),
);
(value: string) => {
changeFilter(dispatch, 'for_new_accounts', value);
},
[dispatch],
);

const handleFilterPrivateMentions = useCallback(
(checked: boolean) => {
void dispatch(
updateNotificationsPolicy({ filter_private_mentions: checked }),
);
(value: string) => {
changeFilter(dispatch, 'for_private_mentions', value);
},
[dispatch],
);

const handleFilterLimitedAccounts = useCallback(
(value: string) => {
changeFilter(dispatch, 'for_limited_accounts', value);
},
[dispatch],
);

if (!notificationPolicy) return null;

const options = [
{
value: 'accept',
text: intl.formatMessage(messages.accept),
meta: intl.formatMessage(messages.accept_hint),
},
{
value: 'filter',
text: intl.formatMessage(messages.filter),
meta: intl.formatMessage(messages.filter_hint),
},
{
value: 'drop',
text: intl.formatMessage(messages.drop),
meta: intl.formatMessage(messages.drop_hint),
},
];

return (
<section>
<h3>
<FormattedMessage
id='notifications.policy.title'
defaultMessage='Filter out notifications from…'
defaultMessage='Manage notifications from…'
/>
</h3>

<div className='column-settings__row'>
<CheckboxWithLabel
checked={notificationPolicy.filter_not_following}
<SelectWithLabel
value={notificationPolicy.for_not_following}
onChange={handleFilterNotFollowing}
options={options}
>
<strong>
<FormattedMessage
Expand All @@ -81,11 +135,12 @@ export const PolicyControls: React.FC = () => {
defaultMessage='Until you manually approve them'
/>
</span>
</CheckboxWithLabel>
</SelectWithLabel>

<CheckboxWithLabel
checked={notificationPolicy.filter_not_followers}
<SelectWithLabel
value={notificationPolicy.for_not_followers}
onChange={handleFilterNotFollowers}
options={options}
>
<strong>
<FormattedMessage
Expand All @@ -100,11 +155,12 @@ export const PolicyControls: React.FC = () => {
values={{ days: 3 }}
/>
</span>
</CheckboxWithLabel>
</SelectWithLabel>

<CheckboxWithLabel
checked={notificationPolicy.filter_new_accounts}
<SelectWithLabel
value={notificationPolicy.for_new_accounts}
onChange={handleFilterNewAccounts}
options={options}
>
<strong>
<FormattedMessage
Expand All @@ -119,11 +175,12 @@ export const PolicyControls: React.FC = () => {
values={{ days: 30 }}
/>
</span>
</CheckboxWithLabel>
</SelectWithLabel>

<CheckboxWithLabel
checked={notificationPolicy.filter_private_mentions}
<SelectWithLabel
value={notificationPolicy.for_private_mentions}
onChange={handleFilterPrivateMentions}
options={options}
>
<strong>
<FormattedMessage
Expand All @@ -137,9 +194,13 @@ export const PolicyControls: React.FC = () => {
defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender"
/>
</span>
</CheckboxWithLabel>
</SelectWithLabel>

<CheckboxWithLabel checked disabled onChange={noop}>
<SelectWithLabel
value={notificationPolicy.for_limited_accounts}
onChange={handleFilterLimitedAccounts}
options={options}
>
<strong>
<FormattedMessage
id='notifications.policy.filter_limited_accounts_title'
Expand All @@ -152,7 +213,7 @@ export const PolicyControls: React.FC = () => {
defaultMessage='Limited by server moderators'
/>
</span>
</CheckboxWithLabel>
</SelectWithLabel>
</div>
</section>
);
Expand Down
Loading

0 comments on commit 1701575

Please sign in to comment.