Skip to content

Commit

Permalink
Further de-emphasize filtered notifications banner and add setting to…
Browse files Browse the repository at this point in the history
… minimize it (mastodon#31250)
  • Loading branch information
ClearlyClaire authored Aug 2, 2024
1 parent 2ec1181 commit ad95c98
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 119 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { PropsWithChildren } from 'react';
import { useCallback } from 'react';

import Toggle from 'react-toggle';

interface Props {
checked: boolean;
disabled?: boolean;
onChange: (checked: boolean) => void;
}

export const CheckboxWithLabel: React.FC<PropsWithChildren<Props>> = ({
checked,
disabled,
children,
onChange,
}) => {
const handleChange = useCallback(
({ target }: React.ChangeEvent<HTMLInputElement>) => {
onChange(target.checked);
},
[onChange],
);

return (
<label className='app-form__toggle'>
<div className='app-form__toggle__label'>{children}</div>

<div className='app-form__toggle__toggle'>
<div>
<Toggle
checked={checked}
onChange={handleChange}
disabled={disabled}
/>
</div>
</div>
</label>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';

import { CheckboxWithLabel } from './checkbox_with_label';
import ClearColumnButton from './clear_column_button';
import GrantPermissionButton from './grant_permission_button';
import { PolicyControls } from './policy_controls';
import SettingToggle from './setting_toggle';

class ColumnSettings extends PureComponent {
Expand All @@ -24,32 +24,14 @@ class ColumnSettings extends PureComponent {
alertsEnabled: PropTypes.bool,
browserSupport: PropTypes.bool,
browserPermission: PropTypes.string,
notificationPolicy: PropTypes.object.isRequired,
onChangePolicy: PropTypes.func.isRequired,
};

onPushChange = (path, checked) => {
this.props.onChange(['push', ...path], checked);
};

handleFilterNotFollowing = checked => {
this.props.onChangePolicy('filter_not_following', checked);
};

handleFilterNotFollowers = checked => {
this.props.onChangePolicy('filter_not_followers', checked);
};

handleFilterNewAccounts = checked => {
this.props.onChangePolicy('filter_new_accounts', checked);
};

handleFilterPrivateMentions = checked => {
this.props.onChangePolicy('filter_private_mentions', checked);
};

render () {
const { settings, pushSettings, onChange, onClear, alertsEnabled, browserSupport, browserPermission, onRequestNotificationPermission, notificationPolicy } = this.props;
const { settings, pushSettings, onChange, onClear, alertsEnabled, browserSupport, browserPermission, onRequestNotificationPermission } = this.props;

const filterAdvancedStr = <FormattedMessage id='notifications.column_settings.filter_bar.advanced' defaultMessage='Display all categories' />;
const unreadMarkersShowStr = <FormattedMessage id='notifications.column_settings.unread_notifications.highlight' defaultMessage='Highlight unread notifications' />;
Expand Down Expand Up @@ -79,31 +61,7 @@ class ColumnSettings extends PureComponent {
</section>
)}

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

<div className='column-settings__row'>
<CheckboxWithLabel checked={notificationPolicy.filter_not_following} onChange={this.handleFilterNotFollowing}>
<strong><FormattedMessage id='notifications.policy.filter_not_following_title' defaultMessage="People you don't follow" /></strong>
<span className='hint'><FormattedMessage id='notifications.policy.filter_not_following_hint' defaultMessage='Until you manually approve them' /></span>
</CheckboxWithLabel>

<CheckboxWithLabel checked={notificationPolicy.filter_not_followers} onChange={this.handleFilterNotFollowers}>
<strong><FormattedMessage id='notifications.policy.filter_not_followers_title' defaultMessage='People not following you' /></strong>
<span className='hint'><FormattedMessage id='notifications.policy.filter_not_followers_hint' defaultMessage='Including people who have been following you fewer than {days, plural, one {one day} other {# days}}' values={{ days: 3 }} /></span>
</CheckboxWithLabel>

<CheckboxWithLabel checked={notificationPolicy.filter_new_accounts} onChange={this.handleFilterNewAccounts}>
<strong><FormattedMessage id='notifications.policy.filter_new_accounts_title' defaultMessage='New accounts' /></strong>
<span className='hint'><FormattedMessage id='notifications.policy.filter_new_accounts.hint' defaultMessage='Created within the past {days, plural, one {one day} other {# days}}' values={{ days: 30 }} /></span>
</CheckboxWithLabel>

<CheckboxWithLabel checked={notificationPolicy.filter_private_mentions} onChange={this.handleFilterPrivateMentions}>
<strong><FormattedMessage id='notifications.policy.filter_private_mentions_title' defaultMessage='Unsolicited private mentions' /></strong>
<span className='hint'><FormattedMessage id='notifications.policy.filter_private_mentions_hint' defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender" /></span>
</CheckboxWithLabel>
</div>
</section>
<PolicyControls />

<section role='group' aria-labelledby='notifications-beta'>
<h3 id='notifications-beta'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,62 @@
import { useEffect } from 'react';
import { useCallback, useEffect } from 'react';

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

import { Link } from 'react-router-dom';
import { Link, useHistory } from 'react-router-dom';

import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react';
import { fetchNotificationPolicy } from 'mastodon/actions/notification_policies';
import { Icon } from 'mastodon/components/icon';
import { selectSettingsNotificationsMinimizeFilteredBanner } from 'mastodon/selectors/settings';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
import { toCappedNumber } from 'mastodon/utils/numbers';

const messages = defineMessages({
filteredNotifications: {
id: 'notification_requests.title',
defaultMessage: 'Filtered notifications',
},
});

export const FilteredNotificationsIconButton: React.FC<{
className?: string;
}> = ({ className }) => {
const intl = useIntl();
const history = useHistory();
const policy = useAppSelector((state) => state.notificationPolicy);
const minimizeSetting = useAppSelector(
selectSettingsNotificationsMinimizeFilteredBanner,
);

const handleClick = useCallback(() => {
history.push('/notifications/requests');
}, [history]);

if (policy === null || policy.summary.pending_notifications_count === 0) {
return null;
}

if (!minimizeSetting) {
return null;
}

return (
<button
aria-label={intl.formatMessage(messages.filteredNotifications)}
title={intl.formatMessage(messages.filteredNotifications)}
onClick={handleClick}
className={className}
>
<Icon id='filtered-notifications' icon={InventoryIcon} />
</button>
);
};

export const FilteredNotificationsBanner: React.FC = () => {
const dispatch = useAppDispatch();
const policy = useAppSelector((state) => state.notificationPolicy);
const minimizeSetting = useAppSelector(
selectSettingsNotificationsMinimizeFilteredBanner,
);

useEffect(() => {
void dispatch(fetchNotificationPolicy());
Expand All @@ -30,6 +74,10 @@ export const FilteredNotificationsBanner: React.FC = () => {
return null;
}

if (minimizeSetting) {
return null;
}

return (
<Link
className='filtered-notifications-banner'
Expand All @@ -54,10 +102,6 @@ export const FilteredNotificationsBanner: React.FC = () => {
/>
</span>
</div>

<div className='filtered-notifications-banner__badge'>
{toCappedNumber(policy.summary.pending_notifications_count)}
</div>
</Link>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { useCallback } from 'react';

import { FormattedMessage } from 'react-intl';

import { updateNotificationsPolicy } from 'mastodon/actions/notification_policies';
import { useAppSelector, useAppDispatch } from 'mastodon/store';

import { CheckboxWithLabel } from './checkbox_with_label';

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

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

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

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

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

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

if (!notificationPolicy) return null;

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

<div className='column-settings__row'>
<CheckboxWithLabel
checked={notificationPolicy.filter_not_following}
onChange={handleFilterNotFollowing}
>
<strong>
<FormattedMessage
id='notifications.policy.filter_not_following_title'
defaultMessage="People you don't follow"
/>
</strong>
<span className='hint'>
<FormattedMessage
id='notifications.policy.filter_not_following_hint'
defaultMessage='Until you manually approve them'
/>
</span>
</CheckboxWithLabel>

<CheckboxWithLabel
checked={notificationPolicy.filter_not_followers}
onChange={handleFilterNotFollowers}
>
<strong>
<FormattedMessage
id='notifications.policy.filter_not_followers_title'
defaultMessage='People not following you'
/>
</strong>
<span className='hint'>
<FormattedMessage
id='notifications.policy.filter_not_followers_hint'
defaultMessage='Including people who have been following you fewer than {days, plural, one {one day} other {# days}}'
values={{ days: 3 }}
/>
</span>
</CheckboxWithLabel>

<CheckboxWithLabel
checked={notificationPolicy.filter_new_accounts}
onChange={handleFilterNewAccounts}
>
<strong>
<FormattedMessage
id='notifications.policy.filter_new_accounts_title'
defaultMessage='New accounts'
/>
</strong>
<span className='hint'>
<FormattedMessage
id='notifications.policy.filter_new_accounts.hint'
defaultMessage='Created within the past {days, plural, one {one day} other {# days}}'
values={{ days: 30 }}
/>
</span>
</CheckboxWithLabel>

<CheckboxWithLabel
checked={notificationPolicy.filter_private_mentions}
onChange={handleFilterPrivateMentions}
>
<strong>
<FormattedMessage
id='notifications.policy.filter_private_mentions_title'
defaultMessage='Unsolicited private mentions'
/>
</strong>
<span className='hint'>
<FormattedMessage
id='notifications.policy.filter_private_mentions_hint'
defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender"
/>
</span>
</CheckboxWithLabel>
</div>
</section>
);
};
Loading

0 comments on commit ad95c98

Please sign in to comment.