Skip to content

(feat)O3-2971: Adding conformation modal for an empty form. #464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/form-engine.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface FormEngineProps {
onCancel?: () => void;
handleClose?: () => void;
handleConfirmQuestionDeletion?: (question: Readonly<FormField>) => Promise<void>;
handleEmptyFormSubmission?: () => Promise<void>;
markFormAsDirty?: (isDirty: boolean) => void;
}

Expand All @@ -47,6 +48,7 @@ const FormEngine = ({
onCancel,
handleClose,
handleConfirmQuestionDeletion,
handleEmptyFormSubmission,
markFormAsDirty,
}: FormEngineProps) => {
const { t } = useTranslation();
Expand Down Expand Up @@ -127,6 +129,8 @@ const FormEngine = ({
provider={session?.currentProvider}
visit={visit}
handleConfirmQuestionDeletion={handleConfirmQuestionDeletion}
handleEmptyFormSubmission={handleEmptyFormSubmission}
handleDiscardForm={handleClose}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may not have to add this considering that handleClose is basically a workspace property.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then how should I approach this , should i call the workspace method directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a second look, I realized you added this property to the FormFactoryProvider as opposed to the root component as I had previously assumed, my bad! It seems like we are lifting the handleClose property twice, any reason for not using formSubmissionProps.handleClose?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause that handleClose is passed as a void function in the formProps

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooppss!! That's something we should fix. Can you update those props with valid values from the parent component and use that instead? (It's probably safe to get rid of the onError prop)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an issue when i updated it with the value the form never opened ig that's the reason it was not passed as for removing onError properly i can do it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which error do you get exactly?

isFormExpanded={isFormExpanded}
formSubmissionProps={{
isSubmitting,
Expand Down
18 changes: 18 additions & 0 deletions src/provider/form-factory-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ export function validateForm(context: FormContextProps) {
return errors.length === 0;
}

export function validateEmptyForm(context: FormContextProps){
const {
formFields,
formFieldValidators,
patient,
sessionMode,
addInvalidField,
updateFormField,
methods: { getValues, trigger },
} = context;
const values = getValues();
return Object.values(values).every(value =>
value === null ||
value === undefined ||
(Array.isArray(value) && value.length === 0)
);
}

export async function processPostSubmissionActions(
postSubmissionHandlers: PostSubmissionActionMeta[],
submissionResults: OpenmrsResource[],
Expand Down
54 changes: 38 additions & 16 deletions src/provider/form-factory-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '@openmrs/esm-framework';
import { type FormProcessorConstructor } from '../processors/form-processor';
import { type FormContextProps } from './form-provider';
import { processPostSubmissionActions, validateForm } from './form-factory-helper';
import { processPostSubmissionActions, validateForm, validateEmptyForm } from './form-factory-helper';
import { useTranslation } from 'react-i18next';
import { usePostSubmissionActions } from '../hooks/usePostSubmissionActions';

Expand Down Expand Up @@ -51,7 +51,9 @@ interface FormFactoryProviderProps {
handleClose: () => void;
};
hideFormCollapseToggle: () => void;
handleDiscardForm: () => void;
handleConfirmQuestionDeletion?: (question: Readonly<FormField>) => Promise<void>;
handleEmptyFormSubmission?: () => Promise<void>;
setIsFormDirty: (isFormDirty: boolean) => void;
}

Expand All @@ -70,6 +72,8 @@ export const FormFactoryProvider: React.FC<FormFactoryProviderProps> = ({
children,
formSubmissionProps,
hideFormCollapseToggle,
handleDiscardForm,
handleEmptyFormSubmission,
handleConfirmQuestionDeletion,
setIsFormDirty,
}) => {
Expand All @@ -96,14 +100,31 @@ export const FormFactoryProvider: React.FC<FormFactoryProviderProps> = ({
});

useEffect(() => {
if (isSubmitting) {
// TODO: find a dynamic way of managing the form processing order
const forms = [rootForm.current, ...Object.values(subForms.current)];
// validate all forms
const isValid = forms.every((formContext) => validateForm(formContext));
if (isValid) {
Promise.all(forms.map((formContext) => formContext.processor.processSubmission(formContext, abortController)))
.then(async (results) => {
const handleFormSubmission = async () => {
if (isSubmitting) {
const forms = [rootForm.current, ...Object.values(subForms.current)];
// Validate all forms
const isValid = forms.every((formContext) => validateForm(formContext));
// Check if the form is empty
const isEmpty = forms.every((formContext) => validateEmptyForm(formContext));

if (isEmpty && isValid) {
if (handleEmptyFormSubmission && typeof handleEmptyFormSubmission === 'function') {
try {
await handleEmptyFormSubmission();
handleDiscardForm()
return setIsSubmitting(false)
} catch (error) {
return setIsSubmitting(false);
}
}
}

if (isValid) {
try {
const results = await Promise.all(
forms.map((formContext) => formContext.processor.processSubmission(formContext, abortController))
);
formSubmissionProps.setIsSubmitting(false);
if (sessionMode === 'edit') {
showSnackbar({
Expand All @@ -129,8 +150,7 @@ export const FormFactoryProvider: React.FC<FormFactoryProviderProps> = ({
} else {
handleClose();
}
})
.catch((errorObject: Error | ToastDescriptor) => {
} catch (errorObject) {
setIsSubmitting(false);
if (errorObject instanceof Error) {
showToast({
Expand All @@ -142,11 +162,13 @@ export const FormFactoryProvider: React.FC<FormFactoryProviderProps> = ({
} else {
showToast(errorObject);
}
});
} else {
setIsSubmitting(false);
}
} else {
setIsSubmitting(false);
}
}
}
};
handleFormSubmission();
return () => {
abortController.abort();
};
Expand Down Expand Up @@ -181,4 +203,4 @@ export const useFormFactory = () => {
throw new Error('useFormFactoryContext must be used within a FormFactoryProvider');
}
return context;
};
};
Loading