Commit 1373af74 authored by Florent Chehab's avatar Florent Chehab

Added notistack for crasy easy handling of notifications.

Notifications in the editor are handled again.
parent c3ddb098
Pipeline #35657 canceled with stages
......@@ -8521,6 +8521,15 @@
"resolved": "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.1.2.tgz",
"integrity": "sha512-F9YMRls0zCF6BFIE2YnXDRpHPpfd91nOIaNdDgrx5YMoPLo8Wqj+6jNXHQsYBavJeXP4ww8HCt0xQAKc5qk2Fg=="
},
"notistack": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-0.4.3.tgz",
"integrity": "sha512-YVG4IqA7+eCmMRH42UE+KZOIXTPg/3HEWU+pE1S+Tc8mUNSTQlZMdLy7XwDF1+WimyLiA7Glm+y+ClSu/4t+WA==",
"requires": {
"classnames": "^2.2.6",
"prop-types": "^15.6.2"
}
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
......
......@@ -33,6 +33,7 @@
"leaflet": "^1.4.0",
"lodash": "^4.17.11",
"material-ui-pickers": "^2.2.1",
"notistack": "^0.4.3",
"react": "^16.8.3",
"react-awesome-slider": "^0.5.2",
"react-dom": "^16.8.3",
......
......@@ -6,8 +6,6 @@
// ie common fot the entire app
export const OPEN_FULL_SCREEN_DIALOG = "OPEN_FULL_SCREEN_DIALOG";
export const CLOSE_FULL_SCREEN_DIALOG = "CLOSE_UNIVERSITY_BEING_VIEWED";
export const CREATE_NOTIFICATION = "CREATE_NOTIFICATION";
export const DELETE_NOTIFICATION = "DELETE_NOTIFICATION";
// Other redux actions
export const SAVE_MAIN_MAP_STATUS = "SAVE_MAIN_MAP_STATUS";
......
/*
* This file contains the redux actions related to the handling of notifications in the app
*/
import {
CREATE_NOTIFICATION,
DELETE_NOTIFICATION,
} from "./action-types";
/**
* Action: Create a notifiacation in the app
*
* @export
* @param {object} attrs
* @returns {object}
*/
export function createNotification(attrs) {
return {
type: CREATE_NOTIFICATION,
attrs
};
}
/**
* Action: Delete a notification
* TODO add support for multiple
*
* @export
* @returns {object}
*/
export function deleteNotification() {
return {
type: DELETE_NOTIFICATION,
};
}
......@@ -18,7 +18,6 @@ import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import SchoolIcon from "@material-ui/icons/School";
import { mainListItems, secondaryListItems, thirdListItems } from "./appRelated/listItems";
import FullScreenDialog from "./appRelated/FullScreenDialog";
import Notifications from "./appRelated/Notifications";
import { connect } from "react-redux";
import CustomComponentForAPI from "./CustomComponentForAPI";
......@@ -113,8 +112,6 @@ class App extends CustomComponentForAPI {
</Drawer>
<Notifications />
<FullScreenDialog />
<main className={classNames(classes.content, classes.noPaddingTop)}>
......
......@@ -11,6 +11,7 @@ import TextField from "../shared/fields/TextField";
import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor";
import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor";
import { withSnackbar } from "notistack";
const styles = theme => ({
...editorStyle(theme)
......@@ -58,6 +59,7 @@ class UniversityGeneralEditor extends Editor {
export default compose(
withSnackbar,
withStyles(styles, { withTheme: true }),
connect(
getMapStateToPropsForEditor("universities"),
......
......@@ -9,6 +9,7 @@ import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close";
import Alert from "./Alert";
// import renderFieldsMixIn from "./editorFunctions/renderFieldsMixIn";
// Form is imported only for type hints
......@@ -37,13 +38,13 @@ class Editor extends Component {
alert: {
open: false,
},
notification: {
open: false,
},
}
formRef = React.createRef();
// Store the "saving" notification so that we can delete it when done saving.
savingNotification = null;
/**
* Returns the form instance associated with the editor
*
......@@ -127,7 +128,7 @@ class Editor extends Component {
* @param {Boolean} somethingWasSaved
* @memberof Editor
*/
closeEditor(somethingWasSaved){
closeEditor(somethingWasSaved) {
this.props.closeFullScreenDialog();
this.props.handleEditorWasClosed(somethingWasSaved);
}
......@@ -225,7 +226,7 @@ class Editor extends Component {
</Toolbar>
</AppBar>
<Paper className={classes.paper}>
{this.props.open ? this.renderForm() : <div></div>}
{this.renderForm()}
</Paper>
</div>
);
......@@ -242,13 +243,6 @@ class Editor extends Component {
// user request handlers
handleCloseNotificationRequest() {
this.setState({
// backup message to prevent graphic artefact
notification: { open: false, message: this.state.notification.message }
});
}
handleCloseAlertRequest() {
this.setState({
alert: { open: false }
......@@ -258,51 +252,20 @@ class Editor extends Component {
// Notifications and alerts from JS
notifyNoChangesDetected() {
console.log("no changes detected")
// this.setState({
// notification: {
// open: true,
// message: "Aucun changement n'a été repéré.",
// success: true,
// }
// });
this.props.enqueueSnackbar("Aucun changement n'a été repéré.", { variant: "info" });
}
notifyFormHasErrors(errors) {
console.log("errors in the form")
// this.setState({
// notification: {
// open: true,
// message: "Le formulaire semble incohérent, merci de vérifier son contenu.",
// error: true,
// errors,
// handleClose: this.handleCloseNotificationRequest()
// }
// });
this.props.enqueueSnackbar(`Le formulaire semble incohérent, merci de vérifier son contenu. ${errors}`, { variant: "error" });
}
notifyIsSaving() {
console.log("is saving")
// this.setState({
// notification: {
// open: true,
// message: "Enregistrement en cours",
// isLoading: true,
// duration: null
// }
// });
this.savingNotification = this.props.enqueueSnackbar("Enregistrement en cours", { variant: "info", persist: true, action: null });
}
notifySaveSuccessful(message) {
console.log("save success")
// this.setState({
// notification: {
// open: true,
// message,
// success: true,
// preventClickAway: false
// }
// });
this.props.closeSnackbar(this.savingNotification);
this.props.enqueueSnackbar(message, { variant: "success", autoHideDuration: 5000});
}
alertSaveFailed(error) {
......@@ -362,6 +325,9 @@ Editor.propTypes = {
openFullScreenDialog: PropTypes.func.isRequired,
closeFullScreenDialog: PropTypes.func.isRequired,
saveData: PropTypes.func.isRequired,
// Notifications related
enqueueSnackbar: PropTypes.func.isRequired,
closeSnackbar: PropTypes.func.isRequired,
};
Editor.defaultProps = {
......
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import Snackbar from "@material-ui/core/Snackbar";
import DoneIcon from "@material-ui/icons/Done";
import Loading from "../../other/Loading";
import IconButton from "@material-ui/core/IconButton";
import CloseIcon from "@material-ui/icons/Close";
const styles = theme => ({
close: {
width: theme.spacing.unit * 4,
height: theme.spacing.unit * 4,
},
error: {
color: "red",
display: "block"
}
});
class Notification extends React.Component {
handleClose = (event, reason) => {
if (reason === "clickaway" && this.props.preventClickAway) {
return;
}
this.props.handleClose();
};
renderMessage() {
const { classes } = this.props;
return (
<div>
<span id="message-id">{this.props.message}</span>
{this.props.errors.map((error, idx) => (<span key={idx} className={classes.error}>{error}</span>))}
</div>
);
}
render() {
const { classes } = this.props;
let actions = Array();
if (this.props.isLoading) {
actions.push(
<Loading size={20} />
);
} else if (this.props.success) {
actions.push(
<DoneIcon color='primary' />
);
} else if (this.props.error) {
actions.push(
<IconButton
key="close"
aria-label="Fermer"
color="inherit"
className={classes.close}
onClick={this.props.handleClose}
>
<CloseIcon />
</IconButton>
);
}
return (
<div>
<Snackbar
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
open={this.props.open}
autoHideDuration={this.props.duration}
onClose={this.handleClose}
ContentProps={{
"aria-describedby": "message-id",
}}
message={this.renderMessage()}
action={actions}
/>
</div>
);
}
}
Notification.defaultProps = {
open: false,
duration: 5000,
message: "",
preventClickAway: true,
success: false,
error: false,
errors: [],
isLoading: false,
// eslint-disable-next-line no-console
handleClose: () => console.error("cloossee notif")
};
Notification.propTypes = {
classes: PropTypes.object.isRequired,
open: PropTypes.bool.isRequired,
duration: PropTypes.number,
message: PropTypes.string.isRequired,
preventClickAway: PropTypes.bool.isRequired,
success: PropTypes.bool.isRequired,
error: PropTypes.bool.isRequired,
errors: PropTypes.arrayOf(PropTypes.string),
isLoading: PropTypes.bool.isRequired,
handleClose: PropTypes.func.isRequired,
};
export default withStyles(styles)(Notification);
......@@ -2,6 +2,8 @@ import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { Route } from "react-router-dom";
import { SnackbarProvider } from "notistack"; // provider to easily handle notifications across the app
import Button from "@material-ui/core/Button";
import store from "./store/index";
import App from "./components/App";
......@@ -11,7 +13,21 @@ const MainReactEntry = () => (
<Provider store={store}>
{/* <React.StrictMode> */}
<ThemeProvider>
<Route path="/:filter?" component={App} />
<SnackbarProvider
maxSnack={3}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
action={[
<Button key={0} color="secondary" size="small">
{"Fermer"}
</Button>
]}
>
<Route path="/:filter?" component={App} />
</SnackbarProvider>
</ThemeProvider>
{/* </React.StrictMode> */}
</Provider>
......
import { combineReducers } from "redux";
import { fullScreenDialog } from "./fullScreenDialog";
import { notifications } from "./notifications";
import { saveMainMapStatus } from "./map";
import { saveSelectedUniversities, saveFilterConfig } from "./filter";
import { saveAppTheme, saveAppColorPicker } from "./theme";
......@@ -11,7 +10,6 @@ import { apiReducers } from "../api/buildApiActionsAndReducers";
// Combine the reducers related to the app
const app = combineReducers({
fullScreenDialog,
notifications,
mainMap: saveMainMapStatus,
selectedUniversities: saveSelectedUniversities,
filter: saveFilterConfig,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment