Further de-emphasize filtered notifications banner and add setting to minimize it (#31250)
This commit is contained in:
		
					parent
					
						
							
								2ec1181ee5
							
						
					
				
			
			
				commit
				
					
						ad95c98054
					
				
			
		
					 12 changed files with 321 additions and 119 deletions
				
			
		|  | @ -1,31 +0,0 @@ | |||
| import PropTypes from 'prop-types'; | ||||
| import { useCallback } from 'react'; | ||||
| 
 | ||||
| import Toggle from 'react-toggle'; | ||||
| 
 | ||||
| export const CheckboxWithLabel = ({ checked, disabled, children, onChange }) => { | ||||
|   const handleChange = useCallback(({ target }) => { | ||||
|     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> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| CheckboxWithLabel.propTypes = { | ||||
|   checked: PropTypes.bool, | ||||
|   disabled: PropTypes.bool, | ||||
|   children: PropTypes.children, | ||||
|   onChange: PropTypes.func, | ||||
| }; | ||||
|  | @ -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> | ||||
|   ); | ||||
| }; | ||||
|  | @ -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 { | ||||
|  | @ -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' />; | ||||
|  | @ -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'> | ||||
|  |  | |||
|  | @ -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()); | ||||
|  | @ -30,6 +74,10 @@ export const FilteredNotificationsBanner: React.FC = () => { | |||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   if (minimizeSetting) { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <Link | ||||
|       className='filtered-notifications-banner' | ||||
|  | @ -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> | ||||
|   ); | ||||
| }; | ||||
|  |  | |||
|  | @ -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> | ||||
|   ); | ||||
| }; | ||||
|  | @ -6,7 +6,6 @@ import { openModal } from 'mastodon/actions/modal'; | |||
| import { initializeNotifications } from 'mastodon/actions/notifications_migration'; | ||||
| 
 | ||||
| import { showAlert } from '../../../actions/alerts'; | ||||
| import { updateNotificationsPolicy } from '../../../actions/notification_policies'; | ||||
| import { setFilter, requestBrowserPermission } from '../../../actions/notifications'; | ||||
| import { changeAlerts as changePushNotifications } from '../../../actions/push_notifications'; | ||||
| import { changeSetting } from '../../../actions/settings'; | ||||
|  | @ -25,7 +24,6 @@ const mapStateToProps = state => ({ | |||
|   alertsEnabled: state.getIn(['settings', 'notifications', 'alerts']).includes(true), | ||||
|   browserSupport: state.getIn(['notifications', 'browserSupport']), | ||||
|   browserPermission: state.getIn(['notifications', 'browserPermission']), | ||||
|   notificationPolicy: state.notificationPolicy, | ||||
| }); | ||||
| 
 | ||||
| const mapDispatchToProps = (dispatch) => ({ | ||||
|  | @ -74,12 +72,6 @@ const mapDispatchToProps = (dispatch) => ({ | |||
|     dispatch(requestBrowserPermission()); | ||||
|   }, | ||||
| 
 | ||||
|   onChangePolicy (param, checked) { | ||||
|     dispatch(updateNotificationsPolicy({ | ||||
|       [param]: checked, | ||||
|     })); | ||||
|   }, | ||||
| 
 | ||||
| }); | ||||
| 
 | ||||
| export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ColumnSettings)); | ||||
|  |  | |||
|  | @ -34,7 +34,10 @@ import ColumnHeader from '../../components/column_header'; | |||
| import { LoadGap } from '../../components/load_gap'; | ||||
| import ScrollableList from '../../components/scrollable_list'; | ||||
| 
 | ||||
| import { FilteredNotificationsBanner } from './components/filtered_notifications_banner'; | ||||
| import { | ||||
|   FilteredNotificationsBanner, | ||||
|   FilteredNotificationsIconButton, | ||||
| } from './components/filtered_notifications_banner'; | ||||
| import NotificationsPermissionBanner from './components/notifications_permission_banner'; | ||||
| import ColumnSettingsContainer from './containers/column_settings_container'; | ||||
| import FilterBarContainer from './containers/filter_bar_container'; | ||||
|  | @ -255,20 +258,21 @@ class Notifications extends PureComponent { | |||
|       scrollContainer = <NotSignedInIndicator />; | ||||
|     } | ||||
| 
 | ||||
|     let extraButton = null; | ||||
| 
 | ||||
|     if (canMarkAsRead) { | ||||
|       extraButton = ( | ||||
|         <button | ||||
|           aria-label={intl.formatMessage(messages.markAsRead)} | ||||
|           title={intl.formatMessage(messages.markAsRead)} | ||||
|           onClick={this.handleMarkAsRead} | ||||
|           className='column-header__button' | ||||
|         > | ||||
|           <Icon id='done-all' icon={DoneAllIcon} /> | ||||
|         </button> | ||||
|       ); | ||||
|     } | ||||
|     const extraButton = ( | ||||
|       <> | ||||
|         <FilteredNotificationsIconButton className='column-header__button' /> | ||||
|         {canMarkAsRead && ( | ||||
|           <button | ||||
|             aria-label={intl.formatMessage(messages.markAsRead)} | ||||
|             title={intl.formatMessage(messages.markAsRead)} | ||||
|             onClick={this.handleMarkAsRead} | ||||
|             className='column-header__button' | ||||
|           > | ||||
|             <Icon id='done-all' icon={DoneAllIcon} /> | ||||
|           </button> | ||||
|         )} | ||||
|       </> | ||||
|     ); | ||||
| 
 | ||||
|     return ( | ||||
|       <Column bindToDocument={!multiColumn} ref={this.setColumnRef} label={intl.formatMessage(messages.title)}> | ||||
|  |  | |||
|  | @ -9,16 +9,52 @@ import { useSelector, useDispatch } from 'react-redux'; | |||
| 
 | ||||
| import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; | ||||
| import { fetchNotificationRequests, expandNotificationRequests } from 'mastodon/actions/notifications'; | ||||
| import { changeSetting } from 'mastodon/actions/settings'; | ||||
| import Column from 'mastodon/components/column'; | ||||
| import ColumnHeader from 'mastodon/components/column_header'; | ||||
| import ScrollableList from 'mastodon/components/scrollable_list'; | ||||
| 
 | ||||
| import { NotificationRequest } from './components/notification_request'; | ||||
| import { PolicyControls } from './components/policy_controls'; | ||||
| import SettingToggle from './components/setting_toggle'; | ||||
| 
 | ||||
| const messages = defineMessages({ | ||||
|   title: { id: 'notification_requests.title', defaultMessage: 'Filtered notifications' }, | ||||
|   maximize: { id: 'notification_requests.maximize', defaultMessage: 'Maximize' } | ||||
| }); | ||||
| 
 | ||||
| const ColumnSettings = () => { | ||||
|   const dispatch = useDispatch(); | ||||
|   const settings = useSelector((state) => state.settings.get('notifications')); | ||||
| 
 | ||||
|   const onChange = useCallback( | ||||
|     (key, checked) => { | ||||
|       dispatch(changeSetting(['notifications', ...key], checked)); | ||||
|     }, | ||||
|     [dispatch], | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className='column-settings'> | ||||
|       <section> | ||||
|         <div className='column-settings__row'> | ||||
|           <SettingToggle | ||||
|             prefix='notifications' | ||||
|             settings={settings} | ||||
|             settingPath={['minimizeFilteredBanner']} | ||||
|             onChange={onChange} | ||||
|             label={ | ||||
|               <FormattedMessage id='notification_requests.minimize_banner' defaultMessage='Minimize filtred notifications banner' /> | ||||
|             } | ||||
|           /> | ||||
|         </div> | ||||
|       </section> | ||||
| 
 | ||||
|       <PolicyControls /> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export const NotificationRequests = ({ multiColumn }) => { | ||||
|   const columnRef = useRef(); | ||||
|   const intl = useIntl(); | ||||
|  | @ -48,7 +84,9 @@ export const NotificationRequests = ({ multiColumn }) => { | |||
|         onClick={handleHeaderClick} | ||||
|         multiColumn={multiColumn} | ||||
|         showBackButton | ||||
|       /> | ||||
|       > | ||||
|         <ColumnSettings /> | ||||
|       </ColumnHeader> | ||||
| 
 | ||||
|       <ScrollableList | ||||
|         scrollKey='notification_requests' | ||||
|  |  | |||
|  | @ -43,7 +43,10 @@ import Column from '../../components/column'; | |||
| import { ColumnHeader } from '../../components/column_header'; | ||||
| import { LoadGap } from '../../components/load_gap'; | ||||
| import ScrollableList from '../../components/scrollable_list'; | ||||
| import { FilteredNotificationsBanner } from '../notifications/components/filtered_notifications_banner'; | ||||
| import { | ||||
|   FilteredNotificationsBanner, | ||||
|   FilteredNotificationsIconButton, | ||||
| } from '../notifications/components/filtered_notifications_banner'; | ||||
| import NotificationsPermissionBanner from '../notifications/components/notifications_permission_banner'; | ||||
| import ColumnSettingsContainer from '../notifications/containers/column_settings_container'; | ||||
| 
 | ||||
|  | @ -306,16 +309,21 @@ export const Notifications: React.FC<{ | |||
|     <NotSignedInIndicator /> | ||||
|   ); | ||||
| 
 | ||||
|   const extraButton = canMarkAsRead ? ( | ||||
|     <button | ||||
|       aria-label={intl.formatMessage(messages.markAsRead)} | ||||
|       title={intl.formatMessage(messages.markAsRead)} | ||||
|       onClick={handleMarkAsRead} | ||||
|       className='column-header__button' | ||||
|     > | ||||
|       <Icon id='done-all' icon={DoneAllIcon} /> | ||||
|     </button> | ||||
|   ) : null; | ||||
|   const extraButton = ( | ||||
|     <> | ||||
|       <FilteredNotificationsIconButton className='column-header__button' /> | ||||
|       {canMarkAsRead && ( | ||||
|         <button | ||||
|           aria-label={intl.formatMessage(messages.markAsRead)} | ||||
|           title={intl.formatMessage(messages.markAsRead)} | ||||
|           onClick={handleMarkAsRead} | ||||
|           className='column-header__button' | ||||
|         > | ||||
|           <Icon id='done-all' icon={DoneAllIcon} /> | ||||
|         </button> | ||||
|       )} | ||||
|     </> | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <Column | ||||
|  |  | |||
|  | @ -505,6 +505,8 @@ | |||
|   "notification.update": "{name} edited a post", | ||||
|   "notification_requests.accept": "Accept", | ||||
|   "notification_requests.dismiss": "Dismiss", | ||||
|   "notification_requests.maximize": "Maximize", | ||||
|   "notification_requests.minimize_banner": "Minimize filtred notifications banner", | ||||
|   "notification_requests.notifications_from": "Notifications from {name}", | ||||
|   "notification_requests.title": "Filtered notifications", | ||||
|   "notifications.clear": "Clear notifications", | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ const initialState = ImmutableMap({ | |||
| 
 | ||||
|     dismissPermissionBanner: false, | ||||
|     showUnread: true, | ||||
|     minimizeFilteredBanner: false, | ||||
| 
 | ||||
|     shows: ImmutableMap({ | ||||
|       follow: true, | ||||
|  |  | |||
|  | @ -37,4 +37,9 @@ export const selectNeedsNotificationPermission = (state: RootState) => | |||
|       'dismissPermissionBanner', | ||||
|     ])) as boolean; | ||||
| 
 | ||||
| export const selectSettingsNotificationsMinimizeFilteredBanner = ( | ||||
|   state: RootState, | ||||
| ) => | ||||
|   state.settings.getIn(['notifications', 'minimizeFilteredBanner']) as boolean; | ||||
| 
 | ||||
| /* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue