Skip to content

Commit

Permalink
Merge pull request #1995 from hackforla/1896-communicating-unsaved-ch…
Browse files Browse the repository at this point in the history
…anges-FAQ-page

1896 communicating unsaved changes faq page
  • Loading branch information
heejung-hong authored Dec 7, 2024
2 parents bfbaec8 + 03ec4a0 commit 5c9e5d5
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 3 deletions.
82 changes: 82 additions & 0 deletions client/src/components/Faq/FaqConfirmDialog.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<ModalDialog
mounted={blocker.state === "blocked"}
onClose={blocker.reset}
showCloseBox={false}
>
<div className={classes.warningWrapper}>
<MdWarning alt="Warning" size={70} />
</div>
<h2 className={classes.title}>
<strong>Unsaved changes will be lost</strong>
</h2>
<p className={classes.warningMessage}>
<span>
&nbsp; Leaving this page will permanently delete any unsaved changes
to the FAQ.
</span>
</p>
<div className={classes.modalActions}>
<Button
color="colorCancel"
variant="outlined"
id="modalCancel"
data-testid="transitionCancel"
onClick={() => blocker.reset()}
>
<p style={{ fontWeight: "bold" }}>Cancel</p>
</Button>
<Button
color="colorError"
id="modalProceed"
data-testid="transitionProceed"
onClick={() => blocker.proceed()}
>
<p className={classes.proceedButton}>Proceed</p>
</Button>
</div>
</ModalDialog>
);
};

FaqConfirmDialog.propTypes = {
blocker: PropTypes.object.isRequired
};

export default FaqConfirmDialog;
44 changes: 43 additions & 1 deletion client/src/components/Faq/FaqView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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);
Expand All @@ -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;

Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -198,6 +233,7 @@ const FaqView = () => {
return category;
})
);
setFormHasSaved(true);
};

const handleEditFAQ = (categoryId, faqId, question, answer) => {
Expand All @@ -224,6 +260,7 @@ const FaqView = () => {
return category;
})
);
setFormHasSaved(true);
};

const handleEditCategory = (category, name) => {
Expand All @@ -240,6 +277,7 @@ const FaqView = () => {
return cat;
})
);
setFormHasSaved(true);
};

const onDeleteFAQ = (categoryId, faqId) => {
Expand All @@ -256,6 +294,7 @@ const FaqView = () => {
return category;
})
);
setFormHasSaved(true);
};

const expandFaq = faq => {
Expand Down Expand Up @@ -312,20 +351,22 @@ const FaqView = () => {
// Submit data and set admin to false
submitFaqData();
setAdmin(false);

setFormHasSaved(false);
// Close the save confirmation modal
closeSaveConfirmationModal();
};

const handleDeleteCategory = categoryId => {
setCategoryToDelete(categoryId);
setIsDeleteConfirmationModalOpen(true);
setFormHasSaved(true);
};

const handleDeleteFAQ = (categoryId, faqId) => {
setCategoryToDelete(categoryId);
setFaqToDelete(faqId);
setIsDeleteConfirmationModalOpen(true);
setFormHasSaved(true);
};

const closeModal = () => {
Expand Down Expand Up @@ -405,6 +446,7 @@ const FaqView = () => {
onClose={closeSaveConfirmationModal}
onYes={handleSaveConfirmationYes}
/>
{blocker ? <FaqConfirmDialog blocker={blocker} /> : null}
</ContentContainer>
);
};
Expand Down
2 changes: 0 additions & 2 deletions client/src/components/ProjectWizard/TdmCalculationWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,13 @@ const TdmCalculationWizard = props => {
},
nextLocation.pathname
);

return (
currentMatch &&
nextMatch &&
(currentMatch.params.projectId === nextMatch.params.projectId ||
!projectId)
);
};

return formIsDirty && !isSameProject(currentLocation, nextLocation);
},
[formIsDirty, projectId]
Expand Down

0 comments on commit 5c9e5d5

Please sign in to comment.