From aef0fdc9743d7022400849d2b6a696a5064328cd Mon Sep 17 00:00:00 2001 From: Fikri Milano Date: Fri, 6 Dec 2024 22:11:45 +0700 Subject: [PATCH] Add configurable confirmation dialog on form submission (#3619) * Add feature * spotless * Add notes to CHANGELOG.md * Add doc * Fix post merge conflict error * spotless --- CHANGELOG.md | 1 + .../configuration/QuestionnaireConfig.kt | 3 + .../ui/questionnaire/QuestionnaireActivity.kt | 95 ++++++++++++------- android/quest/src/main/res/values/strings.xml | 2 + .../app/configuring/forms/forms.mdx | 2 + 5 files changed, 67 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b01eff17..57c1828cbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 3. Implemented functionality to launch PDF generation using a configuration setup - Added Save draft MVP functionality - Added Delete saved draft feature +- Add configurable confirmation dialog on form submission ## [1.1.0] - 2024-02-15 diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/QuestionnaireConfig.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/QuestionnaireConfig.kt index ff865ce566..0fd117df60 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/QuestionnaireConfig.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/QuestionnaireConfig.kt @@ -67,6 +67,7 @@ data class QuestionnaireConfig( val uniqueIdAssignment: UniqueIdAssignmentConfig? = null, val linkIds: List? = null, val showSubmitAnywayButton: String = "false", + val showSubmissionConfirmationDialog: String = "false", ) : java.io.Serializable, Parcelable { fun interpolate(computedValuesMap: Map) = @@ -102,6 +103,8 @@ data class QuestionnaireConfig( linkIds = linkIds?.onEach { it.linkId.interpolate(computedValuesMap) }, saveButtonText = saveButtonText?.interpolate(computedValuesMap), showSubmitAnywayButton = showSubmitAnywayButton.interpolate(computedValuesMap), + showSubmissionConfirmationDialog = + showSubmissionConfirmationDialog.interpolate(computedValuesMap), ) } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireActivity.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireActivity.kt index e0608a8062..9ed3132b57 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireActivity.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireActivity.kt @@ -52,6 +52,7 @@ import org.smartregister.fhircore.engine.domain.model.isReadOnly import org.smartregister.fhircore.engine.domain.model.isSummary import org.smartregister.fhircore.engine.ui.base.AlertDialogButton import org.smartregister.fhircore.engine.ui.base.AlertDialogue +import org.smartregister.fhircore.engine.ui.base.AlertIntent import org.smartregister.fhircore.engine.ui.base.BaseMultiLanguageActivity import org.smartregister.fhircore.engine.util.DispatcherProvider import org.smartregister.fhircore.engine.util.extension.encodeResourceToString @@ -304,44 +305,66 @@ class QuestionnaireActivity : BaseMultiLanguageActivity() { QuestionnaireFragment.SUBMIT_REQUEST_KEY, this, ) { _, _ -> - lifecycleScope.launch { - val questionnaireResponse = retrieveQuestionnaireResponse() + if (questionnaireConfig.showSubmissionConfirmationDialog.toBooleanStrict()) { + AlertDialogue.showAlert( + context = this, + alertIntent = AlertIntent.CONFIRM, + message = getString(R.string.questionnaire_submission_confirmation_message), + title = getString(R.string.questionnaire_submission_confirmation_title), + confirmButton = + AlertDialogButton( + listener = { processSubmission() }, + ), + neutralButton = + AlertDialogButton( + text = R.string.no, + listener = { it.dismiss() }, + ), + ) + } else { + processSubmission() + } + } + } - // Close questionnaire if opened in read only mode or if experimental - if (questionnaireConfig.isReadOnly() || questionnaire?.experimental == true) { - finish() - } - if (questionnaireResponse != null && questionnaire != null) { - viewModel.run { - setProgressState(QuestionnaireProgressState.ExtractionInProgress(true)) - - if (currentLocation != null) { - questionnaireResponse.contained.add( - ResourceUtils.createFhirLocationFromGpsLocation(gpsLocation = currentLocation!!), - ) - } + private fun processSubmission() { + lifecycleScope.launch { + val questionnaireResponse = retrieveQuestionnaireResponse() - handleQuestionnaireSubmission( - questionnaire = questionnaire!!, - currentQuestionnaireResponse = questionnaireResponse, - questionnaireConfig = questionnaireConfig, - actionParameters = actionParameters, - context = this@QuestionnaireActivity, - ) { idTypes, questionnaireResponse -> - // Dismiss progress indicator dialog, submit result then finish activity - // TODO Ensure this dialog is dismissed even when an exception is encountered - setProgressState(QuestionnaireProgressState.ExtractionInProgress(false)) - setResult( - Activity.RESULT_OK, - Intent().apply { - putExtra(QUESTIONNAIRE_RESPONSE, questionnaireResponse as Serializable) - putExtra(QUESTIONNAIRE_SUBMISSION_EXTRACTED_RESOURCE_IDS, idTypes as Serializable) - putExtra(QUESTIONNAIRE_CONFIG, questionnaireConfig as Parcelable) - putExtra(ON_RESULT_TYPE, ActivityOnResultType.QUESTIONNAIRE.name) - }, - ) - finish() - } + // Close questionnaire if opened in read only mode or if experimental + if (questionnaireConfig.isReadOnly() || questionnaire?.experimental == true) { + finish() + } + if (questionnaireResponse != null && questionnaire != null) { + viewModel.run { + setProgressState(QuestionnaireProgressState.ExtractionInProgress(true)) + + if (currentLocation != null) { + questionnaireResponse.contained.add( + ResourceUtils.createFhirLocationFromGpsLocation(gpsLocation = currentLocation!!), + ) + } + + handleQuestionnaireSubmission( + questionnaire = questionnaire!!, + currentQuestionnaireResponse = questionnaireResponse, + questionnaireConfig = questionnaireConfig, + actionParameters = actionParameters, + context = this@QuestionnaireActivity, + ) { idTypes, questionnaireResponse -> + // Dismiss progress indicator dialog, submit result then finish activity + // TODO Ensure this dialog is dismissed even when an exception is encountered + setProgressState(QuestionnaireProgressState.ExtractionInProgress(false)) + setResult( + Activity.RESULT_OK, + Intent().apply { + putExtra(QUESTIONNAIRE_RESPONSE, questionnaireResponse as Serializable) + putExtra(QUESTIONNAIRE_SUBMISSION_EXTRACTED_RESOURCE_IDS, idTypes as Serializable) + putExtra(QUESTIONNAIRE_CONFIG, questionnaireConfig as Parcelable) + putExtra(ON_RESULT_TYPE, ActivityOnResultType.QUESTIONNAIRE.name) + }, + ) + finish() } } } diff --git a/android/quest/src/main/res/values/strings.xml b/android/quest/src/main/res/values/strings.xml index 9c96b97c3d..4e1f1588a9 100644 --- a/android/quest/src/main/res/values/strings.xml +++ b/android/quest/src/main/res/values/strings.xml @@ -142,4 +142,6 @@ %1$d matching location(s) rendered successfully" Cancel adding location Error rendering profile + Are you sure you want to submit? + You are about to submit diff --git a/docs/engineering/app/configuring/forms/forms.mdx b/docs/engineering/app/configuring/forms/forms.mdx index f5d4878e95..1095718387 100644 --- a/docs/engineering/app/configuring/forms/forms.mdx +++ b/docs/engineering/app/configuring/forms/forms.mdx @@ -126,6 +126,8 @@ These are used when generating other tasks, CarePlans and related resources.See | onSubmitActions | Configurations for actions invoked post Questionnaire submission | no | null | | extractedResourceUniquePropertyExpressions | Configurations for unique properties used to identify resources during Questionnaire edit | no | null | | uniqueIdAssignment | Configuration for unique identifier assignment | no | null | +| showSubmitAnywayButton | When a form submission detects a validation error, the app will display a validation error dialog that prevents the user from submitting the form. Enabling this property will show a button in the validation error dialog. When pressed, the form will be submitted regardless of the validation error. | no | false | +| showSubmissionConfirmationDialog | Display a submission confirmation dialog once the submit button is pressed | no | false | ## Dynamic data pass between Profiles and Questionnaires