From bf7cd98c038ca197f09a1244ba61e215c0e4aefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 27 Jan 2022 16:00:05 +0100 Subject: [PATCH] Add 'View' action link to some notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/compose.js | 3 +- app/soapbox/actions/interactions.js | 9 ++--- app/soapbox/actions/snackbar.js | 16 +++++---- app/soapbox/containers/status_container.js | 4 +-- app/soapbox/features/edit_profile/index.js | 5 +-- .../containers/detailed_status_container.js | 4 +-- app/soapbox/features/status/index.js | 4 +-- .../ui/containers/notifications_container.js | 33 ++++++++++++++----- app/soapbox/reducers/alerts.js | 2 ++ app/soapbox/selectors/index.js | 2 ++ app/styles/components/snackbar.scss | 15 +++++++++ 11 files changed, 68 insertions(+), 29 deletions(-) diff --git a/app/soapbox/actions/compose.js b/app/soapbox/actions/compose.js index 4eca355d4..44d9d9c95 100644 --- a/app/soapbox/actions/compose.js +++ b/app/soapbox/actions/compose.js @@ -81,6 +81,7 @@ const messages = defineMessages({ uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, scheduleError: { id: 'compose.invalid_schedule', defaultMessage: 'You must schedule a post at least 5 minutes out.' }, success: { id: 'compose.submit_success', defaultMessage: 'Your post was sent' }, + view: { id: 'snackbar.view', defaultMessage: 'View' }, }); const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1); @@ -190,7 +191,7 @@ export function handleComposeSubmit(dispatch, getState, data, status) { dispatch(insertIntoTagHistory(data.tags || [], status)); dispatch(submitComposeSuccess({ ...data })); - dispatch(snackbar.success(messages.success)); + dispatch(snackbar.success(messages.success, messages.view, `/@${data.account.acct}/posts/${data.id}`)); } const needsDescriptions = state => { diff --git a/app/soapbox/actions/interactions.js b/app/soapbox/actions/interactions.js index d7f27a96c..bb0461411 100644 --- a/app/soapbox/actions/interactions.js +++ b/app/soapbox/actions/interactions.js @@ -58,6 +58,7 @@ export const REMOTE_INTERACTION_FAIL = 'REMOTE_INTERACTION_FAIL'; const messages = defineMessages({ bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' }, bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' }, + view: { id: 'snackbar.view', defaultMessage: 'View' }, }); export function reblog(status) { @@ -220,28 +221,28 @@ export function unfavouriteFail(status, error) { }; } -export function bookmark(intl, status) { +export function bookmark(status) { return function(dispatch, getState) { dispatch(bookmarkRequest(status)); api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function(response) { dispatch(importFetchedStatus(response.data)); dispatch(bookmarkSuccess(status, response.data)); - dispatch(snackbar.success(intl.formatMessage(messages.bookmarkAdded))); + dispatch(snackbar.success(messages.bookmarkAdded, messages.view, '/bookmarks')); }).catch(function(error) { dispatch(bookmarkFail(status, error)); }); }; } -export function unbookmark(intl, status) { +export function unbookmark(status) { return (dispatch, getState) => { dispatch(unbookmarkRequest(status)); api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unbookmarkSuccess(status, response.data)); - dispatch(snackbar.success(intl.formatMessage(messages.bookmarkRemoved))); + dispatch(snackbar.success(messages.bookmarkRemoved)); }).catch(error => { dispatch(unbookmarkFail(status, error)); }); diff --git a/app/soapbox/actions/snackbar.js b/app/soapbox/actions/snackbar.js index c1be02757..47fd11137 100644 --- a/app/soapbox/actions/snackbar.js +++ b/app/soapbox/actions/snackbar.js @@ -1,21 +1,23 @@ import { ALERT_SHOW } from './alerts'; -export const show = (severity, message) => ({ +export const show = (severity, message, actionLabel, actionLink) => ({ type: ALERT_SHOW, message, + actionLabel, + actionLink, severity, }); -export function info(message) { - return show('info', message); +export function info(message, actionLabel, actionLink) { + return show('info', message, actionLabel, actionLink); } -export function success(message) { - return show('success', message); +export function success(message, actionLabel, actionLink) { + return show('success', message, actionLabel, actionLink); } -export function error(message) { - return show('error', message); +export function error(message, actionLabel, actionLink) { + return show('error', message, actionLabel, actionLink); } export default { diff --git a/app/soapbox/containers/status_container.js b/app/soapbox/containers/status_container.js index e6dec8beb..e479647e9 100644 --- a/app/soapbox/containers/status_container.js +++ b/app/soapbox/containers/status_container.js @@ -134,9 +134,9 @@ const mapDispatchToProps = (dispatch, { intl }) => { onBookmark(status) { if (status.get('bookmarked')) { - dispatch(unbookmark(intl, status)); + dispatch(unbookmark(status)); } else { - dispatch(bookmark(intl, status)); + dispatch(bookmark(status)); } }, diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index f38197653..339cd4d00 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -49,6 +49,7 @@ const messages = defineMessages({ error: { id: 'edit_profile.error', defaultMessage: 'Profile update failed' }, bioPlaceholder: { id: 'edit_profile.fields.bio_placeholder', defaultMessage: 'Tell us about yourself.' }, displayNamePlaceholder: { id: 'edit_profile.fields.display_name_placeholder', defaultMessage: 'Name' }, + view: { id: 'snackbar.view', defaultMessage: 'View' }, }); const makeMapStateToProps = () => { @@ -171,7 +172,7 @@ class EditProfile extends ImmutablePureComponent { } handleSubmit = (event) => { - const { dispatch, intl } = this.props; + const { dispatch, intl, account } = this.props; const credentials = dispatch(patchMe(this.getFormdata())); const notifications = dispatch(updateNotificationSettings({ @@ -182,7 +183,7 @@ class EditProfile extends ImmutablePureComponent { Promise.all([credentials, notifications]).then(() => { this.setState({ isLoading: false }); - dispatch(snackbar.success(intl.formatMessage(messages.success))); + dispatch(snackbar.success(intl.formatMessage(messages.success), intl.formatMessage(messages.view), `/@${account.get('acct')}`)); }).catch((error) => { this.setState({ isLoading: false }); dispatch(snackbar.error(intl.formatMessage(messages.error))); diff --git a/app/soapbox/features/status/containers/detailed_status_container.js b/app/soapbox/features/status/containers/detailed_status_container.js index b20fa54f4..070e70c14 100644 --- a/app/soapbox/features/status/containers/detailed_status_container.js +++ b/app/soapbox/features/status/containers/detailed_status_container.js @@ -98,9 +98,9 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ onBookmark(status) { if (status.get('bookmarked')) { - dispatch(unbookmark(intl, status)); + dispatch(unbookmark(status)); } else { - dispatch(bookmark(intl, status)); + dispatch(bookmark(status)); } }, diff --git a/app/soapbox/features/status/index.js b/app/soapbox/features/status/index.js index eb6c670c7..4c554252f 100644 --- a/app/soapbox/features/status/index.js +++ b/app/soapbox/features/status/index.js @@ -221,9 +221,9 @@ class Status extends ImmutablePureComponent { handleBookmark = (status) => { if (status.get('bookmarked')) { - this.props.dispatch(unbookmark(this.props.intl, status)); + this.props.dispatch(unbookmark(status)); } else { - this.props.dispatch(bookmark(this.props.intl, status)); + this.props.dispatch(bookmark(status)); } } diff --git a/app/soapbox/features/ui/containers/notifications_container.js b/app/soapbox/features/ui/containers/notifications_container.js index 484e2b9fe..5904a8d66 100644 --- a/app/soapbox/features/ui/containers/notifications_container.js +++ b/app/soapbox/features/ui/containers/notifications_container.js @@ -1,6 +1,8 @@ +import React from 'react'; import { injectIntl } from 'react-intl'; import { NotificationStack } from 'react-notification'; import { connect } from 'react-redux'; +import { Link } from 'react-router-dom'; import { dismissAlert } from '../../../actions/alerts'; import { getAlerts } from '../../../selectors'; @@ -16,22 +18,35 @@ const defaultBarStyleFactory = (index, style, notification) => { const mapStateToProps = (state, { intl }) => { const notifications = getAlerts(state); - notifications.forEach(notification => ['title', 'message'].forEach(key => { - const value = notification[key]; + notifications.forEach(notification => { + ['title', 'message', 'actionLabel'].forEach(key => { + const value = notification[key]; - if (typeof value === 'object') { - notification[key] = intl.formatMessage(value); + if (typeof value === 'object') { + notification[key] = intl.formatMessage(value); + } + }); + + if (notification.actionLabel) { + notification.action = ( + + {notification.actionLabel} + + ); } - })); + }); - return { notifications }; + return { notifications, linkComponent: Link }; }; const mapDispatchToProps = (dispatch) => { + const onDismiss = alert => { + dispatch(dismissAlert(alert)); + }; + return { - onDismiss: alert => { - dispatch(dismissAlert(alert)); - }, + onDismiss, + onClick: onDismiss, barStyleFactory: defaultBarStyleFactory, activeBarStyleFactory: defaultBarStyleFactory, }; diff --git a/app/soapbox/reducers/alerts.js b/app/soapbox/reducers/alerts.js index 794133b14..79fad30e6 100644 --- a/app/soapbox/reducers/alerts.js +++ b/app/soapbox/reducers/alerts.js @@ -16,6 +16,8 @@ export default function alerts(state = initialState, action) { title: action.title, message: action.message, severity: action.severity || 'info', + actionLabel: action.actionLabel, + actionLink: action.actionLink, })); case ALERT_DISMISS: return state.filterNot(item => item.get('key') === action.alert.key); diff --git a/app/soapbox/selectors/index.js b/app/soapbox/selectors/index.js index bf14c99bf..b7ca3a14a 100644 --- a/app/soapbox/selectors/index.js +++ b/app/soapbox/selectors/index.js @@ -171,6 +171,8 @@ export const getAlerts = createSelector([getAlertsBase], (base) => { arr.push({ message: item.get('message'), title: item.get('title'), + actionLabel: item.get('actionLabel'), + actionLink: item.get('actionLink'), key: item.get('key'), className: `snackbar snackbar--${item.get('severity', 'info')}`, activeClassName: 'snackbar--active', diff --git a/app/styles/components/snackbar.scss b/app/styles/components/snackbar.scss index ffbb4c502..3f43043ca 100644 --- a/app/styles/components/snackbar.scss +++ b/app/styles/components/snackbar.scss @@ -55,4 +55,19 @@ .notification-bar-wrapper { transform: translateY(1px); } + + .notification-bar-action a { + @include font-roboto; + font-size: 16px; + color: white; + font-weight: 700; + text-decoration: none; + text-transform: none; + + &:hover, + &:active, + &:focus { + text-decoration: underline; + } + } }