From d37a3b8a3ec96acfbb2c848adb5d0a5d988dba2c Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Thu, 2 Jan 2025 16:02:46 +0100 Subject: [PATCH] add addon feature flag to moving flow and change tier flow --- .../MutationChangeTierDeductible.graphql | 6 +++-- ...CreateChangeTierDeductibleIntentUseCase.kt | 6 +++-- ...angeTierDeductibleIntentUseCaseImplTest.kt | 27 +++++++++++++------ .../feature-movingflow/build.gradle.kts | 3 +++ .../graphql/MutationMoveIntentRequest.graphql | 8 +++--- .../movingflow/data/MovingFlowQuotes.kt | 8 +++--- .../feature/movingflow/di/movingFlowModule.kt | 15 ++++++++--- .../AddHouseInformationViewModel.kt | 15 ++++++++++- .../EnterNewAddressViewModel.kt | 15 ++++++++++- 9 files changed, 78 insertions(+), 25 deletions(-) diff --git a/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql b/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql index ebe7ef3d5b..21d1ec2d6d 100644 --- a/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql +++ b/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql @@ -1,4 +1,6 @@ -mutation ChangeTierDeductibleCreateIntent($contractId: ID!, $source: ChangeTierDeductibleSource!) { +mutation ChangeTierDeductibleCreateIntent($contractId: ID!, + $source: ChangeTierDeductibleSource!, +$addonsFlagOn: Boolean!) { changeTierDeductibleCreateIntent(input:{ contractId: $contractId, source: $source }) { intent { activationDate @@ -34,7 +36,7 @@ mutation ChangeTierDeductibleCreateIntent($contractId: ID!, $source: ChangeTierD } tierLevel tierName - addons { + addons @include(if: $addonsFlagOn) { addonId displayName displayItems { diff --git a/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt b/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt index 18c41221c1..2d5fb0d753 100644 --- a/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt +++ b/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt @@ -36,6 +36,7 @@ internal class CreateChangeTierDeductibleIntentUseCaseImpl( ): Either { return either { val isTierEnabled = featureManager.isFeatureEnabled(Feature.TIER).first() + val isAddonFlagEnabled = featureManager.isFeatureEnabled(Feature.TRAVEL_ADDON).first() if (!isTierEnabled) { logcat(ERROR) { "Tried to get changeTierQuotes when feature flag is disabled!" } raise(ErrorMessage()) @@ -45,6 +46,7 @@ internal class CreateChangeTierDeductibleIntentUseCaseImpl( ChangeTierDeductibleCreateIntentMutation( contractId = insuranceId, source = source.toSource(), + addonsFlagOn = isAddonFlagEnabled, ), ) .safeExecute() @@ -92,7 +94,7 @@ internal class CreateChangeTierDeductibleIntentUseCaseImpl( tierDescription = it.productVariant.tierDescription, tierDisplayName = it.productVariant.displayNameTier, ), - addons = it.addons.map { addon -> + addons = it.addons?.map { addon -> ChangeTierDeductibleAddonQuote( addonId = addon.addonId, displayName = addon.displayName, @@ -101,7 +103,7 @@ internal class CreateChangeTierDeductibleIntentUseCaseImpl( premium = UiMoney.fromMoneyFragment(addon.premium), addonVariant = addon.addonVariant.toAddonVariant(), ) - }, + } ?: emptyList(), ) } val intentResult = ChangeTierDeductibleIntent( diff --git a/app/data/data-changetier/src/test/kotlin/data/CreateChangeTierDeductibleIntentUseCaseImplTest.kt b/app/data/data-changetier/src/test/kotlin/data/CreateChangeTierDeductibleIntentUseCaseImplTest.kt index 72b459b85f..1eff575712 100644 --- a/app/data/data-changetier/src/test/kotlin/data/CreateChangeTierDeductibleIntentUseCaseImplTest.kt +++ b/app/data/data-changetier/src/test/kotlin/data/CreateChangeTierDeductibleIntentUseCaseImplTest.kt @@ -53,6 +53,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { operation = ChangeTierDeductibleCreateIntentMutation( contractId = testId, source = testSource, + addonsFlagOn = true, ), errors = listOf(com.apollographql.apollo.api.Error.Builder(message = "Bad message").build()), ) @@ -65,6 +66,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { operation = ChangeTierDeductibleCreateIntentMutation( contractId = testId, source = testSource, + addonsFlagOn = true, ), data = ChangeTierDeductibleCreateIntentMutation.Data(OctopusFakeResolver) { changeTierDeductibleCreateIntent = buildChangeTierDeductibleCreateIntentOutput { @@ -81,6 +83,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { operation = ChangeTierDeductibleCreateIntentMutation( contractId = testId, source = testSource, + addonsFlagOn = true, ), data = ChangeTierDeductibleCreateIntentMutation.Data(OctopusFakeResolver) { changeTierDeductibleCreateIntent = buildChangeTierDeductibleCreateIntentOutput { @@ -156,6 +159,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { operation = ChangeTierDeductibleCreateIntentMutation( contractId = testId, source = testSource, + addonsFlagOn = true, ), data = ChangeTierDeductibleCreateIntentMutation.Data(OctopusFakeResolver) { changeTierDeductibleCreateIntent = buildChangeTierDeductibleCreateIntentOutput { @@ -231,6 +235,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { operation = ChangeTierDeductibleCreateIntentMutation( contractId = testId, source = testSource, + addonsFlagOn = true, ), data = ChangeTierDeductibleCreateIntentMutation.Data(OctopusFakeResolver) { changeTierDeductibleCreateIntent = buildChangeTierDeductibleCreateIntentOutput { @@ -277,6 +282,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { operation = ChangeTierDeductibleCreateIntentMutation( contractId = testId, source = testSource, + addonsFlagOn = true, ), data = ChangeTierDeductibleCreateIntentMutation.Data(OctopusFakeResolver) { changeTierDeductibleCreateIntent = buildChangeTierDeductibleCreateIntentOutput { @@ -347,7 +353,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when BE response has empty quotes return intent with empty quotes`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodResponseButEmptyQuotes, featureManager = featureManager, @@ -362,7 +368,12 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when response is fine and tier feature flag is on get a good result`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2( + fixedMap = mapOf( + Feature.TIER to true, + Feature.TRAVEL_ADDON to true, + ), + ) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodResponse, featureManager = featureManager, @@ -390,7 +401,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when response is fine but tier feature flag is off the result is ErrorMessage`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to false)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to false, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodResponse, featureManager = featureManager, @@ -404,7 +415,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when response is bad and tier feature flag is on the result is ErrorMessage`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithBadResponse, featureManager = featureManager, @@ -418,7 +429,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when response is otherwise good but the intent is null the result is ErrorMessage`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodButNullResponse, featureManager = featureManager, @@ -433,7 +444,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when response is otherwise good but the tierName in existing agreement is null the result is ErrorMessage`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodResponseButNullTierNameInExisting, featureManager = featureManager, @@ -448,7 +459,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `when response is otherwise good but the tierName in one of the quotes is null the result is ErrorMessage`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodResponseButNullTierNameInOneQuote, featureManager = featureManager, @@ -462,7 +473,7 @@ class CreateChangeTierDeductibleIntentUseCaseImplTest { @Test fun `in good response one of the quotes should have the current const id`() = runTest { - val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true)) + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TIER to true, Feature.TRAVEL_ADDON to true)) val createChangeTierDeductibleIntentUseCase = CreateChangeTierDeductibleIntentUseCaseImpl( apolloClient = apolloClientWithGoodResponse, featureManager = featureManager, diff --git a/app/feature/feature-movingflow/build.gradle.kts b/app/feature/feature-movingflow/build.gradle.kts index 4cf23b7ec6..668ef55b63 100644 --- a/app/feature/feature-movingflow/build.gradle.kts +++ b/app/feature/feature-movingflow/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.fir.expressions.builder.buildImplicitInvokeCall + plugins { id("hedvig.gradle.plugin") id("hedvig.android.library") @@ -39,4 +41,5 @@ dependencies { implementation(projects.uiTiersAndAddons) implementation(libs.compose.richtext) implementation(libs.compose.richtextCommonmark) + implementation(projects.featureFlagsPublic) } diff --git a/app/feature/feature-movingflow/src/main/graphql/MutationMoveIntentRequest.graphql b/app/feature/feature-movingflow/src/main/graphql/MutationMoveIntentRequest.graphql index 6d1f687a34..197f495f02 100644 --- a/app/feature/feature-movingflow/src/main/graphql/MutationMoveIntentRequest.graphql +++ b/app/feature/feature-movingflow/src/main/graphql/MutationMoveIntentRequest.graphql @@ -1,4 +1,6 @@ -mutation MoveIntentV2Request($intentId: ID!, $moveIntentRequestInput: MoveIntentRequestInput!) { +mutation MoveIntentV2Request($intentId: ID!, + $moveIntentRequestInput: MoveIntentRequestInput!, + $addonsFlagOn: Boolean!) { moveIntentRequest(intentId: $intentId, input: $moveIntentRequestInput) { moveIntent { ...MoveIntentQuotesFragment @@ -34,7 +36,7 @@ fragment MoveIntentQuotesFragment on MoveIntent { ...ProductVariantFragment # todo This is not in the fragment, why? -> displayNameSubtype } - addons { + addons @include(if: $addonsFlagOn) { ...MoveAddonQuoteFragment } } @@ -50,7 +52,7 @@ fragment MoveIntentQuotesFragment on MoveIntent { productVariant { ...ProductVariantFragment } - addons { + addons @include(if: $addonsFlagOn) { ...MoveAddonQuoteFragment } } diff --git a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/data/MovingFlowQuotes.kt b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/data/MovingFlowQuotes.kt index 264e2f4a85..4127877620 100644 --- a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/data/MovingFlowQuotes.kt +++ b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/data/MovingFlowQuotes.kt @@ -100,7 +100,7 @@ internal fun MoveIntentQuotesFragment.toMovingFlowQuotes(): MovingFlowQuotes { ) }, defaultChoice = houseQuote.defaultChoice, - relatedAddonQuotes = houseQuote.addons.map { addon -> + relatedAddonQuotes = houseQuote.addons?.map { addon -> MovingFlowQuotes.AddonQuote( premium = UiMoney.fromMoneyFragment(addon.premium), startDate = addon.startDate, @@ -114,7 +114,7 @@ internal fun MoveIntentQuotesFragment.toMovingFlowQuotes(): MovingFlowQuotes { }, addonVariant = addon.addonVariant.toAddonVariant(), ) - }, + } ?: emptyList(), ) }, mtaQuotes = (mtaQuotes ?: emptyList()).map { mtaQuote -> @@ -124,7 +124,7 @@ internal fun MoveIntentQuotesFragment.toMovingFlowQuotes(): MovingFlowQuotes { productVariant = mtaQuote.productVariant.toProductVariant(), startDate = mtaQuote.startDate, displayItems = mtaQuote.displayItems.map { it.toDisplayItem() }, - relatedAddonQuotes = mtaQuote.addons.map { addon -> + relatedAddonQuotes = mtaQuote.addons?.map { addon -> MovingFlowQuotes.AddonQuote( premium = UiMoney.fromMoneyFragment(addon.premium), startDate = addon.startDate, @@ -138,7 +138,7 @@ internal fun MoveIntentQuotesFragment.toMovingFlowQuotes(): MovingFlowQuotes { }, addonVariant = addon.addonVariant.toAddonVariant(), ) - }, + } ?: emptyList(), ) }, ) diff --git a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/di/movingFlowModule.kt b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/di/movingFlowModule.kt index 2c3ed4028f..8329fa9508 100644 --- a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/di/movingFlowModule.kt +++ b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/di/movingFlowModule.kt @@ -11,6 +11,7 @@ import com.hedvig.android.feature.movingflow.ui.chosecoveragelevelanddeductible. import com.hedvig.android.feature.movingflow.ui.enternewaddress.EnterNewAddressViewModel import com.hedvig.android.feature.movingflow.ui.start.StartViewModel import com.hedvig.android.feature.movingflow.ui.summary.SummaryViewModel +import com.hedvig.android.featureflags.FeatureManager import org.koin.core.module.dsl.viewModel import org.koin.dsl.module @@ -29,13 +30,19 @@ val movingFlowModule = module { } viewModel { EnterNewAddressViewModel( - get(), - get(), - get(), + savedStateHandle = get(), + movingFlowRepository = get(), + apolloClient = get(), + featureManager = get(), ) } viewModel { - AddHouseInformationViewModel(get(), get(), get()) + AddHouseInformationViewModel( + savedStateHandle = get(), + movingFlowRepository = get(), + apolloClient = get(), + featureManager = get(), + ) } viewModel { ChoseCoverageLevelAndDeductibleViewModel(get()) diff --git a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/addhouseinformation/AddHouseInformationViewModel.kt b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/addhouseinformation/AddHouseInformationViewModel.kt index 86fdbeb54d..741eacaf32 100644 --- a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/addhouseinformation/AddHouseInformationViewModel.kt +++ b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/addhouseinformation/AddHouseInformationViewModel.kt @@ -50,9 +50,12 @@ import com.hedvig.android.feature.movingflow.ui.addhouseinformation.AddHouseInfo import com.hedvig.android.feature.movingflow.ui.addhouseinformation.AddHouseInformationUiState.Content.SubmittingInfoFailure.NetworkFailure import com.hedvig.android.feature.movingflow.ui.addhouseinformation.AddHouseInformationUiState.Loading import com.hedvig.android.feature.movingflow.ui.addhouseinformation.AddHouseInformationUiState.MissingOngoingMovingFlow +import com.hedvig.android.featureflags.FeatureManager +import com.hedvig.android.featureflags.flags.Feature import com.hedvig.android.molecule.android.MoleculeViewModel import com.hedvig.android.molecule.public.MoleculePresenter import com.hedvig.android.molecule.public.MoleculePresenterScope +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import octopus.feature.movingflow.MoveIntentV2RequestMutation import octopus.type.MoveApiVersion @@ -79,12 +82,14 @@ internal class AddHouseInformationViewModel( savedStateHandle: SavedStateHandle, movingFlowRepository: MovingFlowRepository, apolloClient: ApolloClient, + featureManager: FeatureManager, ) : MoleculeViewModel( AddHouseInformationUiState.Loading, AddHouseInformationPresenter( savedStateHandle.toRoute().moveIntentId, movingFlowRepository, apolloClient, + featureManager, ), ) @@ -92,6 +97,7 @@ internal class AddHouseInformationPresenter( private val moveIntentId: String, private val movingFlowRepository: MovingFlowRepository, private val apolloClient: ApolloClient, + private val featureManager: FeatureManager, ) : MoleculePresenter { @Composable override fun MoleculePresenterScope.present( @@ -156,8 +162,15 @@ internal class AddHouseInformationPresenter( LaunchedEffect(inputForSubmission) { @Suppress("NAME_SHADOWING") val inputForSubmissionValue = inputForSubmission ?: return@LaunchedEffect + val isAddonFlagEnabled = featureManager.isFeatureEnabled(Feature.TRAVEL_ADDON).first() apolloClient - .mutation(MoveIntentV2RequestMutation(moveIntentId, inputForSubmissionValue.moveIntentRequestInput)) + .mutation( + MoveIntentV2RequestMutation( + moveIntentId, + inputForSubmissionValue.moveIntentRequestInput, + isAddonFlagEnabled, + ), + ) .safeExecute() .map { it.moveIntentRequest } .fold( diff --git a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressViewModel.kt b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressViewModel.kt index 29e23a5810..f10d742509 100644 --- a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressViewModel.kt +++ b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressViewModel.kt @@ -52,10 +52,13 @@ import com.hedvig.android.feature.movingflow.ui.enternewaddress.EnterNewAddressV import com.hedvig.android.feature.movingflow.ui.enternewaddress.EnterNewAddressValidationError.InvalidPostalCode.Missing import com.hedvig.android.feature.movingflow.ui.enternewaddress.EnterNewAddressValidationError.InvalidPostalCode.MustBeOnlyDigits import com.hedvig.android.feature.movingflow.ui.enternewaddress.EnterNewAddressValidationError.InvalidSquareMeters +import com.hedvig.android.featureflags.FeatureManager +import com.hedvig.android.featureflags.flags.Feature import com.hedvig.android.molecule.android.MoleculeViewModel import com.hedvig.android.molecule.public.MoleculePresenter import com.hedvig.android.molecule.public.MoleculePresenterScope import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.datetime.LocalDate import octopus.feature.movingflow.MoveIntentV2RequestMutation @@ -70,12 +73,14 @@ internal class EnterNewAddressViewModel( savedStateHandle: SavedStateHandle, movingFlowRepository: MovingFlowRepository, apolloClient: ApolloClient, + featureManager: FeatureManager, ) : MoleculeViewModel( EnterNewAddressUiState.Loading, EnterNewAddressPresenter( savedStateHandle.toRoute().moveIntentId, movingFlowRepository, apolloClient, + featureManager, ), ) @@ -83,6 +88,7 @@ private class EnterNewAddressPresenter( private val moveIntentId: String, private val movingFlowRepository: MovingFlowRepository, private val apolloClient: ApolloClient, + private val featureManager: FeatureManager, ) : MoleculePresenter { @Composable override fun MoleculePresenterScope.present( @@ -157,8 +163,15 @@ private class EnterNewAddressPresenter( LaunchedEffect(inputForSubmission) { @Suppress("NAME_SHADOWING") val inputForSubmissionValue = inputForSubmission ?: return@LaunchedEffect + val isAddonFlagEnabled = featureManager.isFeatureEnabled(Feature.TRAVEL_ADDON).first() apolloClient - .mutation(MoveIntentV2RequestMutation(moveIntentId, inputForSubmissionValue.moveIntentRequestInput)) + .mutation( + MoveIntentV2RequestMutation( + intentId = moveIntentId, + moveIntentRequestInput = inputForSubmissionValue.moveIntentRequestInput, + addonsFlagOn = isAddonFlagEnabled, + ), + ) .safeExecute() .map { it.moveIntentRequest } .fold(