All files / src/utils/components UnsavedChangesDialog.jsx

100% Statements 7/7
100% Branches 4/4
100% Functions 3/3
100% Lines 5/5

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42                    15x             3550x   3550x 3550x   3550x                                      
import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Button } from "@mui/material";
 
/**
 * Confirm dialog shown when a user tries to navigate away (incl. the browser
 * BACK button) from a form with unsaved changes. Driven by the blocker returned
 * from useUnsavedChangesWarning. (EI-3115 / EI-TC-4562)
 *
 * - "Stay on page" → blocker.reset()   (cancel the navigation, keep editing)
 * - "Leave"        → blocker.proceed() (discard changes and navigate)
 */
const UnsavedChangesDialog = ({
    blocker,
    title = "Discard unsaved changes?",
    message = "You have unsaved changes on this page. If you leave now, your changes will be lost.",
    stayLabel = "Stay on page",
    leaveLabel = "Leave",
}) => {
    const isBlocked = blocker?.state === "blocked";
 
    const handleStay = () => blocker?.reset?.();
    const handleLeave = () => blocker?.proceed?.();
 
    return (
        <Dialog open={isBlocked} onClose={handleStay} aria-labelledby="unsaved-changes-title">
            <DialogTitle id="unsaved-changes-title">{title}</DialogTitle>
            <DialogContent>
                <DialogContentText>{message}</DialogContentText>
            </DialogContent>
            <DialogActions>
                <Button onClick={handleStay} autoFocus>
                    {stayLabel}
                </Button>
                <Button onClick={handleLeave} color="error" variant="contained">
                    {leaveLabel}
                </Button>
            </DialogActions>
        </Dialog>
    );
};
 
export default UnsavedChangesDialog;