From dfadd3f2ec4ca7617ea9449fbbe91f6bfca2376b Mon Sep 17 00:00:00 2001 From: Shashank Shekhar Date: Mon, 2 Dec 2024 15:40:16 -0800 Subject: [PATCH] #3035 - Enable Application Saving on Page Change (#4001) ### As a part of this PR, the following is achieved: - For draft applications, enabled saving the draft whenever the user navigates between sections of the application. (Next Section/Prev Section/Section Headings). Note: As a part of the discussion with the business, no toast is shown on the UI for the automatic saving of the draft. **Video illustrating the PR work:** https://github.com/user-attachments/assets/1c7fc402-8e98-42ca-a6a1-0a5759649021 --- .../FullTimeApplication.vue | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue b/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue index cd76d1df00..3252e1db6f 100644 --- a/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue +++ b/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue @@ -147,6 +147,7 @@ export default defineComponent({ const savingDraft = ref(false); const submittingApplication = ref(false); let applicationWizard: any; + let savedDraftData: string; const isFirstPage = ref(true); const isLastPage = ref(false); const isReadOnly = ref(false); @@ -154,6 +155,9 @@ export default defineComponent({ const existingApplication = ref({} as ApplicationDataAPIOutDTO); const editApplicationModal = ref({} as ModalDialog); const conditionsAccepted = ref(false); + // automaticDraftSaveInProgress is a boolean that ensures that multiple api calls for save + // draft are not made while a draft save is in progress. + let automaticDraftSaveInProgress = false; const checkProgramYear = async () => { // check program year, if not active allow only readonly mode with a snackBar @@ -219,17 +223,21 @@ export default defineComponent({ existingApplication.value = applicationData; }); + const callSaveDraft = async () => { + const associatedFiles = formioUtils.getAssociatedFiles(applicationWizard); + await ApplicationService.shared.saveApplicationDraft(props.id, { + programYearId: props.programYearId, + data: applicationWizard.submission.data, + associatedFiles, + }); + savedDraftData = JSON.stringify(applicationWizard.submission.data); + }; + // Save the current state of the student application skipping all validations. const saveDraft = async () => { savingDraft.value = true; try { - const associatedFiles = - formioUtils.getAssociatedFiles(applicationWizard); - await ApplicationService.shared.saveApplicationDraft(props.id, { - programYearId: props.programYearId, - data: applicationWizard.submission.data, - associatedFiles, - }); + await callSaveDraft(); snackBar.success("Application draft saved with success."); } catch { snackBar.error("An unexpected error has happened."); @@ -238,6 +246,15 @@ export default defineComponent({ } }; + const saveDraftAutomatically = async () => { + automaticDraftSaveInProgress = true; + try { + await callSaveDraft(); + } finally { + automaticDraftSaveInProgress = false; + } + }; + // Execute the final submission of the student application. const submitApplication = async (args: any, form: any) => { submittingApplication.value = true; @@ -281,13 +298,28 @@ export default defineComponent({ applicationWizard = form; }; - const pageChanged = ( + const pageChanged = async ( isInFirstPage: boolean, - currentPage: number, + _currentPage: number, isInLastPage: boolean, ) => { isFirstPage.value = isInFirstPage; isLastPage.value = isInLastPage; + if (!savedDraftData) { + savedDraftData = JSON.stringify(applicationWizard.submission.data); + } + const dataChanged = + savedDraftData !== JSON.stringify(applicationWizard.submission.data); + if ( + !notDraft.value && + !isFirstPage.value && + !submittingApplication.value && + !automaticDraftSaveInProgress && + !savingDraft.value && + dataChanged + ) { + await saveDraftAutomatically(); + } }; const customEventCallback = async (form: any, event: FormIOCustomEvent) => {