Skip to content

Commit

Permalink
Merge pull request #2499 from ClearlyClaire/glitch-soc/port-toasts
Browse files Browse the repository at this point in the history
Port upstream's toast changes
  • Loading branch information
ClearlyClaire authored Dec 3, 2023
2 parents 1390290 + cede2f5 commit 23ee393
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 88 deletions.
70 changes: 33 additions & 37 deletions app/javascript/flavours/glitch/actions/alerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,52 +12,48 @@ export const ALERT_DISMISS = 'ALERT_DISMISS';
export const ALERT_CLEAR = 'ALERT_CLEAR';
export const ALERT_NOOP = 'ALERT_NOOP';

export function dismissAlert(alert) {
return {
type: ALERT_DISMISS,
alert,
};
}

export function clearAlert() {
return {
type: ALERT_CLEAR,
};
}

export function showAlert(title = messages.unexpectedTitle, message = messages.unexpectedMessage, message_values = undefined) {
return {
type: ALERT_SHOW,
title,
message,
message_values,
};
}

export function showAlertForError(error, skipNotFound = false) {
export const dismissAlert = alert => ({
type: ALERT_DISMISS,
alert,
});

export const clearAlert = () => ({
type: ALERT_CLEAR,
});

export const showAlert = alert => ({
type: ALERT_SHOW,
alert,
});

export const showAlertForError = (error, skipNotFound = false) => {
if (error.response) {
const { data, status, statusText, headers } = error.response;

// Skip these errors as they are reflected in the UI
if (skipNotFound && (status === 404 || status === 410)) {
// Skip these errors as they are reflected in the UI
return { type: ALERT_NOOP };
}

// Rate limit errors
if (status === 429 && headers['x-ratelimit-reset']) {
const reset_date = new Date(headers['x-ratelimit-reset']);
return showAlert(messages.rateLimitedTitle, messages.rateLimitedMessage, { 'retry_time': reset_date });
return showAlert({
title: messages.rateLimitedTitle,
message: messages.rateLimitedMessage,
values: { 'retry_time': new Date(headers['x-ratelimit-reset']) },
});
}

let message = statusText;
let title = `${status}`;
return showAlert({
title: `${status}`,
message: data.error || statusText,
});
}

if (data.error) {
message = data.error;
}
console.error(error);

return showAlert(title, message);
} else {
console.error(error);
return showAlert();
}
}
return showAlert({
title: messages.unexpectedTitle,
message: messages.unexpectedMessage,
});
};
19 changes: 15 additions & 4 deletions app/javascript/flavours/glitch/actions/compose.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export const COMPOSE_FOCUS = 'COMPOSE_FOCUS';
const messages = defineMessages({
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
open: { id: 'compose.published.open', defaultMessage: 'Open' },
published: { id: 'compose.published.body', defaultMessage: 'Post published.' },
saved: { id: 'compose.saved.body', defaultMessage: 'Post saved.' },
});

export const ensureComposeIsVisible = (getState, routerHistory) => {
Expand Down Expand Up @@ -274,6 +277,13 @@ export function submitCompose(routerHistory) {
} else if (statusId === null && response.data.visibility === 'direct') {
insertIfOnline('direct');
}

dispatch(showAlert({
message: statusId === null ? messages.published : messages.saved,
action: messages.open,
dismissAfter: 10000,
onClick: () => routerHistory.push(`/@${response.data.account.username}/${response.data.id}`),
}));
}).catch(function (error) {
dispatch(submitComposeFail(error));
});
Expand Down Expand Up @@ -310,18 +320,19 @@ export function doodleSet(options) {
export function uploadCompose(files) {
return function (dispatch, getState) {
const uploadLimit = 4;
const media = getState().getIn(['compose', 'media_attachments']);
const pending = getState().getIn(['compose', 'pending_media_attachments']);
const media = getState().getIn(['compose', 'media_attachments']);
const pending = getState().getIn(['compose', 'pending_media_attachments']);
const progress = new Array(files.length).fill(0);

let total = Array.from(files).reduce((a, v) => a + v.size, 0);

if (files.length + media.size + pending > uploadLimit) {
dispatch(showAlert(undefined, messages.uploadErrorLimit));
dispatch(showAlert({ message: messages.uploadErrorLimit }));
return;
}

if (getState().getIn(['compose', 'poll'])) {
dispatch(showAlert(undefined, messages.uploadErrorPoll));
dispatch(showAlert({ message: messages.uploadErrorPoll }));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
if (permission === 'granted') {
dispatch(changePushNotifications(path.slice(1), checked));
} else {
dispatch(showAlert(undefined, messages.permissionDenied));
dispatch(showAlert({ message: messages.permissionDenied }));
}
}));
} else {
Expand All @@ -47,7 +47,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
if (permission === 'granted') {
dispatch(changeSetting(['notifications', ...path], checked));
} else {
dispatch(showAlert(undefined, messages.permissionDenied));
dispatch(showAlert({ message: messages.permissionDenied }));
}
}));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,27 @@ import { NotificationStack } from 'react-notification';
import { dismissAlert } from '../../../actions/alerts';
import { getAlerts } from '../../../selectors';

const mapStateToProps = (state, { intl }) => {
const notifications = getAlerts(state);
const formatIfNeeded = (intl, message, values) => {
if (typeof message === 'object') {
return intl.formatMessage(message, values);
}

notifications.forEach(notification => ['title', 'message'].forEach(key => {
const value = notification[key];

if (typeof value === 'object') {
notification[key] = intl.formatMessage(value, notification[`${key}_values`]);
}
}));

return { notifications };
return message;
};

const mapDispatchToProps = (dispatch) => {
return {
onDismiss: alert => {
dispatch(dismissAlert(alert));
},
};
};
const mapStateToProps = (state, { intl }) => ({
notifications: getAlerts(state).map(alert => ({
...alert,
action: formatIfNeeded(intl, alert.action, alert.values),
title: formatIfNeeded(intl, alert.title, alert.values),
message: formatIfNeeded(intl, alert.message, alert.values),
})),
});

const mapDispatchToProps = (dispatch) => ({
onDismiss (alert) {
dispatch(dismissAlert(alert));
},
});

export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(NotificationStack));
19 changes: 11 additions & 8 deletions app/javascript/flavours/glitch/reducers/alerts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { List as ImmutableList } from 'immutable';

import {
ALERT_SHOW,
Expand All @@ -8,17 +8,20 @@ import {

const initialState = ImmutableList([]);

let id = 0;

const addAlert = (state, alert) =>
state.push({
key: id++,
...alert,
});

export default function alerts(state = initialState, action) {
switch(action.type) {
case ALERT_SHOW:
return state.push(ImmutableMap({
key: state.size > 0 ? state.last().get('key') + 1 : 0,
title: action.title,
message: action.message,
message_values: action.message_values,
}));
return addAlert(state, action.alert);
case ALERT_DISMISS:
return state.filterNot(item => item.get('key') === action.alert.key);
return state.filterNot(item => item.key === action.alert.key);
case ALERT_CLEAR:
return state.clear();
default:
Expand Down
28 changes: 9 additions & 19 deletions app/javascript/flavours/glitch/selectors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,26 +85,16 @@ export const makeGetPictureInPicture = () => {
}));
};

const getAlertsBase = state => state.get('alerts');

export const getAlerts = createSelector([getAlertsBase], (base) => {
let arr = [];

base.forEach(item => {
arr.push({
message: item.get('message'),
message_values: item.get('message_values'),
title: item.get('title'),
key: item.get('key'),
dismissAfter: 5000,
barStyle: {
zIndex: 200,
},
});
});
const ALERT_DEFAULTS = {
dismissAfter: 5000,
style: false,
};

return arr;
});
export const getAlerts = createSelector(state => state.get('alerts'), alerts =>
alerts.map(item => ({
...ALERT_DEFAULTS,
...item,
})).toArray());

export const makeGetNotification = () => createSelector([
(_, base) => base,
Expand Down
63 changes: 63 additions & 0 deletions app/javascript/flavours/glitch/styles/components/misc.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1675,3 +1675,66 @@ noscript {
opacity: 1;
}
}

.notification-list {
position: fixed;
bottom: 2rem;
inset-inline-start: 0;
z-index: 999;
display: flex;
flex-direction: column;
gap: 4px;
}

.notification-bar {
flex: 0 0 auto;
position: relative;
inset-inline-start: -100%;
width: auto;
padding: 15px;
margin: 0;
color: $white;
background: rgba($black, 0.85);
backdrop-filter: blur(8px);
border: 1px solid rgba(lighten($classic-base-color, 4%), 0.85);
border-radius: 8px;
box-shadow:
0 10px 15px -3px rgba($base-shadow-color, 0.25),
0 4px 6px -4px rgba($base-shadow-color, 0.25);
cursor: default;
font-size: 15px;
line-height: 21px;

&.notification-bar-active {
inset-inline-start: 1rem;
}

.no-reduce-motion & {
transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1);
transform: translateZ(0);
}
}

.notification-bar-title {
margin-inline-end: 5px;
}

.notification-bar-title,
.notification-bar-action {
font-weight: 700;
}

.notification-bar-action {
text-transform: uppercase;
margin-inline-start: 10px;
cursor: pointer;
color: $blurple-300;
border-radius: 4px;
padding: 0 4px;

&:hover,
&:focus,
&:active {
background: rgba($ui-base-color, 0.85);
}
}

0 comments on commit 23ee393

Please sign in to comment.