Skip to content

Commit

Permalink
(feat) Implement 'markFormAsDirty' to prompt the user before closing …
Browse files Browse the repository at this point in the history
…a dirty form (#364)
  • Loading branch information
samuelmale authored Aug 8, 2024
1 parent e07d2c7 commit 6f04f6c
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 4 deletions.
11 changes: 10 additions & 1 deletion src/components/renderer/form/form-renderer.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ export type FormRendererProps = {

export const FormRenderer = ({ processorContext, initialValues, setIsLoadingFormDependencies }: FormRendererProps) => {
const { evaluatedFields, evaluatedFormJson } = useEvaluateFormFieldExpressions(initialValues, processorContext);
const { registerForm, workspaceLayout } = useFormFactory();
const { registerForm, setIsFormDirty, workspaceLayout } = useFormFactory();
const methods = useForm({
defaultValues: initialValues,
});

const {
formState: { isDirty },
} = methods;

const [{ formFields, invalidFields, formJson }, dispatch] = useReducer(formStateReducer, {
...initialState,
formFields: evaluatedFields,
Expand Down Expand Up @@ -62,6 +67,10 @@ export const FormRenderer = ({ processorContext, initialValues, setIsLoadingForm
registerForm(formJson.name, context);
}, [formJson.name, context]);

useEffect(() => {
setIsFormDirty(isDirty);
}, [isDirty]);

return (
<FormProvider {...context}>
{formJson.pages.map((page) => {
Expand Down
8 changes: 8 additions & 0 deletions src/form-engine.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface FormEngineProps {
onCancel?: () => void;
handleClose?: () => void;
handleConfirmQuestionDeletion?: (question: Readonly<FormField>) => Promise<void>;
markFormAsDirty?: (isDirty: boolean) => void;
}

// TODOs:
Expand All @@ -48,6 +49,7 @@ const FormEngine = ({
onCancel,
handleClose,
handleConfirmQuestionDeletion,
markFormAsDirty,
}: FormEngineProps) => {
const { t } = useTranslation();
const session = useSession();
Expand All @@ -60,6 +62,7 @@ const FormEngine = ({
const [isLoadingDependencies, setIsLoadingDependencies] = useState(false);
const [showSidebar, setShowSidebar] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isFormDirty, setIsFormDirty] = useState(false);
// TODO: Updating this prop triggers a rerender of the entire form. This means whenever we scroll into a new page, the form is rerendered.
// Figure out a way to avoid this. Maybe use a ref with an observer instead of a state?
const [currentPage, setCurrentPage] = useState('');
Expand Down Expand Up @@ -89,6 +92,10 @@ const FormEngine = ({
};
}, []);

useEffect(() => {
markFormAsDirty?.(isFormDirty);
}, [isFormDirty]);

const handleSubmit = useCallback((e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsSubmitting(true);
Expand Down Expand Up @@ -116,6 +123,7 @@ const FormEngine = ({
onError: () => {},
handleClose: () => {},
}}
setIsFormDirty={setIsFormDirty}
setCurrentPage={setCurrentPage}>
<div className={styles.formContainer}>
{isLoadingDependencies && (
Expand Down
4 changes: 4 additions & 0 deletions src/provider/form-factory-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface FormFactoryProviderContextProps {
registerForm: (formId: string, context: FormContextProps) => void;
setCurrentPage: (page: string) => void;
handleConfirmQuestionDeletion?: (question: Readonly<FormField>) => Promise<void>;
setIsFormDirty: (isFormDirty: boolean) => void;
}

interface FormFactoryProviderProps {
Expand All @@ -51,6 +52,7 @@ interface FormFactoryProviderProps {
};
setCurrentPage: (page: string) => void;
handleConfirmQuestionDeletion?: (question: Readonly<FormField>) => Promise<void>;
setIsFormDirty: (isFormDirty: boolean) => void;
}

const FormFactoryProviderContext = createContext<FormFactoryProviderContextProps | undefined>(undefined);
Expand All @@ -68,6 +70,7 @@ export const FormFactoryProvider: React.FC<FormFactoryProviderProps> = ({
formSubmissionProps,
setCurrentPage,
handleConfirmQuestionDeletion,
setIsFormDirty,
}) => {
const { t } = useTranslation();
const rootForm = useRef<FormContextProps>();
Expand Down Expand Up @@ -154,6 +157,7 @@ export const FormFactoryProvider: React.FC<FormFactoryProviderProps> = ({
registerForm,
setCurrentPage,
handleConfirmQuestionDeletion,
setIsFormDirty,
}}>
{formProcessors.current && children}
</FormFactoryProviderContext.Provider>
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3316,8 +3316,8 @@ __metadata:
linkType: hard

"@openmrs/esm-patient-common-lib@npm:next":
version: 8.0.1-pre.4537
resolution: "@openmrs/esm-patient-common-lib@npm:8.0.1-pre.4537"
version: 8.1.1-pre.5183
resolution: "@openmrs/esm-patient-common-lib@npm:8.1.1-pre.5183"
dependencies:
"@carbon/react": "npm:^1.12.0"
lodash-es: "npm:^4.17.21"
Expand All @@ -3326,7 +3326,7 @@ __metadata:
"@openmrs/esm-framework": 5.x
react: 18.x
single-spa: 6.x
checksum: 10/2c8e7348732d3baf37876e983ff523bb8c0cc2c0e676fca96a4459e2c524e05b97b350244964ee96137af9b2f4e94988518ef4fb0b3727833bff4d1f9a2f3cca
checksum: 10/b6d1a4ecf05e06447dbab30068af204157bb67f6e6c207ad568a01599974e5afd2e9a106621d5ed5db3d1d6c129baa13ecd1c615cec58fb6e9bf70287dc7a463
languageName: node
linkType: hard

Expand Down

0 comments on commit 6f04f6c

Please sign in to comment.