From 9007ccc26df0d442e5603b233fdb7d5fbbc715ad Mon Sep 17 00:00:00 2001 From: Christopher Seven Phiri Date: Wed, 29 May 2024 12:01:43 +0200 Subject: [PATCH 1/3] Add Transfer out screen --- .../fhircore/engine/util/SystemConstants.kt | 1 + .../quest/navigation/MainNavigationScreen.kt | 3 + .../fhircore/quest/ui/main/AppMainActivity.kt | 2 +- .../fhircore/quest/ui/main/AppMainScreen.kt | 13 ++ .../profile/PatientProfileViewModel.kt | 28 ++- .../profile/tranfer/TransferOutScreen.kt | 200 ++++++++++++++++++ .../profile/tranfer/TransferOutScreenState.kt | 41 ++++ .../profile/tranfer/TransferOutViewModel.kt | 107 ++++++++++ .../quest/ui/shared/models/ProfileViewData.kt | 1 - 9 files changed, 386 insertions(+), 10 deletions(-) create mode 100644 android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt create mode 100644 android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt create mode 100644 android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt index d439ef5dc6..cbb5faec7d 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt @@ -31,6 +31,7 @@ object SystemConstants { const val OBSERVATION_CODE_SYSTEM = "https://d-tree.org/fhir/observation-codes" const val CARE_PLAN_REFERENCE_SYSTEM = "https://d-tree.org/fhir/careplan-reference" const val QUESTIONNAIRE_REFERENCE_SYSTEM = "https://d-tree.org/fhir/procedure-code" + const val LOCATION_TAG = "http://smartregister.org/fhir/location-tag" } object ReasonConstants { diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/navigation/MainNavigationScreen.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/navigation/MainNavigationScreen.kt index 33f06fc4b3..4c8222a7f4 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/navigation/MainNavigationScreen.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/navigation/MainNavigationScreen.kt @@ -68,6 +68,8 @@ sealed class MainNavigationScreen( route = "tracingProfileRoute", ) + object TransferOut : MainNavigationScreen(route = "transferOut") + object PatientGuardians : MainNavigationScreen(route = "patientProfileGuardians") object FamilyProfile : MainNavigationScreen(route = "familyProfileRoute") @@ -94,6 +96,7 @@ sealed class MainNavigationScreen( FamilyProfile, ViewChildContacts, GuardianProfile, + TransferOut, TracingProfile, TracingHistory, TracingOutcomes, diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt index b63bfdf8e6..e31283d4f2 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt @@ -158,7 +158,7 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { schedulePlan(applicationContext) scheduleCheckForMissedAppointments(applicationContext) scheduleWelcomeServiceAppointments(applicationContext) -// scheduleWelcomeServiceToCarePlanForMissedAppointments(applicationContext) + // scheduleWelcomeServiceToCarePlanForMissedAppointments(applicationContext) scheduleResourcePurger(applicationContext) } } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainScreen.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainScreen.kt index e414472d21..2219269f25 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainScreen.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainScreen.kt @@ -49,6 +49,7 @@ import org.smartregister.fhircore.quest.ui.patient.profile.PatientProfileScreen import org.smartregister.fhircore.quest.ui.patient.profile.childcontact.ChildContactsProfileScreen import org.smartregister.fhircore.quest.ui.patient.profile.guardians.GuardianRelatedPersonProfileScreen import org.smartregister.fhircore.quest.ui.patient.profile.guardians.GuardiansRoute +import org.smartregister.fhircore.quest.ui.patient.profile.tranfer.TransferOutScreen import org.smartregister.fhircore.quest.ui.patient.register.PatientRegisterScreen import org.smartregister.fhircore.quest.ui.report.measure.MeasureReportViewModel import org.smartregister.fhircore.quest.ui.report.measure.measureReportNavigationGraph @@ -213,6 +214,18 @@ private fun AppMainNavigationGraph( onBackPress = { navController.popBackStack() }, ) } + MainNavigationScreen.TransferOut -> + composable( + route = "${it.route}/{${NavigationArg.PATIENT_ID}}", + arguments = + commonNavArgs.plus( + listOf( + navArgument(NavigationArg.PATIENT_ID) { type = NavType.StringType }, + ), + ), + ) { _ -> + TransferOutScreen { navController.popBackStack() } + } MainNavigationScreen.GuardianProfile -> composable( route = diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/PatientProfileViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/PatientProfileViewModel.kt index 0d5a22da94..d4a29062d1 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/PatientProfileViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/PatientProfileViewModel.kt @@ -302,14 +302,26 @@ constructor( questionnaireType = QuestionnaireType.DEFAULT, populationResources = profile.populationResources, ) - R.id.patient_transfer_out -> - QuestionnaireActivity.launchQuestionnaire( - event.context, - questionnaireId = PATIENT_TRANSFER_OUT, - clientIdentifier = patientId, - questionnaireType = QuestionnaireType.DEFAULT, - populationResources = profile.populationResources, - ) + R.id.patient_transfer_out -> { + // QuestionnaireActivity.launchQuestionnaire( + // event.context, + // questionnaireId = PATIENT_TRANSFER_OUT, + // clientIdentifier = patientId, + // questionnaireType = QuestionnaireType.DEFAULT, + // populationResources = profile.populationResources, + // ) + patientId.let { + val urlParams = + NavigationArg.bindArgumentsOf( + Pair(NavigationArg.FEATURE, AppFeature.PatientManagement.name), + Pair(NavigationArg.HEALTH_MODULE, HealthModule.HIV), + Pair(NavigationArg.PATIENT_ID, it), + ) + event.navController.navigate( + route = "${MainNavigationScreen.TransferOut.route}/$it$urlParams", + ) + } + } R.id.patient_change_status -> QuestionnaireActivity.launchQuestionnaire( event.context, diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt new file mode 100644 index 0000000000..5504386a45 --- /dev/null +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt @@ -0,0 +1,200 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.quest.ui.patient.profile.tranfer + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.ParagraphStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextIndent +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import kotlin.text.Typography.bullet +import org.smartregister.fhircore.engine.domain.util.DataLoadState +import org.smartregister.fhircore.engine.ui.appsetting.getMessageFromException +import org.smartregister.fhircore.engine.ui.login.LOGIN_ERROR_TEXT_TAG +import org.smartregister.fhircore.quest.R + +@Composable +fun TransferOutScreen( + viewModel: TransferOutViewModel = hiltViewModel(), + onBackPress: () -> Boolean, +) { + val state by viewModel.state.collectAsState() + val context = LocalContext.current + + Scaffold( + topBar = { + TopAppBar( + title = { Text(stringResource(id = R.string.transfer_out)) }, + navigationIcon = { + IconButton(onClick = { onBackPress() }) { + Icon(imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) + } + }, + ) + }, + ) { innerPadding -> + Box( + modifier = Modifier.padding(innerPadding).fillMaxSize(), + ) { + when (state) { + is DataLoadState.Success -> { + val data = (state as DataLoadState.Success).data + TransferOutScreenContainer(data) { viewModel.transferPatient(context) } + } + is DataLoadState.Error -> { + Column( + Modifier.fillMaxWidth().align(Alignment.Center), + ) { + Text( + fontSize = 14.sp, + color = MaterialTheme.colors.error, + text = + stringResource( + id = getMessageFromException((state as DataLoadState.Error).exception), + ), + modifier = + Modifier.wrapContentWidth() + .padding(vertical = 10.dp) + .align(Alignment.CenterHorizontally) + .testTag(LOGIN_ERROR_TEXT_TAG), + ) + Button(onClick = { viewModel.fetchPatientDetails() }) { Text(text = "Retry") } + } + } + else -> { + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.align(Alignment.Center), + ) { + CircularProgressIndicator( + modifier = Modifier.padding(bottom = 16.dp), + strokeWidth = 1.6.dp, + ) + } + } + } + } + } +} + +@Composable +fun TransferOutScreenContainer(data: TransferOutScreenState, onClick: () -> Unit) { + val paragraphStyle = ParagraphStyle(textIndent = TextIndent(restLine = 12.sp)) + val steps = + listOf( + "Click Transfer out button", + "A screen for writing emails will appear for you to fill in the transfer out request", + "Fill in the name of the facility the patient is transferring to in the email", + "Fill in any additional information in the email", + "Send the email", + ) + Column( + Modifier.fillMaxSize().padding(28.dp), + ) { + Text( + text = + buildAnnotatedString { + append("Are you sure you want to transfer ") + withStyle( + style = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold).toSpanStyle(), + ) { + append(data.fullName) + } + append(" to a new facility?") + }, + style = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Normal), + textAlign = TextAlign.Center, + ) + Spacer(Modifier.height(12.dp)) + Text( + text = + buildAnnotatedString { + appendLine("To transfer out a patient, carry out the following steps") + steps.forEach { + withStyle(style = paragraphStyle) { + append(bullet) + append("\t\t") + append(it) + } + } + appendLine() + appendLine() + withStyle( + style = MaterialTheme.typography.subtitle2.copy( + color = MaterialTheme.colors.error + ).toSpanStyle(), + ) { + appendLine("Note: Once the process starts the patient will be disabled and will not be accessible from within the app") + } + }, + ) + Spacer(Modifier.height(20.dp)) + Button(onClick = onClick, modifier = Modifier.fillMaxWidth()) { Text(text = "Transfer Out") } + } +} + +@Preview(showSystemUi = true) +@Composable +private fun TransferOutScreenContainerPreview() { + val data = + TransferOutScreenState( + "", + "Maliko", + "", + "Maliko Samuel", + ) + Scaffold { innerPadding -> + Box( + modifier = Modifier.padding(innerPadding).fillMaxSize(), + ) { + TransferOutScreenContainer(data) {} + } + } +} diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt new file mode 100644 index 0000000000..6197b51cd9 --- /dev/null +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.quest.ui.patient.profile.tranfer + +import org.hl7.fhir.r4.model.Patient +import org.smartregister.fhircore.engine.util.SystemConstants +import org.smartregister.fhircore.engine.util.extension.extractGivenName +import org.smartregister.fhircore.engine.util.extension.extractName + +data class TransferOutScreenState( + val patientId: String, + val facilityId: String, + val firstName: String, + val fullName: String, +) { + companion object { + fun fromPatient(patient: Patient): TransferOutScreenState { + return TransferOutScreenState( + patientId = patient.id, + facilityId = + patient.meta.tag.firstOrNull { it.system == SystemConstants.LOCATION_TAG }?.id ?: "NA", + firstName = patient.extractGivenName(), + fullName = patient.extractName(), + ) + } + } +} diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt new file mode 100644 index 0000000000..04ca790234 --- /dev/null +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.quest.ui.patient.profile.tranfer + +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch +import org.hl7.fhir.r4.model.Patient +import org.smartregister.fhircore.engine.data.local.DefaultRepository +import org.smartregister.fhircore.engine.domain.util.DataLoadState +import org.smartregister.fhircore.quest.navigation.NavigationArg +import timber.log.Timber + +@HiltViewModel +class TransferOutViewModel +@Inject +constructor(savedStateHandle: SavedStateHandle, private val defaultRepository: DefaultRepository) : + ViewModel() { + private val patientId: String = savedStateHandle[NavigationArg.PATIENT_ID]!! + val state = MutableStateFlow>(DataLoadState.Loading) + + init { + fetchPatientDetails() + } + + fun fetchPatientDetails() { + viewModelScope.launch(Dispatchers.IO) { + try { + state.value = DataLoadState.Loading + val patient: Patient? = defaultRepository.loadResource(patientId) + if (patient == null) { + state.value = DataLoadState.Error(java.lang.Exception("Failed to load patient")) + return@launch + } + state.value = DataLoadState.Success(TransferOutScreenState.fromPatient(patient)) + } catch (e: Exception) { + state.value = DataLoadState.Error(e) + } + } + } + + fun transferPatient(context: Context) { + viewModelScope.launch(Dispatchers.IO) { + try { + val value = state.value + if (value is DataLoadState.Success) { + val data = value.data + val email = "ss@ddd.ccc" + val subject = "Request for Patient Transfer out for ${data.fullName}" + val body = + """ + Where is the patient transferring to? + + Do you have any additional information you want to add? + + --------- Do not edit below this line --------- + Current facility: ${data.facilityId} + Patient id: ${data.patientId} + Patient name: ${data.fullName} + """ + .trimIndent() + composeEmail(context, arrayOf(email), subject, body) + } + } catch (e: Exception) { + Timber.e(e) + } + } + } +} + +private fun composeEmail( + context: Context, + addresses: Array, + subject: String, + body: String +) { + val intent = + Intent(Intent.ACTION_SENDTO).apply { + setData(Uri.parse("mailto:")) + putExtra(Intent.EXTRA_EMAIL, addresses) + putExtra(Intent.EXTRA_SUBJECT, subject) + putExtra(Intent.EXTRA_TEXT, body) + } + context.startActivity(intent) +} diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/shared/models/ProfileViewData.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/shared/models/ProfileViewData.kt index b9ec1d91d4..7e2b85a71d 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/shared/models/ProfileViewData.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/shared/models/ProfileViewData.kt @@ -27,7 +27,6 @@ import org.hl7.fhir.r4.model.Task import org.smartregister.fhircore.engine.data.domain.Guardian import org.smartregister.fhircore.engine.domain.model.FormButtonData import org.smartregister.fhircore.engine.domain.model.TracingAttempt -import org.smartregister.fhircore.engine.util.extension.extractedTracingCategoryIsPhone import org.smartregister.fhircore.quest.ui.family.profile.model.FamilyMemberViewState sealed class ProfileViewData( From c41967af864349254c6557c0dde31d485d5ae770 Mon Sep 17 00:00:00 2001 From: Christopher Seven Phiri Date: Thu, 30 May 2024 12:39:26 +0200 Subject: [PATCH 2/3] Transfer out patient --- .../dataclerk/DataClerkApplication.kt | 2 + android/engine/build.gradle.kts | 5 +- .../fhircore/engine/di/AnalyticsModule.kt | 4 ++ .../fhircore/engine/task/FhirResourceUtil.kt | 14 ++-- .../fhircore/engine/trace/AnalyticReporter.kt | 25 +++++++ .../engine/trace/FirebaseAnalyticReporter.kt | 44 ++++++++++++ .../fhircore/engine/util/SystemConstants.kt | 3 + .../util/extension/FhirEngineExtension.kt | 18 +++++ .../fhircore/quest/QuestApplication.kt | 2 + .../profile/tranfer/TransferOutScreen.kt | 70 ++++++++++++++++--- .../profile/tranfer/TransferOutScreenState.kt | 5 +- .../profile/tranfer/TransferOutViewModel.kt | 69 ++++++++++++++---- 12 files changed, 226 insertions(+), 35 deletions(-) create mode 100644 android/engine/src/main/java/org/smartregister/fhircore/engine/trace/AnalyticReporter.kt create mode 100644 android/engine/src/main/java/org/smartregister/fhircore/engine/trace/FirebaseAnalyticReporter.kt diff --git a/android/dataclerk/src/main/java/org/dtree/fhircore/dataclerk/DataClerkApplication.kt b/android/dataclerk/src/main/java/org/dtree/fhircore/dataclerk/DataClerkApplication.kt index ef072e2fd3..ae997f36ee 100644 --- a/android/dataclerk/src/main/java/org/dtree/fhircore/dataclerk/DataClerkApplication.kt +++ b/android/dataclerk/src/main/java/org/dtree/fhircore/dataclerk/DataClerkApplication.kt @@ -21,6 +21,7 @@ import android.util.Log import androidx.hilt.work.HiltWorkerFactory import androidx.work.Configuration import com.google.android.fhir.datacapture.DataCaptureConfig +import com.google.firebase.analytics.ktx.analytics import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.ktx.Firebase import com.google.firebase.perf.ktx.performance @@ -50,6 +51,7 @@ class DataClerkApplication : Application(), DataCaptureConfig.Provider, Configur if (BuildConfig.DEBUG) { Firebase.performance.isPerformanceCollectionEnabled = false Firebase.crashlytics.setCrashlyticsCollectionEnabled(false) + Firebase.analytics.setAnalyticsCollectionEnabled(false) Timber.plant(Timber.DebugTree()) } } diff --git a/android/engine/build.gradle.kts b/android/engine/build.gradle.kts index 23f8623ffd..ee90e37d93 100644 --- a/android/engine/build.gradle.kts +++ b/android/engine/build.gradle.kts @@ -216,11 +216,12 @@ dependencies { api("com.squareup.okhttp3:okhttp:$okhttpVersion") api("com.squareup.okhttp3:logging-interceptor:$okhttpVersion") - implementation(platform("com.google.firebase:firebase-bom:32.7.3")) + implementation(platform("com.google.firebase:firebase-bom:33.0.0")) implementation("com.google.firebase:firebase-perf-ktx") implementation("com.google.firebase:firebase-crashlytics-ktx") + implementation("com.google.firebase:firebase-analytics") - implementation("androidx.core:core-splashscreen:1.0.0") + implementation("androidx.core:core-splashscreen:1.0.1") // Hilt test dependencies testImplementation("com.google.dagger:hilt-android-testing:${Deps.versions.hiltVersion}") diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/di/AnalyticsModule.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/di/AnalyticsModule.kt index 62be255e54..07042543c3 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/di/AnalyticsModule.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/di/AnalyticsModule.kt @@ -22,6 +22,8 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton +import org.smartregister.fhircore.engine.trace.AnalyticReporter +import org.smartregister.fhircore.engine.trace.FirebaseAnalyticReporter import org.smartregister.fhircore.engine.trace.FirebasePerformanceReporter import org.smartregister.fhircore.engine.trace.PerformanceReporter @@ -35,4 +37,6 @@ class AnalyticsModule { @Provides fun providePerformanceReporter(firebasePerformance: FirebasePerformance): PerformanceReporter = FirebasePerformanceReporter(firebasePerformance) + + @Provides fun providesAnalyticsReporter(): AnalyticReporter = FirebaseAnalyticReporter() } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/task/FhirResourceUtil.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/task/FhirResourceUtil.kt index 82107233de..8309dd2821 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/task/FhirResourceUtil.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/task/FhirResourceUtil.kt @@ -209,7 +209,7 @@ constructor( appointment.status = Appointment.AppointmentStatus.WAITLIST tracingTasksToAdd.addAll(addMissedAppointment(appointment, true)) } - if(missedAppointmentInRange) { + if (missedAppointmentInRange) { appointment.status = Appointment.AppointmentStatus.NOSHOW tracingTasksToAdd.addAll(addMissedAppointment(appointment, false)) } @@ -361,13 +361,13 @@ constructor( } } } - if(!isMilestoneAppointment) { + if (!isMilestoneAppointment) { addToTracingList( - appointment, - if (isEID) { - ReasonConstants.missedRoutineAppointmentTracingCode - } else ReasonConstants.missedAppointmentTracingCode, - ) + appointment, + if (isEID) { + ReasonConstants.missedRoutineAppointmentTracingCode + } else ReasonConstants.missedAppointmentTracingCode, + ) ?.let { tracingTasks.add(it) } } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/trace/AnalyticReporter.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/trace/AnalyticReporter.kt new file mode 100644 index 0000000000..9682646d00 --- /dev/null +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/trace/AnalyticReporter.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.engine.trace + +interface AnalyticReporter { + fun log(key: String, params: Map) + + fun log(key: String) + + fun login(id: String) +} diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/trace/FirebaseAnalyticReporter.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/trace/FirebaseAnalyticReporter.kt new file mode 100644 index 0000000000..5cbdc23c3b --- /dev/null +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/trace/FirebaseAnalyticReporter.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.engine.trace + +import com.google.firebase.analytics.FirebaseAnalytics +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.analytics.logEvent +import com.google.firebase.ktx.Firebase + +class FirebaseAnalyticReporter : AnalyticReporter { + private var firebaseAnalytics: FirebaseAnalytics = Firebase.analytics + + override fun log(key: String, params: Map) { + firebaseAnalytics.logEvent(key) { params.forEach { entry -> param(entry.key, entry.value) } } + } + + override fun log(key: String) { + firebaseAnalytics.logEvent(key, null) + } + + override fun login(id: String) { + log(AnalyticsKeys.LOGIN) + } +} + +object AnalyticsKeys { + const val LOGIN = "login" + const val SEARCH = "search" + const val TRANSFER_OUT = "transfer_out" +} diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt index cbb5faec7d..02a1fc9d2d 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/util/SystemConstants.kt @@ -54,6 +54,9 @@ object ReasonConstants { var interruptedTreatmentTracingCode = Coding(SystemConstants.REASON_CODE_SYSTEM, "interrupted-treatment", "Interrupted Treatment") + var pendingTransferOutCode = + Coding("https://d-tree.org/fhir/transfer-out-status", "pending", "Pending") + const val TRACING_OUTCOME_CODE = "tracing-outcome" const val DATE_OF_AGREED_APPOINTMENT = "date-of-agreed-appointment" } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/util/extension/FhirEngineExtension.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/util/extension/FhirEngineExtension.kt index 0fcff19cbc..3baca8b803 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/util/extension/FhirEngineExtension.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/util/extension/FhirEngineExtension.kt @@ -21,6 +21,7 @@ import ca.uhn.fhir.util.UrlUtil import com.google.android.fhir.FhirEngine import com.google.android.fhir.db.ResourceNotFoundException import com.google.android.fhir.get +import com.google.android.fhir.logicalId import com.google.android.fhir.search.Operation import com.google.android.fhir.search.SearchQuery import com.google.android.fhir.search.filter.TokenParamFilterCriterion @@ -116,3 +117,20 @@ suspend inline fun FhirEngine.getResourcesByIds( } .map { it.resource } } + +suspend fun FhirEngine.forceTagsUpdate(source: Resource) { + try { + var resource = source + /** Increment [Resource.meta] versionId of [source]. */ + resource.meta.versionId?.toInt()?.plus(1)?.let { + /** Assign [Resource.meta] versionId of [source]. */ + resource = resource.copy().apply { meta.versionId = "$it" } + /** Delete a FHIR [source] in the local storage. */ + this.purge(resource.resourceType, resource.logicalId, forcePurge = true) + /** Recreate a FHIR [source] in the local storage. */ + this.create(resource) + } + } catch (e: Exception) { + Timber.e(e) + } +} diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/QuestApplication.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/QuestApplication.kt index 92bdbaee40..82d76a3e91 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/QuestApplication.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/QuestApplication.kt @@ -30,6 +30,7 @@ import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration import com.github.anrwatchdog.ANRWatchDog import com.google.android.fhir.datacapture.DataCaptureConfig +import com.google.firebase.analytics.ktx.analytics import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.ktx.Firebase import com.google.firebase.perf.ktx.performance @@ -93,6 +94,7 @@ class QuestApplication : } else { Firebase.performance.isPerformanceCollectionEnabled = false Firebase.crashlytics.setCrashlyticsCollectionEnabled(false) + Firebase.analytics.setAnalyticsCollectionEnabled(false) Timber.plant(Timber.DebugTree()) } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt index 5504386a45..f1a163863b 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt @@ -16,6 +16,7 @@ package org.smartregister.fhircore.quest.ui.patient.profile.tranfer +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -24,7 +25,9 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon @@ -36,6 +39,7 @@ import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -46,7 +50,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.ParagraphStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextIndent import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview @@ -65,8 +68,15 @@ fun TransferOutScreen( onBackPress: () -> Boolean, ) { val state by viewModel.state.collectAsState() + val uploadState by viewModel.updateState.collectAsState() val context = LocalContext.current + LaunchedEffect(uploadState) { + if (uploadState is DataLoadState.Success) { + onBackPress() + } + } + Scaffold( topBar = { TopAppBar( @@ -85,7 +95,7 @@ fun TransferOutScreen( when (state) { is DataLoadState.Success -> { val data = (state as DataLoadState.Success).data - TransferOutScreenContainer(data) { viewModel.transferPatient(context) } + TransferOutScreenContainer(data, uploadState) { viewModel.transferPatient(context) } } is DataLoadState.Error -> { Column( @@ -125,7 +135,11 @@ fun TransferOutScreen( } @Composable -fun TransferOutScreenContainer(data: TransferOutScreenState, onClick: () -> Unit) { +fun TransferOutScreenContainer( + data: TransferOutScreenState, + uploadState: DataLoadState, + onClick: () -> Unit, +) { val paragraphStyle = ParagraphStyle(textIndent = TextIndent(restLine = 12.sp)) val steps = listOf( @@ -150,7 +164,6 @@ fun TransferOutScreenContainer(data: TransferOutScreenState, onClick: () -> Unit append(" to a new facility?") }, style = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Normal), - textAlign = TextAlign.Center, ) Spacer(Modifier.height(12.dp)) Text( @@ -167,16 +180,51 @@ fun TransferOutScreenContainer(data: TransferOutScreenState, onClick: () -> Unit appendLine() appendLine() withStyle( - style = MaterialTheme.typography.subtitle2.copy( - color = MaterialTheme.colors.error - ).toSpanStyle(), + style = + MaterialTheme.typography.subtitle2 + .copy( + color = MaterialTheme.colors.error, + ) + .toSpanStyle(), ) { - appendLine("Note: Once the process starts the patient will be disabled and will not be accessible from within the app") + appendLine( + "Note: Once the process starts the patient will not be accessible. The transfer out process is not immediate and might take up to 24 hours before the client is accessible at the target facility", + ) } }, ) - Spacer(Modifier.height(20.dp)) - Button(onClick = onClick, modifier = Modifier.fillMaxWidth()) { Text(text = "Transfer Out") } + Spacer(Modifier.height(10.dp)) + if (uploadState is DataLoadState.Error) { + Box( + modifier = + Modifier.fillMaxWidth() + .background( + color = MaterialTheme.colors.error, + shape = RoundedCornerShape(12.dp), + ) + .padding(12.dp), + ) { + Text( + text = "Something went wrong while, transferring out the patient, please try again..", + color = MaterialTheme.colors.onError, + ) + } + Spacer(Modifier.height(10.dp)) + } + + Button( + onClick = onClick, + modifier = Modifier.fillMaxWidth(), + enabled = uploadState !is DataLoadState.Loading, + ) { + if (uploadState is DataLoadState.Loading) { + CircularProgressIndicator() + Spacer(modifier = Modifier.width(6.dp)) + Text(text = "Preparing information....") + } else { + Text(text = "Transfer Out") + } + } } } @@ -194,7 +242,7 @@ private fun TransferOutScreenContainerPreview() { Box( modifier = Modifier.padding(innerPadding).fillMaxSize(), ) { - TransferOutScreenContainer(data) {} + TransferOutScreenContainer(data, DataLoadState.Loading) {} } } } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt index 6197b51cd9..7779f8009f 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreenState.kt @@ -16,6 +16,7 @@ package org.smartregister.fhircore.quest.ui.patient.profile.tranfer +import com.google.android.fhir.logicalId import org.hl7.fhir.r4.model.Patient import org.smartregister.fhircore.engine.util.SystemConstants import org.smartregister.fhircore.engine.util.extension.extractGivenName @@ -30,9 +31,9 @@ data class TransferOutScreenState( companion object { fun fromPatient(patient: Patient): TransferOutScreenState { return TransferOutScreenState( - patientId = patient.id, + patientId = patient.logicalId, facilityId = - patient.meta.tag.firstOrNull { it.system == SystemConstants.LOCATION_TAG }?.id ?: "NA", + patient.meta.tag.firstOrNull { it.system == SystemConstants.LOCATION_TAG }?.code ?: "NA", firstName = patient.extractGivenName(), fullName = patient.extractName(), ) diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt index 04ca790234..8ccb169ca0 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt @@ -22,6 +22,7 @@ import android.net.Uri import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.google.android.fhir.FhirEngine import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.Dispatchers @@ -30,16 +31,35 @@ import kotlinx.coroutines.launch import org.hl7.fhir.r4.model.Patient import org.smartregister.fhircore.engine.data.local.DefaultRepository import org.smartregister.fhircore.engine.domain.util.DataLoadState +import org.smartregister.fhircore.engine.trace.AnalyticReporter +import org.smartregister.fhircore.engine.trace.AnalyticsKeys +import org.smartregister.fhircore.engine.util.ReasonConstants +import org.smartregister.fhircore.engine.util.SharedPreferenceKey +import org.smartregister.fhircore.engine.util.SharedPreferencesHelper +import org.smartregister.fhircore.engine.util.extension.forceTagsUpdate import org.smartregister.fhircore.quest.navigation.NavigationArg import timber.log.Timber @HiltViewModel class TransferOutViewModel @Inject -constructor(savedStateHandle: SavedStateHandle, private val defaultRepository: DefaultRepository) : - ViewModel() { +constructor( + savedStateHandle: SavedStateHandle, + private val defaultRepository: DefaultRepository, + private val fhirEngine: FhirEngine, + private val analytics: AnalyticReporter, + private val sharedPreferencesHelper: SharedPreferencesHelper, +) : ViewModel() { private val patientId: String = savedStateHandle[NavigationArg.PATIENT_ID]!! val state = MutableStateFlow>(DataLoadState.Loading) + val updateState = MutableStateFlow>(DataLoadState.Idle) + + private val currentPractitioner by lazy { + sharedPreferencesHelper.read( + key = SharedPreferenceKey.PRACTITIONER_ID.name, + defaultValue = null, + ) + } init { fetchPatientDetails() @@ -64,27 +84,50 @@ constructor(savedStateHandle: SavedStateHandle, private val defaultRepository: D fun transferPatient(context: Context) { viewModelScope.launch(Dispatchers.IO) { try { + updateState.value = DataLoadState.Loading val value = state.value - if (value is DataLoadState.Success) { - val data = value.data - val email = "ss@ddd.ccc" - val subject = "Request for Patient Transfer out for ${data.fullName}" - val body = - """ + if (value !is DataLoadState.Success) { + updateState.value = DataLoadState.Error(java.lang.Exception()) + return@launch + } + val data = value.data + val patient = defaultRepository.loadResource(data.patientId) + if (patient == null) { + updateState.value = DataLoadState.Error(java.lang.Exception()) + return@launch + } + patient.active = false + val meta = patient.meta + meta.addTag(ReasonConstants.pendingTransferOutCode) + patient.meta = meta + fhirEngine.forceTagsUpdate(patient) + analytics.log( + AnalyticsKeys.TRANSFER_OUT, + mapOf(Pair("patient", patient.id), Pair("practitioner", currentPractitioner ?: "")), + ) + val email = "cphiri@d-tree.org" + val subject = "Request for Patient Transfer out for ${data.fullName}" + val body = + """ Where is the patient transferring to? + + Do you have any additional information you want to add? + + --------- Do not edit below this line --------- Current facility: ${data.facilityId} Patient id: ${data.patientId} - Patient name: ${data.fullName} + Practitioner: $currentPractitioner """ - .trimIndent() - composeEmail(context, arrayOf(email), subject, body) - } + .trimIndent() + composeEmail(context, arrayOf(email), subject, body) + updateState.value = DataLoadState.Success(true) } catch (e: Exception) { Timber.e(e) + updateState.value = DataLoadState.Error(e) } } } @@ -94,7 +137,7 @@ private fun composeEmail( context: Context, addresses: Array, subject: String, - body: String + body: String, ) { val intent = Intent(Intent.ACTION_SENDTO).apply { From 97c043170d523dfbe23d2df5cb8a249b1feaf269 Mon Sep 17 00:00:00 2001 From: Christopher Seven Phiri Date: Thu, 30 May 2024 14:05:23 +0200 Subject: [PATCH 3/3] Get support email from configs --- .../configuration/app/ApplicationConfiguration.kt | 2 ++ .../ui/patient/profile/tranfer/TransferOutScreen.kt | 1 + .../patient/profile/tranfer/TransferOutViewModel.kt | 12 +++++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt index 449d10b7f4..f6467c0470 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt @@ -36,6 +36,8 @@ data class ApplicationConfiguration( var taskOrderFilterTagViaMetaCodingSystem: String = SystemConstants.TASK_TASK_ORDER_SYSTEM, var taskFilterTagViaMetaCodingSystem: String = SystemConstants.TASK_FILTER_TAG_SYSTEM, var registrationForm: String = "patient-demographic-registration", + var supportEmail: String = "info@tingathe.org", + var supportPhoneNumber: String = "" ) : Configuration /** diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt index f1a163863b..c361e96fb7 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutScreen.kt @@ -74,6 +74,7 @@ fun TransferOutScreen( LaunchedEffect(uploadState) { if (uploadState is DataLoadState.Success) { onBackPress() + onBackPress() } } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt index 8ccb169ca0..79df3e7704 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/profile/tranfer/TransferOutViewModel.kt @@ -29,8 +29,11 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import org.hl7.fhir.r4.model.Patient +import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry +import org.smartregister.fhircore.engine.configuration.app.ApplicationConfiguration import org.smartregister.fhircore.engine.data.local.DefaultRepository import org.smartregister.fhircore.engine.domain.util.DataLoadState +import org.smartregister.fhircore.engine.sync.SyncBroadcaster import org.smartregister.fhircore.engine.trace.AnalyticReporter import org.smartregister.fhircore.engine.trace.AnalyticsKeys import org.smartregister.fhircore.engine.util.ReasonConstants @@ -49,11 +52,17 @@ constructor( private val fhirEngine: FhirEngine, private val analytics: AnalyticReporter, private val sharedPreferencesHelper: SharedPreferencesHelper, + configurationRegistry: ConfigurationRegistry, + private val syncBroadcaster: SyncBroadcaster + ) : ViewModel() { private val patientId: String = savedStateHandle[NavigationArg.PATIENT_ID]!! val state = MutableStateFlow>(DataLoadState.Loading) val updateState = MutableStateFlow>(DataLoadState.Idle) + private val applicationConfiguration: ApplicationConfiguration = + configurationRegistry.getAppConfigs() + private val currentPractitioner by lazy { sharedPreferencesHelper.read( key = SharedPreferenceKey.PRACTITIONER_ID.name, @@ -105,7 +114,7 @@ constructor( AnalyticsKeys.TRANSFER_OUT, mapOf(Pair("patient", patient.id), Pair("practitioner", currentPractitioner ?: "")), ) - val email = "cphiri@d-tree.org" + val email = applicationConfiguration.supportEmail val subject = "Request for Patient Transfer out for ${data.fullName}" val body = """ @@ -125,6 +134,7 @@ constructor( .trimIndent() composeEmail(context, arrayOf(email), subject, body) updateState.value = DataLoadState.Success(true) + syncBroadcaster.runSync() } catch (e: Exception) { Timber.e(e) updateState.value = DataLoadState.Error(e)