Skip to content

Commit

Permalink
Add a hook for adding message.
Browse files Browse the repository at this point in the history
  • Loading branch information
huwshimi committed Sep 17, 2019
1 parent d2bc89b commit 1415d34
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 102 deletions.
7 changes: 7 additions & 0 deletions ui/src/app/base/components/Notification/Notification.js
Expand Up @@ -2,6 +2,13 @@ import classNames from "classnames";
import PropTypes from "prop-types";
import React, { useEffect, useRef } from "react";

export const notificationTypes = {
CAUTION: "caution",
INFORMATION: "information",
NEGATIVE: "negative",
POSITIVE: "positive"
};

const Notification = ({
children,
className,
Expand Down
1 change: 1 addition & 0 deletions ui/src/app/base/components/Notification/index.js
@@ -1 +1,2 @@
export { default } from "./Notification";
export { notificationTypes } from "./Notification";
34 changes: 32 additions & 2 deletions ui/src/app/base/hooks.js
@@ -1,7 +1,10 @@
import { useEffect, useRef } from "react";
import { useContext } from "react";
import { __RouterContext as RouterContext } from "react-router";
import { useContext } from "react";
import { useDispatch } from "react-redux";
import { useEffect, useRef } from "react";

import { messages } from "app/base/actions";
import { notificationTypes } from "app/base/components/Notification";
import { simpleObjectEquality } from "app/settings/utils";

// Router hooks inspired by: https://github.com/ReactTraining/react-router/issues/6430#issuecomment-510266079
Expand Down Expand Up @@ -65,3 +68,30 @@ export const useFormikErrors = (errors, formikProps) => {
}
}, [errors, previousErrors, setStatus, values]);
};

/**
* Add a message in response to a state change e.g. when something is created.
* @param {Boolean} addCondition - Whether the message should be added.
* @param {Function} cleanup - A cleanup action to fire.
* @param {String} message - The message to be displayed.
* @param {Function} onMessageAdded - A function to call once the message has
been displayed.
* @param {String} messageType - The notification type.
*/
export const useAddMessage = (
addCondition,
cleanup,
message,
onMessageAdded,
messageType = notificationTypes.INFORMATION
) => {
const dispatch = useDispatch();

useEffect(() => {
if (addCondition) {
dispatch(messages.add(message, messageType));
onMessageAdded && onMessageAdded();
dispatch(cleanup());
}
}, [addCondition, cleanup, dispatch, message, messageType, onMessageAdded]);
};
19 changes: 7 additions & 12 deletions ui/src/app/settings/views/Dhcp/DhcpForm/DhcpForm.js
Expand Up @@ -12,8 +12,8 @@ import {
subnet as subnetActions
} from "app/base/actions";
import { dhcpsnippet as dhcpsnippetSelectors } from "app/base/selectors";
import { messages } from "app/base/actions";
import { DhcpSnippetShape } from "app/settings/proptypes";
import { useAddMessage } from "app/base/hooks";
import { useDhcpTarget } from "app/settings/hooks";
import DhcpFormFields from "../DhcpFormFields";
import FormCard from "app/base/components/FormCard";
Expand Down Expand Up @@ -43,6 +43,12 @@ export const DhcpForm = ({ dhcpSnippet }) => {
editing ? dhcpSnippet.node : null,
editing ? dhcpSnippet.subnet : null
);
useAddMessage(
saved,
dhcpsnippetActions.cleanup,
`${savingDhcp} ${editing ? "updated" : "added"} successfully.`,
setSaving
);

useEffect(() => {
dispatch(subnetActions.fetch());
Expand All @@ -55,17 +61,6 @@ export const DhcpForm = ({ dhcpSnippet }) => {
};
}, [dispatch]);

useEffect(() => {
if (saved) {
const action = editing ? "updated" : "added";
dispatch(dhcpsnippetActions.cleanup());
dispatch(
messages.add(`${savingDhcp} ${action} successfully.`, "information")
);
setSaving();
}
}, [dispatch, editing, saved, savingDhcp]);

if (saved) {
// The snippet was successfully created/updated so redirect to the dhcp list.
return <Redirect to="/dhcp" />;
Expand Down
18 changes: 7 additions & 11 deletions ui/src/app/settings/views/Dhcp/DhcpList/DhcpList.js
Expand Up @@ -19,7 +19,7 @@ import {
machine as machineSelectors,
subnet as subnetSelectors
} from "app/base/selectors";
import { messages } from "app/base/actions";
import { useAddMessage } from "app/base/hooks";
import Button from "app/base/components/Button";
import Code from "app/base/components/Code";
import Col from "app/base/components/Col";
Expand Down Expand Up @@ -203,6 +203,12 @@ const DhcpList = () => {
const devices = useSelector(deviceSelectors.all);
const machines = useSelector(machineSelectors.all);
const dispatch = useDispatch();
useAddMessage(
saved && deletingName,
dhcpsnippetActions.cleanup,
`${deletingName} removed successfully.`,
setDeleting
);

const hideExpanded = () => {
setExpandedId();
Expand All @@ -219,16 +225,6 @@ const DhcpList = () => {
dispatch(machineActions.fetch());
}, [dispatch]);

useEffect(() => {
if (saved && deletingName) {
dispatch(
messages.add(`${deletingName} removed successfully.`, "information")
);
setDeleting();
dispatch(dhcpsnippetActions.cleanup());
}
}, [deletingName, dispatch, saved]);

return (
<>
{dhcpsnippetLoading && <Loader text="Loading..." />}
Expand Down
Expand Up @@ -6,7 +6,7 @@ import "./RepositoriesList.scss";
import { packagerepository as repositoryActions } from "app/base/actions";
import { packagerepository as repositorySelectors } from "app/base/selectors";
import { getRepoDisplayName } from "../utils";
import { messages } from "app/base/actions";
import { useAddMessage } from "app/base/hooks";
import Button from "app/base/components/Button";
import Loader from "app/base/components/Loader";
import MainTable from "app/base/components/MainTable";
Expand Down Expand Up @@ -93,32 +93,25 @@ export const Repositories = () => {
const [expandedId, setExpandedId] = useState(null);
const [searchText, setSearchText] = useState("");
const [deletedRepo, setDeletedRepo] = useState();

const loaded = useSelector(repositorySelectors.loaded);
const loading = useSelector(repositorySelectors.loading);
const saved = useSelector(repositorySelectors.saved);
const repositories = useSelector(state =>
repositorySelectors.search(state, searchText)
);

const dispatch = useDispatch();
useAddMessage(
saved,
repositoryActions.cleanup,
`${deletedRepo} removed successfully.`,
setDeletedRepo
);

// Fetch repositories on load
useEffect(() => {
dispatch(repositoryActions.fetch());
}, [dispatch]);

// Create a deleted notification if successful
useEffect(() => {
if (saved) {
dispatch(repositoryActions.cleanup());
dispatch(
messages.add(`${deletedRepo} removed successfully.`, "information")
);
setDeletedRepo();
}
}, [deletedRepo, dispatch, saved]);

// Clean up saved and error states on unmount.
useEffect(() => {
dispatch(repositoryActions.cleanup());
Expand Down
Expand Up @@ -15,7 +15,7 @@ import {
} from "app/base/selectors";
import { formikFormDisabled } from "app/settings/utils";
import { getRepoDisplayName } from "../utils";
import { messages } from "app/base/actions";
import { useAddMessage } from "app/base/hooks";
import Form from "app/base/components/Form";
import FormCard from "app/base/components/FormCard";
import FormCardButtons from "app/base/components/FormCardButtons";
Expand Down Expand Up @@ -59,6 +59,12 @@ export const RepositoryForm = ({ type, repository }) => {
repositoriesLoaded;

const dispatch = useDispatch();
useAddMessage(
repositoriesSaved,
repositoryActions.cleanup,
`${savedRepo} ${repository ? "updated" : "added"} successfully.`,
setSavedRepo
);

// Fetch data if not all loaded.
useEffect(() => {
Expand All @@ -70,18 +76,6 @@ export const RepositoryForm = ({ type, repository }) => {
}
}, [dispatch, allLoaded]);

// Create a saved notification if successful
useEffect(() => {
if (repositoriesSaved) {
const action = repository ? "updated" : "added";
dispatch(repositoryActions.cleanup());
dispatch(
messages.add(`${savedRepo} ${action} successfully.`, "information")
);
setSavedRepo();
}
}, [dispatch, repository, repositoriesSaved, savedRepo]);

// Clean up saved and error states on unmount.
useEffect(() => {
dispatch(repositoryActions.cleanup());
Expand Down
39 changes: 14 additions & 25 deletions ui/src/app/settings/views/Scripts/ScriptsList.js
Expand Up @@ -6,7 +6,7 @@ import classNames from "classnames";
import { Link } from "react-router-dom";

import "./ScriptsList.scss";
import { messages } from "app/base/actions";
import { useAddMessage } from "app/base/hooks";
import Button from "app/base/components/Button";
import Code from "app/base/components/Code";
import Col from "app/base/components/Col";
Expand Down Expand Up @@ -163,6 +163,19 @@ const ScriptsList = ({ type = "commissioning" }) => {
const userScripts = useSelector(state =>
scriptSelectors.search(state, searchText, type)
);
useAddMessage(
saved,
scriptActions.cleanup,
`${deletingScript} removed successfully.`,
setDeleting
);
useAddMessage(
hasErrors,
scriptActions.cleanup,
`Error removing ${deletingScript}: ${errors}`,
null,
"negative"
);

const hideExpanded = () => {
setExpandedId();
Expand All @@ -173,30 +186,6 @@ const ScriptsList = ({ type = "commissioning" }) => {
dispatch(scriptActions.fetch());
}, [dispatch, type]);

useEffect(() => {
if (saved) {
dispatch(
messages.add(`${deletingScript} removed successfully.`, "information")
);
setDeleting();
dispatch(scriptActions.cleanup());
}
}, [deletingScript, dispatch, saved]);

useEffect(() => {
if (hasErrors) {
Object.keys(errors).forEach(key => {
dispatch(
messages.add(
`Error deleting ${deletingScript}: ${errors[key]}`,
"negative"
)
);
});
dispatch(scriptActions.cleanup());
}
}, [deletingScript, hasErrors, errors, dispatch]);

return (
<>
{scriptsLoading && <Loader text="Loading..." />}
Expand Down
19 changes: 7 additions & 12 deletions ui/src/app/settings/views/Users/UserForm/UserForm.js
Expand Up @@ -7,7 +7,7 @@ import React, { useEffect, useState } from "react";

import { user as userActions } from "app/base/actions";
import { user as userSelectors } from "app/base/selectors";
import { messages } from "app/base/actions";
import { useAddMessage } from "app/base/hooks";
import { UserShape } from "app/base/proptypes";
import FormCard from "app/base/components/FormCard";
import UserFormFields from "../UserFormFields";
Expand Down Expand Up @@ -44,6 +44,12 @@ export const UserForm = ({ title, user }) => {
const saved = useSelector(userSelectors.saved);
const [savingUser, setSaving] = useState();
const editing = !!user;
useAddMessage(
saved,
userActions.cleanup,
`${savingUser} ${editing ? "updated" : "added"} successfully.`,
setSaving
);

useEffect(() => {
return () => {
Expand All @@ -52,17 +58,6 @@ export const UserForm = ({ title, user }) => {
};
}, [dispatch]);

useEffect(() => {
if (saved) {
const action = editing ? "updated" : "added";
dispatch(userActions.cleanup());
dispatch(
messages.add(`${savingUser} ${action} successfully.`, "information")
);
setSaving();
}
}, [dispatch, editing, saved, savingUser]);

if (saved) {
// The user was successfully created/updated so redirect to the user list.
return <Redirect to="/users" />;
Expand Down
22 changes: 9 additions & 13 deletions ui/src/app/settings/views/Users/UsersList/UsersList.js
Expand Up @@ -5,10 +5,10 @@ import classNames from "classnames";
import React, { useEffect, useState } from "react";

import "./UsersList.scss";
import { messages } from "app/base/actions";
import { useAddMessage } from "app/base/hooks";
import { user as userActions } from "app/base/actions";
import { auth as authActions } from "app/base/actions";
import { user as userSelectors } from "app/base/selectors";
import { auth } from "app/base/selectors";
import Button from "app/base/components/Button";
import Loader from "app/base/components/Loader";
import MainTable from "app/base/components/MainTable";
Expand Down Expand Up @@ -121,9 +121,15 @@ const Users = () => {
const users = useSelector(state => userSelectors.search(state, searchText));
const loading = useSelector(userSelectors.loading);
const loaded = useSelector(userSelectors.loaded);
const authUser = useSelector(auth.get);
const authUser = useSelector(authActions.fetch);
const saved = useSelector(userSelectors.saved);
const dispatch = useDispatch();
useAddMessage(
saved,
userActions.cleanup,
`${deletingUser} removed successfully.`,
setDeleting
);

useEffect(() => {
dispatch(userActions.fetch());
Expand All @@ -136,16 +142,6 @@ const Users = () => {
};
}, [dispatch]);

useEffect(() => {
if (saved) {
dispatch(
messages.add(`${deletingUser} removed successfully.`, "information")
);
setDeleting();
dispatch(userActions.cleanup());
}
}, [deletingUser, dispatch, saved]);

return (
<>
{loading && <Loader text="Loading..." inline />}
Expand Down

0 comments on commit 1415d34

Please sign in to comment.