diff options
author | Fire Demon <firedemon@creature.cafe> | 2020-09-20 21:10:14 -0500 |
---|---|---|
committer | Fire Demon <firedemon@creature.cafe> | 2020-09-20 22:53:42 -0500 |
commit | e3cb18ba7520997a0f605c7f90db258ccccd5e33 (patch) | |
tree | 77ad166f04c96b2bf97bf989eabc8ca1fa61948c /app/javascript/flavours/glitch/features/notifications | |
parent | 8ede83b2179488e0a28101033e8ce9e6978ea849 (diff) | |
parent | 787d5d728923393f12421a480b3c7aee789a11fe (diff) |
Merge remote-tracking branch 'upstream/master' into merge-glitch
Diffstat (limited to 'app/javascript/flavours/glitch/features/notifications')
4 files changed, 50 insertions, 7 deletions
diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow.js b/app/javascript/flavours/glitch/features/notifications/components/follow.js index 5f405e976..7b47f411b 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/follow.js +++ b/app/javascript/flavours/glitch/features/notifications/components/follow.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { HotKeys } from 'react-hotkeys'; +import classNames from 'classnames'; // Our imports. import Permalink from 'flavours/glitch/components/permalink'; @@ -19,6 +20,7 @@ export default class NotificationFollow extends ImmutablePureComponent { id: PropTypes.string.isRequired, account: ImmutablePropTypes.map.isRequired, notification: ImmutablePropTypes.map.isRequired, + unread: PropTypes.bool, }; handleMoveUp = () => { @@ -59,7 +61,7 @@ export default class NotificationFollow extends ImmutablePureComponent { } render () { - const { account, notification, hidden } = this.props; + const { account, notification, hidden, unread } = this.props; // Links to the display name. const displayName = account.get('display_name_html') || account.get('username'); @@ -76,7 +78,7 @@ export default class NotificationFollow extends ImmutablePureComponent { // Renders. return ( <HotKeys handlers={this.getHandlers()}> - <div className='notification notification-follow focusable' tabIndex='0'> + <div className={classNames('notification notification-follow focusable', { unread })} tabIndex='0'> <div className='notification__message'> <div className='notification__favourite-icon-wrapper'> <Icon fixedWidth id='user-plus' /> diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow_request.js b/app/javascript/flavours/glitch/features/notifications/components/follow_request.js index d73dac434..f351c1035 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/follow_request.js +++ b/app/javascript/flavours/glitch/features/notifications/components/follow_request.js @@ -10,6 +10,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import NotificationOverlayContainer from '../containers/overlay_container'; import { HotKeys } from 'react-hotkeys'; import Icon from 'flavours/glitch/components/icon'; +import classNames from 'classnames'; const messages = defineMessages({ authorize: { id: 'follow_request.authorize', defaultMessage: 'Authorize' }, @@ -25,6 +26,7 @@ class FollowRequest extends ImmutablePureComponent { onReject: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, notification: ImmutablePropTypes.map.isRequired, + unread: PropTypes.bool, }; handleMoveUp = () => { @@ -65,7 +67,7 @@ class FollowRequest extends ImmutablePureComponent { } render () { - const { intl, hidden, account, onAuthorize, onReject, notification } = this.props; + const { intl, hidden, account, onAuthorize, onReject, notification, unread } = this.props; if (!account) { return <div />; @@ -94,7 +96,7 @@ class FollowRequest extends ImmutablePureComponent { return ( <HotKeys handlers={this.getHandlers()}> - <div className='notification notification-follow-request focusable' tabIndex='0'> + <div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex='0'> <div className='notification__message'> <div className='notification__favourite-icon-wrapper'> <Icon id='user' fixedWidth /> diff --git a/app/javascript/flavours/glitch/features/notifications/components/notification.js b/app/javascript/flavours/glitch/features/notifications/components/notification.js index 62fc28386..bd415856c 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/notification.js +++ b/app/javascript/flavours/glitch/features/notifications/components/notification.js @@ -22,6 +22,7 @@ export default class Notification extends ImmutablePureComponent { cacheMediaWidth: PropTypes.func, cachedMediaWidth: PropTypes.number, onUnmount: PropTypes.func, + unread: PropTypes.bool, }; render () { @@ -46,6 +47,7 @@ export default class Notification extends ImmutablePureComponent { onMoveDown={onMoveDown} onMoveUp={onMoveUp} onMention={onMention} + unread={this.props.unread} /> ); case 'follow_request': @@ -58,6 +60,7 @@ export default class Notification extends ImmutablePureComponent { onMoveDown={onMoveDown} onMoveUp={onMoveUp} onMention={onMention} + unread={this.props.unread} /> ); case 'mention': @@ -77,6 +80,7 @@ export default class Notification extends ImmutablePureComponent { cacheMediaWidth={this.props.cacheMediaWidth} onUnmount={this.props.onUnmount} withDismiss + unread={this.props.unread} /> ); case 'favourite': @@ -98,6 +102,7 @@ export default class Notification extends ImmutablePureComponent { cacheMediaWidth={this.props.cacheMediaWidth} onUnmount={this.props.onUnmount} withDismiss + unread={this.props.unread} /> ); case 'reblog': @@ -119,6 +124,7 @@ export default class Notification extends ImmutablePureComponent { cacheMediaWidth={this.props.cacheMediaWidth} onUnmount={this.props.onUnmount} withDismiss + unread={this.props.unread} /> ); case 'poll': @@ -140,6 +146,7 @@ export default class Notification extends ImmutablePureComponent { cacheMediaWidth={this.props.cacheMediaWidth} onUnmount={this.props.onUnmount} withDismiss + unread={this.props.unread} /> ); default: diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 26710feff..681323860 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -12,8 +12,10 @@ import { mountNotifications, unmountNotifications, loadPending, + markNotificationsAsRead, } from 'flavours/glitch/actions/notifications'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; +import { submitMarkers } from 'flavours/glitch/actions/markers'; import NotificationContainer from './containers/notification_container'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ColumnSettingsContainer from './containers/column_settings_container'; @@ -24,12 +26,14 @@ import { debounce } from 'lodash'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import LoadGap from 'flavours/glitch/components/load_gap'; import Icon from 'flavours/glitch/components/icon'; +import compareId from 'flavours/glitch/util/compare_id'; import NotificationPurgeButtonsContainer from 'flavours/glitch/containers/notification_purge_buttons_container'; const messages = defineMessages({ title: { id: 'column.notifications', defaultMessage: 'Notifications' }, enterNotifCleaning : { id: 'notification_purge.start', defaultMessage: 'Enter notification cleaning mode' }, + markAsRead : { id: 'notifications.mark_as_read', defaultMessage: 'Mark every notification as read' }, }); const getNotifications = createSelector([ @@ -56,6 +60,8 @@ const mapStateToProps = state => ({ hasMore: state.getIn(['notifications', 'hasMore']), numPending: state.getIn(['notifications', 'pendingItems'], ImmutableList()).size, notifCleaningActive: state.getIn(['notifications', 'cleaningMode']), + lastReadId: state.getIn(['notifications', 'readMarkerId']), + canMarkAsRead: state.getIn(['notifications', 'readMarkerId']) !== '0' && getNotifications(state).some(item => item !== null && compareId(item.get('id'), state.getIn(['notifications', 'readMarkerId'])) > 0), }); /* glitch */ @@ -63,6 +69,10 @@ const mapDispatchToProps = dispatch => ({ onEnterCleaningMode(yes) { dispatch(enterNotificationClearingMode(yes)); }, + onMarkAsRead() { + dispatch(markNotificationsAsRead()); + dispatch(submitMarkers()); + }, onMount() { dispatch(mountNotifications()); }, @@ -93,6 +103,8 @@ class Notifications extends React.PureComponent { onEnterCleaningMode: PropTypes.func, onMount: PropTypes.func, onUnmount: PropTypes.func, + lastReadId: PropTypes.string, + canMarkAsRead: PropTypes.bool, }; static defaultProps = { @@ -194,8 +206,12 @@ class Notifications extends React.PureComponent { this.props.onEnterCleaningMode(!this.props.notifCleaningActive); } + handleMarkAsRead = () => { + this.props.onMarkAsRead(); + } + render () { - const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar } = this.props; + const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar, lastReadId, canMarkAsRead } = this.props; const { notifCleaning, notifCleaningActive } = this.props; const { animatingNCD } = this.state; const pinned = !!columnId; @@ -224,6 +240,7 @@ class Notifications extends React.PureComponent { accountId={item.get('account')} onMoveUp={this.handleMoveUp} onMoveDown={this.handleMoveDown} + unread={lastReadId !== '0' && compareId(item.get('id'), lastReadId) > 0} /> )); } else { @@ -252,6 +269,21 @@ class Notifications extends React.PureComponent { </ScrollableList> ); + const extraButtons = []; + + if (canMarkAsRead) { + extraButtons.push( + <button + aria-label={intl.formatMessage(messages.markAsRead)} + title={intl.formatMessage(messages.markAsRead)} + onClick={this.handleMarkAsRead} + className='column-header__button' + > + <Icon id='check' /> + </button> + ); + } + const notifCleaningButtonClassName = classNames('column-header__button', { 'active': notifCleaningActive, }); @@ -263,7 +295,7 @@ class Notifications extends React.PureComponent { const msgEnterNotifCleaning = intl.formatMessage(messages.enterNotifCleaning); - const notifCleaningButton = ( + extraButtons.push( <button aria-label={msgEnterNotifCleaning} title={msgEnterNotifCleaning} @@ -300,7 +332,7 @@ class Notifications extends React.PureComponent { pinned={pinned} multiColumn={multiColumn} localSettings={this.props.localSettings} - extraButton={notifCleaningButton} + extraButton={extraButtons} appendContent={notifCleaningDrawer} > <ColumnSettingsContainer /> |