Skip to content

Commit

Permalink
Implement blocking globally (#1717)
Browse files Browse the repository at this point in the history
  • Loading branch information
MiraGeowerkstatt authored Dec 3, 2024
2 parents 9638840 + 3187dbd commit c23a533
Show file tree
Hide file tree
Showing 12 changed files with 44 additions and 32 deletions.
4 changes: 2 additions & 2 deletions src/client/src/pages/detail/detailHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ import {
import DateText from "../../components/legacyComponents/dateText";
import { PromptContext } from "../../components/prompt/promptContext.tsx";
import { DetailHeaderStack } from "../../components/styledComponents.ts";
import { useFormDirty } from "./useFormDirty.tsx";

interface DetailHeaderProps {
editingEnabled: boolean;
setEditingEnabled: (editingEnabled: boolean) => void;
editableByCurrentUser: boolean;
borehole: BoreholeV2;
isFormDirty: boolean;
triggerReset: () => void;
}

const DetailHeader = ({
editingEnabled,
setEditingEnabled,
editableByCurrentUser,
isFormDirty,
triggerReset,
borehole,
}: DetailHeaderProps) => {
const history = useHistory();
const dispatch = useDispatch();
const { t } = useTranslation();
const { showPrompt } = useContext(PromptContext);
const { isFormDirty } = useFormDirty();
const auth = useAuth();

const toggleEditing = (editing: boolean) => {
Expand Down
16 changes: 4 additions & 12 deletions src/client/src/pages/detail/detailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import { DetailPageContent } from "./detailPageContent.tsx";
import { DetailSideNav } from "./detailSideNav.tsx";
import { BoreholeFormInputs } from "./form/borehole/boreholePanelInterfaces.ts";
import { LocationFormInputs, LocationFormSubmission } from "./form/location/locationPanelInterfaces.tsx";
import { FormDirtyProvider } from "./formDirtyContext.tsx";
import { useLabelingContext } from "./labeling/labelingInterfaces.tsx";
import LabelingPanel from "./labeling/labelingPanel.tsx";
import { SaveBar } from "./saveBar";

export const DetailPage: FC = () => {
const [editingEnabled, setEditingEnabled] = useState(false);
const [loading, setLoading] = useState(true);
const [isFormDirty, setIsFormDirty] = useState(false);
const [editableByCurrentUser, setEditableByCurrentUser] = useState(false);
const [borehole, setBorehole] = useState<BoreholeV2 | null>(null);
const legacyBorehole: Borehole = useSelector((state: ReduxRootState) => state.core_borehole);
Expand Down Expand Up @@ -76,10 +76,6 @@ export const DetailPage: FC = () => {
getAndUpdateBorehole(prepareLocationDataForSubmit(formInputs));
};

const handleDirtyChange = (isDirty: boolean) => {
setIsFormDirty(isDirty);
};

const triggerSubmit = () => {
boreholePanelRef.current?.submit();
locationPanelRef.current?.submit();
Expand Down Expand Up @@ -132,13 +128,12 @@ export const DetailPage: FC = () => {
(location.pathname.endsWith("/borehole") && location.hash === "#general");

return (
<>
<FormDirtyProvider>
<DetailHeader
borehole={borehole}
editingEnabled={editingEnabled}
setEditingEnabled={setEditingEnabled}
editableByCurrentUser={editableByCurrentUser}
isFormDirty={isFormDirty}
triggerReset={triggerReset}
/>
<LayoutBox>
Expand Down Expand Up @@ -173,18 +168,15 @@ export const DetailPage: FC = () => {
onLocationFormSubmit={onLocationFormSubmit}
boreholePanelRef={boreholePanelRef}
onBoreholeFormSubmit={onBoreholeFormSubmit}
handleDirtyChange={handleDirtyChange}
borehole={borehole}
panelOpen={panelOpen}
/>
</MainContentBox>
{editingEnabled && panelOpen && <LabelingPanel boreholeId={Number(id)} />}
</Box>
{editingEnabled && shouldShowSaveBar && (
<SaveBar triggerSubmit={triggerSubmit} triggerReset={triggerReset} isFormDirty={isFormDirty} />
)}
{editingEnabled && shouldShowSaveBar && <SaveBar triggerSubmit={triggerSubmit} triggerReset={triggerReset} />}
</Stack>
</LayoutBox>
</>
</FormDirtyProvider>
);
};
4 changes: 0 additions & 4 deletions src/client/src/pages/detail/detailPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ interface DetailPageContentProps {
boreholePanelRef: RefObject<{ submit: () => void; reset: () => void }>;
onLocationFormSubmit: (data: LocationFormInputs) => void;
onBoreholeFormSubmit: (data: BoreholeFormInputs) => void;
handleDirtyChange: (isDirty: boolean) => void;
borehole: BoreholeV2;
panelOpen: boolean;
}
Expand All @@ -44,7 +43,6 @@ export const DetailPageContent = ({
boreholePanelRef,
onLocationFormSubmit,
onBoreholeFormSubmit,
handleDirtyChange,
borehole,
panelOpen,
}: DetailPageContentProps) => {
Expand Down Expand Up @@ -101,7 +99,6 @@ export const DetailPageContent = ({
editingEnabled={editingEnabled}
onSubmit={onLocationFormSubmit}
borehole={borehole}
onDirtyChange={handleDirtyChange}
labelingPanelOpen={panelOpen}
/>
)}
Expand All @@ -116,7 +113,6 @@ export const DetailPageContent = ({
boreholeId={id}
borehole={borehole}
editingEnabled={editingEnabled}
onDirtyChange={handleDirtyChange}
/>
)}
/>
Expand Down
3 changes: 1 addition & 2 deletions src/client/src/pages/detail/form/borehole/boreholePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Geometry from "./geometry.jsx";
import Sections from "./sections.jsx";

export const BoreholePanel = forwardRef(
({ boreholeId, borehole, editingEnabled, onDirtyChange, onSubmit }: BoreholePanelProps, ref) => {
({ boreholeId, borehole, editingEnabled, onSubmit }: BoreholePanelProps, ref) => {
const { t } = useTranslation();
const history = useHistory();
const location = useLocation();
Expand All @@ -36,7 +36,6 @@ export const BoreholePanel = forwardRef(

UseFormWithSaveBar({
formMethods,
onDirtyChange,
onSubmit,
ref,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export interface BoreholeDetailProps extends BoreholeGeneralProps {
export interface BoreholePanelProps extends BoreholeGeneralProps {
boreholeId: string;
onSubmit: (data: BoreholeFormInputs) => void;
onDirtyChange: (isDirty: boolean) => void;
}

export interface BoreholeFormInputs {
Expand Down
3 changes: 1 addition & 2 deletions src/client/src/pages/detail/form/location/locationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import NameSegment from "./nameSegment.tsx";
import RestrictionSegment from "./restrictionSegment.tsx";

export const LocationPanel = forwardRef(
({ editingEnabled, onSubmit, onDirtyChange, borehole, labelingPanelOpen }: LocationPanelProps, ref) => {
({ editingEnabled, onSubmit, borehole, labelingPanelOpen }: LocationPanelProps, ref) => {
const [resetKey, setResetKey] = useState(0);
const formMethods = useForm<LocationFormInputs>({
mode: "onChange",
Expand Down Expand Up @@ -44,7 +44,6 @@ export const LocationPanel = forwardRef(

UseFormWithSaveBar({
formMethods,
onDirtyChange,
onSubmit,
ref,
incrementResetKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export interface LocationBaseProps {

export interface LocationPanelProps extends LocationBaseProps {
onSubmit: (data: LocationFormInputs) => void;
onDirtyChange: (isDirty: boolean) => void;
labelingPanelOpen: boolean;
ref: RefObject<{ submit: () => void; reset: () => void }>;
}
Expand Down
11 changes: 6 additions & 5 deletions src/client/src/pages/detail/form/useFormWithSaveBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import { ForwardedRef, useCallback, useEffect, useImperativeHandle } from "react
import { FieldValues, UseFormReturn } from "react-hook-form";
import { useHistory } from "react-router-dom";
import { useBlockNavigation } from "../useBlockNavigation.tsx";
import { useFormDirty } from "../useFormDirty.tsx";

interface UseFormWithSaveBarProps<T extends FieldValues> {
formMethods: UseFormReturn<T>;
onDirtyChange: (isDirty: boolean) => void;
onSubmit: (data: T) => void;
ref: ForwardedRef<unknown>;
incrementResetKey?: () => void;
}

export function UseFormWithSaveBar<T extends FieldValues>({
formMethods,
onDirtyChange,
onSubmit,
incrementResetKey,
ref,
}: UseFormWithSaveBarProps<T>) {
const history = useHistory();
const { handleBlockedNavigation } = useBlockNavigation(formMethods.formState.isDirty);
const { handleBlockedNavigation } = useBlockNavigation();
const { setIsFormDirty } = useFormDirty();

// Block navigation if form is dirty
history.block(nextLocation => {
Expand All @@ -30,13 +30,14 @@ export function UseFormWithSaveBar<T extends FieldValues>({

// Track form dirty state
useEffect(() => {
onDirtyChange(Object.keys(formMethods.formState.dirtyFields).length > 0);
setIsFormDirty(Object.keys(formMethods.formState.dirtyFields).length > 0);
return () => setIsFormDirty(false);
}, [
formMethods.formState.dirtyFields,
formMethods.formState.isDirty,
formMethods,
formMethods.formState,
onDirtyChange,
setIsFormDirty,
]);

// Handle form reset and submit
Expand Down
14 changes: 14 additions & 0 deletions src/client/src/pages/detail/formDirtyContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React, { createContext, useMemo, useState } from "react";

interface FormDirtyContextType {
isFormDirty: boolean;
setIsFormDirty: (dirty: boolean) => void;
}

export const FormDirtyContext = createContext<FormDirtyContextType | undefined>(undefined);

export const FormDirtyProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [isFormDirty, setIsFormDirty] = useState(false);
const value = useMemo(() => ({ isFormDirty, setIsFormDirty }), [isFormDirty]);
return <FormDirtyContext.Provider value={value}>{children}</FormDirtyContext.Provider>;
};
5 changes: 3 additions & 2 deletions src/client/src/pages/detail/saveBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import { Box, Stack } from "@mui/material";
import { CircleCheck, CircleX } from "lucide-react";
import { theme } from "../../AppTheme.ts";
import { DeleteButton, SaveButton } from "../../components/buttons/buttons.tsx";
import { useFormDirty } from "./useFormDirty.tsx";

interface SaveBarProps {
triggerSubmit: () => void;
triggerReset: () => void;
isFormDirty: boolean;
}
export const SaveBar = ({ triggerSubmit, triggerReset, isFormDirty }: SaveBarProps) => {
export const SaveBar = ({ triggerSubmit, triggerReset }: SaveBarProps) => {
const [showSaveFeedback, setShowSaveFeedback] = useState(false);
const { t } = useTranslation();
const location = useLocation();
const { isFormDirty } = useFormDirty();

useEffect(() => {
setShowSaveFeedback(false);
Expand Down
4 changes: 3 additions & 1 deletion src/client/src/pages/detail/useBlockNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom";
import { Trash2, X } from "lucide-react";
import { PromptContext } from "../../components/prompt/promptContext.tsx";
import { useFormDirty } from "./useFormDirty.tsx";

interface UseBlockNavigationResult {
handleBlockedNavigation: (nextLocation: string) => boolean;
}

export const useBlockNavigation = (isFormDirty: boolean): UseBlockNavigationResult => {
export const useBlockNavigation = (): UseBlockNavigationResult => {
const [nextLocation, setNextLocation] = useState<string | null>(null);
const [confirmedNavigation, setConfirmedNavigation] = useState(false);
const { isFormDirty } = useFormDirty();
const { showPrompt } = useContext(PromptContext);
const { t } = useTranslation();
const history = useHistory();
Expand Down
10 changes: 10 additions & 0 deletions src/client/src/pages/detail/useFormDirty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useContext } from "react";
import { FormDirtyContext } from "./formDirtyContext.tsx";

export const useFormDirty = () => {
const context = useContext(FormDirtyContext);
if (!context) {
throw new Error("useFormDirty must be used within a FormDirtyProvider");
}
return context;
};

0 comments on commit c23a533

Please sign in to comment.