From 001bdb01d048f4b8df8019092061a5fb4e0faa7a Mon Sep 17 00:00:00 2001 From: Nelson Pang Date: Fri, 6 Dec 2024 16:51:38 -0800 Subject: [PATCH] created an modal that gives options to confirming leaving the page or cancel after making an edit to the FAQ in admin mode --- .../src/components/Faq/FaqConfirmDialog.jsx | 82 +++++++++++++++++++ client/src/components/Faq/FaqView.jsx | 44 +++++++++- .../ProjectWizard/TdmCalculationWizard.jsx | 2 - 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 client/src/components/Faq/FaqConfirmDialog.jsx diff --git a/client/src/components/Faq/FaqConfirmDialog.jsx b/client/src/components/Faq/FaqConfirmDialog.jsx new file mode 100644 index 00000000..820d85ce --- /dev/null +++ b/client/src/components/Faq/FaqConfirmDialog.jsx @@ -0,0 +1,82 @@ +import React from "react"; +import PropTypes from "prop-types"; +import ModalDialog from "../UI/AriaModal/ModalDialog"; +import Button from "../Button/Button"; +import { createUseStyles } from "react-jss"; +import { MdWarning } from "react-icons/md"; + +const useStyles = createUseStyles({ + title: { + textAlign: "center" + }, + warningWrapper: { + color: "#B64E38", + display: "flex", + alignItems: "center", + justifyContent: "center" + }, + warningMessage: { + verticalAlign: "middle", + display: "flex", + alignItems: "center", + justifyContent: "center", + marginBottom: "1em" + }, + modalActions: { + display: "flex", + justifyContent: "center" + }, + proceedButton: { + color: "white", + fontWeight: "bold" + } +}); + +const FaqConfirmDialog = ({ blocker }) => { + const classes = useStyles(); + return ( + +
+ +
+

+ Unsaved changes will be lost +

+

+ +   Leaving this page will permanently delete any unsaved changes + to the FAQ. + +

+
+ + +
+
+ ); +}; + +FaqConfirmDialog.propTypes = { + blocker: PropTypes.object.isRequired +}; + +export default FaqConfirmDialog; diff --git a/client/src/components/Faq/FaqView.jsx b/client/src/components/Faq/FaqView.jsx index 053f8373..022a1978 100644 --- a/client/src/components/Faq/FaqView.jsx +++ b/client/src/components/Faq/FaqView.jsx @@ -10,6 +10,8 @@ import AddNewCategoryButton from "../Button/AddNewCategory"; import { createUseStyles } from "react-jss"; import DeleteFaqModal from "./DeleteFaqModal"; import SaveConfirmationModal from "./SaveConfirmationModal"; +import FaqConfirmDialog from "./FaqConfirmDialog"; +import { matchPath, unstable_useBlocker as useBlocker } from "react-router-dom"; const useStyles = createUseStyles(theme => ({ headerContainer: { @@ -35,6 +37,7 @@ const FaqView = () => { const [highestFaqId, setHighestFaqId] = useState(0); const [highestCategoryId, setHighestCategoryId] = useState(0); const [expanded, setExpanded] = useState(false); + const [formHasSaved, setFormHasSaved] = useState(false); const [admin, setAdmin] = useState(false); const [categoryToDelete, setCategoryToDelete] = useState(null); const [faqToDelete, setFaqToDelete] = useState(null); @@ -47,6 +50,36 @@ const FaqView = () => { fetchFaqData(); }, []); + const calculationPath = "/faqs"; + + const shouldBlock = React.useCallback( + ({ currentLocation, nextLocation }) => { + const isSamePage = (currentLocation, nextLocation) => { + const currentMatch = matchPath( + { + path: calculationPath, + exact: true + }, + currentLocation.pathname + ); + const nextMatch = matchPath( + { + path: calculationPath, + exact: true + }, + nextLocation.pathname + ); + + return currentMatch && nextMatch; + }; + + return formHasSaved && !isSamePage(currentLocation, nextLocation); + }, + [formHasSaved] + ); + + const blocker = useBlocker(shouldBlock); + const handleDragEnd = result => { const { type, destination, source } = result; @@ -161,12 +194,14 @@ const FaqView = () => { }; setHighestCategoryId(updatedHighestCategoryId); setFaqCategoryList(prevState => [...prevState, newCategory]); + setFormHasSaved(true); }; const onDeleteCategory = categoryId => { setFaqCategoryList(prevState => prevState.filter(category => category.id !== categoryId) ); + setFormHasSaved(true); }; const handleAddFAQ = (category, question, answer) => { @@ -198,6 +233,7 @@ const FaqView = () => { return category; }) ); + setFormHasSaved(true); }; const handleEditFAQ = (categoryId, faqId, question, answer) => { @@ -224,6 +260,7 @@ const FaqView = () => { return category; }) ); + setFormHasSaved(true); }; const handleEditCategory = (category, name) => { @@ -240,6 +277,7 @@ const FaqView = () => { return cat; }) ); + setFormHasSaved(true); }; const onDeleteFAQ = (categoryId, faqId) => { @@ -256,6 +294,7 @@ const FaqView = () => { return category; }) ); + setFormHasSaved(true); }; const expandFaq = faq => { @@ -312,7 +351,7 @@ const FaqView = () => { // Submit data and set admin to false submitFaqData(); setAdmin(false); - + setFormHasSaved(false); // Close the save confirmation modal closeSaveConfirmationModal(); }; @@ -320,12 +359,14 @@ const FaqView = () => { const handleDeleteCategory = categoryId => { setCategoryToDelete(categoryId); setIsDeleteConfirmationModalOpen(true); + setFormHasSaved(true); }; const handleDeleteFAQ = (categoryId, faqId) => { setCategoryToDelete(categoryId); setFaqToDelete(faqId); setIsDeleteConfirmationModalOpen(true); + setFormHasSaved(true); }; const closeModal = () => { @@ -405,6 +446,7 @@ const FaqView = () => { onClose={closeSaveConfirmationModal} onYes={handleSaveConfirmationYes} /> + {blocker ? : null} ); }; diff --git a/client/src/components/ProjectWizard/TdmCalculationWizard.jsx b/client/src/components/ProjectWizard/TdmCalculationWizard.jsx index 8922b0a2..6175f248 100644 --- a/client/src/components/ProjectWizard/TdmCalculationWizard.jsx +++ b/client/src/components/ProjectWizard/TdmCalculationWizard.jsx @@ -96,7 +96,6 @@ const TdmCalculationWizard = props => { }, nextLocation.pathname ); - return ( currentMatch && nextMatch && @@ -104,7 +103,6 @@ const TdmCalculationWizard = props => { !projectId) ); }; - return formIsDirty && !isSameProject(currentLocation, nextLocation); }, [formIsDirty, projectId]