Skip to content

Commit

Permalink
Update the model when statin info is loaded
Browse files Browse the repository at this point in the history
  • Loading branch information
Siddharth Agarwal committed Dec 20, 2024
1 parent 9f41b95 commit 01898df
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.simple.clinic.summary

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.simple.clinic.cvdrisk.StatinInfo
import org.simple.clinic.facility.Facility
import org.simple.clinic.overdue.Appointment
import org.simple.clinic.patient.PatientStatus
Expand All @@ -27,7 +28,7 @@ data class PatientSummaryModel(
val hasPrescribedDrugsChangedToday: Boolean?,
val scheduledAppointment: ParcelableOptional<Appointment>?,
val hasShownDiagnosisWarningDialog: Boolean,
val canPrescribeStatin: Boolean?,
val statinInfo: StatinInfo?,
) : Parcelable, PatientSummaryChildModel {

companion object {
Expand All @@ -46,7 +47,7 @@ data class PatientSummaryModel(
hasPrescribedDrugsChangedToday = null,
scheduledAppointment = null,
hasShownDiagnosisWarningDialog = false,
canPrescribeStatin = null,
statinInfo = null,
)
}
}
Expand Down Expand Up @@ -82,7 +83,7 @@ data class PatientSummaryModel(
get() = scheduledAppointment != null && scheduledAppointment.isPresent()

val hasStatinInfoLoaded: Boolean
get() = canPrescribeStatin != null
get() = statinInfo != null

override fun readyToRender(): Boolean {
return hasLoadedPatientSummaryProfile && hasLoadedCurrentFacility && hasPatientRegistrationData != null
Expand Down Expand Up @@ -128,7 +129,7 @@ data class PatientSummaryModel(
return copy(scheduledAppointment = appointment.toOptional().parcelable())
}

fun updateStatinInfo(canPrescribeStatin: Boolean): PatientSummaryModel {
return copy(canPrescribeStatin = canPrescribeStatin)
fun updateStatinInfo(statinInfo: StatinInfo?): PatientSummaryModel {
return copy(statinInfo = statinInfo)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import org.simple.clinic.R
import org.simple.clinic.ReportAnalyticsEvents
import org.simple.clinic.common.ui.theme.SimpleTheme
import org.simple.clinic.contactpatient.ContactPatientBottomSheet
import org.simple.clinic.cvdrisk.StatinInfo
import org.simple.clinic.databinding.ScreenPatientSummaryBinding
import org.simple.clinic.di.injector
import org.simple.clinic.editpatient.EditPatientScreen
Expand Down Expand Up @@ -763,7 +764,7 @@ class PatientSummaryScreen :
clinicalDecisionSupportAlertView.visibility = GONE
}

override fun showStatinAlert() {
override fun showStatinAlert(statinInfo: StatinInfo) {
shouldShowStatinNudge = true
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.simple.clinic.summary

import org.simple.clinic.cvdrisk.StatinInfo

interface PatientSummaryScreenUi {
fun populatePatientProfile(patientSummaryProfile: PatientSummaryProfile)
fun showEditButton()
Expand All @@ -18,6 +20,6 @@ interface PatientSummaryScreenUi {
fun showClinicalDecisionSupportAlert()
fun hideClinicalDecisionSupportAlert()
fun hideClinicalDecisionSupportAlertWithoutAnimation()
fun showStatinAlert()
fun showStatinAlert(statinInfo: StatinInfo)
fun hideStatinAlert()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.spotify.mobius.Next
import com.spotify.mobius.Next.next
import com.spotify.mobius.Next.noChange
import com.spotify.mobius.Update
import org.simple.clinic.cvdrisk.StatinInfo
import org.simple.clinic.drugs.DiagnosisWarningPrescriptions
import org.simple.clinic.drugs.PrescribedDrug
import org.simple.clinic.medicalhistory.Answer.Yes
Expand Down Expand Up @@ -106,21 +107,36 @@ class PatientSummaryUpdate(
model: PatientSummaryModel
): Next<PatientSummaryModel, PatientSummaryEffect> {
val minAgeForStatin = 40
val maxAgeForCVDRisk = 74
val hasHadStroke = event.medicalHistory.hasHadStroke == Yes
val hasHadHeartAttack = event.medicalHistory.hasHadHeartAttack == Yes
val hasDiabetes = event.medicalHistory.diagnosedWithDiabetes == Yes

val hasCVD = hasHadStroke || hasHadHeartAttack
val isPatientEligibleForStatin = (event.age >= minAgeForStatin && hasDiabetes) || hasCVD
val hasStatinsPrescribedAlready = event.prescriptions.any { it.name.contains("statin", ignoreCase = true) }
val canPrescribeStatin = event.isPatientDead.not() &&
event.assignedFacility?.facilityType.equals("UHC", ignoreCase = true) &&
event.hasBPRecordedToday &&
hasStatinsPrescribedAlready.not() &&
isPatientEligibleForStatin
hasStatinsPrescribedAlready.not()

val updatedModel = model.updateStatinInfo(canPrescribeStatin)
return next(updatedModel)
return when {
event.age < minAgeForStatin -> {
val updatedModel = model.updateStatinInfo(StatinInfo(canPrescribeStatin = false))
next(updatedModel)
}

event.age > maxAgeForCVDRisk -> {
val updatedModel = model.updateStatinInfo(StatinInfo(canPrescribeStatin = canPrescribeStatin && (hasCVD || hasDiabetes)))
next(updatedModel)
}

hasCVD || hasDiabetes -> {
val updatedModel = model.updateStatinInfo(StatinInfo(canPrescribeStatin = canPrescribeStatin))
next(updatedModel)
}

else -> dispatch(LoadCVDRisk(model.patientUuid))
}
}

private fun cvdRiskLoaded(
Expand All @@ -131,17 +147,15 @@ class PatientSummaryUpdate(
return if (cvdRisk != null) {
dispatch(LoadStatinInfo(model.patientUuid))
} else {
dispatch(CalculateCVDRisk(model.patientSummaryProfile!!.patient))
dispatch(CalculateCVDRisk(model.patientSummaryProfile!!.patient))
}
}

private fun statinInfoLoaded(
event: StatinInfoLoaded,
model: PatientSummaryModel
): Next<PatientSummaryModel, PatientSummaryEffect> {
val statinInfo = event.statinInfo
//update model with statin info
return noChange()
return next(model.updateStatinInfo(event.statinInfo))
}

private fun hypertensionNotNowClicked(continueToDiabetesDiagnosisWarning: Boolean): Next<PatientSummaryModel, PatientSummaryEffect> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class PatientSummaryViewRenderer(
}

private fun renderClinicalDecisionBasedOnAppointment(model: PatientSummaryModel) {
if (model.canPrescribeStatin == true)
if (model.statinInfo?.canPrescribeStatin == true)
return

if (model.hasScheduledAppointment) {
Expand Down Expand Up @@ -153,8 +153,8 @@ class PatientSummaryViewRenderer(
private fun renderStatinAlert(model: PatientSummaryModel) {
if (model.hasStatinInfoLoaded.not()) return

if (model.canPrescribeStatin == true) {
ui.showStatinAlert()
if (model.statinInfo?.canPrescribeStatin == true) {
ui.showStatinAlert(model.statinInfo)
ui.hideClinicalDecisionSupportAlertWithoutAnimation()
} else {
ui.hideStatinAlert()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.spotify.mobius.test.NextMatchers.hasNoModel
import com.spotify.mobius.test.UpdateSpec
import com.spotify.mobius.test.UpdateSpec.assertThatNext
import org.junit.Test
import org.simple.clinic.cvdrisk.StatinInfo
import org.simple.clinic.drugs.DiagnosisWarningPrescriptions
import org.simple.clinic.facility.FacilityConfig
import org.simple.clinic.medicalhistory.Answer.No
Expand Down Expand Up @@ -2108,7 +2109,61 @@ class PatientSummaryUpdateTest {
}

@Test
fun `when statin prescription check info is loaded and can prescribe statin, then update the state`() {
fun `when statin prescription check info is loaded and person is below 40, then update the state with false`() {
updateSpec
.given(defaultModel)
.whenEvent(StatinPrescriptionCheckInfoLoaded(
age = 39,
isPatientDead = false,
hasBPRecordedToday = true,
assignedFacility = TestData.facility(
name = "UHC Simple",
facilityType = "UHC"
),
medicalHistory = TestData.medicalHistory(
hasDiabetes = No,
hasHadStroke = No,
hasHadHeartAttack = No,
),
prescriptions = listOf(
TestData.prescription(name = "losartin")
),
))
.then(assertThatNext(
hasModel(defaultModel.updateStatinInfo(StatinInfo(canPrescribeStatin = false))),
hasNoEffects()
))
}

@Test
fun `when statin prescription check info is loaded and person is above 74, then update the state`() {
updateSpec
.given(defaultModel)
.whenEvent(StatinPrescriptionCheckInfoLoaded(
age = 75,
isPatientDead = false,
hasBPRecordedToday = true,
assignedFacility = TestData.facility(
name = "UHC Simple",
facilityType = "UHC"
),
medicalHistory = TestData.medicalHistory(
hasDiabetes = No,
hasHadStroke = No,
hasHadHeartAttack = No,
),
prescriptions = listOf(
TestData.prescription(name = "losartin")
),
))
.then(assertThatNext(
hasModel(defaultModel.updateStatinInfo(StatinInfo(canPrescribeStatin = false))),
hasNoEffects()
))
}

@Test
fun `when statin prescription check info is loaded and has history of cvd or diabetes, then update the state`() {
updateSpec
.given(defaultModel)
.whenEvent(StatinPrescriptionCheckInfoLoaded(
Expand All @@ -2129,11 +2184,38 @@ class PatientSummaryUpdateTest {
),
))
.then(assertThatNext(
hasModel(defaultModel.updateStatinInfo(true)),
hasModel(defaultModel.updateStatinInfo(StatinInfo(canPrescribeStatin = true))),
hasNoEffects()
))
}

@Test
fun `when statin prescription check info is loaded and is eligible for cvd risk, then load cvd risk`() {
updateSpec
.given(defaultModel)
.whenEvent(StatinPrescriptionCheckInfoLoaded(
age = 50,
isPatientDead = false,
hasBPRecordedToday = true,
assignedFacility = TestData.facility(
name = "UHC Simple",
facilityType = "UHC"
),
medicalHistory = TestData.medicalHistory(
hasDiabetes = No,
hasHadStroke = No,
hasHadHeartAttack = No,
),
prescriptions = listOf(
TestData.prescription(name = "losartin")
),
))
.then(assertThatNext(
hasNoModel(),
hasEffects(LoadCVDRisk(defaultModel.patientUuid))
))
}

@Test
fun `when cvd risk is loaded and risk score is not null, then load statin info`() {
updateSpec
Expand Down Expand Up @@ -2172,6 +2254,22 @@ class PatientSummaryUpdateTest {
))
}

@Test
fun `when statin info is loaded, then update the state`() {
val statinInfo = StatinInfo(
canPrescribeStatin = true
)
updateSpec
.given(defaultModel)
.whenEvent(StatinInfoLoaded(
statinInfo = statinInfo
))
.then(assertThatNext(
hasModel(defaultModel.updateStatinInfo(statinInfo)),
hasNoEffects()
))
}

private fun PatientSummaryModel.forExistingPatient(): PatientSummaryModel {
return copy(openIntention = ViewExistingPatient)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.simple.clinic.cvdrisk.StatinInfo
import org.simple.clinic.facility.FacilityConfig
import org.simple.clinic.patient.PatientStatus
import org.simple.clinic.patient.businessid.Identifier
Expand Down Expand Up @@ -766,9 +767,10 @@ class PatientSummaryViewRendererTest {
@Test
fun `when statin info is loaded and can prescribe statin then show the statin alert`() {
//given
val statinInfo = StatinInfo(canPrescribeStatin = true)
val model = defaultModel
.currentFacilityLoaded(facilityWithDiabetesManagementDisabled)
.updateStatinInfo(true)
.updateStatinInfo(statinInfo)

// when
uiRenderer.render(model)
Expand All @@ -778,16 +780,17 @@ class PatientSummaryViewRendererTest {
verify(ui).hideTeleconsultButton()
verify(ui).hideNextAppointmentCard()
verify(ui, times(2)).hideClinicalDecisionSupportAlertWithoutAnimation()
verify(ui).showStatinAlert()
verify(ui).showStatinAlert(statinInfo)
verifyNoMoreInteractions(ui)
}

@Test
fun `when statin info is loaded and can not prescribe statin then hide the statin alert`() {
//given
val statinInfo = StatinInfo(canPrescribeStatin = false)
val model = defaultModel
.currentFacilityLoaded(facilityWithDiabetesManagementDisabled)
.updateStatinInfo(false)
.updateStatinInfo(statinInfo)

// when
uiRenderer.render(model)
Expand Down Expand Up @@ -838,7 +841,7 @@ class PatientSummaryViewRendererTest {
.patientSummaryProfileLoaded(patientSummaryProfile = patientSummaryProfile)
.clinicalDecisionSupportInfoLoaded(isNewestBpEntryHigh = true, hasPrescribedDrugsChangedToday = false)
.scheduledAppointmentLoaded(appointment)
.updateStatinInfo(true)
.updateStatinInfo(StatinInfo(canPrescribeStatin = true))


val uiRenderer = PatientSummaryViewRenderer(
Expand All @@ -858,7 +861,7 @@ class PatientSummaryViewRendererTest {
verify(ui).showPatientDiedStatus()
verify(ui).hideDiabetesView()
verify(ui).hideTeleconsultButton()
verify(ui).showStatinAlert()
verify(ui).showStatinAlert(StatinInfo(canPrescribeStatin = true))
verify(ui).hideClinicalDecisionSupportAlertWithoutAnimation()
verify(ui).showNextAppointmentCard()
verifyNoMoreInteractions(ui)
Expand Down

0 comments on commit 01898df

Please sign in to comment.