From 4928eceaae478293f8f061b855f709b45132b96a Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 15:10:26 +0100 Subject: [PATCH 01/42] add new module --- .../android/app/navigation/HedvigNavHost.kt | 1 + app/feature/feature-chip-id/build.gradle.kts | 29 ++++++++++ .../src/graphql/UpdateChipIdMutation.graphql | 0 .../src/main/AndroidManifest.xml | 2 + .../feature/chip/id/ui/AddChipIdScreen.kt | 8 +++ .../data/GetInsuranceContractsUseCase.kt | 7 +++ .../data/GetInsuranceContractsUseCaseDemo.kt | 1 + .../insurances/data/InsuranceContract.kt | 10 ++++ .../insurance/InsuranceDestination.kt | 3 + .../ContractDetailDestination.kt | 11 ++++ .../UpcomingChangesBottomSheetContent.kt | 1 + .../insurancedetail/yourinfo/YourInfoTab.kt | 56 +++++++++++++++++++ .../insurances/navigation/InsuranceGraph.kt | 2 + .../TerminatedContractsDestination.kt | 2 + .../lint-baseline-feature-chip-id.xml | 51 +++++++++++++++++ 15 files changed, 184 insertions(+) create mode 100644 app/feature/feature-chip-id/build.gradle.kts create mode 100644 app/feature/feature-chip-id/src/graphql/UpdateChipIdMutation.graphql create mode 100644 app/feature/feature-chip-id/src/main/AndroidManifest.xml create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt create mode 100644 hedvig-lint/lint-baseline/lint-baseline-feature-chip-id.xml diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index cce68da7c4..dbd96f200d 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -329,6 +329,7 @@ internal fun HedvigNavHost( ), ) }, + navigateToChipIdScreen = TODO(), ) foreverGraph( hedvigDeepLinkContainer = hedvigDeepLinkContainer, diff --git a/app/feature/feature-chip-id/build.gradle.kts b/app/feature/feature-chip-id/build.gradle.kts new file mode 100644 index 0000000000..cac9669c29 --- /dev/null +++ b/app/feature/feature-chip-id/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + id("hedvig.android.library") + id("hedvig.gradle.plugin") +} + +hedvig { + apollo("octopus") + serialization() + compose() +} + +dependencies { + api(libs.androidx.navigation.common) + + implementation(libs.androidx.navigation.compose) + implementation(libs.apollo.runtime) + implementation(libs.arrow.core) + implementation(libs.coroutines.core) + implementation(libs.jetbrains.lifecycle.runtime.compose) + implementation(libs.koin.composeViewModel) + implementation(libs.kotlinx.datetime) + implementation(libs.kotlinx.serialization.core) + implementation(projects.apolloCore) + implementation(projects.apolloOctopusPublic) + implementation(projects.composeUi) + implementation(projects.coreCommonPublic) + implementation(projects.coreResources) + implementation(projects.coreUiData) +} diff --git a/app/feature/feature-chip-id/src/graphql/UpdateChipIdMutation.graphql b/app/feature/feature-chip-id/src/graphql/UpdateChipIdMutation.graphql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/feature/feature-chip-id/src/main/AndroidManifest.xml b/app/feature/feature-chip-id/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..568741e54f --- /dev/null +++ b/app/feature/feature-chip-id/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt new file mode 100644 index 0000000000..ebce366764 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -0,0 +1,8 @@ +package com.hedvig.android.feature.chip.id.ui + +import androidx.compose.runtime.Composable + +@Composable +internal fun AddChipIdScreen() { +//todo +} diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt index 478ed902a8..51ab14f3f1 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt @@ -12,7 +12,9 @@ import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.core.common.formatName import com.hedvig.android.core.common.formatSsn import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractId +import com.hedvig.android.data.contract.toContractGroup import com.hedvig.android.data.display.items.DisplayItem import com.hedvig.android.data.productvariant.toAddonVariant import com.hedvig.android.data.productvariant.toProductVariant @@ -139,6 +141,7 @@ private fun InsuranceContractsQuery.Data.CurrentMember.PendingContract.toPending }, cost = this.cost.toMonthlyCost(), basePremium = UiMoney.fromMoneyFragment(this.basePremium), + chipId = ChipIdState.NotRequired ) } @@ -226,6 +229,10 @@ private fun ContractFragment.toContract( description = it.description, ) }.orEmpty(), + chipId = when (currentAgreement.productVariant.typeOfContract.toContractGroup()) { + ContractGroup.CAT, ContractGroup.DOG -> ChipIdState.Missing //todo!!! + else -> ChipIdState.NotRequired + } ) } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt index bcd09c12f8..8def8d5ded 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt @@ -91,6 +91,7 @@ internal class GetInsuranceContractsUseCaseDemo : GetInsuranceContractsUseCase { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.NotRequired ), ).right(), ) diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt index 4d914ffbe5..2a556c57cc 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt @@ -37,6 +37,8 @@ sealed interface InsuranceContract { val basePremium: UiMoney + val chipId: ChipIdState + data class EstablishedInsuranceContract( override val id: String, override val displayName: String, @@ -56,6 +58,7 @@ sealed interface InsuranceContract { override val tierName: String?, override val existingAddons: List, override val availableAddons: List, + override val chipId: ChipIdState, ) : InsuranceContract { override val productVariant: ProductVariant = currentInsuranceAgreement.productVariant override val displayItems: List = currentInsuranceAgreement.displayItems @@ -81,6 +84,7 @@ sealed interface InsuranceContract { override val addons: List?, override val cost: MonthlyCost, override val basePremium: UiMoney, + override val chipId: ChipIdState, ) : InsuranceContract { override val coInsured: List = listOf() override val coOwners: List = listOf() @@ -96,6 +100,12 @@ sealed interface InsuranceContract { } } +sealed interface ChipIdState { + data object Missing: ChipIdState + data object NotRequired: ChipIdState + data class Present(val value: String): ChipIdState +} + data class Addon( val addonVariant: AddonVariant, val premium: UiMoney, diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt index d6d5e01def..72a4d20354 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt @@ -74,6 +74,7 @@ import com.hedvig.android.design.system.hedvig.NotificationDefaults.Notification import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.hedvigDropShadow import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader +import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceContract import com.hedvig.android.feature.insurances.data.InsuranceContract.EstablishedInsuranceContract @@ -689,6 +690,7 @@ private val previewPendingContract = InsuranceContract.PendingInsuranceContract( UiMoney(89.0, UiCurrencyCode.SEK), discounts = emptyList(), ), + chipId = ChipIdState.NotRequired ) private val previewInsurance = EstablishedInsuranceContract( @@ -737,4 +739,5 @@ private val previewInsurance = EstablishedInsuranceContract( supportsTierChange = true, existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ) diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt index 921a116e8a..a131bc560b 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt @@ -69,6 +69,7 @@ import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader import com.hedvig.android.feature.insurances.data.Addon import com.hedvig.android.feature.insurances.data.AvailableAddon import com.hedvig.android.feature.insurances.data.CancelInsuranceData +import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceAgreement.CreationCause.NEW_CONTRACT import com.hedvig.android.feature.insurances.data.InsuranceContract @@ -111,6 +112,7 @@ internal fun ContractDetailDestination( navigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, navigateToAddAddon: (AvailableAddon) -> Unit, + navigateToChipIdScreen: (contractId: String) -> Unit, ) { val uiState: ContractDetailsUiState by viewModel.uiState.collectAsStateWithLifecycle() ContractDetailScreen( @@ -131,6 +133,7 @@ internal fun ContractDetailDestination( navigateToAddAddon = navigateToAddAddon, navigateToRemoveAddon = navigateToRemoveAddon, navigateToUpgradeAddon = navigateToUpgradeAddon, + navigateToChipIdScreen = navigateToChipIdScreen ) } @@ -153,6 +156,7 @@ private fun ContractDetailScreen( openUrl: (String) -> Unit, navigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, + navigateToChipIdScreen: (String) -> Unit, navigateToAddAddon: (AvailableAddon) -> Unit, ) { Column(Modifier.fillMaxSize()) { @@ -358,6 +362,10 @@ private fun ContractDetailScreen( navigateToAddAddon = navigateToAddAddon, navigateToRemoveAddon = navigateToRemoveAddon, navigateToUpgradeAddon = navigateToUpgradeAddon, + chipIdState = contract.chipId, + onFillChipId = { + navigateToChipIdScreen(contract.id) + } ) } @@ -495,6 +503,7 @@ private fun PreviewContractDetailScreen() { supportsTierChange = true, existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), true, ), @@ -515,6 +524,7 @@ private fun PreviewContractDetailScreen() { navigateToAddAddon = {}, navigateToRemoveAddon = { _, _ -> }, navigateToUpgradeAddon = { _, _ -> }, + navigateToChipIdScreen = {} ) } } @@ -544,6 +554,7 @@ private fun PreviewContractDetailScreenFailure() { navigateToAddAddon = {}, navigateToRemoveAddon = { _, _ -> }, navigateToUpgradeAddon = { _, _ -> }, + navigateToChipIdScreen = {} ) } } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt index fa475ab710..ca2a9d7eb0 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt @@ -31,6 +31,7 @@ import com.hedvig.android.design.system.hedvig.NotificationDefaults.Notification import com.hedvig.android.design.system.hedvig.PriceInfoForBottomSheet import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState +import com.hedvig.android.feature.insurances.data.ChipIdState import hedvig.resources.CONTRACT_VIEW_CERTIFICATE_BUTTON import hedvig.resources.Res import hedvig.resources.general_close_button diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index 5cc4c14c14..dd12303891 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -79,6 +79,7 @@ import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.design.system.hedvig.rememberHedvigDateTimeFormatter import com.hedvig.android.design.system.hedvig.show import com.hedvig.android.feature.insurances.data.AvailableAddon +import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.ContractAddon import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceAgreement.CoInsured @@ -137,6 +138,7 @@ internal fun YourInfoTab( onChangeTierClick: () -> Unit, isDecommissioned: Boolean, upcomingChangesInsuranceAgreement: InsuranceAgreement?, + chipIdState: ChipIdState, onEditCoInsuredClick: () -> Unit, onEditCoOwnersClick: () -> Unit, onMissingCoInsuredInfoClick: () -> Unit, @@ -145,6 +147,7 @@ internal fun YourInfoTab( onNavigateToNewConversation: () -> Unit, openUrl: (String) -> Unit, onCancelInsuranceClick: () -> Unit, + onFillChipId: () -> Unit, isTerminated: Boolean, contractHolderDisplayName: String, contractHolderSSN: String?, @@ -300,6 +303,12 @@ internal fun YourInfoTab( onInfoIconClick, Modifier.padding(horizontal = 16.dp), ) + if (chipIdState is ChipIdState.Present) { + ChipIdRow( + chipIdState.value, + Modifier.padding(horizontal = 16.dp), + ) + } if (allowEditCoInsured && coInsured.isNotEmpty()) { HorizontalDivider(Modifier.padding(horizontal = 16.dp)) Spacer(Modifier.height(16.dp)) @@ -384,6 +393,17 @@ internal fun YourInfoTab( .fillMaxWidth(), ) } + if (chipIdState is ChipIdState.Missing) { + HedvigButton( + text = "Fill missing chipId", //todo!!! + buttonStyle = Ghost, + enabled = true, + onClick = { onFillChipId() }, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + } } } } @@ -715,6 +735,40 @@ internal fun PriceRow( ) } +@Composable +internal fun ChipIdRow( + chipId: String, + modifier: Modifier = Modifier, +) { + HorizontalItemsWithMaximumSpaceTaken( + modifier = modifier.horizontalDivider(DividerPosition.Top), + startSlot = { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(vertical = 16.dp), + ) { + HedvigText( + "Pet Chip-ID" //todo!!! + ) + } + }, + endSlot = { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.End, + modifier = Modifier.padding(vertical = 16.dp), + ) { + HedvigText( + text = chipId, + color = HedvigTheme.colorScheme.textSecondary, + textAlign = TextAlign.End, + ) + } + }, + spaceBetween = 8.dp, + ) +} + @Composable internal fun CoInsuredSection( coInsuredList: List, @@ -1007,6 +1061,8 @@ private fun PreviewYourInfoTab() { navigateToRemoveAddon = { _, _ -> }, navigateToUpgradeAddon = { _, _ -> }, navigateToAddAddon = {}, + chipIdState = ChipIdState.Present("12345678903456"), + onFillChipId = {} ) } } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt index 68c771b0cc..a0ae7e70a2 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt @@ -40,6 +40,7 @@ fun NavGraphBuilder.insuranceGraph( onNavigateToAddonPurchaseFlow: (List, AvailableAddon?) -> Unit, onNavigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, + navigateToChipIdScreen: (String) -> Unit, ) { navgraph( startDestination = InsurancesDestination.Insurances::class, @@ -98,6 +99,7 @@ fun NavGraphBuilder.insuranceGraph( navigateToAddAddon = { availableAddon -> onNavigateToAddonPurchaseFlow(listOf(availableAddon.relatedContractId), availableAddon) }, + navigateToChipIdScreen = navigateToChipIdScreen ) } navdestination { diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt index 93f7a883ca..85216b41d8 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt @@ -26,6 +26,7 @@ import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.InsuranceCard import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader +import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceContract.EstablishedInsuranceContract import com.hedvig.android.feature.insurances.data.MonthlyCost @@ -178,6 +179,7 @@ private class PreviewTerminatedContractsUiStateProvider : supportsTierChange = false, existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), ), ), diff --git a/hedvig-lint/lint-baseline/lint-baseline-feature-chip-id.xml b/hedvig-lint/lint-baseline/lint-baseline-feature-chip-id.xml new file mode 100644 index 0000000000..249a9d603a --- /dev/null +++ b/hedvig-lint/lint-baseline/lint-baseline-feature-chip-id.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + From a3f3ba46c3cb593fcaa3e27418519e2bf7ebb8ea Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 15:29:55 +0100 Subject: [PATCH 02/42] add structure and navigation --- app/app/build.gradle.kts | 1 + .../android/app/di/ApplicationModule.kt | 2 + .../android/app/navigation/HedvigNavHost.kt | 9 +++- app/feature/feature-chip-id/build.gradle.kts | 5 ++ .../feature/chip/id/di/ChipIdModule.kt | 11 ++++ .../feature/chip/id/navigation/ChipIdGraph.kt | 24 +++++++++ .../id/navigation/ChipIdNavDestination.kt | 20 +++++++ .../feature/chip/id/ui/AddChipIdScreen.kt | 54 ++++++++++++++++++- .../feature/chip/id/ui/AddChipIdViewModel.kt | 51 ++++++++++++++++++ 9 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt diff --git a/app/app/build.gradle.kts b/app/app/build.gradle.kts index 0dd224a104..8b6925da8b 100644 --- a/app/app/build.gradle.kts +++ b/app/app/build.gradle.kts @@ -184,6 +184,7 @@ dependencies { implementation(projects.designSystemInternals) implementation(projects.featureAddonPurchase) implementation(projects.featureChat) + implementation(projects.featureChipId) implementation(projects.featureChooseTier) implementation(projects.featureClaimChat) implementation(projects.featureClaimDetails) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/di/ApplicationModule.kt b/app/app/src/main/kotlin/com/hedvig/android/app/di/ApplicationModule.kt index 60842d8c39..f64939d278 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/di/ApplicationModule.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/di/ApplicationModule.kt @@ -66,6 +66,7 @@ import com.hedvig.android.design.system.hedvig.pdfrenderer.PdfDecoder import com.hedvig.android.feature.addon.purchase.di.addonPurchaseModule import com.hedvig.android.feature.change.tier.di.chooseTierModule import com.hedvig.android.feature.chat.di.chatModule +import com.hedvig.android.feature.chip.id.di.chipIdModule import com.hedvig.android.feature.claim.details.di.claimDetailsModule import com.hedvig.android.feature.claimhistory.di.claimHistoryModule import com.hedvig.android.feature.claimtriaging.di.claimTriagingModule @@ -298,6 +299,7 @@ val applicationModule = module { authModule, buildConstantsModule, chatModule, + chipIdModule, chooseTierModule, claimChatModule, claimDetailsModule, diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index dbd96f200d..ccea92d5e2 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -25,6 +25,8 @@ import com.hedvig.android.feature.change.tier.navigation.InsuranceCustomizationP import com.hedvig.android.feature.change.tier.navigation.StartTierFlowChooseInsuranceDestination import com.hedvig.android.feature.change.tier.navigation.StartTierFlowDestination import com.hedvig.android.feature.change.tier.navigation.changeTierGraph +import com.hedvig.android.feature.chip.id.navigation.ChipIdGraphDestination +import com.hedvig.android.feature.chip.id.navigation.chipIdGraph import com.hedvig.android.feature.chat.navigation.ChatDestination import com.hedvig.android.feature.chat.navigation.ChatDestinations import com.hedvig.android.feature.chat.navigation.cbmChatGraph @@ -329,7 +331,9 @@ internal fun HedvigNavHost( ), ) }, - navigateToChipIdScreen = TODO(), + navigateToChipIdScreen = { contractId: String -> + navController.navigate(ChipIdGraphDestination(contractId)) + }, ) foreverGraph( hedvigDeepLinkContainer = hedvigDeepLinkContainer, @@ -413,6 +417,9 @@ internal fun HedvigNavHost( hedvigDeepLinkContainer = hedvigDeepLinkContainer, onNavigateToNewConversation = ::navigateToNewConversation, ) + chipIdGraph( + navigateUp = navController::navigateUp, + ) movingFlowGraph( navController = navController, goToChat = ::navigateToNewConversation, diff --git a/app/feature/feature-chip-id/build.gradle.kts b/app/feature/feature-chip-id/build.gradle.kts index cac9669c29..5bee08e070 100644 --- a/app/feature/feature-chip-id/build.gradle.kts +++ b/app/feature/feature-chip-id/build.gradle.kts @@ -26,4 +26,9 @@ dependencies { implementation(projects.coreCommonPublic) implementation(projects.coreResources) implementation(projects.coreUiData) + implementation(projects.designSystemHedvig) + implementation(projects.moleculePublic) + implementation(projects.navigationCommon) + implementation(projects.navigationCompose) + implementation(projects.navigationComposeTyped) } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt new file mode 100644 index 0000000000..a3a6fed5b3 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt @@ -0,0 +1,11 @@ +package com.hedvig.android.feature.chip.id.di + +import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module + +val chipIdModule = module { + viewModel { + AddChipIdViewModel() + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt new file mode 100644 index 0000000000..f5a62ac5c5 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -0,0 +1,24 @@ +package com.hedvig.android.feature.chip.id.navigation + +import androidx.navigation.NavGraphBuilder +import com.hedvig.android.feature.chip.id.ui.AddChipIdDestination +import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel +import com.hedvig.android.navigation.compose.navdestination +import com.hedvig.android.navigation.compose.navgraph +import org.koin.compose.viewmodel.koinViewModel + +fun NavGraphBuilder.chipIdGraph( + navigateUp: () -> Unit, +) { + navgraph( + startDestination = ChipIdDestination.AddChipId::class, + ) { + navdestination { _ -> + val viewModel: AddChipIdViewModel = koinViewModel() + AddChipIdDestination( + viewModel = viewModel, + navigateUp = navigateUp, + ) + } + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt new file mode 100644 index 0000000000..ace86983d0 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt @@ -0,0 +1,20 @@ +package com.hedvig.android.feature.chip.id.navigation + +import com.hedvig.android.navigation.common.Destination +import com.hedvig.android.navigation.common.DestinationNavTypeAware +import kotlin.reflect.KType +import kotlin.reflect.typeOf +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ChipIdGraphDestination(val contractId: String) : Destination { + companion object : DestinationNavTypeAware { + override val typeList: List = listOf(typeOf()) + } +} + +internal sealed interface ChipIdDestination { + @Serializable + data object AddChipId : ChipIdDestination, Destination +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index ebce366764..5a3547db6e 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -1,8 +1,58 @@ package com.hedvig.android.feature.chip.id.ui +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress +import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText @Composable -internal fun AddChipIdScreen() { -//todo +internal fun AddChipIdDestination( + viewModel: AddChipIdViewModel, + navigateUp: () -> Unit, +) { + val uiState: AddChipIdUiState by viewModel.uiState.collectAsStateWithLifecycle() + AddChipIdScreen( + uiState = uiState, + navigateUp = navigateUp, + reload = { + viewModel.emit(AddChipIdEvent.Reload) + }, + ) +} + +@Composable +private fun AddChipIdScreen( + uiState: AddChipIdUiState, + navigateUp: () -> Unit, + reload: () -> Unit, +) { + when (uiState) { + AddChipIdUiState.Loading -> { + HedvigFullScreenCenterAlignedProgress() + } + + AddChipIdUiState.Content -> { + HedvigScaffold(navigateUp = navigateUp) { + Column(Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + HedvigText( "Chip id content") + } + } + } + + is AddChipIdUiState.Failure -> { + HedvigScaffold(navigateUp = navigateUp) { + // TODO: Add error UI here + } + } + } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt new file mode 100644 index 0000000000..3fec2035d1 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -0,0 +1,51 @@ +package com.hedvig.android.feature.chip.id.ui + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import com.hedvig.android.molecule.public.MoleculePresenter +import com.hedvig.android.molecule.public.MoleculePresenterScope +import com.hedvig.android.molecule.public.MoleculeViewModel + +internal class AddChipIdViewModel : MoleculeViewModel( + initialState = AddChipIdUiState.Loading, + presenter = AddChipIdPresenter(), +) + +internal class AddChipIdPresenter : MoleculePresenter { + @Composable + override fun MoleculePresenterScope.present( + lastState: AddChipIdUiState, + ): AddChipIdUiState { + var currentState by remember { mutableStateOf(lastState) } + var loadIteration by remember { mutableIntStateOf(0) } + + LaunchedEffect(loadIteration) { + currentState = AddChipIdUiState.Loading + // TODO: Load chip ID data here + currentState = AddChipIdUiState.Content + } + + CollectEvents { event -> + when (event) { + AddChipIdEvent.Reload -> loadIteration++ + } + } + + return currentState + } +} + +internal sealed interface AddChipIdUiState { + data object Loading : AddChipIdUiState + data object Content : AddChipIdUiState + data class Failure(val message: String) : AddChipIdUiState +} + +internal sealed interface AddChipIdEvent { + data object Reload : AddChipIdEvent +} From ed684da389cf82e7be258a0286b91aea6570674f Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 15:40:51 +0100 Subject: [PATCH 03/42] move button to bottom sheet --- .../EditInsuranceBottomSheetContent.kt | 17 ++++++++++++ .../insurancedetail/yourinfo/YourInfoTab.kt | 27 +++++++++---------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt index 705cec954c..63736770ac 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt @@ -53,12 +53,14 @@ internal fun EditInsuranceBottomSheetContent( allowChangeTier: Boolean, allowTerminatingInsurance: Boolean, allowRemovingAddon: Boolean, + missingChipId: Boolean, onEditCoInsuredClick: () -> Unit, onEditCoOwnersClick: () -> Unit, onChangeTierClick: () -> Unit, onCancelInsuranceClick: () -> Unit, onRemoveAddonClick: () -> Unit, onDismiss: () -> Unit, + onNavigateToChipId: () -> Unit, modifier: Modifier = Modifier, ) { var selectedItemId: String? by rememberSaveable { mutableStateOf(null) } @@ -108,6 +110,15 @@ internal fun EditInsuranceBottomSheetContent( ), ) } + if (missingChipId) { + add( + RadioOption( + RadioOptionId("5"), + "Add missing chip id for your pet", //todo! + "Speed up any potential claims", //todo + ), + ) + } } Column( modifier = modifier, @@ -151,6 +162,10 @@ internal fun EditInsuranceBottomSheetContent( "4" if allowRemovingAddon -> { onRemoveAddonClick() } + + "5" if missingChipId -> { + onNavigateToChipId() + } else -> {} } @@ -187,6 +202,8 @@ private fun PreviewEditInsuranceBottomSheetContent() { onCancelInsuranceClick = {}, onRemoveAddonClick = {}, modifier = Modifier.padding(horizontal = 16.dp), + missingChipId = true, + onNavigateToChipId = {}, ) } } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index dd12303891..906ff0f38f 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -193,6 +193,11 @@ internal fun YourInfoTab( editYourInfoBottomSheet.dismiss() navigateToRemoveAddon(ContractId(contractId), null) }, + missingChipId = chipIdState is ChipIdState.Missing, + onNavigateToChipId = { + editYourInfoBottomSheet.dismiss() + onFillChipId() + }, ) } @@ -371,7 +376,12 @@ internal fun YourInfoTab( ) if (!isTerminated) { Column(Modifier.padding(bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { - if (allowEditCoInsured || allowEditCoOwners || allowChangeTier || allowTerminatingInsurance) { + if (allowEditCoInsured || + allowEditCoOwners || + allowChangeTier || + allowTerminatingInsurance || + chipIdState is ChipIdState.Missing + ) { HedvigButton( text = stringResource(Res.string.CONTRACT_EDIT_INFO_LABEL), enabled = true, @@ -393,17 +403,6 @@ internal fun YourInfoTab( .fillMaxWidth(), ) } - if (chipIdState is ChipIdState.Missing) { - HedvigButton( - text = "Fill missing chipId", //todo!!! - buttonStyle = Ghost, - enabled = true, - onClick = { onFillChipId() }, - modifier = Modifier - .padding(horizontal = 16.dp) - .fillMaxWidth(), - ) - } } } } @@ -748,7 +747,7 @@ internal fun ChipIdRow( modifier = Modifier.padding(vertical = 16.dp), ) { HedvigText( - "Pet Chip-ID" //todo!!! + "Pet Chip-ID", //todo!!! ) } }, @@ -1062,7 +1061,7 @@ private fun PreviewYourInfoTab() { navigateToUpgradeAddon = { _, _ -> }, navigateToAddAddon = {}, chipIdState = ChipIdState.Present("12345678903456"), - onFillChipId = {} + onFillChipId = {}, ) } } From d84b2a20a79e20f3d2203c55f489372421fe6f14 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 15:47:40 +0100 Subject: [PATCH 04/42] add content and error --- .../feature/chip/id/ui/AddChipIdScreen.kt | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 5a3547db6e..18828ab1fc 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -3,11 +3,13 @@ package com.hedvig.android.feature.chip.id.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.hedvig.android.design.system.hedvig.HedvigErrorSection import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress import com.hedvig.android.design.system.hedvig.HedvigScaffold import com.hedvig.android.design.system.hedvig.HedvigText @@ -39,20 +41,33 @@ private fun AddChipIdScreen( } AddChipIdUiState.Content -> { - HedvigScaffold(navigateUp = navigateUp) { - Column(Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - HedvigText( "Chip id content") - } - } + AddChipIdContent(navigateUp) } is AddChipIdUiState.Failure -> { - HedvigScaffold(navigateUp = navigateUp) { - // TODO: Add error UI here + HedvigScaffold(navigateUp = navigateUp, + Modifier.fillMaxSize()) { + HedvigErrorSection( + onButtonClick = reload, + modifier = Modifier + .weight(1f) + .wrapContentHeight(), + ) } } } } + +@Composable +internal fun AddChipIdContent( + navigateUp: () -> Unit, +) { + HedvigScaffold(navigateUp = navigateUp) { + Column(Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + TODO() + } + } +} From 1d0161a5d45206e002b9490d089148219a28014e Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 16:18:22 +0100 Subject: [PATCH 05/42] check input etc --- .../android/app/navigation/HedvigNavHost.kt | 2 + .../chip/id/data/UpdateChipIdUseCase.kt | 28 +++ .../feature/chip/id/di/ChipIdModule.kt | 16 +- .../feature/chip/id/navigation/ChipIdGraph.kt | 19 +- .../id/navigation/ChipIdNavDestination.kt | 1 - .../feature/chip/id/ui/AddChipIdScreen.kt | 193 +++++++++++++++--- .../feature/chip/id/ui/AddChipIdViewModel.kt | 105 ++++++++-- 7 files changed, 318 insertions(+), 46 deletions(-) create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index ccea92d5e2..c8f6510675 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -418,6 +418,8 @@ internal fun HedvigNavHost( onNavigateToNewConversation = ::navigateToNewConversation, ) chipIdGraph( + navController = navController, + globalSnackBarState = globalSnackBarState, navigateUp = navController::navigateUp, ) movingFlowGraph( diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt new file mode 100644 index 0000000000..480490ee73 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt @@ -0,0 +1,28 @@ +package com.hedvig.android.feature.chip.id.data + +import arrow.core.Either +import arrow.core.raise.context.either +import arrow.core.raise.context.raise +import com.apollographql.apollo.ApolloClient +import com.hedvig.android.core.common.ErrorMessage + +internal interface UpdateChipIdUseCase { + suspend fun invoke(insuranceId: String): Either +} + +internal class UpdateChipIdUseCaseImpl( + private val apolloClient: ApolloClient, +) : UpdateChipIdUseCase { + override suspend fun invoke(insuranceId: String): Either { + return either { + // raise(ErrorMessage()) + } + // TODO: Implement actual mutation call + // return apolloClient.mutation(UpdateChipIdMutation(insuranceId)) + // .execute() + // .fold( + // ifLeft = { Either.left(ErrorMessage()) }, + // ifRight = { Either.right(Unit) } + // ) + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt index a3a6fed5b3..464f24645e 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt @@ -1,11 +1,23 @@ package com.hedvig.android.feature.chip.id.di +import com.apollographql.apollo.ApolloClient +import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase +import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCaseImpl import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel import org.koin.core.module.dsl.viewModel import org.koin.dsl.module val chipIdModule = module { - viewModel { - AddChipIdViewModel() + single { + UpdateChipIdUseCaseImpl( + apolloClient = get(), + ) + } + + viewModel { params -> + AddChipIdViewModel( + updateChipIdUseCase = get(), + insuranceId = params.get(), + ) } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index f5a62ac5c5..0b2c07dc82 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -1,23 +1,38 @@ package com.hedvig.android.feature.chip.id.navigation +import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder +import com.hedvig.android.design.system.hedvig.GlobalSnackBarState import com.hedvig.android.feature.chip.id.ui.AddChipIdDestination import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel import com.hedvig.android.navigation.compose.navdestination import com.hedvig.android.navigation.compose.navgraph +import com.hedvig.android.navigation.compose.typed.getRouteFromBackStack import org.koin.compose.viewmodel.koinViewModel +import org.koin.core.parameter.parametersOf fun NavGraphBuilder.chipIdGraph( + navController: NavController, + globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, ) { navgraph( startDestination = ChipIdDestination.AddChipId::class, + destinationNavTypeAware = ChipIdGraphDestination, ) { - navdestination { _ -> - val viewModel: AddChipIdViewModel = koinViewModel() + navdestination { backStackEntry -> + val chipIdGraphDestination = navController + .getRouteFromBackStack(backStackEntry) + val viewModel: AddChipIdViewModel = koinViewModel { + parametersOf(chipIdGraphDestination.contractId) + } AddChipIdDestination( viewModel = viewModel, + globalSnackBarState = globalSnackBarState, navigateUp = navigateUp, + popBackStack = { + navController.popBackStack() + }, ) } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt index ace86983d0..e2a538b2a3 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt @@ -4,7 +4,6 @@ import com.hedvig.android.navigation.common.Destination import com.hedvig.android.navigation.common.DestinationNavTypeAware import kotlin.reflect.KType import kotlin.reflect.typeOf -import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 18828ab1fc..48a4f22883 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -1,30 +1,77 @@ package com.hedvig.android.feature.chip.id.ui -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState +import androidx.compose.foundation.layout.ColumnScope +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.wrapContentHeight +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.InputTransformation +import androidx.compose.foundation.text.input.KeyboardActionHandler +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.text.input.byValue +import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusManager +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.hedvig.android.design.system.hedvig.GlobalSnackBarState +import com.hedvig.android.design.system.hedvig.HedvigButton import com.hedvig.android.design.system.hedvig.HedvigErrorSection -import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress +import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgressDebounced +import com.hedvig.android.design.system.hedvig.HedvigNotificationCard import com.hedvig.android.design.system.hedvig.HedvigScaffold -import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTextField +import com.hedvig.android.design.system.hedvig.HedvigTextFieldDefaults +import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority +import com.hedvig.android.design.system.hedvig.clearFocusOnTap +import com.hedvig.android.feature.chip.id.ui.AddChipIdEvent.RetryLoadData +import com.hedvig.android.feature.chip.id.ui.AddChipIdEvent.SubmitData +import com.hedvig.android.feature.chip.id.ui.AddChipIdUiState.Content +import hedvig.resources.CONTACT_INFO_CHANGES_SAVED +import hedvig.resources.Res +import hedvig.resources.general_save_button +import org.jetbrains.compose.resources.stringResource @Composable internal fun AddChipIdDestination( viewModel: AddChipIdViewModel, + globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, + popBackStack: () -> Unit, ) { val uiState: AddChipIdUiState by viewModel.uiState.collectAsStateWithLifecycle() AddChipIdScreen( uiState = uiState, - navigateUp = navigateUp, + globalSnackBarState = globalSnackBarState, + submitChipId = { + viewModel.emit(SubmitData) + }, reload = { - viewModel.emit(AddChipIdEvent.Reload) + viewModel.emit(RetryLoadData) + }, + navigateUp = navigateUp, + showedSnackBar = { + viewModel.emit(AddChipIdEvent.ShowedMessage) + popBackStack() }, ) } @@ -32,21 +79,30 @@ internal fun AddChipIdDestination( @Composable private fun AddChipIdScreen( uiState: AddChipIdUiState, - navigateUp: () -> Unit, + globalSnackBarState: GlobalSnackBarState, + submitChipId: () -> Unit, reload: () -> Unit, + navigateUp: () -> Unit, + showedSnackBar: () -> Unit, ) { - when (uiState) { - AddChipIdUiState.Loading -> { - HedvigFullScreenCenterAlignedProgress() - } - - AddChipIdUiState.Content -> { - AddChipIdContent(navigateUp) - } + val focusManager = LocalFocusManager.current + HedvigScaffold( + topAppBarText = "Update pet Chip-ID", //todo + navigateUp = navigateUp, + modifier = Modifier + .fillMaxSize() + .clearFocusOnTap(), + ) { + when (uiState) { + AddChipIdUiState.Loading -> { + HedvigFullScreenCenterAlignedProgressDebounced( + Modifier + .weight(1f) + .wrapContentHeight(), + ) + } - is AddChipIdUiState.Failure -> { - HedvigScaffold(navigateUp = navigateUp, - Modifier.fillMaxSize()) { + AddChipIdUiState.Error -> { HedvigErrorSection( onButtonClick = reload, modifier = Modifier @@ -54,20 +110,103 @@ private fun AddChipIdScreen( .wrapContentHeight(), ) } + + is Content -> { + AddChipIdContent( + uiState = uiState, + globalSnackBarState = globalSnackBarState, + submitChipId = submitChipId, + focusManager = focusManager, + showedSnackBar = showedSnackBar, + ) + } } } } @Composable -internal fun AddChipIdContent( - navigateUp: () -> Unit, +private fun ColumnScope.AddChipIdContent( + uiState: Content, + globalSnackBarState: GlobalSnackBarState, + submitChipId: () -> Unit, + focusManager: FocusManager, + showedSnackBar: () -> Unit, ) { - HedvigScaffold(navigateUp = navigateUp) { - Column(Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - TODO() + val successMessage = stringResource(Res.string.CONTACT_INFO_CHANGES_SAVED) + LaunchedEffect(uiState.showSuccessSnackBar) { + if (!uiState.showSuccessSnackBar) return@LaunchedEffect + globalSnackBarState.show(successMessage, NotificationPriority.Campaign) + showedSnackBar() + } + + Spacer(Modifier.weight(1f)) + Spacer(Modifier.height(16.dp)) + + ChipIdTextField( + textFieldState = uiState.chipIdState, + labelText = "Chip ID", + keyboardActionHandler = KeyboardActionHandler { + submitChipId() + focusManager.clearFocus() + }, + ) + + AnimatedContent( + targetState = uiState.errorSnackBarText, + transitionSpec = { fadeIn() + expandVertically() togetherWith fadeOut() + shrinkVertically() }, + modifier = Modifier.padding(top = 4.dp), + ) { errorText -> + if (errorText != null) { + HedvigNotificationCard( + message = errorText, + priority = NotificationPriority.Error, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) } } + + Spacer(Modifier.height(16.dp)) + HedvigButton( + text = stringResource(Res.string.general_save_button), + enabled = !uiState.submittingData, + onClick = { + focusManager.clearFocus() + submitChipId() + }, + isLoading = uiState.submittingData, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxSize(), + ) + Spacer(Modifier.height(16.dp)) +} + +@Composable +private fun ChipIdTextField( + textFieldState: TextFieldState, + labelText: String, + keyboardActionHandler: KeyboardActionHandler?, +) { + val interactionSource = remember { MutableInteractionSource() } + val digitsOnlyTransformation = InputTransformation.byValue { _, proposed -> + proposed.filter { it.isDigit() } + } + HedvigTextField( + state = textFieldState, + labelText = labelText, + errorState = HedvigTextFieldDefaults.ErrorState.NoError, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Done, + ), + inputTransformation = digitsOnlyTransformation, + keyboardActions = keyboardActionHandler, + textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, + interactionSource = interactionSource, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 3fec2035d1..872065d241 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -1,5 +1,7 @@ package com.hedvig.android.feature.chip.id.ui +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -7,45 +9,120 @@ import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.Snapshot +import androidx.compose.ui.text.TextRange +import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase import com.hedvig.android.molecule.public.MoleculePresenter import com.hedvig.android.molecule.public.MoleculePresenterScope import com.hedvig.android.molecule.public.MoleculeViewModel -internal class AddChipIdViewModel : MoleculeViewModel( +internal class AddChipIdViewModel( + private val updateChipIdUseCase: UpdateChipIdUseCase, + insuranceId: String, +) : MoleculeViewModel( initialState = AddChipIdUiState.Loading, - presenter = AddChipIdPresenter(), + presenter = AddChipIdPresenter( + updateChipIdUseCase = updateChipIdUseCase, + insuranceId = insuranceId, + ), ) -internal class AddChipIdPresenter : MoleculePresenter { +internal class AddChipIdPresenter( + private val updateChipIdUseCase: UpdateChipIdUseCase, + private val insuranceId: String, +) : MoleculePresenter { @Composable override fun MoleculePresenterScope.present( lastState: AddChipIdUiState, ): AddChipIdUiState { - var currentState by remember { mutableStateOf(lastState) } - var loadIteration by remember { mutableIntStateOf(0) } + val chipIdState = remember { + val lastChipIdState = lastState.content?.chipIdState + TextFieldState(lastChipIdState?.text?.toString() ?: "", lastChipIdState?.selection ?: TextRange(0)) + } + var submittingData by remember { mutableStateOf(false) } + var showSuccessSnackBar by remember { mutableStateOf(false) } + var errorSnackBarText by remember { mutableStateOf(null) } + + var submitIteration by remember { mutableIntStateOf(0) } + + LaunchedEffect(submitIteration) { + if (submitIteration == 0) return@LaunchedEffect - LaunchedEffect(loadIteration) { - currentState = AddChipIdUiState.Loading - // TODO: Load chip ID data here - currentState = AddChipIdUiState.Content + submittingData = true + errorSnackBarText = null + + updateChipIdUseCase.invoke(insuranceId).fold( + ifLeft = { error -> + Snapshot.withMutableSnapshot { + submittingData = false + errorSnackBarText = error.message ?: "Something went wrong" + } + }, + ifRight = { + Snapshot.withMutableSnapshot { + showSuccessSnackBar = true + submittingData = false + } + }, + ) } CollectEvents { event -> when (event) { - AddChipIdEvent.Reload -> loadIteration++ + AddChipIdEvent.RetryLoadData -> { + // Retry by resetting state + chipIdState.setTextAndPlaceCursorAtEnd("") + } + + AddChipIdEvent.SubmitData -> { + if (!chipIdState.text.toString().all { it.isDigit() } || chipIdState.text.toString().length != 15) { + Snapshot.withMutableSnapshot { + errorSnackBarText = "Must be 15 digits" + } + } else { + submitIteration++ + } + } + + AddChipIdEvent.ShowedMessage -> { + Snapshot.withMutableSnapshot { + showSuccessSnackBar = false + errorSnackBarText = null + } + } } } - return currentState + return AddChipIdUiState.Content( + chipIdState = chipIdState, + showSuccessSnackBar = showSuccessSnackBar, + submittingData = submittingData, + errorSnackBarText = errorSnackBarText, + ) } } internal sealed interface AddChipIdUiState { + val content: Content? + get() = this as? Content + data object Loading : AddChipIdUiState - data object Content : AddChipIdUiState - data class Failure(val message: String) : AddChipIdUiState + + data object Error : AddChipIdUiState + + data class Content( + val chipIdState: TextFieldState, + val showSuccessSnackBar: Boolean = false, + val submittingData: Boolean = false, + val errorSnackBarText: String? = null, + ) : AddChipIdUiState { + val isChipIdValid: Boolean + get() = chipIdState.text.toString().length == 15 && chipIdState.text.toString().all { it.isDigit() } + } } internal sealed interface AddChipIdEvent { - data object Reload : AddChipIdEvent + data object RetryLoadData : AddChipIdEvent + data object SubmitData : AddChipIdEvent + data object ShowedMessage : AddChipIdEvent } From e931f65e76710123b23581178cec779eaca732a8 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 16:21:03 +0100 Subject: [PATCH 06/42] add error types --- .../feature/chip/id/ui/AddChipIdScreen.kt | 14 +++++++++----- .../feature/chip/id/ui/AddChipIdViewModel.kt | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 48a4f22883..ac5d0142b1 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -144,7 +144,7 @@ private fun ColumnScope.AddChipIdContent( ChipIdTextField( textFieldState = uiState.chipIdState, - labelText = "Chip ID", + labelText = "Chip ID", //todo keyboardActionHandler = KeyboardActionHandler { submitChipId() focusManager.clearFocus() @@ -152,13 +152,17 @@ private fun ColumnScope.AddChipIdContent( ) AnimatedContent( - targetState = uiState.errorSnackBarText, + targetState = uiState.errorType, transitionSpec = { fadeIn() + expandVertically() togetherWith fadeOut() + shrinkVertically() }, modifier = Modifier.padding(top = 4.dp), - ) { errorText -> - if (errorText != null) { + ) { errorType -> + if (errorType != null) { + val errorMessage = when (errorType) { + ChipIdErrorType.WrongInput -> "Must be 15 digits only" //todo + ChipIdErrorType.GeneralError -> "Something went wrong" //todo + } HedvigNotificationCard( - message = errorText, + message = errorMessage, priority = NotificationPriority.Error, modifier = Modifier .padding(horizontal = 16.dp) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 872065d241..77720488ea 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -41,7 +41,7 @@ internal class AddChipIdPresenter( } var submittingData by remember { mutableStateOf(false) } var showSuccessSnackBar by remember { mutableStateOf(false) } - var errorSnackBarText by remember { mutableStateOf(null) } + var errorType by remember { mutableStateOf(null) } var submitIteration by remember { mutableIntStateOf(0) } @@ -49,13 +49,13 @@ internal class AddChipIdPresenter( if (submitIteration == 0) return@LaunchedEffect submittingData = true - errorSnackBarText = null + errorType = null updateChipIdUseCase.invoke(insuranceId).fold( ifLeft = { error -> Snapshot.withMutableSnapshot { submittingData = false - errorSnackBarText = error.message ?: "Something went wrong" + errorType = ChipIdErrorType.GeneralError } }, ifRight = { @@ -77,7 +77,7 @@ internal class AddChipIdPresenter( AddChipIdEvent.SubmitData -> { if (!chipIdState.text.toString().all { it.isDigit() } || chipIdState.text.toString().length != 15) { Snapshot.withMutableSnapshot { - errorSnackBarText = "Must be 15 digits" + errorType = ChipIdErrorType.WrongInput } } else { submitIteration++ @@ -87,7 +87,7 @@ internal class AddChipIdPresenter( AddChipIdEvent.ShowedMessage -> { Snapshot.withMutableSnapshot { showSuccessSnackBar = false - errorSnackBarText = null + errorType = null } } } @@ -97,7 +97,7 @@ internal class AddChipIdPresenter( chipIdState = chipIdState, showSuccessSnackBar = showSuccessSnackBar, submittingData = submittingData, - errorSnackBarText = errorSnackBarText, + errorType = errorType, ) } } @@ -114,13 +114,18 @@ internal sealed interface AddChipIdUiState { val chipIdState: TextFieldState, val showSuccessSnackBar: Boolean = false, val submittingData: Boolean = false, - val errorSnackBarText: String? = null, + val errorType: ChipIdErrorType? = null, ) : AddChipIdUiState { val isChipIdValid: Boolean get() = chipIdState.text.toString().length == 15 && chipIdState.text.toString().all { it.isDigit() } } } +internal sealed interface ChipIdErrorType { + data object WrongInput : ChipIdErrorType + data object GeneralError : ChipIdErrorType +} + internal sealed interface AddChipIdEvent { data object RetryLoadData : AddChipIdEvent data object SubmitData : AddChipIdEvent From ea9e8d7b5e5149fa06135aead5a99b8f1caac801 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 25 Mar 2026 16:21:54 +0100 Subject: [PATCH 07/42] add error types --- .../com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index ac5d0142b1..91ca1fc408 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -158,7 +158,7 @@ private fun ColumnScope.AddChipIdContent( ) { errorType -> if (errorType != null) { val errorMessage = when (errorType) { - ChipIdErrorType.WrongInput -> "Must be 15 digits only" //todo + ChipIdErrorType.WrongInput -> "Must be 15 digits" //todo ChipIdErrorType.GeneralError -> "Something went wrong" //todo } HedvigNotificationCard( From 53d8900812c35828a4ba43b7860d2fcc9e9627f5 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Thu, 26 Mar 2026 08:04:11 +0100 Subject: [PATCH 08/42] remonder cards in home --- .../android/app/navigation/HedvigNavHost.kt | 3 ++ .../src/main/graphql/QueryHome.graphql | 16 +++++++++ .../home/home/data/GetHomeDataUseCase.kt | 21 ++++++++++++ .../feature/home/home/navigation/HomeGraph.kt | 2 ++ .../feature/home/home/ui/HomeDestination.kt | 9 +++++ .../feature/home/home/ui/HomePresenter.kt | 16 ++++++++- .../feature/profile/tab/ProfileDestination.kt | 1 + .../GetMemberRemindersUseCase.kt | 9 +++++ .../memberreminders/ui/MemberReminderCards.kt | 33 ++++++++++++++++++- 9 files changed, 108 insertions(+), 2 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index c8f6510675..68a46e858e 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -223,6 +223,9 @@ internal fun HedvigNavHost( navController.navigate(ProfileDestination.ContactInfo) }, imageLoader = imageLoader, + navigateToChipIdScreen = { contractId: String -> + navController.navigate(ChipIdGraphDestination(contractId)) + }, ) insuranceGraph( nestedGraphs = { diff --git a/app/feature/feature-home/src/main/graphql/QueryHome.graphql b/app/feature/feature-home/src/main/graphql/QueryHome.graphql index 967925ad07..448965eb09 100644 --- a/app/feature/feature-home/src/main/graphql/QueryHome.graphql +++ b/app/feature/feature-home/src/main/graphql/QueryHome.graphql @@ -8,11 +8,21 @@ query Home($claimsHistoryFlag: Boolean!) { } terminatedContracts { id + currentAgreement { + productVariant { + typeOfContract + } + } } pendingContracts { id externalInsuranceCancellationHandledByHedvig exposureDisplayName + + productVariant { + typeOfContract + } + } importantMessages { id @@ -57,7 +67,13 @@ query Home($claimsHistoryFlag: Boolean!) { } } activeContracts { + id masterInceptionDate + currentAgreement { + productVariant { + typeOfContract + } + } } } } diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt index 512923e69c..463e472fe6 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt @@ -17,8 +17,10 @@ import com.hedvig.android.crosssells.RecommendedCrossSell import com.hedvig.android.data.addons.data.AddonBannerInfo import com.hedvig.android.data.addons.data.AddonBannerSource import com.hedvig.android.data.addons.data.GetTravelAddonBannerInfoUseCaseProvider +import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.CrossSell import com.hedvig.android.data.contract.ImageAsset +import com.hedvig.android.data.contract.toContractGroup import com.hedvig.android.data.conversations.HasAnyActiveConversationUseCase import com.hedvig.android.featureflags.FeatureManager import com.hedvig.android.featureflags.flags.Feature @@ -165,6 +167,8 @@ internal class GetHomeDataUseCaseImpl( ) } ?: emptyList() val travelBannerInfo = travelBannerInfo.getOrNull() + val hasMissingChipId = homeQueryData.currentMember.hasMissingChipId() + val missingChipIdContractId = homeQueryData.currentMember.getMissingChipIdContractId() HomeData( contractStatus = contractStatus, claimStatusCardsData = homeQueryData.claimStatusCards(), @@ -176,6 +180,8 @@ internal class GetHomeDataUseCaseImpl( firstVetSections = firstVetActions, crossSells = crossSells, travelBannerInfo = travelBannerInfo?.firstOrNull(), // todo: check for CAR_ADDON LATER! + hasMissingChipId = hasMissingChipId, + missingChipIdContractId = missingChipIdContractId, ) }.onLeft { error: ApolloOperationError -> logcat(operationError = error) { "GetHomeDataUseCase failed with $error" } @@ -263,6 +269,19 @@ internal class GetHomeDataUseCaseImpl( private fun HomeQuery.Data.CurrentMember.areAllNonTerminatedContractsPending(): Boolean { return activeContracts.isEmpty() && pendingContracts.isNotEmpty() } + + private fun HomeQuery.Data.CurrentMember.hasMissingChipId(): Boolean { + return getMissingChipIdContractId() != null + } + + private fun HomeQuery.Data.CurrentMember.getMissingChipIdContractId(): String? { + activeContracts.firstOrNull { contract -> + val contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup() + contractGroup == ContractGroup.CAT || contractGroup == ContractGroup.DOG + }?.let { return it.id } + + return null + } } private fun HomeQuery.Data.claimStatusCards(): HomeData.ClaimStatusCardsData? { @@ -284,6 +303,8 @@ internal data class HomeData( val firstVetSections: List, val crossSells: CrossSellSheetData, val travelBannerInfo: AddonBannerInfo?, + val hasMissingChipId: Boolean = false, + val missingChipIdContractId: String? = null, ) { @Immutable data class ClaimStatusCardsData( diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt index 3161b8739d..842eb1e0fa 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt @@ -30,6 +30,7 @@ fun NavGraphBuilder.homeGraph( navigateToHelpCenter: () -> Unit, navigateToClaimChat: () -> Unit, navigateToClaimChatInDevMode: () -> Unit, + navigateToChipIdScreen: (String) -> Unit, openAppSettings: () -> Unit, openUrl: (String) -> Unit, imageLoader: ImageLoader, @@ -65,6 +66,7 @@ fun NavGraphBuilder.homeGraph( navigateToContactInfo() }, imageLoader = imageLoader, + navigateToChipId = navigateToChipIdScreen ) } navdestination( diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt index 31d647a62e..f36bf3ddec 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt @@ -165,6 +165,7 @@ internal fun HomeDestination( navigateToMissingInfo: (String, CoInsuredFlowType) -> Unit, navigateToFirstVet: (List) -> Unit, navigateToContactInfo: () -> Unit, + navigateToChipId: (String) -> Unit, imageLoader: ImageLoader, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -188,6 +189,7 @@ internal fun HomeDestination( navigateToFirstVet = navigateToFirstVet, markCrossSellsNotificationAsSeen = { viewModel.emit(HomeEvent.MarkCardCrossSellsAsSeen) }, navigateToContactInfo = navigateToContactInfo, + navigateToChipIdScreen = navigateToChipId, setEpochDayWhenLastToolTipShown = { epochDay -> viewModel.emit(HomeEvent.CrossSellToolTipShown(epochDay)) }, @@ -214,6 +216,7 @@ private fun HomeScreen( navigateToMissingInfo: (String, CoInsuredFlowType) -> Unit, navigateToFirstVet: (List) -> Unit, navigateToContactInfo: () -> Unit, + navigateToChipIdScreen: (String) -> Unit, markCrossSellsNotificationAsSeen: () -> Unit, setEpochDayWhenLastToolTipShown: (Long) -> Unit, imageLoader: ImageLoader, @@ -284,6 +287,7 @@ private fun HomeScreen( onNavigateToNewConversation = onNavigateToNewConversation, markMessageAsSeen = markMessageAsSeen, navigateToContactInfo = navigateToContactInfo, + navigateToChipIdScreen = navigateToChipIdScreen ) } } @@ -431,6 +435,7 @@ private fun HomeScreenSuccess( navigateToMissingInfo: (String, CoInsuredFlowType) -> Unit, onNavigateToNewConversation: () -> Unit, navigateToContactInfo: () -> Unit, + navigateToChipIdScreen: (String) -> Unit, modifier: Modifier = Modifier, ) { val isInPreview = LocalInspectionMode.current @@ -509,6 +514,7 @@ private fun HomeScreenSuccess( openUrl = openUrl, contentPadding = PaddingValues(horizontal = 16.dp) + horizontalInsets, navigateToContactInfo = navigateToContactInfo, + navigateToChipId = navigateToChipIdScreen, ) } }, @@ -813,6 +819,7 @@ private fun PreviewHomeScreen( navigateToFirstVet = {}, markCrossSellsNotificationAsSeen = {}, navigateToContactInfo = {}, + navigateToChipIdScreen = {}, setEpochDayWhenLastToolTipShown = {}, imageLoader = rememberPreviewImageLoader(), navigateToClaimChatInDevMode = {}, @@ -844,6 +851,7 @@ private fun PreviewHomeScreenWithError() { navigateToFirstVet = {}, markCrossSellsNotificationAsSeen = {}, navigateToContactInfo = {}, + navigateToChipIdScreen = {}, setEpochDayWhenLastToolTipShown = {}, imageLoader = rememberPreviewImageLoader(), navigateToClaimChatInDevMode = {}, @@ -897,6 +905,7 @@ private fun PreviewHomeScreenAllHomeTextTypes( navigateToFirstVet = {}, markCrossSellsNotificationAsSeen = {}, navigateToContactInfo = {}, + navigateToChipIdScreen = {}, setEpochDayWhenLastToolTipShown = {}, imageLoader = rememberPreviewImageLoader(), navigateToClaimChatInDevMode = {}, diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt index e30dc18ef6..73635c83e3 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt @@ -19,6 +19,7 @@ import com.hedvig.android.feature.home.home.data.HomeData import com.hedvig.android.feature.home.home.data.SeenImportantMessagesStorage import com.hedvig.android.featureflags.FeatureManager import com.hedvig.android.featureflags.flags.Feature +import com.hedvig.android.memberreminders.MemberReminder import com.hedvig.android.memberreminders.MemberReminders import com.hedvig.android.molecule.public.MoleculePresenter import com.hedvig.android.molecule.public.MoleculePresenterScope @@ -146,6 +147,8 @@ internal class HomePresenter( addonBannerInfo = successData.addonBannerInfo, isExperimentalClaimChatEnabled = isExperimentalClaimChatEnabled, isProduction = isProduction, + hasMissingChipId = successData.hasMissingChipId, + missingChipIdContractId = successData.missingChipIdContractId, ) } } @@ -186,6 +189,8 @@ internal sealed interface HomeUiState { val isProduction: Boolean, override val isHelpCenterEnabled: Boolean, override val hasUnseenChatMessages: Boolean, + val hasMissingChipId: Boolean = false, + val missingChipIdContractId: String? = null, ) : HomeUiState data class Error(val message: String?) : HomeUiState @@ -204,6 +209,8 @@ private data class SuccessData( val crossSellsAction: HomeTopBarAction.CrossSellsAction?, val hasUnseenChatMessages: Boolean, val addonBannerInfo: AddonBannerInfo?, + val hasMissingChipId: Boolean = false, + val missingChipIdContractId: String? = null, ) { companion object { fun fromLastState(lastState: HomeUiState): SuccessData? { @@ -219,6 +226,8 @@ private data class SuccessData( firstVetAction = lastState.firstVetAction, hasUnseenChatMessages = lastState.hasUnseenChatMessages, addonBannerInfo = lastState.addonBannerInfo, + hasMissingChipId = lastState.hasMissingChipId, + missingChipIdContractId = lastState.missingChipIdContractId, ) } @@ -258,13 +267,18 @@ private data class SuccessData( }, claimStatusCardsData = homeData.claimStatusCardsData, veryImportantMessages = homeData.veryImportantMessages, - memberReminders = homeData.memberReminders.copy(enableNotifications = null), + memberReminders = homeData.memberReminders.copy( + enableNotifications = null, + missingChipId = homeData.missingChipIdContractId?.let { MemberReminder.MissingChipId(it) }, + ), showHelpCenter = homeData.showHelpCenter, chatAction = chatAction, firstVetAction = firstVetAction, crossSellsAction = crossSellsAction, hasUnseenChatMessages = homeData.hasUnseenChatMessages, addonBannerInfo = homeData.travelBannerInfo, + hasMissingChipId = homeData.hasMissingChipId, + missingChipIdContractId = homeData.missingChipIdContractId, ) } } diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt index defc760a8f..df0542b361 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt @@ -226,6 +226,7 @@ private fun ProfileScreen( modifier = Modifier.onConsumedWindowInsetsChanged { consumedWindowInsets.insets = it }, onNavigateToNewConversation = onNavigateToNewConversation, navigateToContactInfo = navigateToContactInfo, + navigateToChipId = {}, //todo ) if (memberReminders.isNotEmpty()) { Spacer(Modifier.height(16.dp)) diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt index 198f49b21d..3ac8f43778 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt @@ -76,6 +76,7 @@ data class MemberReminders( val enableNotifications: MemberReminder.EnableNotifications? = null, val coInsuredInfo: List? = null, val updateContactInfo: ContactInfoUpdateNeeded? = null, + val missingChipId: MemberReminder.MissingChipId? = null, ) { /** * In some cases a reminder may be present but may not be applicable in our current app state. @@ -101,6 +102,9 @@ data class MemberReminders( updateContactInfo?.let { add(it) } + missingChipId?.let { + add(it) + } } } } @@ -139,4 +143,9 @@ sealed interface MemberReminder { data object ContactInfoUpdateNeeded : MemberReminder { override val id: String = UUID.randomUUID().toString() } + + data class MissingChipId( + val contractId: String, + override val id: String = UUID.randomUUID().toString(), + ) : MemberReminder } diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 4353baf69a..6bd289efa0 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -60,6 +60,7 @@ fun MemberReminderCardsWithoutNotification( onNavigateToNewConversation: () -> Unit, contentPadding: PaddingValues, navigateToContactInfo: () -> Unit, + navigateToChipId: (String) -> Unit, modifier: Modifier = Modifier, ) { MemberReminderCards( @@ -72,6 +73,7 @@ fun MemberReminderCardsWithoutNotification( notificationPermissionState = null, contentPadding = contentPadding, navigateToContactInfo = navigateToContactInfo, + navigateToChipId = navigateToChipId, modifier = modifier, ) } @@ -85,6 +87,7 @@ fun MemberReminderCards( snoozeNotificationPermissionReminder: () -> Unit, onNavigateToNewConversation: () -> Unit, navigateToContactInfo: () -> Unit, + navigateToChipId: (String) -> Unit, notificationPermissionState: NotificationPermissionState?, contentPadding: PaddingValues, modifier: Modifier = Modifier, @@ -99,8 +102,9 @@ fun MemberReminderCards( onNavigateToNewConversation = onNavigateToNewConversation, snoozeNotificationPermissionReminder = snoozeNotificationPermissionReminder, notificationPermissionState = notificationPermissionState, - modifier = modifier.padding(contentPadding), navigateToContactInfo = navigateToContactInfo, + navigateToChipId = navigateToChipId, + modifier = modifier.padding(contentPadding), ) } else if (memberReminders.isNotEmpty()) { val pagerState = rememberPagerState(pageCount = { memberReminders.size }) @@ -123,6 +127,7 @@ fun MemberReminderCards( snoozeNotificationPermissionReminder = snoozeNotificationPermissionReminder, notificationPermissionState = notificationPermissionState, navigateToContactInfo = navigateToContactInfo, + navigateToChipId = navigateToChipId, modifier = modifier.fillMaxWidth(), ) } @@ -147,6 +152,7 @@ private fun ColumnScope.MemberReminderCard( navigateToAddMissingInfo: (String, CoInsuredFlowType) -> Unit, navigateToConnectPayment: () -> Unit, navigateToContactInfo: () -> Unit, + navigateToChipId: (String) -> Unit, openUrl: (String) -> Unit, snoozeNotificationPermissionReminder: () -> Unit, onNavigateToNewConversation: () -> Unit, @@ -210,6 +216,14 @@ private fun ColumnScope.MemberReminderCard( modifier = modifier, ) } + + is MemberReminder.MissingChipId -> { + ReminderMissingChipId( + contractId = memberReminder.contractId, + navigateToChipId = { navigateToChipId(memberReminder.contractId) }, + modifier = modifier, + ) + } } } @@ -254,6 +268,23 @@ fun ReminderCardUpdateContactInfo(navigateToContactInfo: () -> Unit, modifier: M ) } +@Composable +internal fun ReminderMissingChipId( + contractId: String, + navigateToChipId: () -> Unit, + modifier: Modifier = Modifier, +) { + HedvigNotificationCard( + message = "Chip ID for your pet is missing", //todo + modifier = modifier, + priority = NotificationPriority.Attention, + style = InfoCardStyle.Button( + buttonText = "Add ID", //todo + onButtonClick = navigateToChipId, + ), + ) +} + @Composable private fun ReminderCardConnectPayment(navigateToConnectPayment: () -> Unit, modifier: Modifier = Modifier) { HedvigNotificationCard( From 23ac5bad5df01025d4e403be6a0df4157a963e74 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Fri, 27 Mar 2026 09:15:16 +0100 Subject: [PATCH 09/42] add string keys --- .../src/androidMain/res/values-sv-rSE/strings.xml | 12 +++++++++++- .../src/androidMain/res/values/strings.xml | 12 +++++++++++- .../composeResources/values-sv-rSE/strings.xml | 12 +++++++++++- .../commonMain/composeResources/values/strings.xml | 12 +++++++++++- .../android/feature/chip/id/ui/AddChipIdScreen.kt | 13 +++++++++---- .../feature/home/home/data/GetHomeDataUseCase.kt | 2 +- .../memberreminders/ui/MemberReminderCards.kt | 6 ++++-- 7 files changed, 58 insertions(+), 11 deletions(-) diff --git a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml index 0f033ae2d5..2c59853791 100644 --- a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml @@ -168,6 +168,11 @@ Meddelanden Skicka Checkout + Chip-ID + Lägg till Chip-ID + Chip-ID för ditt husdjur saknas + Uppdatera husdjurets chip-ID + Måste vara 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. Aktivera Ärende @@ -210,7 +215,7 @@ Beskriv i text Din skadeanmälan Röstinspelning - Anpassat objekt + Annat föremål Om du inte vet exakt datum, fyll i på ett ungefär när det inträffade. Ändra svar Ändrar du det här svaret rensas allt du fyllt i efter det. Du behöver gå igenom de stegen igen. @@ -843,6 +848,9 @@ Säg upp försäkring Välj slutdatum Vi skickar en bekräftelse på uppsägningen inom några dagar. Hör gärna av dig om du inte fått den efter 5 dagar. + Eftersom din bil har avställts kommer din försäkring att sägas upp automatiskt. + Eftersom din bil har skrotats kommer din försäkring att sägas upp automatiskt. + Eftersom du har sålt din bil kommer din försäkring att sägas upp automatiskt. Vi avslutar din försäkring automatiskt Du kommer att få ett bekräftelsemail på din avställningsförsäkring inom några dagar, där du kommer att se ditt nya pris. Vad kostar det @@ -855,6 +863,8 @@ Du kan närsomhelst avsluta din försäkring. Avslutar du din försäkring kommer du endast att debiteras för den tid du varit aktiv medlem hos Hedvig. När du avslutat din försäkring kan du se din sista betalning under fliken \"Betalningar\" här i appen. Avsluta din försäkring Avsluta försäkring + Eftersom din bil är påställd igen kommer din försäkring automatiskt att ändras tillbaka till ditt ordinarie skydd. + Din bil är tillbaka på vägen Observera att du bara kan säga upp en försäkring åt gången Välj den försäkring du vill säga upp Din försäkring kommer avlutas direkt diff --git a/app/core/core-resources/src/androidMain/res/values/strings.xml b/app/core/core-resources/src/androidMain/res/values/strings.xml index 80bca7c89a..7428a9b828 100644 --- a/app/core/core-resources/src/androidMain/res/values/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values/strings.xml @@ -168,6 +168,11 @@ Messages Send Checkout + Chip-ID + Add Chip-ID + Chip ID for your pet is missing + Update pet Chip-ID + Must be 15 digits Don’t miss out on important information for your claim Enable notifications Case @@ -210,7 +215,7 @@ Describe using text Your claim Voice recording - Custom item + Other item If you don\'t know the exact date, enter an approximate date. Edit answer Editing this answer will clear everything you’ve filled in after it. You’ll need to go through those steps again. @@ -843,6 +848,9 @@ Cancel insurance Select termination date We’ll send a cancellation confirmation within a few days. If you don’t get it after 5 days, feel free to contact us. + Since your car has been decommissioned, your insurance will be automatically cancelled. + Since your car has been scrapped, your insurance will be automatically cancelled. + Since you\'ve sold your car, your insurance will be automatically cancelled. We’ll cancel your insurance automatically You’ll receive a confirmation email within a few days, where you can see your new price. What it costs @@ -855,6 +863,8 @@ You can cancel your insurance at any time. You will only be charged for the time you have been an active member. When the insurance is cancelled you can see your last payment under the tab \"Payments\" here in the app. Cancelling your insurance Cancel insurance + Since your car is registered again, your insurance will automatically switch back to your regular coverage. + Your car is back on the road Please note that you can only cancel one insurance at a time Select the insurance you want to cancel Your insurance will be cancelled directly diff --git a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml index 86a3ad6147..ce0d6791fa 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml @@ -168,6 +168,11 @@ Meddelanden Skicka Checkout + Chip-ID + Lägg till Chip-ID + Chip-ID för ditt husdjur saknas + Uppdatera husdjurets chip-ID + Måste vara 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. Aktivera Ärende @@ -210,7 +215,7 @@ Beskriv i text Din skadeanmälan Röstinspelning - Anpassat objekt + Annat föremål Om du inte vet exakt datum, fyll i på ett ungefär när det inträffade. Ändra svar Ändrar du det här svaret rensas allt du fyllt i efter det. Du behöver gå igenom de stegen igen. @@ -843,6 +848,9 @@ Säg upp försäkring Välj slutdatum Vi skickar en bekräftelse på uppsägningen inom några dagar. Hör gärna av dig om du inte fått den efter 5 dagar. + Eftersom din bil har avställts kommer din försäkring att sägas upp automatiskt. + Eftersom din bil har skrotats kommer din försäkring att sägas upp automatiskt. + Eftersom du har sålt din bil kommer din försäkring att sägas upp automatiskt. Vi avslutar din försäkring automatiskt Du kommer att få ett bekräftelsemail på din avställningsförsäkring inom några dagar, där du kommer att se ditt nya pris. Vad kostar det @@ -855,6 +863,8 @@ Du kan närsomhelst avsluta din försäkring. Avslutar du din försäkring kommer du endast att debiteras för den tid du varit aktiv medlem hos Hedvig. När du avslutat din försäkring kan du se din sista betalning under fliken "Betalningar" här i appen. Avsluta din försäkring Avsluta försäkring + Eftersom din bil är påställd igen kommer din försäkring automatiskt att ändras tillbaka till ditt ordinarie skydd. + Din bil är tillbaka på vägen Observera att du bara kan säga upp en försäkring åt gången Välj den försäkring du vill säga upp Din försäkring kommer avlutas direkt diff --git a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml index 14e7fc8865..5b11704e52 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml @@ -168,6 +168,11 @@ Messages Send Checkout + Chip-ID + Add Chip-ID + Chip ID for your pet is missing + Update pet Chip-ID + Must be 15 digits Don’t miss out on important information for your claim Enable notifications Case @@ -210,7 +215,7 @@ Describe using text Your claim Voice recording - Custom item + Other item If you don't know the exact date, enter an approximate date. Edit answer Editing this answer will clear everything you’ve filled in after it. You’ll need to go through those steps again. @@ -843,6 +848,9 @@ Cancel insurance Select termination date We’ll send a cancellation confirmation within a few days. If you don’t get it after 5 days, feel free to contact us. + Since your car has been decommissioned, your insurance will be automatically cancelled. + Since your car has been scrapped, your insurance will be automatically cancelled. + Since you've sold your car, your insurance will be automatically cancelled. We’ll cancel your insurance automatically You’ll receive a confirmation email within a few days, where you can see your new price. What it costs @@ -855,6 +863,8 @@ You can cancel your insurance at any time. You will only be charged for the time you have been an active member. When the insurance is cancelled you can see your last payment under the tab "Payments" here in the app. Cancelling your insurance Cancel insurance + Since your car is registered again, your insurance will automatically switch back to your regular coverage. + Your car is back on the road Please note that you can only cancel one insurance at a time Select the insurance you want to cancel Your insurance will be cancelled directly diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 91ca1fc408..6ce1640699 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -46,9 +46,14 @@ import com.hedvig.android.design.system.hedvig.clearFocusOnTap import com.hedvig.android.feature.chip.id.ui.AddChipIdEvent.RetryLoadData import com.hedvig.android.feature.chip.id.ui.AddChipIdEvent.SubmitData import com.hedvig.android.feature.chip.id.ui.AddChipIdUiState.Content +import hedvig.resources.CHIP_ID_LABEL +import hedvig.resources.CHIP_ID_TOP_TITLE +import hedvig.resources.CHIP_ID_WRONG_INPUT import hedvig.resources.CONTACT_INFO_CHANGES_SAVED import hedvig.resources.Res +import hedvig.resources.general_error import hedvig.resources.general_save_button +import hedvig.resources.something_went_wrong import org.jetbrains.compose.resources.stringResource @Composable @@ -87,7 +92,7 @@ private fun AddChipIdScreen( ) { val focusManager = LocalFocusManager.current HedvigScaffold( - topAppBarText = "Update pet Chip-ID", //todo + topAppBarText = stringResource(Res.string.CHIP_ID_TOP_TITLE), navigateUp = navigateUp, modifier = Modifier .fillMaxSize() @@ -144,7 +149,7 @@ private fun ColumnScope.AddChipIdContent( ChipIdTextField( textFieldState = uiState.chipIdState, - labelText = "Chip ID", //todo + labelText = stringResource(Res.string.CHIP_ID_LABEL), keyboardActionHandler = KeyboardActionHandler { submitChipId() focusManager.clearFocus() @@ -158,8 +163,8 @@ private fun ColumnScope.AddChipIdContent( ) { errorType -> if (errorType != null) { val errorMessage = when (errorType) { - ChipIdErrorType.WrongInput -> "Must be 15 digits" //todo - ChipIdErrorType.GeneralError -> "Something went wrong" //todo + ChipIdErrorType.WrongInput -> stringResource(Res.string.CHIP_ID_WRONG_INPUT) + ChipIdErrorType.GeneralError -> stringResource(Res.string.something_went_wrong) } HedvigNotificationCard( message = errorMessage, diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt index 463e472fe6..caa7722de4 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt @@ -179,7 +179,7 @@ internal class GetHomeDataUseCaseImpl( showHelpCenter = isHelpCenterEnabled, firstVetSections = firstVetActions, crossSells = crossSells, - travelBannerInfo = travelBannerInfo?.firstOrNull(), // todo: check for CAR_ADDON LATER! + travelBannerInfo = travelBannerInfo?.firstOrNull(), hasMissingChipId = hasMissingChipId, missingChipIdContractId = missingChipIdContractId, ) diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 6bd289efa0..32fc5d95c9 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -32,6 +32,8 @@ import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.memberreminders.MemberReminder import com.hedvig.android.memberreminders.MemberReminder.UpcomingRenewal import com.hedvig.android.notification.permission.NotificationPermissionState +import hedvig.resources.CHIP_ID_MISSING_BUTTON +import hedvig.resources.CHIP_ID_MISSING_MESSAGE import hedvig.resources.CONTRACT_COINSURED_MISSING_ADD_INFO import hedvig.resources.CONTRACT_COINSURED_MISSING_INFO_TEXT import hedvig.resources.CONTRACT_COOWNERS_MISSING_INFO_TEXT @@ -275,11 +277,11 @@ internal fun ReminderMissingChipId( modifier: Modifier = Modifier, ) { HedvigNotificationCard( - message = "Chip ID for your pet is missing", //todo + message = stringResource(Res.string.CHIP_ID_MISSING_MESSAGE), modifier = modifier, priority = NotificationPriority.Attention, style = InfoCardStyle.Button( - buttonText = "Add ID", //todo + buttonText = stringResource(Res.string.CHIP_ID_MISSING_BUTTON), onButtonClick = navigateToChipId, ), ) From e9648f354e05aa3ee4e5dc8f4726e914d79155a0 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 09:28:38 +0200 Subject: [PATCH 10/42] impl useCase schema --- .../android/apollo/octopus/schema.graphqls | 139 +++++++++++++----- .../src/graphql/UpdateChipIdMutation.graphql | 0 .../main/graphql/UpdateChipIdMutation.graphql | 8 + .../chip/id/data/UpdateChipIdUseCase.kt | 36 +++-- .../feature/chip/id/ui/AddChipIdViewModel.kt | 2 +- 5 files changed, 134 insertions(+), 51 deletions(-) delete mode 100644 app/feature/feature-chip-id/src/graphql/UpdateChipIdMutation.graphql create mode 100644 app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql diff --git a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls index 7b1a59d90b..e5195cf758 100644 --- a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls +++ b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls @@ -2179,24 +2179,6 @@ enum FlowTerminationNotificationType { INFO WARNING } -enum FlowTerminationOfferAction { - UPDATE_ADDRESS - CHANGE_TIER -} -input FlowTerminationOfferInput { - """ - This has no significance and is ignored by the backend. It exists to satisfy some codegen limitations - """ - confirmed: Boolean! -} -type FlowTerminationOfferStep implements FlowStep { - id: ID! - title: String! - description: String! - buttonTitle: String! - skipButtonTitle: String! - action: FlowTerminationOfferAction! -} input FlowTerminationStartInput { contractId: ID! supportedSteps: [String!] @@ -2232,9 +2214,9 @@ interface FlowTerminationSurveyOptionSuggestion { } type FlowTerminationSurveyOptionSuggestionAction implements FlowTerminationSurveyOptionSuggestion { id: ID! - action: FlowTerminationSurveyRedirectAction! @deprecated(reason: "Use FlowTerminationOfferStep instead") - description: String! @deprecated(reason: "Use FlowTerminationOfferStep instead") - buttonTitle: String! @deprecated(reason: "Use FlowTerminationOfferStep instead") + action: FlowTerminationSurveyRedirectAction! + description: String! + buttonTitle: String! infoType: FlowTerminationSurveyOptionSuggestionInfoType! } type FlowTerminationSurveyOptionSuggestionInfo implements FlowTerminationSurveyOptionSuggestion { @@ -2507,6 +2489,10 @@ type Member { """ isEligibleToMakeClaim: Boolean! memberActions: MemberActions + """ + Get contract info during termination flow. Null if no message to display. + """ + terminationNotification(input: TerminationFlowNotificationInput!): TerminationFlowNotification """ Call this to get the info to show banner. If empty list is returned then member is not eligible for the addon. @@ -2905,6 +2891,10 @@ enum MidtermChangeIntentState { INITIATED COMPLETED } +type MidtermChangePetIdOutput { + activationDate: Date + userError: UserError +} type MidtermChangePriceDetailItem { displayName: String! displayValue: String! @@ -3391,7 +3381,6 @@ type Mutation { flowTerminationDeletionNext(input: FlowTerminationDeletionInput, context: FlowContext!): Flow! flowTerminationSurveyNext(input: FlowTerminationSurveyInput!, context: FlowContext!): Flow! flowTerminationCarAutoDecomNext(input: FlowTerminationCarAutoDecomInput!, context: FlowContext!): Flow! - flowTerminationOfferNext(input: FlowTerminationOfferInput!, context: FlowContext!): Flow! travelCertificateCreate(input: TravelCertificateCreateInput!): TravelCertificate! """ The document includes details of the member’s home insurance, @@ -3457,6 +3446,14 @@ type Mutation { """ productOfferAddonsSelect(productOfferId: UUID!, addonIds: [UUID!]!): ProductOffersMutationOutput! """ + Reprice an existing product offer with updated data. Merges the provided data with the offer's + existing `priceIntentData`, creates a new underwriter quote matching the original variant, + and replaces the offer. + Useful for recommendation offers that don't have a `priceIntentId` and therefore can't use the + normal `priceIntentDataUpdate` + `priceIntentConfirm` flow. + """ + productOfferReprice(offerId: UUID!, data: PricingFormData!): ProductOffersMutationOutput! + """ Update the customer of the shop session. Only non-null fields will be changed. Can trigger automatic lookup of other information. The session can be placed in a "point of no return" state where it is no longer legal to update the customer, @@ -3529,9 +3526,15 @@ type Mutation { """ midtermChangeIntentCommit(intentId: ID!): MidtermChangeIntentMutationOutput! """ + Called to change the Pet-Id of a cat/dog contract. Creates a midterm change without price change and commits it. + """ + midtermChangePetId(contractId: ID!, petId: String!): MidtermChangePetIdOutput + """ Call this to confirm removal of selected addon(s). """ addonRemoveConfirm(contractId: ID!, addonIds: [ID!]!): UserError + terminateContract(input: TerminationFlowTerminateContractInput!): TerminationFlowContractMutationOutput! + deleteContract(input: TerminationFlowDeleteContractInput!): TerminationFlowContractMutationOutput! """ Call this to get addon quotes with price etc to show in the offer page. Call this when starting the add/upgrade addon flow. @@ -3894,20 +3897,6 @@ type ProductOfferAddon { """ isSelected: Boolean! } -type ProductOfferAddonCost { - """ - The ID of the addon - """ - addonId: UUID! - """ - Gross cost of the addon. - """ - grossCost: Money! - """ - Net cost of the addon. - """ - netCost: Money! -} """ Bundle discount information for a product offer """ @@ -3943,10 +3932,6 @@ type ProductOfferCost { """ discounts: [ItemDiscount!]! @deprecated(reason: "Use 'discountsV2' instead") discountsV2: [ExtendedItemDiscount!]! - """ - Collection of costs for addons that affect an item. - """ - addonCosts: [ProductOfferAddonCost!]! } type ProductOfferDeductible { displayName: String! @@ -3998,6 +3983,10 @@ type ProductOfferPriceMatch { externalPrice: Money! externalInsurer: ExternalInsurer! priceReduction: Money! + """ + Renewal date of the external insurer's policy. Null when not provided by the external insurer. + """ + renewalDate: Date } type ProductOffersMutationOutput { productOffers: [ProductOffer!]! @@ -4138,6 +4127,7 @@ type Query { Cost for selected configuration of removed addon offer """ addonRemoveOfferCost(contractId: ID!, addonIds: [ID!]!): ItemCost! + terminationSurvey(contractId: ID!): TerminationFlowSurvey! """ Call this to get the cost of an addon offer for selected addon(s). """ @@ -4338,6 +4328,11 @@ type ShopSessionCustomer { """ ssn: String """ + The customer's email address. Only available for new members. + Returns null for existing/returning members to protect their PII. + """ + email: String + """ The list of fields that need to be added in order to sign properly. Can be updated through `Mutation.shopSessionCustomerUpdate`. """ @@ -4498,10 +4493,74 @@ type SwitcherCaseMutationOutput { switcherCase: SwitcherCase userError: UserError } +union TerminationFlowAction = TerminationFlowActionTerminateWithDate|TerminationFlowActionDeleteInsurance +type TerminationFlowActionDeleteInsurance { + extraCoverage: [TerminationFlowExtraCoverageItem!]! +} +type TerminationFlowActionTerminateWithDate { + minDate: Date! + maxDate: Date! + extraCoverage: [TerminationFlowExtraCoverageItem!]! +} +type TerminationFlowContractMutationOutput { + contract: Contract + userError: UserError +} +input TerminationFlowDeleteContractInput { + contractId: ID! + terminationSurveyOptionId: ID! + terminationComment: String +} +type TerminationFlowExtraCoverageItem { + displayName: String! + displayValue: String +} +type TerminationFlowNotification { + message: String! + type: TerminationFlowNotificationType! +} input TerminationFlowNotificationInput { contractId: ID! terminationDate: Date! } +enum TerminationFlowNotificationType { + INFO + WARNING +} +type TerminationFlowSurvey { + options: [TerminationFlowSurveyOption!]! + action: TerminationFlowAction! +} +type TerminationFlowSurveyOption { + id: ID! + title: String! + subOptions: [TerminationFlowSurveyOption!]! + feedbackRequired: Boolean! + suggestion: TerminationFlowSurveyOptionSuggestion +} +type TerminationFlowSurveyOptionSuggestion { + type: TerminationFlowSurveyOptionSuggestionType! + description: String! + url: String +} +enum TerminationFlowSurveyOptionSuggestionType { + UPDATE_ADDRESS + UPGRADE_COVERAGE + DOWNGRADE_PRICE + REDIRECT + INFO + AUTO_CANCEL_SOLD + AUTO_CANCEL_SCRAPPED + AUTO_DECOMMISSION + AUTO_CANCEL_DECOMMISSION + CAR_ALREADY_DECOMMISSION +} +input TerminationFlowTerminateContractInput { + contractId: ID! + terminationDate: Date! + terminationSurveyOptionId: ID! + terminationComment: String +} type TotalCost { monthlyGross: Money! monthlyNet: Money! diff --git a/app/feature/feature-chip-id/src/graphql/UpdateChipIdMutation.graphql b/app/feature/feature-chip-id/src/graphql/UpdateChipIdMutation.graphql deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql b/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql new file mode 100644 index 0000000000..e00b92f6de --- /dev/null +++ b/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql @@ -0,0 +1,8 @@ +mutation UpdateChipIdNumber($petId: String!, $contractId: ID!) { + midtermChangePetId(petId: $petId, contractId: $contractId) { + userError { + message + } + activationDate + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt index 480490ee73..968969cb32 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt @@ -1,28 +1,44 @@ package com.hedvig.android.feature.chip.id.data import arrow.core.Either +import arrow.core.raise.context.bind import arrow.core.raise.context.either import arrow.core.raise.context.raise import com.apollographql.apollo.ApolloClient +import com.hedvig.android.apollo.ErrorMessage +import com.hedvig.android.apollo.safeExecute import com.hedvig.android.core.common.ErrorMessage +import com.hedvig.android.logger.logcat +import octopus.UpdateChipIdNumberMutation internal interface UpdateChipIdUseCase { - suspend fun invoke(insuranceId: String): Either + suspend fun invoke(petId: String, insuranceId: String): Either } internal class UpdateChipIdUseCaseImpl( private val apolloClient: ApolloClient, ) : UpdateChipIdUseCase { - override suspend fun invoke(insuranceId: String): Either { + override suspend fun invoke(petId: String, insuranceId: String): Either { return either { - // raise(ErrorMessage()) + logcat { "UpdateChipIdNumberMutation start" } + val result = apolloClient.mutation(UpdateChipIdNumberMutation( + petId = petId, + contractId = insuranceId,)) + .safeExecute{ + logcat { "UpdateChipIdNumberMutation error: $it" } + ErrorMessage() + } + .bind() + + val userError = result.midtermChangePetId?.userError + if (userError != null) { + raise(ErrorMessage(userError.message)) + } + if (result.midtermChangePetId?.activationDate!=null) { + Unit + } else { + raise(ErrorMessage()) + } } - // TODO: Implement actual mutation call - // return apolloClient.mutation(UpdateChipIdMutation(insuranceId)) - // .execute() - // .fold( - // ifLeft = { Either.left(ErrorMessage()) }, - // ifRight = { Either.right(Unit) } - // ) } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 77720488ea..e1a10a840c 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -51,7 +51,7 @@ internal class AddChipIdPresenter( submittingData = true errorType = null - updateChipIdUseCase.invoke(insuranceId).fold( + updateChipIdUseCase.invoke(insuranceId = insuranceId, petId = chipIdState.text.toString()).fold( ifLeft = { error -> Snapshot.withMutableSnapshot { submittingData = false From e44e43092a258050ab063a2ea269e2388c7113a5 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 11:25:18 +0200 Subject: [PATCH 11/42] move chipId data to common module, use it in profile memberReminders too --- .../android/app/navigation/HedvigNavHost.kt | 3 ++ .../android/data/contract/ChipIdState.kt | 9 +++++ .../home/home/data/GetHomeDataUseCase.kt | 18 --------- .../feature/home/home/ui/HomePresenter.kt | 11 ------ .../data/GetInsuranceContractsUseCase.kt | 1 + .../data/GetInsuranceContractsUseCaseDemo.kt | 1 + .../insurances/data/InsuranceContract.kt | 6 +-- .../insurance/InsuranceDestination.kt | 2 +- .../ContractDetailDestination.kt | 2 +- .../UpcomingChangesBottomSheetContent.kt | 2 +- .../insurancedetail/yourinfo/YourInfoTab.kt | 2 +- .../TerminatedContractsDestination.kt | 2 +- .../feature/profile/tab/ProfileDestination.kt | 5 ++- .../feature/profile/tab/ProfileGraph.kt | 2 + .../member-reminders-public/build.gradle.kts | 1 + .../QueryMissingChipIdReminder.graphql | 12 ++++++ .../GetMemberRemindersUseCase.kt | 18 +++++---- .../GetMissingChipIdReminderUseCase.kt | 38 +++++++++++++++++++ .../di/MemberRemindersModule.kt | 8 ++++ 19 files changed, 96 insertions(+), 47 deletions(-) create mode 100644 app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt create mode 100644 app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql create mode 100644 app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index 68a46e858e..9df464258a 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -389,6 +389,9 @@ internal fun HedvigNavHost( navController.navigate(InsuranceEvidenceGraphDestination) }, openUrl = openUrl, + navigateToChipId = { contractId -> + navController.navigate(ChipIdGraphDestination(contractId)) + }, ) cbmChatGraph( hedvigDeepLinkContainer = hedvigDeepLinkContainer, diff --git a/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt b/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt new file mode 100644 index 0000000000..9c58fe70de --- /dev/null +++ b/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt @@ -0,0 +1,9 @@ +package com.hedvig.android.data.contract + +sealed interface ChipIdState { + data object Missing : ChipIdState + + data object NotRequired : ChipIdState + + data class Present(val value: String) : ChipIdState +} diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt index caa7722de4..17dd747fc6 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt @@ -167,8 +167,6 @@ internal class GetHomeDataUseCaseImpl( ) } ?: emptyList() val travelBannerInfo = travelBannerInfo.getOrNull() - val hasMissingChipId = homeQueryData.currentMember.hasMissingChipId() - val missingChipIdContractId = homeQueryData.currentMember.getMissingChipIdContractId() HomeData( contractStatus = contractStatus, claimStatusCardsData = homeQueryData.claimStatusCards(), @@ -180,8 +178,6 @@ internal class GetHomeDataUseCaseImpl( firstVetSections = firstVetActions, crossSells = crossSells, travelBannerInfo = travelBannerInfo?.firstOrNull(), - hasMissingChipId = hasMissingChipId, - missingChipIdContractId = missingChipIdContractId, ) }.onLeft { error: ApolloOperationError -> logcat(operationError = error) { "GetHomeDataUseCase failed with $error" } @@ -270,18 +266,6 @@ internal class GetHomeDataUseCaseImpl( return activeContracts.isEmpty() && pendingContracts.isNotEmpty() } - private fun HomeQuery.Data.CurrentMember.hasMissingChipId(): Boolean { - return getMissingChipIdContractId() != null - } - - private fun HomeQuery.Data.CurrentMember.getMissingChipIdContractId(): String? { - activeContracts.firstOrNull { contract -> - val contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup() - contractGroup == ContractGroup.CAT || contractGroup == ContractGroup.DOG - }?.let { return it.id } - - return null - } } private fun HomeQuery.Data.claimStatusCards(): HomeData.ClaimStatusCardsData? { @@ -303,8 +287,6 @@ internal data class HomeData( val firstVetSections: List, val crossSells: CrossSellSheetData, val travelBannerInfo: AddonBannerInfo?, - val hasMissingChipId: Boolean = false, - val missingChipIdContractId: String? = null, ) { @Immutable data class ClaimStatusCardsData( diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt index 73635c83e3..1b1eb56080 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomePresenter.kt @@ -147,8 +147,6 @@ internal class HomePresenter( addonBannerInfo = successData.addonBannerInfo, isExperimentalClaimChatEnabled = isExperimentalClaimChatEnabled, isProduction = isProduction, - hasMissingChipId = successData.hasMissingChipId, - missingChipIdContractId = successData.missingChipIdContractId, ) } } @@ -189,8 +187,6 @@ internal sealed interface HomeUiState { val isProduction: Boolean, override val isHelpCenterEnabled: Boolean, override val hasUnseenChatMessages: Boolean, - val hasMissingChipId: Boolean = false, - val missingChipIdContractId: String? = null, ) : HomeUiState data class Error(val message: String?) : HomeUiState @@ -209,8 +205,6 @@ private data class SuccessData( val crossSellsAction: HomeTopBarAction.CrossSellsAction?, val hasUnseenChatMessages: Boolean, val addonBannerInfo: AddonBannerInfo?, - val hasMissingChipId: Boolean = false, - val missingChipIdContractId: String? = null, ) { companion object { fun fromLastState(lastState: HomeUiState): SuccessData? { @@ -226,8 +220,6 @@ private data class SuccessData( firstVetAction = lastState.firstVetAction, hasUnseenChatMessages = lastState.hasUnseenChatMessages, addonBannerInfo = lastState.addonBannerInfo, - hasMissingChipId = lastState.hasMissingChipId, - missingChipIdContractId = lastState.missingChipIdContractId, ) } @@ -269,7 +261,6 @@ private data class SuccessData( veryImportantMessages = homeData.veryImportantMessages, memberReminders = homeData.memberReminders.copy( enableNotifications = null, - missingChipId = homeData.missingChipIdContractId?.let { MemberReminder.MissingChipId(it) }, ), showHelpCenter = homeData.showHelpCenter, chatAction = chatAction, @@ -277,8 +268,6 @@ private data class SuccessData( crossSellsAction = crossSellsAction, hasUnseenChatMessages = homeData.hasUnseenChatMessages, addonBannerInfo = homeData.travelBannerInfo, - hasMissingChipId = homeData.hasMissingChipId, - missingChipIdContractId = homeData.missingChipIdContractId, ) } } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt index 51ab14f3f1..b6637c751d 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt @@ -12,6 +12,7 @@ import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.core.common.formatName import com.hedvig.android.core.common.formatSsn import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractId import com.hedvig.android.data.contract.toContractGroup diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt index 8def8d5ded..8f5873d2d7 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt @@ -5,6 +5,7 @@ import arrow.core.right import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractType import com.hedvig.android.data.productvariant.ProductVariant diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt index 2a556c57cc..5464b3ff5c 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt @@ -3,6 +3,7 @@ package com.hedvig.android.feature.insurances.data import com.hedvig.android.core.common.formatName import com.hedvig.android.core.common.formatSsn import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractId import com.hedvig.android.data.display.items.DisplayItem import com.hedvig.android.data.productvariant.AddonVariant @@ -100,11 +101,6 @@ sealed interface InsuranceContract { } } -sealed interface ChipIdState { - data object Missing: ChipIdState - data object NotRequired: ChipIdState - data class Present(val value: String): ChipIdState -} data class Addon( val addonVariant: AddonVariant, diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt index 72a4d20354..c317a8fcc3 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt @@ -74,7 +74,7 @@ import com.hedvig.android.design.system.hedvig.NotificationDefaults.Notification import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.hedvigDropShadow import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader -import com.hedvig.android.feature.insurances.data.ChipIdState +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceContract import com.hedvig.android.feature.insurances.data.InsuranceContract.EstablishedInsuranceContract diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt index a131bc560b..b856d2c5a9 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt @@ -66,10 +66,10 @@ import com.hedvig.android.design.system.hedvig.hedvigDropShadow import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.design.system.hedvig.rememberHedvigTabRowState import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.feature.insurances.data.Addon import com.hedvig.android.feature.insurances.data.AvailableAddon import com.hedvig.android.feature.insurances.data.CancelInsuranceData -import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceAgreement.CreationCause.NEW_CONTRACT import com.hedvig.android.feature.insurances.data.InsuranceContract diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt index ca2a9d7eb0..e22736b4b5 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt @@ -25,13 +25,13 @@ import com.hedvig.android.design.system.hedvig.HedvigNotificationCard import com.hedvig.android.design.system.hedvig.HedvigPreview import com.hedvig.android.design.system.hedvig.HedvigText import com.hedvig.android.design.system.hedvig.HedvigTextButton +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.NotificationDefaults.InfoCardStyle.Button import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority import com.hedvig.android.design.system.hedvig.PriceInfoForBottomSheet import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState -import com.hedvig.android.feature.insurances.data.ChipIdState import hedvig.resources.CONTRACT_VIEW_CERTIFICATE_BUTTON import hedvig.resources.Res import hedvig.resources.general_close_button diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index 906ff0f38f..dff7ceb2cc 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -74,12 +74,12 @@ import com.hedvig.android.design.system.hedvig.icon.HedvigIcons import com.hedvig.android.design.system.hedvig.icon.InfoFilled import com.hedvig.android.design.system.hedvig.icon.Lock import com.hedvig.android.design.system.hedvig.icon.WarningFilled +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.design.system.hedvig.rememberHedvigBirthDateDateTimeFormatter import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.design.system.hedvig.rememberHedvigDateTimeFormatter import com.hedvig.android.design.system.hedvig.show import com.hedvig.android.feature.insurances.data.AvailableAddon -import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.ContractAddon import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceAgreement.CoInsured diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt index 85216b41d8..19a1607337 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt @@ -15,6 +15,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.ImageLoader import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractType import com.hedvig.android.data.productvariant.ProductVariant @@ -26,7 +27,6 @@ import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.InsuranceCard import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader -import com.hedvig.android.feature.insurances.data.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceContract.EstablishedInsuranceContract import com.hedvig.android.feature.insurances.data.MonthlyCost diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt index df0542b361..0a095ccd0b 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt @@ -108,6 +108,7 @@ internal fun ProfileDestination( openUrl: (String) -> Unit, onNavigateToNewConversation: () -> Unit, viewModel: ProfileViewModel, + navigateToChipId: (contractId: String) -> Unit, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -127,6 +128,7 @@ internal fun ProfileDestination( snoozeNotificationPermission = { viewModel.emit(ProfileUiEvent.SnoozeNotificationPermission) }, onLogout = { viewModel.emit(ProfileUiEvent.Logout) }, onNavigateToNewConversation = onNavigateToNewConversation, + navigateToChipId = navigateToChipId, ) } @@ -148,6 +150,7 @@ private fun ProfileScreen( onNavigateToNewConversation: () -> Unit, snoozeNotificationPermission: () -> Unit, onLogout: () -> Unit, + navigateToChipId: (contractId: String) -> Unit, ) { val systemBarInsetTopDp = with(LocalDensity.current) { WindowInsets.systemBars.getTop(this).toDp() @@ -226,7 +229,7 @@ private fun ProfileScreen( modifier = Modifier.onConsumedWindowInsetsChanged { consumedWindowInsets.insets = it }, onNavigateToNewConversation = onNavigateToNewConversation, navigateToContactInfo = navigateToContactInfo, - navigateToChipId = {}, //todo + navigateToChipId = navigateToChipId, ) if (memberReminders.isNotEmpty()) { Spacer(Modifier.height(16.dp)) diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt index ee1dde4b12..4564152f37 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt @@ -46,6 +46,7 @@ fun NavGraphBuilder.profileGraph( onNavigateToTravelCertificate: () -> Unit, onNavigateToInsuranceEvidence: () -> Unit, openUrl: (String) -> Unit, + navigateToChipId: (contractId: String) -> Unit, ) { navgraph( startDestination = ProfileDestination.Profile::class, @@ -83,6 +84,7 @@ fun NavGraphBuilder.profileGraph( onNavigateToNewConversation = dropUnlessResumed { onNavigateToNewConversation() }, + navigateToChipId = navigateToChipId, ) } navdestination( diff --git a/app/member-reminders/member-reminders-public/build.gradle.kts b/app/member-reminders/member-reminders-public/build.gradle.kts index 08750bf6f2..7ff1c4d7cf 100644 --- a/app/member-reminders/member-reminders-public/build.gradle.kts +++ b/app/member-reminders/member-reminders-public/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { implementation(projects.coreBuildConstants) implementation(projects.coreCommonPublic) implementation(projects.coreDemoMode) + implementation(projects.dataContract) implementation(projects.dataPayingMember) implementation(projects.featureFlagsPublic) diff --git a/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql b/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql new file mode 100644 index 0000000000..682397fddd --- /dev/null +++ b/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql @@ -0,0 +1,12 @@ +query MissingChipIdReminder { + currentMember { + activeContracts { + id + currentAgreement { + productVariant { + typeOfContract + } + } + } + } +} diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt index 3ac8f43778..ef53e19da5 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt @@ -22,6 +22,7 @@ internal class GetMemberRemindersUseCaseImpl( private val getUpcomingRenewalRemindersUseCase: GetUpcomingRenewalRemindersUseCase, private val getNeedsCoInsuredInfoRemindersUseCase: GetNeedsCoInsuredInfoRemindersUseCase, private val getContactInfoUpdateIsNeededUseCase: GetContactInfoUpdateIsNeededUseCase, + private val getMissingChipIdReminderUseCase: GetMissingChipIdReminderUseCase, ) : GetMemberRemindersUseCase { override fun invoke(): Flow { return combine( @@ -52,19 +53,22 @@ internal class GetMemberRemindersUseCaseImpl( getUpcomingRenewalRemindersUseCase.invoke().map { it.mapLeft { null }.merge() }, getNeedsCoInsuredInfoRemindersUseCase.invoke(), getContactInfoUpdateIsNeededUseCase.invoke(), - ) { - enableNotifications: MemberReminder.EnableNotifications?, - connectPayment: MemberReminder.PaymentReminder?, - upcomingRenewalReminders: NonEmptyList?, - coInsuredInfoResult: Either>, - contactInfoReminder: Either, - -> + getMissingChipIdReminderUseCase.invoke(), + ) { values -> + val enableNotifications = values[0] as MemberReminder.EnableNotifications? + val connectPayment = values[1] as MemberReminder.PaymentReminder? + val upcomingRenewalReminders = values[2] as NonEmptyList? + val coInsuredInfoResult = values[3] as Either> + val contactInfoReminder = values[4] as Either + val missingChipId = values[5] as MemberReminder.MissingChipId? + MemberReminders( connectPayment = connectPayment, upcomingRenewals = upcomingRenewalReminders, enableNotifications = enableNotifications, coInsuredInfo = coInsuredInfoResult.getOrNull(), updateContactInfo = contactInfoReminder.getOrNull(), + missingChipId = missingChipId, ) } } diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt new file mode 100644 index 0000000000..a816c017ab --- /dev/null +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt @@ -0,0 +1,38 @@ +package com.hedvig.android.memberreminders + +import com.apollographql.apollo.ApolloClient +import com.apollographql.apollo.cache.normalized.FetchPolicy +import com.apollographql.apollo.cache.normalized.fetchPolicy +import com.hedvig.android.apollo.safeFlow +import com.hedvig.android.data.contract.ContractGroup +import com.hedvig.android.data.contract.toContractGroup +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.mapLatest +import octopus.MissingChipIdReminderQuery + +internal interface GetMissingChipIdReminderUseCase { + fun invoke(): Flow +} + +internal class GetMissingChipIdReminderUseCaseImpl( + private val apolloClient: ApolloClient, +) : GetMissingChipIdReminderUseCase { + override fun invoke(): Flow { + return apolloClient.query(MissingChipIdReminderQuery()) + .fetchPolicy(FetchPolicy.CacheAndNetwork) + .safeFlow() + .mapLatest { result -> + result.fold( + ifRight = { data -> + data.currentMember.activeContracts + .firstOrNull { contract -> + val contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup() + contractGroup == ContractGroup.CAT || contractGroup == ContractGroup.DOG + } + ?.let { MemberReminder.MissingChipId(it.id) } + }, + ifLeft = { null }, + ) + } + } +} diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/di/MemberRemindersModule.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/di/MemberRemindersModule.kt index a5b2208941..1fc843f70e 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/di/MemberRemindersModule.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/di/MemberRemindersModule.kt @@ -14,6 +14,8 @@ import com.hedvig.android.memberreminders.GetContactInfoUpdateIsNeededUseCase import com.hedvig.android.memberreminders.GetContactInfoUpdateIsNeededUseCaseImpl import com.hedvig.android.memberreminders.GetMemberRemindersUseCase import com.hedvig.android.memberreminders.GetMemberRemindersUseCaseImpl +import com.hedvig.android.memberreminders.GetMissingChipIdReminderUseCase +import com.hedvig.android.memberreminders.GetMissingChipIdReminderUseCaseImpl import com.hedvig.android.memberreminders.GetNeedsCoInsuredInfoRemindersUseCase import com.hedvig.android.memberreminders.GetNeedsCoInsuredInfoRemindersUseCaseImpl import com.hedvig.android.memberreminders.GetUpcomingRenewalRemindersUseCase @@ -44,6 +46,11 @@ val memberRemindersModule = module { get(), ) } + single { + GetMissingChipIdReminderUseCaseImpl( + get(), + ) + } single { GetMemberRemindersUseCaseImpl( get(), @@ -51,6 +58,7 @@ val memberRemindersModule = module { get(), get(), get(), + get(), ) } single { From 52a7b41182119faa5a5422e4efd9d06472f56417 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 15:08:38 +0200 Subject: [PATCH 12/42] add select insurance destination --- app/feature/feature-chip-id/build.gradle.kts | 2 + .../GetPetContractsForChipIdQuery.graphql | 14 ++ .../data/GetPetContractsForChipIdUseCase.kt | 52 ++++++ .../chip/id/data/PetContractForChipId.kt | 10 + .../feature/chip/id/di/ChipIdModule.kt | 18 +- .../feature/chip/id/navigation/ChipIdGraph.kt | 38 +++- .../id/navigation/ChipIdNavDestination.kt | 9 +- .../feature/chip/id/ui/AddChipIdScreen.kt | 8 +- .../feature/chip/id/ui/AddChipIdViewModel.kt | 8 +- .../SelectInsuranceForChipIdDestination.kt | 173 ++++++++++++++++++ .../SelectInsuranceForChipIdViewModel.kt | 114 ++++++++++++ 11 files changed, 427 insertions(+), 19 deletions(-) create mode 100644 app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt create mode 100644 app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt diff --git a/app/feature/feature-chip-id/build.gradle.kts b/app/feature/feature-chip-id/build.gradle.kts index 5bee08e070..d4bbd6d821 100644 --- a/app/feature/feature-chip-id/build.gradle.kts +++ b/app/feature/feature-chip-id/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { api(libs.androidx.navigation.common) implementation(libs.androidx.navigation.compose) + implementation(libs.apollo.normalizedCache) implementation(libs.apollo.runtime) implementation(libs.arrow.core) implementation(libs.coroutines.core) @@ -26,6 +27,7 @@ dependencies { implementation(projects.coreCommonPublic) implementation(projects.coreResources) implementation(projects.coreUiData) + implementation(projects.dataContract) implementation(projects.designSystemHedvig) implementation(projects.moleculePublic) implementation(projects.navigationCommon) diff --git a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql new file mode 100644 index 0000000000..1efc4b9ebf --- /dev/null +++ b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql @@ -0,0 +1,14 @@ +query GetPetContractsForChipId { + currentMember { + activeContracts { + id + exposureDisplayNameShort + currentAgreement { + productVariant { + displayName + typeOfContract + } + } + } + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt new file mode 100644 index 0000000000..bae37f2e99 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt @@ -0,0 +1,52 @@ +package com.hedvig.android.feature.chip.id.data + +import arrow.core.Either +import com.apollographql.apollo.ApolloClient +import com.apollographql.apollo.cache.normalized.FetchPolicy +import com.apollographql.apollo.cache.normalized.fetchPolicy +import com.hedvig.android.apollo.ApolloOperationError +import com.hedvig.android.apollo.safeFlow +import com.hedvig.android.data.contract.ContractGroup +import com.hedvig.android.data.contract.toContractGroup +import com.hedvig.android.logger.logcat +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import octopus.GetPetContractsForChipIdQuery + +internal interface GetPetContractsForChipIdUseCase { + suspend fun invoke(): Either> +} + +internal class GetPetContractsForChipIdUseCaseImpl( + private val apolloClient: ApolloClient, +) : GetPetContractsForChipIdUseCase { + override suspend fun invoke(): Either> { + val flow: Flow>> = apolloClient + .query(GetPetContractsForChipIdQuery()) + .fetchPolicy(FetchPolicy.NetworkOnly) + .safeFlow() + .map { result -> + result.map { data -> + data.currentMember.activeContracts + .mapNotNull { contract -> + val contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup() + if (contractGroup == ContractGroup.CAT || contractGroup == ContractGroup.DOG) { + PetContractForChipId( + id = contract.id, + displayName = contract.currentAgreement.productVariant.displayName, + contractExposure = contract.exposureDisplayNameShort, + contractGroup = contractGroup, + ) + } else { + null + } + } + }.onLeft { error -> + logcat(operationError = error) { "GetPetContractsForChipIdUseCase failed with $error" } + } + } + + return flow.first() + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt new file mode 100644 index 0000000000..12e8dc4dd3 --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt @@ -0,0 +1,10 @@ +package com.hedvig.android.feature.chip.id.data + +import com.hedvig.android.data.contract.ContractGroup + +data class PetContractForChipId( + val id: String, + val displayName: String, + val contractExposure: String, + val contractGroup: ContractGroup, +) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt index 464f24645e..98904be0b8 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt @@ -1,9 +1,12 @@ package com.hedvig.android.feature.chip.id.di import com.apollographql.apollo.ApolloClient +import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase +import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCaseImpl import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCaseImpl import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel +import com.hedvig.android.feature.chip.id.ui.selectinsurance.SelectInsuranceForChipIdViewModel import org.koin.core.module.dsl.viewModel import org.koin.dsl.module @@ -14,10 +17,23 @@ val chipIdModule = module { ) } + single { + GetPetContractsForChipIdUseCaseImpl( + apolloClient = get(), + ) + } + + viewModel { params -> + SelectInsuranceForChipIdViewModel( + preselectedContractId = params.getOrNull(), + getPetContractsForChipIdUseCase = get(), + ) + } + viewModel { params -> AddChipIdViewModel( updateChipIdUseCase = get(), - insuranceId = params.get(), + contractId = params.get(), ) } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index 0b2c07dc82..3412b1e0f5 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -5,9 +5,12 @@ import androidx.navigation.NavGraphBuilder import com.hedvig.android.design.system.hedvig.GlobalSnackBarState import com.hedvig.android.feature.chip.id.ui.AddChipIdDestination import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel +import com.hedvig.android.feature.chip.id.ui.selectinsurance.SelectInsuranceForChipIdDestination +import com.hedvig.android.feature.chip.id.ui.selectinsurance.SelectInsuranceForChipIdViewModel import com.hedvig.android.navigation.compose.navdestination import com.hedvig.android.navigation.compose.navgraph import com.hedvig.android.navigation.compose.typed.getRouteFromBackStack +import com.hedvig.android.navigation.compose.typedPopUpTo import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -17,21 +20,46 @@ fun NavGraphBuilder.chipIdGraph( navigateUp: () -> Unit, ) { navgraph( - startDestination = ChipIdDestination.AddChipId::class, + startDestination = ChipIdDestination.SelectInsuranceForChipId::class, destinationNavTypeAware = ChipIdGraphDestination, ) { - navdestination { backStackEntry -> + navdestination { backStackEntry -> val chipIdGraphDestination = navController .getRouteFromBackStack(backStackEntry) + val preselectedContractId = chipIdGraphDestination.contractId + + val viewModel: SelectInsuranceForChipIdViewModel = koinViewModel { + parametersOf(preselectedContractId) + } + SelectInsuranceForChipIdDestination( + viewModel = viewModel, + navigateUp = navigateUp, + popBackStack = { + navController.popBackStack() + }, + navigateToAddChipId = { contractId: String, popSelectInsurance: Boolean -> + navController.navigate(ChipIdDestination.AddChipId(contractId)) { + if (popSelectInsurance) { + typedPopUpTo { + inclusive = true + } + } + } + }, + ) + } + + navdestination { backStackEntry -> + val contractId = this.contractId val viewModel: AddChipIdViewModel = koinViewModel { - parametersOf(chipIdGraphDestination.contractId) + parametersOf(contractId) } AddChipIdDestination( viewModel = viewModel, globalSnackBarState = globalSnackBarState, navigateUp = navigateUp, - popBackStack = { - navController.popBackStack() + popFlowOnSuccess = { + navController.popBackStack(ChipIdGraphDestination::class, inclusive = true) }, ) } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt index e2a538b2a3..f29684d867 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt @@ -7,13 +7,16 @@ import kotlin.reflect.typeOf import kotlinx.serialization.Serializable @Serializable -data class ChipIdGraphDestination(val contractId: String) : Destination { +data class ChipIdGraphDestination(val contractId: String? = null) : Destination { companion object : DestinationNavTypeAware { - override val typeList: List = listOf(typeOf()) + override val typeList: List = emptyList() } } internal sealed interface ChipIdDestination { @Serializable - data object AddChipId : ChipIdDestination, Destination + data class AddChipId(val contractId: String) : ChipIdDestination, Destination + + @Serializable + data object SelectInsuranceForChipId : ChipIdDestination, Destination } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 6ce1640699..2298e836f0 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -1,14 +1,12 @@ package com.hedvig.android.feature.chip.id.ui import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.togetherWith import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -21,7 +19,6 @@ import androidx.compose.foundation.text.input.InputTransformation import androidx.compose.foundation.text.input.KeyboardActionHandler import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.byValue -import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -51,7 +48,6 @@ import hedvig.resources.CHIP_ID_TOP_TITLE import hedvig.resources.CHIP_ID_WRONG_INPUT import hedvig.resources.CONTACT_INFO_CHANGES_SAVED import hedvig.resources.Res -import hedvig.resources.general_error import hedvig.resources.general_save_button import hedvig.resources.something_went_wrong import org.jetbrains.compose.resources.stringResource @@ -61,7 +57,7 @@ internal fun AddChipIdDestination( viewModel: AddChipIdViewModel, globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, - popBackStack: () -> Unit, + popFlowOnSuccess: () -> Unit, ) { val uiState: AddChipIdUiState by viewModel.uiState.collectAsStateWithLifecycle() AddChipIdScreen( @@ -76,7 +72,7 @@ internal fun AddChipIdDestination( navigateUp = navigateUp, showedSnackBar = { viewModel.emit(AddChipIdEvent.ShowedMessage) - popBackStack() + popFlowOnSuccess() }, ) } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index e1a10a840c..325c84a7b1 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -18,18 +18,18 @@ import com.hedvig.android.molecule.public.MoleculeViewModel internal class AddChipIdViewModel( private val updateChipIdUseCase: UpdateChipIdUseCase, - insuranceId: String, + contractId: String, ) : MoleculeViewModel( initialState = AddChipIdUiState.Loading, presenter = AddChipIdPresenter( updateChipIdUseCase = updateChipIdUseCase, - insuranceId = insuranceId, + contractId = contractId, ), ) internal class AddChipIdPresenter( private val updateChipIdUseCase: UpdateChipIdUseCase, - private val insuranceId: String, + private val contractId: String, ) : MoleculePresenter { @Composable override fun MoleculePresenterScope.present( @@ -51,7 +51,7 @@ internal class AddChipIdPresenter( submittingData = true errorType = null - updateChipIdUseCase.invoke(insuranceId = insuranceId, petId = chipIdState.text.toString()).fold( + updateChipIdUseCase.invoke(insuranceId = contractId, petId = chipIdState.text.toString()).fold( ifLeft = { error -> Snapshot.withMutableSnapshot { submittingData = false diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt new file mode 100644 index 0000000000..d036e6ad9a --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt @@ -0,0 +1,173 @@ +package com.hedvig.android.feature.chip.id.ui.selectinsurance + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.compose.dropUnlessResumed +import com.hedvig.android.compose.ui.dropUnlessResumed +import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigErrorSection +import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.RadioGroup +import com.hedvig.android.design.system.hedvig.RadioOption +import com.hedvig.android.design.system.hedvig.RadioOptionId +import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress +import com.hedvig.android.design.system.hedvig.Icon +import com.hedvig.android.design.system.hedvig.IconButton +import com.hedvig.android.design.system.hedvig.a11y.FlowHeading +import com.hedvig.android.design.system.hedvig.icon.Close +import com.hedvig.android.design.system.hedvig.icon.HedvigIcons +import com.hedvig.android.feature.chip.id.data.PetContractForChipId +import hedvig.resources.ADDON_FLOW_SELECT_INSURANCE_SUBTITLE +import hedvig.resources.ADDON_FLOW_SELECT_INSURANCE_TITLE +import hedvig.resources.Res +import hedvig.resources.SELECT_INSURANCE_TO_REMOVE_ADDON_TITLE +import hedvig.resources.TIER_FLOW_SELECT_INSURANCE_SUBTITLE +import hedvig.resources.general_close_button +import hedvig.resources.general_continue_button +import org.jetbrains.compose.resources.stringResource + +@Composable +internal fun SelectInsuranceForChipIdDestination( + viewModel: SelectInsuranceForChipIdViewModel, + navigateUp: () -> Unit, + popBackStack: () -> Unit, + navigateToAddChipId: (contractId: String, popSelectInsurance: Boolean) -> Unit, +) { + val uiState: SelectInsuranceForChipIdState by viewModel.uiState.collectAsStateWithLifecycle() + + SelectInsuranceForChipIdScreen( + uiState = uiState, + navigateUp = navigateUp, + popBackStack = popBackStack, + navigateToAddChipId = { contractId, popSelectInsurance -> + navigateToAddChipId(contractId, popSelectInsurance) + viewModel.emit(SelectInsuranceForChipIdEvent.ClearNavigation) + }, + selectContract = { contract -> + viewModel.emit(SelectInsuranceForChipIdEvent.SelectContract(contract)) + }, + reload = { + viewModel.emit(SelectInsuranceForChipIdEvent.Reload) + }, + ) +} + +@Composable +private fun SelectInsuranceForChipIdScreen( + uiState: SelectInsuranceForChipIdState, + navigateUp: () -> Unit, + popBackStack: () -> Unit, + reload: () -> Unit, + selectContract: (PetContractForChipId) -> Unit, + navigateToAddChipId: (contractId: String, popSelectInsurance: Boolean) -> Unit, +) { + when (uiState) { + SelectInsuranceForChipIdState.Failure -> { + HedvigScaffold( + navigateUp = navigateUp, + ) { + HedvigErrorSection(onButtonClick = reload, modifier = Modifier.padding(16.dp)) + } + } + + SelectInsuranceForChipIdState.Loading -> { + HedvigFullScreenCenterAlignedProgress() + } + + is SelectInsuranceForChipIdState.Success -> { + LaunchedEffect(uiState.contractIdToContinue) { + if (uiState.contractIdToContinue != null) { + navigateToAddChipId(uiState.contractIdToContinue, + uiState.contracts.size == 1) + } + } + if (uiState.contractIdToContinue == null) { + SelectInsuranceForChipIdContentScreen( + uiState = uiState, + navigateUp = navigateUp, + popBackStack = popBackStack, + selectInsurance = selectContract, + navigateToAddChipId = navigateToAddChipId, + ) + } + } + } +} + +@Composable +private fun SelectInsuranceForChipIdContentScreen( + uiState: SelectInsuranceForChipIdState.Success, + navigateUp: () -> Unit, + popBackStack: () -> Unit, + selectInsurance: (selected: PetContractForChipId) -> Unit, + navigateToAddChipId: (contractId: String, popSelectInsurance: Boolean) -> Unit, +) { + HedvigScaffold( + navigateUp = navigateUp, + topAppBarText = "", + topAppBarActions = { + IconButton( + modifier = Modifier.size(24.dp), + onClick = dropUnlessResumed { popBackStack() }, + content = { + Icon( + imageVector = HedvigIcons.Close, + contentDescription = stringResource(Res.string.general_close_button), + ) + }, + ) + }, + ) { + Spacer(modifier = Modifier.height(8.dp)) + FlowHeading( + stringResource(Res.string.TIER_FLOW_SELECT_INSURANCE_SUBTITLE), + null, + Modifier.padding(horizontal = 16.dp), + ) + Spacer(Modifier.weight(1f)) + Spacer(Modifier.height(16.dp)) + RadioGroup( + options = uiState.contracts.map { insuranceForAddon -> + RadioOption( + id = RadioOptionId(insuranceForAddon.id), + text = insuranceForAddon.displayName, + label = insuranceForAddon.contractExposure, + ) + }, + selectedOption = uiState.selectedContract?.id?.let { RadioOptionId(it) }, + onRadioOptionSelected = { optionId -> + uiState.contracts.firstOrNull { it.id == optionId.id }?.let { + selectInsurance(it) + } + }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + Spacer(Modifier.height(12.dp)) + HedvigButton( + stringResource(Res.string.general_continue_button), + enabled = uiState.selectedContract != null, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + onClick = { + uiState.selectedContract?.let { + navigateToAddChipId(it.id, uiState.contracts.size == 1) + } + }, + isLoading = false, + ) + Spacer(Modifier.height(16.dp)) + } +} diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt new file mode 100644 index 0000000000..800a0e97dc --- /dev/null +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt @@ -0,0 +1,114 @@ +package com.hedvig.android.feature.chip.id.ui.selectinsurance + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.Snapshot +import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase +import com.hedvig.android.feature.chip.id.data.PetContractForChipId +import com.hedvig.android.molecule.public.MoleculePresenter +import com.hedvig.android.molecule.public.MoleculePresenterScope +import com.hedvig.android.molecule.public.MoleculeViewModel + +internal class SelectInsuranceForChipIdViewModel( + private val preselectedContractId: String?, + private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, +) : MoleculeViewModel( + initialState = SelectInsuranceForChipIdState.Loading, + presenter = SelectInsuranceForChipIdPresenter(preselectedContractId, getPetContractsForChipIdUseCase), +) + +internal class SelectInsuranceForChipIdPresenter( + private val preselectedContractId: String?, + private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, +) : MoleculePresenter { + @Composable + override fun MoleculePresenterScope.present( + lastState: SelectInsuranceForChipIdState, + ): SelectInsuranceForChipIdState { + var currentState by remember { mutableStateOf(lastState) } + var loadIteration by remember { mutableIntStateOf(0) } + + var selectedContract: PetContractForChipId? by remember { mutableStateOf(null) } + var contractIdToContinue: String? by remember { mutableStateOf(null) } + + LaunchedEffect(loadIteration) { + currentState = SelectInsuranceForChipIdState.Loading + val result = getPetContractsForChipIdUseCase.invoke() + currentState = result.fold( + ifLeft = { SelectInsuranceForChipIdState.Failure }, + ifRight = { contracts -> + val preselected = contracts.firstOrNull { it.id == preselectedContractId } ?: contracts.firstOrNull() + + if (contracts.size == 1) { + contractIdToContinue = contracts[0].id + } + + SelectInsuranceForChipIdState.Success( + contracts = contracts, + selectedContract = preselected, + contractIdToContinue = contractIdToContinue, + ) + }, + ) + } + + CollectEvents { event -> + when (event) { + SelectInsuranceForChipIdEvent.Reload -> { + loadIteration++ + } + + is SelectInsuranceForChipIdEvent.SelectContract -> { + selectedContract = event.contract + } + + SelectInsuranceForChipIdEvent.SubmitSelected -> { + selectedContract?.let { selected -> + contractIdToContinue = selected.id + } + } + + SelectInsuranceForChipIdEvent.ClearNavigation -> { + contractIdToContinue = null + } + } + } + + return when (val state = currentState) { + is SelectInsuranceForChipIdState.Success -> { + state.copy( + selectedContract = selectedContract ?: state.selectedContract, + contractIdToContinue = contractIdToContinue, + ) + } + else -> state + } + } +} + +internal sealed interface SelectInsuranceForChipIdState { + data object Loading : SelectInsuranceForChipIdState + + data class Success( + val contracts: List, + val selectedContract: PetContractForChipId?, + val contractIdToContinue: String? = null, + ) : SelectInsuranceForChipIdState + + data object Failure : SelectInsuranceForChipIdState +} + +internal sealed interface SelectInsuranceForChipIdEvent { + data object Reload : SelectInsuranceForChipIdEvent + + data class SelectContract(val contract: PetContractForChipId) : SelectInsuranceForChipIdEvent + + data object SubmitSelected : SelectInsuranceForChipIdEvent + + data object ClearNavigation : SelectInsuranceForChipIdEvent +} From 055e87ae5e6c8cfe5679cd8141439cd8baec28a9 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 16:05:44 +0200 Subject: [PATCH 13/42] impl missingPetId from BE --- .../android/apollo/octopus/schema.graphqls | 29 +++++---- .../android/app/navigation/HedvigNavHost.kt | 12 ++-- .../android/data/contract/ChipIdState.kt | 2 - .../GetPetContractsForChipIdQuery.graphql | 4 +- .../data/GetPetContractsForChipIdUseCase.kt | 47 ++++++-------- .../chip/id/data/PetContractForChipId.kt | 1 - .../feature/home/home/navigation/HomeGraph.kt | 2 +- .../feature/home/home/ui/HomeDestination.kt | 6 +- .../graphql/QueryInsuranceContracts.graphql | 1 + .../data/GetInsuranceContractsUseCase.kt | 6 +- .../ContractDetailDestination.kt | 6 +- .../EditInsuranceBottomSheetContent.kt | 19 +----- .../insurancedetail/yourinfo/YourInfoTab.kt | 65 +++++-------------- .../insurances/navigation/InsuranceGraph.kt | 2 +- .../feature/profile/tab/ProfileDestination.kt | 4 +- .../feature/profile/tab/ProfileGraph.kt | 2 +- .../QueryMissingChipIdReminder.graphql | 7 +- .../GetMemberRemindersUseCase.kt | 1 - .../GetMissingChipIdReminderUseCase.kt | 7 +- .../memberreminders/ui/MemberReminderCards.kt | 10 ++- 20 files changed, 85 insertions(+), 148 deletions(-) diff --git a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls index e5195cf758..8f16d8b8c4 100644 --- a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls +++ b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls @@ -1308,6 +1308,10 @@ type Contract { """ coOwners: [ContractCoOwner!] """ + Checks if petId is missing on the current or upcoming agreement. + """ + missingPetId: Boolean! + """ User messages to show due to self change is blocked. """ selfChangeBlockers: ContractSelfChangeBlockers @@ -3434,6 +3438,11 @@ type Mutation { """ priceIntentConfirm(priceIntentId: UUID!): PriceIntentMutationOutput! """ + Apply the customer's registered address (from SPAR lookup) directly into the price intent data + server-side, so the real address value never needs to be sent to the client. + """ + priceIntentApplySuggestedAddress(priceIntentId: UUID!): PriceIntentMutationOutput! + """ Change the start date of the given `ProductOffer`s by their ID. This is used because it's common to want to change the start date AFTER getting the offer. """ @@ -3446,14 +3455,6 @@ type Mutation { """ productOfferAddonsSelect(productOfferId: UUID!, addonIds: [UUID!]!): ProductOffersMutationOutput! """ - Reprice an existing product offer with updated data. Merges the provided data with the offer's - existing `priceIntentData`, creates a new underwriter quote matching the original variant, - and replaces the offer. - Useful for recommendation offers that don't have a `priceIntentId` and therefore can't use the - normal `priceIntentDataUpdate` + `priceIntentConfirm` flow. - """ - productOfferReprice(offerId: UUID!, data: PricingFormData!): ProductOffersMutationOutput! - """ Update the customer of the shop session. Only non-null fields will be changed. Can trigger automatic lookup of other information. The session can be placed in a "point of no return" state where it is no longer legal to update the customer, @@ -3652,6 +3653,10 @@ type PriceIntent { """ suggestedData: PricingFormData! """ + Masked display values of the customer's registered address. Null when no suggested address is available. + """ + suggestedAddressDisplay: SuggestedAddressDisplay + """ The resulting product offers generated by inputting data and confirming the intent. """ offers: [ProductOffer!]! @@ -3983,10 +3988,6 @@ type ProductOfferPriceMatch { externalPrice: Money! externalInsurer: ExternalInsurer! priceReduction: Money! - """ - Renewal date of the external insurer's policy. Null when not provided by the external insurer. - """ - renewalDate: Date } type ProductOffersMutationOutput { productOffers: [ProductOffer!]! @@ -4478,6 +4479,10 @@ type StoryblokImageAsset { src: String! alt: String } +type SuggestedAddressDisplay { + maskedStreet: String + maskedZipCode: String +} """ Represents a case of switching, pointing towards a soon-to-be insurance Contract on our platform. If it is not completed, it can be by calling `Mutation.switcherCaseComplete`. diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index 9df464258a..dfde19c516 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -223,8 +223,8 @@ internal fun HedvigNavHost( navController.navigate(ProfileDestination.ContactInfo) }, imageLoader = imageLoader, - navigateToChipIdScreen = { contractId: String -> - navController.navigate(ChipIdGraphDestination(contractId)) + navigateToChipIdScreen = { + navController.navigate(ChipIdGraphDestination()) }, ) insuranceGraph( @@ -334,8 +334,8 @@ internal fun HedvigNavHost( ), ) }, - navigateToChipIdScreen = { contractId: String -> - navController.navigate(ChipIdGraphDestination(contractId)) + navigateToChipIdScreen = { + navController.navigate(ChipIdGraphDestination()) }, ) foreverGraph( @@ -389,8 +389,8 @@ internal fun HedvigNavHost( navController.navigate(InsuranceEvidenceGraphDestination) }, openUrl = openUrl, - navigateToChipId = { contractId -> - navController.navigate(ChipIdGraphDestination(contractId)) + navigateToChipId = { + navController.navigate(ChipIdGraphDestination()) }, ) cbmChatGraph( diff --git a/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt b/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt index 9c58fe70de..15a77b32e3 100644 --- a/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt +++ b/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ChipIdState.kt @@ -4,6 +4,4 @@ sealed interface ChipIdState { data object Missing : ChipIdState data object NotRequired : ChipIdState - - data class Present(val value: String) : ChipIdState } diff --git a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql index 1efc4b9ebf..b4d5f6b4dc 100644 --- a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql +++ b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql @@ -3,10 +3,10 @@ query GetPetContractsForChipId { activeContracts { id exposureDisplayNameShort + missingPetId currentAgreement { productVariant { - displayName - typeOfContract + displayName } } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt index bae37f2e99..3662802d03 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt @@ -5,13 +5,8 @@ import com.apollographql.apollo.ApolloClient import com.apollographql.apollo.cache.normalized.FetchPolicy import com.apollographql.apollo.cache.normalized.fetchPolicy import com.hedvig.android.apollo.ApolloOperationError -import com.hedvig.android.apollo.safeFlow -import com.hedvig.android.data.contract.ContractGroup -import com.hedvig.android.data.contract.toContractGroup +import com.hedvig.android.apollo.safeExecute import com.hedvig.android.logger.logcat -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map import octopus.GetPetContractsForChipIdQuery internal interface GetPetContractsForChipIdUseCase { @@ -22,31 +17,27 @@ internal class GetPetContractsForChipIdUseCaseImpl( private val apolloClient: ApolloClient, ) : GetPetContractsForChipIdUseCase { override suspend fun invoke(): Either> { - val flow: Flow>> = apolloClient + return apolloClient .query(GetPetContractsForChipIdQuery()) .fetchPolicy(FetchPolicy.NetworkOnly) - .safeFlow() - .map { result -> - result.map { data -> - data.currentMember.activeContracts - .mapNotNull { contract -> - val contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup() - if (contractGroup == ContractGroup.CAT || contractGroup == ContractGroup.DOG) { - PetContractForChipId( - id = contract.id, - displayName = contract.currentAgreement.productVariant.displayName, - contractExposure = contract.exposureDisplayNameShort, - contractGroup = contractGroup, - ) - } else { - null - } + .safeExecute() + .map { data -> + data.currentMember.activeContracts + .mapNotNull { contract -> + if (contract.missingPetId) { + val result = PetContractForChipId( + id = contract.id, + displayName = contract.currentAgreement.productVariant.displayName, + contractExposure = contract.exposureDisplayNameShort, + ) + logcat { "GetPetContractsForChipIdUseCaseImpl: result: $result contract.missingPetId: ${contract.missingPetId}" } + result + } else { + null } - }.onLeft { error -> - logcat(operationError = error) { "GetPetContractsForChipIdUseCase failed with $error" } - } + } + }.onLeft { error -> + logcat(operationError = error) { "GetPetContractsForChipIdUseCase failed with $error" } } - - return flow.first() } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt index 12e8dc4dd3..de17a84a51 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt @@ -6,5 +6,4 @@ data class PetContractForChipId( val id: String, val displayName: String, val contractExposure: String, - val contractGroup: ContractGroup, ) diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt index 842eb1e0fa..ece8500197 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt @@ -30,7 +30,7 @@ fun NavGraphBuilder.homeGraph( navigateToHelpCenter: () -> Unit, navigateToClaimChat: () -> Unit, navigateToClaimChatInDevMode: () -> Unit, - navigateToChipIdScreen: (String) -> Unit, + navigateToChipIdScreen: () -> Unit, openAppSettings: () -> Unit, openUrl: (String) -> Unit, imageLoader: ImageLoader, diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt index f36bf3ddec..fe7b538b1f 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt @@ -165,7 +165,7 @@ internal fun HomeDestination( navigateToMissingInfo: (String, CoInsuredFlowType) -> Unit, navigateToFirstVet: (List) -> Unit, navigateToContactInfo: () -> Unit, - navigateToChipId: (String) -> Unit, + navigateToChipId: () -> Unit, imageLoader: ImageLoader, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -216,7 +216,7 @@ private fun HomeScreen( navigateToMissingInfo: (String, CoInsuredFlowType) -> Unit, navigateToFirstVet: (List) -> Unit, navigateToContactInfo: () -> Unit, - navigateToChipIdScreen: (String) -> Unit, + navigateToChipIdScreen: () -> Unit, markCrossSellsNotificationAsSeen: () -> Unit, setEpochDayWhenLastToolTipShown: (Long) -> Unit, imageLoader: ImageLoader, @@ -435,7 +435,7 @@ private fun HomeScreenSuccess( navigateToMissingInfo: (String, CoInsuredFlowType) -> Unit, onNavigateToNewConversation: () -> Unit, navigateToContactInfo: () -> Unit, - navigateToChipIdScreen: (String) -> Unit, + navigateToChipIdScreen: () -> Unit, modifier: Modifier = Modifier, ) { val isInPreview = LocalInspectionMode.current diff --git a/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql b/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql index 65ae234483..27af10ec61 100644 --- a/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql +++ b/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql @@ -82,6 +82,7 @@ fragment ContractFragment on Contract { displayName description } + missingPetId } fragment AgreementFragment on Agreement { diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt index b6637c751d..d6e1e3ad52 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt @@ -230,9 +230,9 @@ private fun ContractFragment.toContract( description = it.description, ) }.orEmpty(), - chipId = when (currentAgreement.productVariant.typeOfContract.toContractGroup()) { - ContractGroup.CAT, ContractGroup.DOG -> ChipIdState.Missing //todo!!! - else -> ChipIdState.NotRequired + chipId = when (missingPetId) { + true -> ChipIdState.Missing + false -> ChipIdState.NotRequired } ) } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt index b856d2c5a9..f9bcfa5261 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt @@ -112,7 +112,7 @@ internal fun ContractDetailDestination( navigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, navigateToAddAddon: (AvailableAddon) -> Unit, - navigateToChipIdScreen: (contractId: String) -> Unit, + navigateToChipIdScreen: () -> Unit, ) { val uiState: ContractDetailsUiState by viewModel.uiState.collectAsStateWithLifecycle() ContractDetailScreen( @@ -156,7 +156,7 @@ private fun ContractDetailScreen( openUrl: (String) -> Unit, navigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, - navigateToChipIdScreen: (String) -> Unit, + navigateToChipIdScreen: () -> Unit, navigateToAddAddon: (AvailableAddon) -> Unit, ) { Column(Modifier.fillMaxSize()) { @@ -364,7 +364,7 @@ private fun ContractDetailScreen( navigateToUpgradeAddon = navigateToUpgradeAddon, chipIdState = contract.chipId, onFillChipId = { - navigateToChipIdScreen(contract.id) + navigateToChipIdScreen() } ) } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt index 63736770ac..bc66579b9b 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt @@ -43,7 +43,6 @@ import hedvig.resources.Res import hedvig.resources.general_cancel_button import hedvig.resources.general_continue_button import hedvig.resources.insurance_details_change_coverage -import kotlin.collections.buildList import org.jetbrains.compose.resources.stringResource @Composable @@ -53,14 +52,12 @@ internal fun EditInsuranceBottomSheetContent( allowChangeTier: Boolean, allowTerminatingInsurance: Boolean, allowRemovingAddon: Boolean, - missingChipId: Boolean, onEditCoInsuredClick: () -> Unit, onEditCoOwnersClick: () -> Unit, onChangeTierClick: () -> Unit, onCancelInsuranceClick: () -> Unit, onRemoveAddonClick: () -> Unit, onDismiss: () -> Unit, - onNavigateToChipId: () -> Unit, modifier: Modifier = Modifier, ) { var selectedItemId: String? by rememberSaveable { mutableStateOf(null) } @@ -110,15 +107,6 @@ internal fun EditInsuranceBottomSheetContent( ), ) } - if (missingChipId) { - add( - RadioOption( - RadioOptionId("5"), - "Add missing chip id for your pet", //todo! - "Speed up any potential claims", //todo - ), - ) - } } Column( modifier = modifier, @@ -162,10 +150,7 @@ internal fun EditInsuranceBottomSheetContent( "4" if allowRemovingAddon -> { onRemoveAddonClick() } - - "5" if missingChipId -> { - onNavigateToChipId() - } + else -> {} } @@ -202,8 +187,6 @@ private fun PreviewEditInsuranceBottomSheetContent() { onCancelInsuranceClick = {}, onRemoveAddonClick = {}, modifier = Modifier.padding(horizontal = 16.dp), - missingChipId = true, - onNavigateToChipId = {}, ) } } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index dff7ceb2cc..f08275470e 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -91,6 +91,8 @@ import hedvig.resources.ADDON_FLOW_UPGRADE_ADDON_DESCRIPTION import hedvig.resources.CHANGE_ADDRESS_CO_INSURED_LABEL import hedvig.resources.CHANGE_ADDRESS_ONLY_YOU import hedvig.resources.CHANGE_ADDRESS_YOU_PLUS +import hedvig.resources.CHIP_ID_MISSING_BUTTON +import hedvig.resources.CHIP_ID_MISSING_MESSAGE import hedvig.resources.CONTRACT_ADD_COINSURED_ACTIVE_FROM import hedvig.resources.CONTRACT_ADD_COINSURED_ACTIVE_UNTIL import hedvig.resources.CONTRACT_COINSURED @@ -192,12 +194,7 @@ internal fun YourInfoTab( onRemoveAddonClick = { editYourInfoBottomSheet.dismiss() navigateToRemoveAddon(ContractId(contractId), null) - }, - missingChipId = chipIdState is ChipIdState.Missing, - onNavigateToChipId = { - editYourInfoBottomSheet.dismiss() - onFillChipId() - }, + } ) } @@ -308,12 +305,6 @@ internal fun YourInfoTab( onInfoIconClick, Modifier.padding(horizontal = 16.dp), ) - if (chipIdState is ChipIdState.Present) { - ChipIdRow( - chipIdState.value, - Modifier.padding(horizontal = 16.dp), - ) - } if (allowEditCoInsured && coInsured.isNotEmpty()) { HorizontalDivider(Modifier.padding(horizontal = 16.dp)) Spacer(Modifier.height(16.dp)) @@ -366,6 +357,20 @@ internal fun YourInfoTab( .padding(horizontal = 16.dp), ) } + val hasMissingChipId = chipIdState is ChipIdState.Missing + if (hasMissingChipId) { + HedvigNotificationCard( + message = stringResource(Res.string.CHIP_ID_MISSING_MESSAGE), + priority = Attention, + style = Button( + stringResource(Res.string.CHIP_ID_MISSING_BUTTON), + onFillChipId + ), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + } AddonsSection( existingAddons = existingAddons, availableAddons = availableAddons, @@ -734,40 +739,6 @@ internal fun PriceRow( ) } -@Composable -internal fun ChipIdRow( - chipId: String, - modifier: Modifier = Modifier, -) { - HorizontalItemsWithMaximumSpaceTaken( - modifier = modifier.horizontalDivider(DividerPosition.Top), - startSlot = { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(vertical = 16.dp), - ) { - HedvigText( - "Pet Chip-ID", //todo!!! - ) - } - }, - endSlot = { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.End, - modifier = Modifier.padding(vertical = 16.dp), - ) { - HedvigText( - text = chipId, - color = HedvigTheme.colorScheme.textSecondary, - textAlign = TextAlign.End, - ) - } - }, - spaceBetween = 8.dp, - ) -} - @Composable internal fun CoInsuredSection( coInsuredList: List, @@ -1060,7 +1031,7 @@ private fun PreviewYourInfoTab() { navigateToRemoveAddon = { _, _ -> }, navigateToUpgradeAddon = { _, _ -> }, navigateToAddAddon = {}, - chipIdState = ChipIdState.Present("12345678903456"), + chipIdState = ChipIdState.Missing, onFillChipId = {}, ) } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt index a0ae7e70a2..ba54bddf73 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt @@ -40,7 +40,7 @@ fun NavGraphBuilder.insuranceGraph( onNavigateToAddonPurchaseFlow: (List, AvailableAddon?) -> Unit, onNavigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, - navigateToChipIdScreen: (String) -> Unit, + navigateToChipIdScreen: () -> Unit, ) { navgraph( startDestination = InsurancesDestination.Insurances::class, diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt index 0a095ccd0b..7dae99dc64 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt @@ -108,7 +108,7 @@ internal fun ProfileDestination( openUrl: (String) -> Unit, onNavigateToNewConversation: () -> Unit, viewModel: ProfileViewModel, - navigateToChipId: (contractId: String) -> Unit, + navigateToChipId: () -> Unit, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -150,7 +150,7 @@ private fun ProfileScreen( onNavigateToNewConversation: () -> Unit, snoozeNotificationPermission: () -> Unit, onLogout: () -> Unit, - navigateToChipId: (contractId: String) -> Unit, + navigateToChipId: () -> Unit, ) { val systemBarInsetTopDp = with(LocalDensity.current) { WindowInsets.systemBars.getTop(this).toDp() diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt index 4564152f37..5d152bd500 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt @@ -46,7 +46,7 @@ fun NavGraphBuilder.profileGraph( onNavigateToTravelCertificate: () -> Unit, onNavigateToInsuranceEvidence: () -> Unit, openUrl: (String) -> Unit, - navigateToChipId: (contractId: String) -> Unit, + navigateToChipId: () -> Unit, ) { navgraph( startDestination = ProfileDestination.Profile::class, diff --git a/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql b/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql index 682397fddd..2b3807d7d2 100644 --- a/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql +++ b/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql @@ -1,12 +1,7 @@ query MissingChipIdReminder { currentMember { activeContracts { - id - currentAgreement { - productVariant { - typeOfContract - } - } + missingPetId } } } diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt index ef53e19da5..87b7bee003 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt @@ -149,7 +149,6 @@ sealed interface MemberReminder { } data class MissingChipId( - val contractId: String, override val id: String = UUID.randomUUID().toString(), ) : MemberReminder } diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt index a816c017ab..ea0e55bbd7 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt @@ -25,11 +25,8 @@ internal class GetMissingChipIdReminderUseCaseImpl( result.fold( ifRight = { data -> data.currentMember.activeContracts - .firstOrNull { contract -> - val contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup() - contractGroup == ContractGroup.CAT || contractGroup == ContractGroup.DOG - } - ?.let { MemberReminder.MissingChipId(it.id) } + .firstOrNull { it.missingPetId } + ?.let { MemberReminder.MissingChipId() } }, ifLeft = { null }, ) diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 32fc5d95c9..be7e19bf35 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -62,7 +62,7 @@ fun MemberReminderCardsWithoutNotification( onNavigateToNewConversation: () -> Unit, contentPadding: PaddingValues, navigateToContactInfo: () -> Unit, - navigateToChipId: (String) -> Unit, + navigateToChipId: () -> Unit, modifier: Modifier = Modifier, ) { MemberReminderCards( @@ -89,7 +89,7 @@ fun MemberReminderCards( snoozeNotificationPermissionReminder: () -> Unit, onNavigateToNewConversation: () -> Unit, navigateToContactInfo: () -> Unit, - navigateToChipId: (String) -> Unit, + navigateToChipId: () -> Unit, notificationPermissionState: NotificationPermissionState?, contentPadding: PaddingValues, modifier: Modifier = Modifier, @@ -154,7 +154,7 @@ private fun ColumnScope.MemberReminderCard( navigateToAddMissingInfo: (String, CoInsuredFlowType) -> Unit, navigateToConnectPayment: () -> Unit, navigateToContactInfo: () -> Unit, - navigateToChipId: (String) -> Unit, + navigateToChipId: () -> Unit, openUrl: (String) -> Unit, snoozeNotificationPermissionReminder: () -> Unit, onNavigateToNewConversation: () -> Unit, @@ -221,8 +221,7 @@ private fun ColumnScope.MemberReminderCard( is MemberReminder.MissingChipId -> { ReminderMissingChipId( - contractId = memberReminder.contractId, - navigateToChipId = { navigateToChipId(memberReminder.contractId) }, + navigateToChipId = navigateToChipId, modifier = modifier, ) } @@ -272,7 +271,6 @@ fun ReminderCardUpdateContactInfo(navigateToContactInfo: () -> Unit, modifier: M @Composable internal fun ReminderMissingChipId( - contractId: String, navigateToChipId: () -> Unit, modifier: Modifier = Modifier, ) { From f8ccfe63db283a72e2bbe0d810e1e5bcd4c801d4 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 16:24:49 +0200 Subject: [PATCH 14/42] run ktlint --- .../android/app/navigation/HedvigNavHost.kt | 10 +++--- .../android/design/system/hedvig/Snackbar.kt | 5 +-- .../data/GetPetContractsForChipIdUseCase.kt | 4 ++- .../chip/id/data/UpdateChipIdUseCase.kt | 13 ++++--- .../feature/chip/id/ui/AddChipIdViewModel.kt | 19 +++++----- .../SelectInsuranceForChipIdDestination.kt | 12 ++++--- .../SelectInsuranceForChipIdViewModel.kt | 11 +++--- .../chat/ui/common/HelipadRiveAnimation.kt | 9 +---- .../feature/claim/chat/data/ClaimIntent.kt | 6 ++-- .../claim/chat/data/FormFieldSearchUseCase.kt | 2 +- .../claim/chat/ui/ClaimChatDestination.kt | 9 +++-- .../chat/ui/LastItemHeightAdjustingState.kt | 7 ++-- .../chat/ui/common/HelipadRiveAnimation.kt | 2 +- .../claim/chat/ui/common/RoundCornersPill.kt | 2 +- .../claim/chat/ui/step/ContentSelectStep.kt | 2 +- .../feature/claim/chat/ui/step/FormStep.kt | 36 ++++++++++--------- .../feature/claim/chat/ui/step/TaskStep.kt | 5 ++- .../AudioRecordingStepSections.kt | 9 +++-- .../ui/common/HelipadRiveAnimation.jvm.kt | 6 +--- .../ui/common/HelipadRiveAnimation.native.kt | 6 +--- .../editcoinsured/data/GetCoInsuredUseCase.kt | 2 +- .../ui/AddCoInsuredBottomSheetContent.kt | 12 +++---- .../EditCoInsuredAddMissingInfoDestination.kt | 2 +- .../ui/EditCoInsuredPresenter.kt | 3 +- .../ui/EditCoinsuredSuccessDestination.kt | 2 +- .../triage/EditCoInsuredTriageDestination.kt | 10 +++--- .../help/center/data/GetQuickLinksUseCase.kt | 36 ++++++++++++------- .../home/home/data/GetHomeDataUseCase.kt | 1 - .../feature/home/home/navigation/HomeGraph.kt | 4 +-- .../feature/home/home/ui/HomeDestination.kt | 4 +-- .../home/home/ui/StartClaimBottomSheet.kt | 14 ++++---- .../data/GetInsuranceContractsUseCase.kt | 4 +-- .../data/GetInsuranceContractsUseCaseDemo.kt | 2 +- .../insurances/data/InsuranceContract.kt | 1 - .../insurance/InsuranceDestination.kt | 6 ++-- .../ContractDetailDestination.kt | 12 +++---- .../EditInsuranceBottomSheetContent.kt | 1 - .../UpcomingChangesBottomSheetContent.kt | 2 +- .../insurancedetail/yourinfo/YourInfoTab.kt | 12 +++---- .../insurances/navigation/InsuranceGraph.kt | 10 ++++-- .../TerminatedContractsDestination.kt | 2 +- .../android/feature/payments/PreviewData.kt | 4 +-- .../payments/data/GetChargeDetailsUseCase.kt | 6 ++-- .../data/GetMemberPaymentsDetailsUseCase.kt | 4 +-- .../feature/payments/data/MemberCharge.kt | 4 +-- .../feature/payments/data/PaymentOverview.kt | 2 +- .../payments/navigation/PaymentsGraph.kt | 4 +-- .../ui/details/PaymentDetailsDestination.kt | 20 +++++------ .../MemberPaymentDetailsDestination.kt | 26 ++++++++------ .../ui/payments/PaymentsDestination.kt | 2 +- .../contactinfo/ContactInfoViewModel.kt | 6 ++-- .../memberreminders/ui/MemberReminderCards.kt | 9 ++--- 52 files changed, 206 insertions(+), 198 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index dfde19c516..89c56f8a9a 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -16,7 +16,9 @@ import com.hedvig.android.core.buildconstants.HedvigBuildConstants import com.hedvig.android.data.addons.data.AddonBannerSource import com.hedvig.android.data.claimflow.ClaimFlowStep import com.hedvig.android.data.claimflow.toClaimFlowDestination +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.data.contract.ContractId +import com.hedvig.android.design.system.hedvig.GlobalSnackBarState import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.addon.purchase.navigation.AddonPurchaseGraphDestination import com.hedvig.android.feature.addon.purchase.navigation.addonPurchaseNavGraph @@ -25,11 +27,11 @@ import com.hedvig.android.feature.change.tier.navigation.InsuranceCustomizationP import com.hedvig.android.feature.change.tier.navigation.StartTierFlowChooseInsuranceDestination import com.hedvig.android.feature.change.tier.navigation.StartTierFlowDestination import com.hedvig.android.feature.change.tier.navigation.changeTierGraph -import com.hedvig.android.feature.chip.id.navigation.ChipIdGraphDestination -import com.hedvig.android.feature.chip.id.navigation.chipIdGraph import com.hedvig.android.feature.chat.navigation.ChatDestination import com.hedvig.android.feature.chat.navigation.ChatDestinations import com.hedvig.android.feature.chat.navigation.cbmChatGraph +import com.hedvig.android.feature.chip.id.navigation.ChipIdGraphDestination +import com.hedvig.android.feature.chip.id.navigation.chipIdGraph import com.hedvig.android.feature.claim.details.navigation.ClaimDetailDestination import com.hedvig.android.feature.claim.details.navigation.claimDetailsGraph import com.hedvig.android.feature.claimhistory.nav.ClaimHistoryDestination @@ -40,8 +42,6 @@ import com.hedvig.android.feature.connect.payment.connectPaymentGraph import com.hedvig.android.feature.connect.payment.trustly.ui.TrustlyDestination import com.hedvig.android.feature.deleteaccount.navigation.DeleteAccountDestination import com.hedvig.android.feature.deleteaccount.navigation.deleteAccountGraph -import com.hedvig.android.data.coinsured.CoInsuredFlowType -import com.hedvig.android.design.system.hedvig.GlobalSnackBarState import com.hedvig.android.feature.editcoinsured.navigation.EditCoInsuredDestination.CoInsuredAddInfo import com.hedvig.android.feature.editcoinsured.navigation.EditCoInsuredDestination.CoInsuredAddOrRemove import com.hedvig.android.feature.editcoinsured.navigation.EditCoInsuredDestination.EditCoInsuredTriage @@ -349,7 +349,7 @@ internal fun HedvigNavHost( navigateToConnectPayment = navigateToConnectPayment, languageService = languageService, hedvigBuildConstants = hedvigBuildConstants, - onOpenChat = ::navigateToNewConversation + onOpenChat = ::navigateToNewConversation, ) profileGraph( settingsDestinationNestedGraphs = { diff --git a/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Snackbar.kt b/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Snackbar.kt index ba1259ab47..33bc4e0ffb 100644 --- a/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Snackbar.kt +++ b/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Snackbar.kt @@ -52,10 +52,7 @@ fun HedvigSnackbar( } @Composable -fun HedvigSnackBar( - globalSnackBarState: GlobalSnackBarState, - modifier: Modifier = Modifier, -) { +fun HedvigSnackBar(globalSnackBarState: GlobalSnackBarState, modifier: Modifier = Modifier) { val priority: NotificationPriority = globalSnackBarState.prio InternalSnackBar( colors = priority.colors.let { notificationColors -> diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt index 3662802d03..5baca946ec 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt @@ -30,7 +30,9 @@ internal class GetPetContractsForChipIdUseCaseImpl( displayName = contract.currentAgreement.productVariant.displayName, contractExposure = contract.exposureDisplayNameShort, ) - logcat { "GetPetContractsForChipIdUseCaseImpl: result: $result contract.missingPetId: ${contract.missingPetId}" } + logcat { + "GetPetContractsForChipIdUseCaseImpl: result: $result contract.missingPetId: ${contract.missingPetId}" + } result } else { null diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt index 968969cb32..462a6e05bc 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt @@ -21,10 +21,13 @@ internal class UpdateChipIdUseCaseImpl( override suspend fun invoke(petId: String, insuranceId: String): Either { return either { logcat { "UpdateChipIdNumberMutation start" } - val result = apolloClient.mutation(UpdateChipIdNumberMutation( - petId = petId, - contractId = insuranceId,)) - .safeExecute{ + val result = apolloClient.mutation( + UpdateChipIdNumberMutation( + petId = petId, + contractId = insuranceId, + ), + ) + .safeExecute { logcat { "UpdateChipIdNumberMutation error: $it" } ErrorMessage() } @@ -34,7 +37,7 @@ internal class UpdateChipIdUseCaseImpl( if (userError != null) { raise(ErrorMessage(userError.message)) } - if (result.midtermChangePetId?.activationDate!=null) { + if (result.midtermChangePetId?.activationDate != null) { Unit } else { raise(ErrorMessage()) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 325c84a7b1..14f095525f 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -20,21 +20,19 @@ internal class AddChipIdViewModel( private val updateChipIdUseCase: UpdateChipIdUseCase, contractId: String, ) : MoleculeViewModel( - initialState = AddChipIdUiState.Loading, - presenter = AddChipIdPresenter( - updateChipIdUseCase = updateChipIdUseCase, - contractId = contractId, - ), -) + initialState = AddChipIdUiState.Loading, + presenter = AddChipIdPresenter( + updateChipIdUseCase = updateChipIdUseCase, + contractId = contractId, + ), + ) internal class AddChipIdPresenter( private val updateChipIdUseCase: UpdateChipIdUseCase, private val contractId: String, ) : MoleculePresenter { @Composable - override fun MoleculePresenterScope.present( - lastState: AddChipIdUiState, - ): AddChipIdUiState { + override fun MoleculePresenterScope.present(lastState: AddChipIdUiState): AddChipIdUiState { val chipIdState = remember { val lastChipIdState = lastState.content?.chipIdState TextFieldState(lastChipIdState?.text?.toString() ?: "", lastChipIdState?.selection ?: TextRange(0)) @@ -123,11 +121,14 @@ internal sealed interface AddChipIdUiState { internal sealed interface ChipIdErrorType { data object WrongInput : ChipIdErrorType + data object GeneralError : ChipIdErrorType } internal sealed interface AddChipIdEvent { data object RetryLoadData : AddChipIdEvent + data object SubmitData : AddChipIdEvent + data object ShowedMessage : AddChipIdEvent } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt index d036e6ad9a..c0b8c3b691 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt @@ -15,14 +15,14 @@ import androidx.lifecycle.compose.dropUnlessResumed import com.hedvig.android.compose.ui.dropUnlessResumed import com.hedvig.android.design.system.hedvig.HedvigButton import com.hedvig.android.design.system.hedvig.HedvigErrorSection +import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress import com.hedvig.android.design.system.hedvig.HedvigScaffold import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.Icon +import com.hedvig.android.design.system.hedvig.IconButton import com.hedvig.android.design.system.hedvig.RadioGroup import com.hedvig.android.design.system.hedvig.RadioOption import com.hedvig.android.design.system.hedvig.RadioOptionId -import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress -import com.hedvig.android.design.system.hedvig.Icon -import com.hedvig.android.design.system.hedvig.IconButton import com.hedvig.android.design.system.hedvig.a11y.FlowHeading import com.hedvig.android.design.system.hedvig.icon.Close import com.hedvig.android.design.system.hedvig.icon.HedvigIcons @@ -87,8 +87,10 @@ private fun SelectInsuranceForChipIdScreen( is SelectInsuranceForChipIdState.Success -> { LaunchedEffect(uiState.contractIdToContinue) { if (uiState.contractIdToContinue != null) { - navigateToAddChipId(uiState.contractIdToContinue, - uiState.contracts.size == 1) + navigateToAddChipId( + uiState.contractIdToContinue, + uiState.contracts.size == 1, + ) } } if (uiState.contractIdToContinue == null) { diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt index 800a0e97dc..32a394682c 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt @@ -18,9 +18,9 @@ internal class SelectInsuranceForChipIdViewModel( private val preselectedContractId: String?, private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, ) : MoleculeViewModel( - initialState = SelectInsuranceForChipIdState.Loading, - presenter = SelectInsuranceForChipIdPresenter(preselectedContractId, getPetContractsForChipIdUseCase), -) + initialState = SelectInsuranceForChipIdState.Loading, + presenter = SelectInsuranceForChipIdPresenter(preselectedContractId, getPetContractsForChipIdUseCase), + ) internal class SelectInsuranceForChipIdPresenter( private val preselectedContractId: String?, @@ -86,7 +86,10 @@ internal class SelectInsuranceForChipIdPresenter( contractIdToContinue = contractIdToContinue, ) } - else -> state + + else -> { + state + } } } } diff --git a/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt b/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt index 9098f17837..08592c3d44 100644 --- a/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt +++ b/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt @@ -21,11 +21,7 @@ private enum class HelipadAnimation(val animationName: String) { } @Composable -internal actual fun HelipadRiveAnimation( - modifier: Modifier, - bottomAnimationFinished: Boolean, - stepId: String, -) { +internal actual fun HelipadRiveAnimation(modifier: Modifier, bottomAnimationFinished: Boolean, stepId: String) { val context = LocalContext.current val isDark = isSystemInDarkTheme() val resourceName = if (isDark) "hedvig_loader_dark" else "hedvig_loader_light" @@ -88,7 +84,4 @@ internal actual fun HelipadRiveAnimation( initialAnimationDone.value = false } } - - } - diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/ClaimIntent.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/ClaimIntent.kt index 1116ac5f9a..54be904de5 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/ClaimIntent.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/ClaimIntent.kt @@ -33,7 +33,7 @@ internal data class ClaimIntentStep( val stepContent: StepContent, val isRegrettable: Boolean, val hint: String?, - val showSpinForThisStep: Boolean = true + val showSpinForThisStep: Boolean = true, ) @Serializable @@ -66,7 +66,7 @@ internal sealed interface StepContent { val descriptions: List, val isCompleted: Boolean, val failedToSubmit: Boolean, - val isAnimationFinished: Boolean = false + val isAnimationFinished: Boolean = false, ) : StepContent { override val isSkippable: Boolean = false } @@ -111,10 +111,8 @@ internal sealed interface StepContent { val value: String, val text: String, val subtitle: String?, - val isCustomSearchEntry: Boolean = false, val imageUrl: String? = null, - ) enum class FieldType { diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/FormFieldSearchUseCase.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/FormFieldSearchUseCase.kt index 468f643bb1..c1f5ae613c 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/FormFieldSearchUseCase.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/data/FormFieldSearchUseCase.kt @@ -55,7 +55,7 @@ internal class FormFieldSearchUseCaseImpl( text = option.title, subtitle = option.subtitle, imageUrl = option.imageUrl, - isCustomSearchEntry = option.isCustomSearchEntry + isCustomSearchEntry = option.isCustomSearchEntry, ) }, suggestedFixedQuery = response.suggestedQuery, diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/ClaimChatDestination.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/ClaimChatDestination.kt index 735d2b3aa7..7cd1961546 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/ClaimChatDestination.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/ClaimChatDestination.kt @@ -490,7 +490,7 @@ private fun ClaimChatScrollableContent( Modifier.requiredHeightIn(lastItemHeightAdjustingState.preferredMinHeightForFullScreenItem) } else { Modifier - } + }, ) } } @@ -645,9 +645,9 @@ private fun StepTopContent( Column(modifier) { val density = LocalDensity.current - if (stepItem.stepContent !is StepContent.Task - && stepItem.stepContent !is StepContent.Summary - && stepItem.showSpinForThisStep + if (stepItem.stepContent !is StepContent.Task && + stepItem.stepContent !is StepContent.Summary && + stepItem.showSpinForThisStep ) { HelipadRiveAnimation( bottomAnimationFinished = isAnimationComplete, @@ -883,7 +883,6 @@ private fun StepBottomContent( } } - internal val animationSize = 32.sp internal val sentAnswersStartPadding = 45.dp diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/LastItemHeightAdjustingState.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/LastItemHeightAdjustingState.kt index e370c85d05..2d5486547b 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/LastItemHeightAdjustingState.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/LastItemHeightAdjustingState.kt @@ -66,8 +66,11 @@ internal class LastItemHeightAdjustingState( .dropLast(1).last().id with(density) { val adjustmentForTask = - if (isPreviousStepTask) animationSize.toDp() + 12.dp - else 0.dp + if (isPreviousStepTask) { + animationSize.toDp() + 12.dp + } else { + 0.dp + } (heightOfItemBottomContentMap[stepId]?.height?.toDp() ?: 0.dp) + adjustmentForTask } } diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt index 423663b709..f1d740104c 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.kt @@ -8,5 +8,5 @@ import androidx.compose.ui.Modifier internal expect fun HelipadRiveAnimation( modifier: Modifier = Modifier, bottomAnimationFinished: Boolean, - stepId: String + stepId: String, ) diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/RoundCornersPill.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/RoundCornersPill.kt index fd254fde2f..1b2848e113 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/RoundCornersPill.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/common/RoundCornersPill.kt @@ -63,7 +63,7 @@ internal fun RoundCornersPill( end = 14.dp, bottom = 9.dp, ), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, ) { ProvideTextStyle(LocalTextStyle.current.copy(color = contentColor)) { if (onClick != null) { diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/ContentSelectStep.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/ContentSelectStep.kt index a04d6adfc8..fb9e2caddf 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/ContentSelectStep.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/ContentSelectStep.kt @@ -113,7 +113,7 @@ internal fun ContentSelectStep( .fillMaxWidth() .wrapContentWidth(Alignment.End) .clearAndSetSemantics { - contentDescription = description + contentDescription = description }, ) { HedvigText(selected.title) diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/FormStep.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/FormStep.kt index 269b5112ad..512c1689f7 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/FormStep.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/FormStep.kt @@ -363,7 +363,6 @@ private fun FormContent( } } else { Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - if (content.fields.flatMap { it.selectedOptions }.isNotEmpty()) { content.fields.forEach { field -> when (field.type) { @@ -379,8 +378,11 @@ private fun FormContent( SentItemCard( imageLoader = imageLoader, itemTitle = selected.text, - itemSubtitle = if (!selected.isCustomSearchEntry) selected.subtitle else - stringResource(Res.string.CLAIM_CHAT_CUSTOM_ITEM_SUBTITLE), + itemSubtitle = if (!selected.isCustomSearchEntry) { + selected.subtitle + } else { + stringResource(Res.string.CLAIM_CHAT_CUSTOM_ITEM_SUBTITLE) + }, itemImageUrl = selected.imageUrl, ) } @@ -402,7 +404,7 @@ private fun FormContent( onClick = null, modifier = Modifier.clearAndSetSemantics { contentDescription = description - } + }, ) { HedvigText(textValue, textAlign = TextAlign.End) } @@ -453,8 +455,11 @@ internal fun SearchForm( enabled = true, ) } else { - val subtitle = if (!selectedOption.isCustomSearchEntry) selectedOption.subtitle else + val subtitle = if (!selectedOption.isCustomSearchEntry) { + selectedOption.subtitle + } else { stringResource(Res.string.CLAIM_CHAT_CUSTOM_ITEM_SUBTITLE) + } SearchItemCard( imageLoader = imageLoader, itemTitle = selectedOption.text, @@ -732,14 +737,12 @@ private fun SearchItemCard( textAlign = TextAlign.Start, ) itemSubtitle?.let { - HedvigText( text = itemSubtitle, textAlign = TextAlign.Start, color = HedvigTheme.colorScheme.textSecondary, style = HedvigTheme.typography.finePrint, ) - } } } @@ -751,13 +754,11 @@ private fun SearchItemCard( ) { Icon( imageVector = HedvigIcons.ChevronRight, - contentDescription = EmptyContentDescription, //todo: not sure + contentDescription = EmptyContentDescription, // todo: not sure tint = HedvigTheme.colorScheme.fillPrimary, modifier = Modifier.size(24.dp), ) - } - }, spaceBetween = 6.dp, ) @@ -783,19 +784,21 @@ private fun SentItemCard( ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(horizontal = 16.dp) + modifier = Modifier.padding(horizontal = 16.dp), ) { if (itemImageUrl != null) { - Box ( + Box( contentAlignment = Alignment.Center, modifier = Modifier .size(46.dp) .background(Color(0xFFFFFFFF), HedvigTheme.shapes.cornerSmall) - .border(1.dp, + .border( + 1.dp, HedvigTheme.colorScheme.borderPrimary, - HedvigTheme.shapes.cornerSmall) - .clip(HedvigTheme.shapes.cornerSmall) - ){ + HedvigTheme.shapes.cornerSmall, + ) + .clip(HedvigTheme.shapes.cornerSmall), + ) { AsyncImage( model = itemImageUrl, contentDescription = EmptyContentDescription, @@ -824,7 +827,6 @@ private fun SentItemCard( color = HedvigTheme.colorScheme.textSecondary, style = HedvigTheme.typography.finePrint, ) - } } } diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/TaskStep.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/TaskStep.kt index 5e7cdf8b80..6889be8b7f 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/TaskStep.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/TaskStep.kt @@ -47,7 +47,6 @@ internal fun TaskStepTopContent( } }, ) { - Column { Row( verticalAlignment = Alignment.CenterVertically, @@ -61,9 +60,9 @@ internal fun TaskStepTopContent( HelipadRiveAnimation( bottomAnimationFinished = taskContent.isAnimationFinished, modifier = Modifier.size( - with (density) { + with(density) { animationSize.toDp() - } + }, ), stepId = stepId, ) diff --git a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/audiorecording/AudioRecordingStepSections.kt b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/audiorecording/AudioRecordingStepSections.kt index ea0134b18d..83dee483df 100644 --- a/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/audiorecording/AudioRecordingStepSections.kt +++ b/app/feature/feature-claim-chat/src/commonMain/kotlin/com/hedvig/feature/claim/chat/ui/step/audiorecording/AudioRecordingStepSections.kt @@ -660,7 +660,7 @@ private fun ControlButton( countDownText = "3" scale.snapTo(1f) } - //custom description for button's "play" state includes its role and click label. Needed + // custom description for button's "play" state includes its role and click label. Needed // because when the recording is stopped but the focus is still on the same button, // only the state updates, the role and label are not announced. val hideFromA11y = audioRecordingState is AudioRecordingStepState.AudioRecording.Playback @@ -778,9 +778,9 @@ private fun ControlButton( fontSize = HedvigTheme.typography.label.fontSize, fontStyle = HedvigTheme.typography.label.fontStyle, color = if (isEnabled) HedvigTheme.colorScheme.textPrimary else HedvigTheme.colorScheme.textTertiary, - modifier = Modifier.semantics{ + modifier = Modifier.semantics { if (hideFromA11y) hideFromAccessibility() - } + }, ) } } @@ -895,7 +895,7 @@ private fun FreeTextInputSection( .padding(start = 48.dp) .wrapContentWidth(Alignment.End) .clearAndSetSemantics { - contentDescription = description + contentDescription = description }, ) { HedvigText(freeText, textAlign = TextAlign.End) @@ -1017,7 +1017,6 @@ private fun AudioWaves( } } - private val fixedRestingColor: Color @Composable get() = HedvigTheme.colorScheme.fillPrimary.copy(alpha = 0.6f) diff --git a/app/feature/feature-claim-chat/src/jvmMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.jvm.kt b/app/feature/feature-claim-chat/src/jvmMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.jvm.kt index 9e465daa69..219569d3ae 100644 --- a/app/feature/feature-claim-chat/src/jvmMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.jvm.kt +++ b/app/feature/feature-claim-chat/src/jvmMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.jvm.kt @@ -4,9 +4,5 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @Composable -internal actual fun HelipadRiveAnimation( - modifier: Modifier, - bottomAnimationFinished: Boolean, - stepId: String -) { +internal actual fun HelipadRiveAnimation(modifier: Modifier, bottomAnimationFinished: Boolean, stepId: String) { } diff --git a/app/feature/feature-claim-chat/src/nativeMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.native.kt b/app/feature/feature-claim-chat/src/nativeMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.native.kt index 9e465daa69..219569d3ae 100644 --- a/app/feature/feature-claim-chat/src/nativeMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.native.kt +++ b/app/feature/feature-claim-chat/src/nativeMain/kotlin/com/hedvig/feature/claim/chat/ui/common/HelipadRiveAnimation.native.kt @@ -4,9 +4,5 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @Composable -internal actual fun HelipadRiveAnimation( - modifier: Modifier, - bottomAnimationFinished: Boolean, - stepId: String -) { +internal actual fun HelipadRiveAnimation(modifier: Modifier, bottomAnimationFinished: Boolean, stepId: String) { } diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/data/GetCoInsuredUseCase.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/data/GetCoInsuredUseCase.kt index 51ea2eee83..741688aedc 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/data/GetCoInsuredUseCase.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/data/GetCoInsuredUseCase.kt @@ -40,7 +40,7 @@ internal class GetCoInsuredUseCaseImpl( coInsureds + coOwners } .filter { !it.hasMissingInfo } - .filter { coinsured -> coInsuredOnContract.any { it.id == coinsured.id} } + .filter { coinsured -> coInsuredOnContract.any { it.id == coinsured.id } } CoInsuredResult( member = Member( diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt index 8d2f6b26a0..8f4ba4011f 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt @@ -116,8 +116,8 @@ internal fun AddCoInsuredBottomSheetContent( }, textAlign = TextAlign.Center, modifier = Modifier - .fillMaxWidth() - .semantics { heading() }, + .fillMaxWidth() + .semantics { heading() }, ) Spacer(Modifier.height(24.dp)) if (bottomSheetState.canPickExistingCoInsured() && bottomSheetState.selectableCoInsured != null) { @@ -354,8 +354,8 @@ private fun ManualInputFields( keyboardType = KeyboardType.Text, ), modifier = Modifier - .weight(1f) - .defaultMinSize(minHeight = 64.dp), + .weight(1f) + .defaultMinSize(minHeight = 64.dp), ) Spacer(Modifier.width(4.dp)) HedvigTextField( @@ -371,8 +371,8 @@ private fun ManualInputFields( keyboardType = KeyboardType.Text, ), modifier = Modifier - .weight(1f) - .defaultMinSize(minHeight = 64.dp), + .weight(1f) + .defaultMinSize(minHeight = 64.dp), ) } AnimatedVisibility( diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt index 39d5f19040..d9adb4c536 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt @@ -197,7 +197,7 @@ private fun EditCoInsuredScreen( if (uiState.listState.anyUpdatedCoInsuredHasMissingInfo() && uiState.listState.hasMadeChanges()) { HedvigNotificationCard( - message = when(uiState.type) { + message = when (uiState.type) { CoInsuredFlowType.CoInsured -> stringResource(Res.string.CONTRACT_ADD_COINSURED_REVIEW_INFO) CoInsuredFlowType.CoOwners -> stringResource(Res.string.CONTRACT_ADD_COOWNER_REVIEW_INFO) }, diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt index 5f07b7e798..294cf81730 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt @@ -10,9 +10,9 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.Snapshot import arrow.core.raise.either import com.hedvig.android.core.common.safeCast +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.feature.editcoinsured.data.CoInsured import com.hedvig.android.feature.editcoinsured.data.CoInsuredError -import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.feature.editcoinsured.data.CoInsuredPersonalInformation import com.hedvig.android.feature.editcoinsured.data.CommitMidtermChangeUseCase import com.hedvig.android.feature.editcoinsured.data.CreateMidtermChangeUseCase @@ -498,6 +498,7 @@ internal sealed interface EditCoInsuredState { originalCoInsured != updatedCoInsured fun anyUpdatedCoInsuredHasMissingInfo() = updatedCoInsured?.any { it.hasMissingInfo } == true + fun noCoInsuredHaveMissingInfo() = coInsured.all { !it.hasMissingInfo } } diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt index 2548bc322f..8abcca177c 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.design.system.hedvig.EmptyState import com.hedvig.android.design.system.hedvig.EmptyStateDefaults import com.hedvig.android.design.system.hedvig.HedvigDateTimeFormatterDefaults @@ -19,7 +20,6 @@ import com.hedvig.android.design.system.hedvig.HedvigTextButton import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.datepicker.getLocale -import com.hedvig.android.data.coinsured.CoInsuredFlowType import hedvig.resources.CONTRACT_ADD_COINSURED_UPDATED_LABEL import hedvig.resources.CONTRACT_ADD_COINSURED_UPDATED_TITLE import hedvig.resources.CONTRACT_ADD_COOWNER_UPDATED_TITLE diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/triage/EditCoInsuredTriageDestination.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/triage/EditCoInsuredTriageDestination.kt index da8a956c64..687ecdd10d 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/triage/EditCoInsuredTriageDestination.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/triage/EditCoInsuredTriageDestination.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.LineBreak import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.design.system.hedvig.HedvigButton import com.hedvig.android.design.system.hedvig.HedvigErrorSection import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress @@ -27,7 +28,6 @@ import com.hedvig.android.design.system.hedvig.RadioOptionId import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.icon.Close import com.hedvig.android.design.system.hedvig.icon.HedvigIcons -import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.feature.editcoinsured.data.EditCoInsuredDestination import com.hedvig.android.feature.editcoinsured.data.InsuranceForEditOrAddCoInsured import com.hedvig.android.feature.editcoinsured.ui.triage.EditCoInsuredTriageUiState.Failure @@ -180,16 +180,16 @@ private fun SuccessScreen( selectedOption = uiState.selected?.id?.let { RadioOptionId(it) }, onRadioOptionSelected = { selectInsurance(it.id) }, modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + .fillMaxWidth() + .padding(horizontal = 16.dp), ) Spacer(Modifier.height(16.dp)) HedvigButton( stringResource(Res.string.general_continue_button), enabled = uiState.selected != null, modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + .fillMaxWidth() + .padding(horizontal = 16.dp), onClick = submitSelectedInsurance, ) Spacer(Modifier.height(16.dp)) diff --git a/app/feature/feature-help-center/src/main/kotlin/com/hedvig/android/feature/help/center/data/GetQuickLinksUseCase.kt b/app/feature/feature-help-center/src/main/kotlin/com/hedvig/android/feature/help/center/data/GetQuickLinksUseCase.kt index 64b5b16ccd..b29925448a 100644 --- a/app/feature/feature-help-center/src/main/kotlin/com/hedvig/android/feature/help/center/data/GetQuickLinksUseCase.kt +++ b/app/feature/feature-help-center/src/main/kotlin/com/hedvig/android/feature/help/center/data/GetQuickLinksUseCase.kt @@ -163,7 +163,10 @@ private fun createEditCoInsuredQuickLink( coInsuredContracts: List, ): StandaloneQuickLink? { return when { - coInsuredContracts.isEmpty() -> null + coInsuredContracts.isEmpty() -> { + null + } + coInsuredContracts.size == 1 -> { val contract = coInsuredContracts.first() if (contract.coInsured?.any { it.hasMissingInfo } == true) { @@ -180,11 +183,14 @@ private fun createEditCoInsuredQuickLink( ) } } - else -> StandaloneQuickLink( - titleRes = Res.string.HC_QUICK_ACTIONS_EDIT_COINSURED, - hintTextRes = Res.string.HC_QUICK_ACTIONS_CO_INSURED_SUBTITLE, - quickLinkDestination = ChooseInsuranceForEditCoInsured, - ) + + else -> { + StandaloneQuickLink( + titleRes = Res.string.HC_QUICK_ACTIONS_EDIT_COINSURED, + hintTextRes = Res.string.HC_QUICK_ACTIONS_CO_INSURED_SUBTITLE, + quickLinkDestination = ChooseInsuranceForEditCoInsured, + ) + } } } @@ -192,7 +198,10 @@ private fun createEditCoOwnersQuickLink( coOwnerContracts: List, ): StandaloneQuickLink? { return when { - coOwnerContracts.isEmpty() -> null + coOwnerContracts.isEmpty() -> { + null + } + coOwnerContracts.size == 1 -> { val contract = coOwnerContracts.first() if (contract.coOwners?.any { it.hasMissingInfo } == true) { @@ -209,11 +218,14 @@ private fun createEditCoOwnersQuickLink( ) } } - else -> StandaloneQuickLink( - titleRes = Res.string.EDIT_COOWNER_TITLE, - hintTextRes = Res.string.EDIT_COOWNER_SUBTITLE, - quickLinkDestination = ChooseInsuranceForEditCoOwners, - ) + + else -> { + StandaloneQuickLink( + titleRes = Res.string.EDIT_COOWNER_TITLE, + hintTextRes = Res.string.EDIT_COOWNER_SUBTITLE, + quickLinkDestination = ChooseInsuranceForEditCoOwners, + ) + } } } diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt index 17dd747fc6..182b2ff26a 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/data/GetHomeDataUseCase.kt @@ -265,7 +265,6 @@ internal class GetHomeDataUseCaseImpl( private fun HomeQuery.Data.CurrentMember.areAllNonTerminatedContractsPending(): Boolean { return activeContracts.isEmpty() && pendingContracts.isNotEmpty() } - } private fun HomeQuery.Data.claimStatusCards(): HomeData.ClaimStatusCardsData? { diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt index ece8500197..1a0b462497 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt @@ -5,11 +5,11 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import coil3.ImageLoader import com.hedvig.android.compose.ui.dropUnlessResumed +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.home.home.ui.FirstVetDestination import com.hedvig.android.feature.home.home.ui.HomeDestination import com.hedvig.android.feature.home.home.ui.HomeViewModel -import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.navigation.compose.navDeepLinks import com.hedvig.android.navigation.compose.navdestination import com.hedvig.android.navigation.compose.navgraph @@ -66,7 +66,7 @@ fun NavGraphBuilder.homeGraph( navigateToContactInfo() }, imageLoader = imageLoader, - navigateToChipId = navigateToChipIdScreen + navigateToChipId = navigateToChipIdScreen, ) } navdestination( diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt index fe7b538b1f..ed5b371f32 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt @@ -70,6 +70,7 @@ import com.hedvig.android.crosssells.CrossSellSheetData import com.hedvig.android.crosssells.RecommendedCrossSell import com.hedvig.android.data.addons.data.AddonBannerInfo import com.hedvig.android.data.addons.data.FlowType +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.data.contract.CrossSell import com.hedvig.android.data.contract.ImageAsset import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonStyle.Secondary @@ -104,7 +105,6 @@ import com.hedvig.android.feature.home.home.ui.HomeTopBarAction.ChatAction import com.hedvig.android.feature.home.home.ui.HomeTopBarAction.CrossSellsAction import com.hedvig.android.feature.home.home.ui.HomeTopBarAction.FirstVetAction import com.hedvig.android.feature.home.home.ui.HomeUiState.Success -import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.memberreminders.MemberReminder.PaymentReminder.ConnectPayment import com.hedvig.android.memberreminders.MemberReminders import com.hedvig.android.memberreminders.ui.MemberReminderCardsWithoutNotification @@ -287,7 +287,7 @@ private fun HomeScreen( onNavigateToNewConversation = onNavigateToNewConversation, markMessageAsSeen = markMessageAsSeen, navigateToContactInfo = navigateToContactInfo, - navigateToChipIdScreen = navigateToChipIdScreen + navigateToChipIdScreen = navigateToChipIdScreen, ) } } diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/StartClaimBottomSheet.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/StartClaimBottomSheet.kt index 7f9c13ef11..28123802d8 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/StartClaimBottomSheet.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/StartClaimBottomSheet.kt @@ -93,8 +93,8 @@ private fun StartClaimBottomSheetContent( text = stringResource(Res.string.HONESTY_PLEDGE_HEADER), textAlign = TextAlign.Center, modifier = Modifier - .fillMaxWidth() - .semantics { heading() }, + .fillMaxWidth() + .semantics { heading() }, ) Spacer(Modifier.height(16.dp)) PledgeNotes() @@ -205,9 +205,9 @@ private fun PledgeNotes() { Row( horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier - .fillMaxWidth() - .horizontalDivider(DividerPosition.Top, index != 0) - .padding(vertical = 16.dp), + .fillMaxWidth() + .horizontalDivider(DividerPosition.Top, index != 0) + .padding(vertical = 16.dp), ) { Icon(HedvigIcons.Checkmark, null, Modifier.size(24.dp)) HedvigText(text, Modifier.weight(1f), color = HedvigTheme.colorScheme.textSecondaryTranslucent) @@ -225,8 +225,8 @@ private fun ImportantInfoCheckBox(isChecked: Boolean, onCheckedChange: () -> Uni Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 16.dp), + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 16.dp), ) { Column(modifier = Modifier.weight(1f)) { HedvigText( diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt index d6e1e3ad52..d2da3de07c 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt @@ -142,7 +142,7 @@ private fun InsuranceContractsQuery.Data.CurrentMember.PendingContract.toPending }, cost = this.cost.toMonthlyCost(), basePremium = UiMoney.fromMoneyFragment(this.basePremium), - chipId = ChipIdState.NotRequired + chipId = ChipIdState.NotRequired, ) } @@ -233,7 +233,7 @@ private fun ContractFragment.toContract( chipId = when (missingPetId) { true -> ChipIdState.Missing false -> ChipIdState.NotRequired - } + }, ) } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt index 8f5873d2d7..6a5f94e878 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCaseDemo.kt @@ -92,7 +92,7 @@ internal class GetInsuranceContractsUseCaseDemo : GetInsuranceContractsUseCase { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), - chipId = ChipIdState.NotRequired + chipId = ChipIdState.NotRequired, ), ).right(), ) diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt index 5464b3ff5c..614261a04b 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/InsuranceContract.kt @@ -101,7 +101,6 @@ sealed interface InsuranceContract { } } - data class Addon( val addonVariant: AddonVariant, val premium: UiMoney, diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt index c317a8fcc3..ee06e30777 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurance/InsuranceDestination.kt @@ -52,6 +52,7 @@ import com.hedvig.android.crosssells.CrossSellItemPlaceholder import com.hedvig.android.crosssells.CrossSellsSection import com.hedvig.android.data.addons.data.AddonBannerInfo import com.hedvig.android.data.addons.data.FlowType +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractId import com.hedvig.android.data.contract.ContractType @@ -74,7 +75,6 @@ import com.hedvig.android.design.system.hedvig.NotificationDefaults.Notification import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.hedvigDropShadow import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader -import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.feature.insurances.data.InsuranceAgreement import com.hedvig.android.feature.insurances.data.InsuranceContract import com.hedvig.android.feature.insurances.data.InsuranceContract.EstablishedInsuranceContract @@ -690,7 +690,7 @@ private val previewPendingContract = InsuranceContract.PendingInsuranceContract( UiMoney(89.0, UiCurrencyCode.SEK), discounts = emptyList(), ), - chipId = ChipIdState.NotRequired + chipId = ChipIdState.NotRequired, ) private val previewInsurance = EstablishedInsuranceContract( @@ -739,5 +739,5 @@ private val previewInsurance = EstablishedInsuranceContract( supportsTierChange = true, existingAddons = emptyList(), availableAddons = emptyList(), - chipId = ChipIdState.Missing + chipId = ChipIdState.Missing, ) diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt index f9bcfa5261..529f584825 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt @@ -43,6 +43,7 @@ import com.hedvig.android.compose.ui.animateContentHeight import com.hedvig.android.compose.ui.plus import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup.RENTAL import com.hedvig.android.data.contract.ContractId import com.hedvig.android.data.contract.ContractType @@ -66,7 +67,6 @@ import com.hedvig.android.design.system.hedvig.hedvigDropShadow import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.design.system.hedvig.rememberHedvigTabRowState import com.hedvig.android.design.system.hedvig.rememberPreviewImageLoader -import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.feature.insurances.data.Addon import com.hedvig.android.feature.insurances.data.AvailableAddon import com.hedvig.android.feature.insurances.data.CancelInsuranceData @@ -133,7 +133,7 @@ internal fun ContractDetailDestination( navigateToAddAddon = navigateToAddAddon, navigateToRemoveAddon = navigateToRemoveAddon, navigateToUpgradeAddon = navigateToUpgradeAddon, - navigateToChipIdScreen = navigateToChipIdScreen + navigateToChipIdScreen = navigateToChipIdScreen, ) } @@ -365,7 +365,7 @@ private fun ContractDetailScreen( chipIdState = contract.chipId, onFillChipId = { navigateToChipIdScreen() - } + }, ) } @@ -503,7 +503,7 @@ private fun PreviewContractDetailScreen() { supportsTierChange = true, existingAddons = emptyList(), availableAddons = emptyList(), - chipId = ChipIdState.Missing + chipId = ChipIdState.Missing, ), true, ), @@ -524,7 +524,7 @@ private fun PreviewContractDetailScreen() { navigateToAddAddon = {}, navigateToRemoveAddon = { _, _ -> }, navigateToUpgradeAddon = { _, _ -> }, - navigateToChipIdScreen = {} + navigateToChipIdScreen = {}, ) } } @@ -554,7 +554,7 @@ private fun PreviewContractDetailScreenFailure() { navigateToAddAddon = {}, navigateToRemoveAddon = { _, _ -> }, navigateToUpgradeAddon = { _, _ -> }, - navigateToChipIdScreen = {} + navigateToChipIdScreen = {}, ) } } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt index bc66579b9b..d572685cc5 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/EditInsuranceBottomSheetContent.kt @@ -151,7 +151,6 @@ internal fun EditInsuranceBottomSheetContent( onRemoveAddonClick() } - else -> {} } }, diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt index e22736b4b5..f21ffe4aa9 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/UpcomingChangesBottomSheetContent.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.display.items.DisplayItem import com.hedvig.android.data.display.items.DisplayItem.DisplayItemValue import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonSize.Large @@ -25,7 +26,6 @@ import com.hedvig.android.design.system.hedvig.HedvigNotificationCard import com.hedvig.android.design.system.hedvig.HedvigPreview import com.hedvig.android.design.system.hedvig.HedvigText import com.hedvig.android.design.system.hedvig.HedvigTextButton -import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.NotificationDefaults.InfoCardStyle.Button import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index f08275470e..a7da9fb90f 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -28,6 +28,7 @@ import com.hedvig.android.compose.ui.preview.DoubleBooleanCollectionPreviewParam import com.hedvig.android.core.common.daysUntil import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractId import com.hedvig.android.data.contract.ContractType @@ -74,7 +75,6 @@ import com.hedvig.android.design.system.hedvig.icon.HedvigIcons import com.hedvig.android.design.system.hedvig.icon.InfoFilled import com.hedvig.android.design.system.hedvig.icon.Lock import com.hedvig.android.design.system.hedvig.icon.WarningFilled -import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.design.system.hedvig.rememberHedvigBirthDateDateTimeFormatter import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.design.system.hedvig.rememberHedvigDateTimeFormatter @@ -194,7 +194,7 @@ internal fun YourInfoTab( onRemoveAddonClick = { editYourInfoBottomSheet.dismiss() navigateToRemoveAddon(ContractId(contractId), null) - } + }, ) } @@ -212,9 +212,9 @@ internal fun YourInfoTab( add( addon.addonVariant.displayName to stringResource( - Res.string.OFFER_COST_AND_PREMIUM_PERIOD_ABBREVIATION, - addon.premium.toString(), - ), + Res.string.OFFER_COST_AND_PREMIUM_PERIOD_ABBREVIATION, + addon.premium.toString(), + ), ) } upcomingChangesInsuranceAgreement.cost.discounts.forEach { discount -> @@ -364,7 +364,7 @@ internal fun YourInfoTab( priority = Attention, style = Button( stringResource(Res.string.CHIP_ID_MISSING_BUTTON), - onFillChipId + onFillChipId, ), modifier = Modifier .fillMaxWidth() diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt index ba54bddf73..1e175d9412 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt @@ -80,8 +80,12 @@ fun NavGraphBuilder.insuranceGraph( viewModel = viewModel, onEditCoInsuredClick = dropUnlessResumed { contractId: String -> startEditCoInsured(contractId) }, onEditCoOwnersClick = dropUnlessResumed { contractId: String -> startEditCoOwners(contractId) }, - onMissingCoInsuredInfoClick = dropUnlessResumed { contractId: String -> startEditCoInsuredAddMissingInfo(contractId) }, - onMissingCoOwnersInfoClick = dropUnlessResumed { contractId: String -> startEditCoOwnersAddMissingInfo(contractId) }, + onMissingCoInsuredInfoClick = dropUnlessResumed { contractId: String -> + startEditCoInsuredAddMissingInfo(contractId) + }, + onMissingCoOwnersInfoClick = dropUnlessResumed { contractId: String -> + startEditCoOwnersAddMissingInfo(contractId) + }, onChangeAddressClick = dropUnlessResumed { startMovingFlow() }, onCancelInsuranceClick = dropUnlessResumed { cancelInsuranceData: CancelInsuranceData -> startTerminationFlow(cancelInsuranceData) @@ -99,7 +103,7 @@ fun NavGraphBuilder.insuranceGraph( navigateToAddAddon = { availableAddon -> onNavigateToAddonPurchaseFlow(listOf(availableAddon.relatedContractId), availableAddon) }, - navigateToChipIdScreen = navigateToChipIdScreen + navigateToChipIdScreen = navigateToChipIdScreen, ) } navdestination { diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt index 19a1607337..a05b18ab40 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsDestination.kt @@ -179,7 +179,7 @@ private class PreviewTerminatedContractsUiStateProvider : supportsTierChange = false, existingAddons = emptyList(), availableAddons = emptyList(), - chipId = ChipIdState.Missing + chipId = ChipIdState.Missing, ), ), ), diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/PreviewData.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/PreviewData.kt index e3548e0e9e..84c517f600 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/PreviewData.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/PreviewData.kt @@ -272,8 +272,8 @@ internal val paymentOverViewPreviewData: PaymentOverview memberChargeShortInfo = memberChargeShortInfo, ongoingCharges = listOf(OngoingCharge("id", LocalDate.fromEpochDays(401), UiMoney(200.0, UiCurrencyCode.SEK))), paymentConnection = PaymentConnection.Active( - displayName = "Nordea", - displayValue = "31489*****", + displayName = "Nordea", + displayValue = "31489*****", ), ) } diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetChargeDetailsUseCase.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetChargeDetailsUseCase.kt index 8b05aaf122..8cbb592072 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetChargeDetailsUseCase.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetChargeDetailsUseCase.kt @@ -38,9 +38,9 @@ internal class GetChargeDetailsUseCaseImpl( val futureMemberChargeWithThisId = futureMemberCharge.takeIf { it?.id == id } val pastMemberChargeWithThisId = pastCharges.firstOrNull { it.id == id } val charge = futureMemberChargeWithThisId ?: pastMemberChargeWithThisId - ?: ongoingChargeWithThisId ?: raise(ErrorMessage()) + ?: ongoingChargeWithThisId ?: raise(ErrorMessage()) val paymentsInfo = run { - if (futureMemberChargeWithThisId == null && ongoingChargeWithThisId == null ) { + if (futureMemberChargeWithThisId == null && ongoingChargeWithThisId == null) { // Only show payment connection information if the charge is a future charge or ongoing charge. // Otherwise, the payment connection info we get is not reliably correct. return@run PaymentsInfo.NoPresentableInfo @@ -57,7 +57,7 @@ internal class GetChargeDetailsUseCaseImpl( MemberPaymentConnectionStatus.PENDING, MemberPaymentConnectionStatus.NEEDS_SETUP, MemberPaymentConnectionStatus.UNKNOWN__, - -> { + -> { PaymentsInfo.NoPresentableInfo } } diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetMemberPaymentsDetailsUseCase.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetMemberPaymentsDetailsUseCase.kt index 60e73a1fe7..379b64175d 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetMemberPaymentsDetailsUseCase.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/GetMemberPaymentsDetailsUseCase.kt @@ -43,7 +43,7 @@ internal class GetMemberPaymentsDetailsUseCaseImpl( displayName = displayName, mandate = mandate, paymentMethod = paymentMethod, - chargeMethod = paymentProvider.toChargeMethod() + chargeMethod = paymentProvider.toChargeMethod(), ) } } @@ -56,5 +56,5 @@ data class MemberPaymentsDetails( val displayName: String?, val mandate: String?, val paymentMethod: String, - val chargeMethod: MemberPaymentChargeMethod + val chargeMethod: MemberPaymentChargeMethod, ) diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/MemberCharge.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/MemberCharge.kt index e39671d69e..99fada4411 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/MemberCharge.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/MemberCharge.kt @@ -28,7 +28,7 @@ internal data class MemberCharge( val referralDiscount: Discount?, private val carriedAdjustment: UiMoney?, private val settlementAdjustment: UiMoney?, - val chargeMethod: MemberPaymentChargeMethod + val chargeMethod: MemberPaymentChargeMethod, ) { fun carriedAdjustmentIfAboveZero(): UiMoney? = if (carriedAdjustment != null && carriedAdjustment.amount > 0) { carriedAdjustment @@ -165,7 +165,7 @@ internal fun MemberChargeFragment.toMemberCharge( statusDescription = null, ) }, - chargeMethod = paymentProvider.toChargeMethod() + chargeMethod = paymentProvider.toChargeMethod(), ) internal fun String?.toChargeMethod(): MemberPaymentChargeMethod { diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/PaymentOverview.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/PaymentOverview.kt index f13a4f5941..ee9fcfb9ed 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/PaymentOverview.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/data/PaymentOverview.kt @@ -26,5 +26,5 @@ internal data class MemberChargeShortInfo( enum class MemberPaymentChargeMethod { TRUSTLY, KIVRA, - UNKNOWN + UNKNOWN, } diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt index aa16ffed87..20fa3dd7a4 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt @@ -32,7 +32,7 @@ fun NavGraphBuilder.paymentsGraph( languageService: LanguageService, hedvigBuildConstants: HedvigBuildConstants, navigateToConnectPayment: () -> Unit, - onOpenChat: () -> Unit + onOpenChat: () -> Unit, ) { navgraph( startDestination = PaymentsDestination.Payments::class, @@ -112,7 +112,7 @@ fun NavGraphBuilder.paymentsGraph( viewModel, onChangeBankAccount = navigateToConnectPayment, navigateUp = navController::navigateUp, - onOpenChat = onOpenChat + onOpenChat = onOpenChat, ) } } diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/details/PaymentDetailsDestination.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/details/PaymentDetailsDestination.kt index 3f7c9e0f24..6cc057ffd4 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/details/PaymentDetailsDestination.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/details/PaymentDetailsDestination.kt @@ -246,7 +246,7 @@ private fun MemberChargeDetailsScreen( MemberPaymentChargeMethod.KIVRA -> stringResource(Res.string.PAYMENTS_IN_PROGRESS_KIVRA) MemberPaymentChargeMethod.UNKNOWN -> null } - if (message!=null) { + if (message != null) { HedvigNotificationCard( message = message, style = NotificationDefaults.InfoCardStyle.Default, @@ -286,11 +286,13 @@ private fun MemberChargeDetailsScreen( when (uiState.paymentDetails.memberCharge.chargeMethod) { MemberPaymentChargeMethod.TRUSTLY, MemberPaymentChargeMethod.KIVRA, - -> { + -> { val textToShow: String = - if (uiState.paymentDetails.memberCharge.chargeMethod == MemberPaymentChargeMethod.TRUSTLY) - stringResource(Res.string.PAYMENTS_PAYMENT_DETAILS_INFO_DESCRIPTION) else + if (uiState.paymentDetails.memberCharge.chargeMethod == MemberPaymentChargeMethod.TRUSTLY) { + stringResource(Res.string.PAYMENTS_PAYMENT_DETAILS_INFO_DESCRIPTION) + } else { stringResource(Res.string.KIVRA_PAYMENT_INFO) + } Icon( imageVector = HedvigIcons.InfoFilled, tint = HedvigTheme.colorScheme.fillSecondary, @@ -359,7 +361,7 @@ private fun MemberChargeDetailsScreen( when (val chargeMethod = uiState.paymentDetails.memberCharge.chargeMethod) { MemberPaymentChargeMethod.TRUSTLY, MemberPaymentChargeMethod.KIVRA, - -> { + -> { HorizontalItemsWithMaximumSpaceTaken( startSlot = { HedvigText(stringResource(Res.string.PAYMENTS_PAYMENT_METHOD)) @@ -409,7 +411,7 @@ private fun MemberChargeDetailsScreen( HorizontalDivider() } - if (paymentsInfo.displayName!=null) { + if (paymentsInfo.displayName != null) { HorizontalItemsWithMaximumSpaceTaken( startSlot = { HedvigText(stringResource(Res.string.PAYMENTS_BANK_LABEL)) }, endSlot = { @@ -479,13 +481,11 @@ private fun PaymentDetailsScreenPreview( MemberChargeDetailsScreen( uiState = PaymentDetailsUiState.Success( PaymentDetails( - memberCharge = when (withPaymentInfo) { + memberCharge = when (withPaymentInfo) { TripleCase.FIRST -> paymentDetailsPreviewData - TripleCase.SECOND -> paymentDetailsKivraPreviewData - TripleCase.THIRD -> paymentDetailsPreviewData - } , + }, pastCharges = chargeHistoryPreviewData, paymentsInfo = when (withPaymentInfo) { TripleCase.FIRST -> PaymentDetails.PaymentsInfo.Active( diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/memberpaymentdetails/MemberPaymentDetailsDestination.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/memberpaymentdetails/MemberPaymentDetailsDestination.kt index 2dfae0ead7..85e16235ba 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/memberpaymentdetails/MemberPaymentDetailsDestination.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/memberpaymentdetails/MemberPaymentDetailsDestination.kt @@ -77,7 +77,7 @@ internal fun MemberPaymentDetailsDestination( }, navigateUp = navigateUp, onChangeBankAccount = onChangeBankAccount, - onOpenChat = onOpenChat + onOpenChat = onOpenChat, ) } @@ -111,7 +111,7 @@ private fun MemberPaymentDetailsScreen( uiState, onChangeBankAccount, modifier = Modifier.weight(1f), - onOpenChat = onOpenChat + onOpenChat = onOpenChat, ) } } @@ -254,15 +254,18 @@ private fun MemberPaymentDetailsSuccessScreen( .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)), ) } + MemberPaymentChargeMethod.KIVRA -> { HedvigNotificationCard( message = stringResource(Res.string.KIVRA_NOTIFICATION_BOX_TEXT), priority = NotificationDefaults.NotificationPriority.Info, style = NotificationDefaults.InfoCardStyle.Button( buttonText = stringResource(Res.string.DASHBOARD_OPEN_CHAT), - onButtonClick = onOpenChat - )) + onButtonClick = onOpenChat, + ), + ) } + MemberPaymentChargeMethod.UNKNOWN -> {} } @@ -271,10 +274,11 @@ private fun MemberPaymentDetailsSuccessScreen( } private sealed interface PaymentExplanationData { - data object Kivra: PaymentExplanationData - data class Trustly(val dueDate: String): PaymentExplanationData + data object Kivra : PaymentExplanationData - data object UnKnown: PaymentExplanationData + data class Trustly(val dueDate: String) : PaymentExplanationData + + data object UnKnown : PaymentExplanationData } @Composable @@ -351,7 +355,7 @@ internal fun MemberPaymentDetailsScreenPreview( {}, {}, {}, - {} + {}, ) } } @@ -369,7 +373,7 @@ private class MemberPaymentDetailsUiStatePreviewParameterProvider() : displayName = "displayName", mandate = "hedvig mandate", paymentMethod = "bankgiro", - chargeMethod = MemberPaymentChargeMethod.TRUSTLY + chargeMethod = MemberPaymentChargeMethod.TRUSTLY, ), ), MemberPaymentDetailsUiState.Success( @@ -379,7 +383,7 @@ private class MemberPaymentDetailsUiStatePreviewParameterProvider() : displayName = "displayName", mandate = "hedvig mandate", paymentMethod = "Faktura", - chargeMethod = MemberPaymentChargeMethod.KIVRA + chargeMethod = MemberPaymentChargeMethod.KIVRA, ), ), MemberPaymentDetailsUiState.Success( @@ -389,7 +393,7 @@ private class MemberPaymentDetailsUiStatePreviewParameterProvider() : displayName = "displayName", mandate = "hedvig mandate", paymentMethod = "bankgiro", - chargeMethod = MemberPaymentChargeMethod.UNKNOWN + chargeMethod = MemberPaymentChargeMethod.UNKNOWN, ), ), ), diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/payments/PaymentsDestination.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/payments/PaymentsDestination.kt index 03a9545a9f..f630e86423 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/payments/PaymentsDestination.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/ui/payments/PaymentsDestination.kt @@ -306,7 +306,7 @@ private fun PaymentsContent( is ConnectedPaymentInfo.NeedsSetup, ConnectedPaymentInfo.Unknown, is ConnectedPaymentInfo.Active, - -> { + -> { } } } diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/contactinfo/ContactInfoViewModel.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/contactinfo/ContactInfoViewModel.kt index c8cfd0022d..44dd871cf8 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/contactinfo/ContactInfoViewModel.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/contactinfo/ContactInfoViewModel.kt @@ -103,9 +103,9 @@ internal sealed interface ContactInfoUiState { internal class ContactInfoViewModel( repository: Provider, ) : MoleculeViewModel( - Loading, - ContactInfoPresenter(repository), -) + Loading, + ContactInfoPresenter(repository), + ) internal class ContactInfoPresenter( private val repository: Provider, diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index be7e19bf35..092d195a8d 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -23,12 +23,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.hedvig.android.compose.pager.indicator.HorizontalPagerIndicator import com.hedvig.android.core.common.daysUntil +import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.design.system.hedvig.HedvigNotificationCard import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.NotificationDefaults.InfoCardStyle import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority import com.hedvig.android.design.system.hedvig.Surface -import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.memberreminders.MemberReminder import com.hedvig.android.memberreminders.MemberReminder.UpcomingRenewal import com.hedvig.android.notification.permission.NotificationPermissionState @@ -270,10 +270,7 @@ fun ReminderCardUpdateContactInfo(navigateToContactInfo: () -> Unit, modifier: M } @Composable -internal fun ReminderMissingChipId( - navigateToChipId: () -> Unit, - modifier: Modifier = Modifier, -) { +internal fun ReminderMissingChipId(navigateToChipId: () -> Unit, modifier: Modifier = Modifier) { HedvigNotificationCard( message = stringResource(Res.string.CHIP_ID_MISSING_MESSAGE), modifier = modifier, @@ -342,7 +339,7 @@ private fun ReminderCardUpcomingRenewals( private fun ReminderCoInsuredInfo( coInsuredType: CoInsuredFlowType, navigateToAddMissingInfo: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { HedvigNotificationCard( message = when (coInsuredType) { From 94f931112705da7e42c3dfe67488f070e2ce2956 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 16:44:16 +0200 Subject: [PATCH 15/42] preselect from insurance details --- .../com/hedvig/android/app/navigation/HedvigNavHost.kt | 4 ++-- .../insurances/insurancedetail/ContractDetailDestination.kt | 6 +++--- .../android/feature/insurances/navigation/InsuranceGraph.kt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index 89c56f8a9a..969ab8ae03 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -334,8 +334,8 @@ internal fun HedvigNavHost( ), ) }, - navigateToChipIdScreen = { - navController.navigate(ChipIdGraphDestination()) + navigateToChipIdScreen = { contractId -> + navController.navigate(ChipIdGraphDestination(contractId)) }, ) foreverGraph( diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt index 529f584825..47e59ddc08 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailDestination.kt @@ -112,7 +112,7 @@ internal fun ContractDetailDestination( navigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, navigateToAddAddon: (AvailableAddon) -> Unit, - navigateToChipIdScreen: () -> Unit, + navigateToChipIdScreen: (String) -> Unit, ) { val uiState: ContractDetailsUiState by viewModel.uiState.collectAsStateWithLifecycle() ContractDetailScreen( @@ -156,7 +156,7 @@ private fun ContractDetailScreen( openUrl: (String) -> Unit, navigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, - navigateToChipIdScreen: () -> Unit, + navigateToChipIdScreen: (String) -> Unit, navigateToAddAddon: (AvailableAddon) -> Unit, ) { Column(Modifier.fillMaxSize()) { @@ -364,7 +364,7 @@ private fun ContractDetailScreen( navigateToUpgradeAddon = navigateToUpgradeAddon, chipIdState = contract.chipId, onFillChipId = { - navigateToChipIdScreen() + navigateToChipIdScreen(contract.id) }, ) } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt index 1e175d9412..51338cead6 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt @@ -40,7 +40,7 @@ fun NavGraphBuilder.insuranceGraph( onNavigateToAddonPurchaseFlow: (List, AvailableAddon?) -> Unit, onNavigateToRemoveAddon: (ContractId?, AddonVariant?) -> Unit, navigateToUpgradeAddon: (ContractId?, AddonVariant?) -> Unit, - navigateToChipIdScreen: () -> Unit, + navigateToChipIdScreen: (String) -> Unit, ) { navgraph( startDestination = InsurancesDestination.Insurances::class, From d4315d47e9f4e4c1206724418dc6722169c69dd4 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 16:49:00 +0200 Subject: [PATCH 16/42] not preselect first --- .../id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt index 32a394682c..0072dba41b 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt @@ -42,7 +42,7 @@ internal class SelectInsuranceForChipIdPresenter( currentState = result.fold( ifLeft = { SelectInsuranceForChipIdState.Failure }, ifRight = { contracts -> - val preselected = contracts.firstOrNull { it.id == preselectedContractId } ?: contracts.firstOrNull() + val preselected = contracts.firstOrNull { it.id == preselectedContractId } if (contracts.size == 1) { contractIdToContinue = contracts[0].id From e0a5fd7ed223ff213a1d694c97842b9476df0555 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 17:16:11 +0200 Subject: [PATCH 17/42] add insurance card --- .../GetPetContractsForChipIdQuery.graphql | 3 +- .../data/GetPetContractsForChipIdUseCase.kt | 8 +- .../chip/id/data/PetContractForChipId.kt | 1 + .../feature/chip/id/di/ChipIdModule.kt | 1 + .../feature/chip/id/ui/AddChipIdScreen.kt | 126 ++++++++++++++++++ .../feature/chip/id/ui/AddChipIdViewModel.kt | 58 ++++++-- .../SelectInsuranceForChipIdDestination.kt | 21 +++ 7 files changed, 198 insertions(+), 20 deletions(-) diff --git a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql index b4d5f6b4dc..1c192bb7e5 100644 --- a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql +++ b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql @@ -6,7 +6,8 @@ query GetPetContractsForChipId { missingPetId currentAgreement { productVariant { - displayName + typeOfContract + displayName } } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt index 5baca946ec..5c09c1863f 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt @@ -6,6 +6,7 @@ import com.apollographql.apollo.cache.normalized.FetchPolicy import com.apollographql.apollo.cache.normalized.fetchPolicy import com.hedvig.android.apollo.ApolloOperationError import com.hedvig.android.apollo.safeExecute +import com.hedvig.android.data.contract.toContractGroup import com.hedvig.android.logger.logcat import octopus.GetPetContractsForChipIdQuery @@ -25,15 +26,12 @@ internal class GetPetContractsForChipIdUseCaseImpl( data.currentMember.activeContracts .mapNotNull { contract -> if (contract.missingPetId) { - val result = PetContractForChipId( + PetContractForChipId( id = contract.id, displayName = contract.currentAgreement.productVariant.displayName, contractExposure = contract.exposureDisplayNameShort, + contractGroup = contract.currentAgreement.productVariant.typeOfContract.toContractGroup(), ) - logcat { - "GetPetContractsForChipIdUseCaseImpl: result: $result contract.missingPetId: ${contract.missingPetId}" - } - result } else { null } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt index de17a84a51..06d83561a6 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/PetContractForChipId.kt @@ -6,4 +6,5 @@ data class PetContractForChipId( val id: String, val displayName: String, val contractExposure: String, + val contractGroup: ContractGroup ) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt index 98904be0b8..c6a3c2c346 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt @@ -34,6 +34,7 @@ val chipIdModule = module { AddChipIdViewModel( updateChipIdUseCase = get(), contractId = params.get(), + getPetContractsForChipIdUseCase = get(), ) } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 2298e836f0..82ea6fb56e 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -6,13 +6,19 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.togetherWith +import androidx.compose.foundation.Image +import androidx.compose.foundation.border import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row 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.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.input.InputTransformation @@ -24,22 +30,35 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.hedvig.android.compose.ui.preview.DoubleBooleanCollectionPreviewParameterProvider +import com.hedvig.android.compose.ui.preview.TripleBooleanCollectionPreviewParameterProvider +import com.hedvig.android.data.contract.ContractGroup +import com.hedvig.android.data.contract.pillowResource import com.hedvig.android.design.system.hedvig.GlobalSnackBarState import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigCard import com.hedvig.android.design.system.hedvig.HedvigErrorSection import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgressDebounced import com.hedvig.android.design.system.hedvig.HedvigNotificationCard +import com.hedvig.android.design.system.hedvig.HedvigPreview import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText import com.hedvig.android.design.system.hedvig.HedvigTextField import com.hedvig.android.design.system.hedvig.HedvigTextFieldDefaults +import com.hedvig.android.design.system.hedvig.HedvigTheme import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority +import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.clearFocusOnTap +import com.hedvig.android.feature.chip.id.data.PetContractForChipId import com.hedvig.android.feature.chip.id.ui.AddChipIdEvent.RetryLoadData import com.hedvig.android.feature.chip.id.ui.AddChipIdEvent.SubmitData import com.hedvig.android.feature.chip.id.ui.AddChipIdUiState.Content @@ -50,6 +69,7 @@ import hedvig.resources.CONTACT_INFO_CHANGES_SAVED import hedvig.resources.Res import hedvig.resources.general_save_button import hedvig.resources.something_went_wrong +import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @Composable @@ -143,6 +163,9 @@ private fun ColumnScope.AddChipIdContent( Spacer(Modifier.weight(1f)) Spacer(Modifier.height(16.dp)) + InsuranceInfoCard(uiState.contract, + modifier = Modifier.padding(horizontal = 16.dp)) + Spacer(Modifier.height(16.dp)) ChipIdTextField( textFieldState = uiState.chipIdState, labelText = stringResource(Res.string.CHIP_ID_LABEL), @@ -215,3 +238,106 @@ private fun ChipIdTextField( .padding(horizontal = 16.dp), ) } + + +@Composable +private fun InsuranceInfoCard( + insuranceInfo: PetContractForChipId, + modifier: Modifier = Modifier, +) { + HedvigCard(modifier + .border( + width = 1.dp, + color = HedvigTheme.colorScheme.borderPrimary, + shape = HedvigTheme.shapes.cornerXLarge, + ), + color = HedvigTheme.colorScheme.backgroundPrimary) { + Column(Modifier.padding(16.dp)) { + Row { + Image( + painter = painterResource(insuranceInfo.contractGroup.pillowResource()), + contentDescription = null, + modifier = Modifier.size(48.dp), + ) + Spacer(Modifier.width(12.dp)) + Column(Modifier.weight(1f)) { + HedvigText(insuranceInfo.displayName) + HedvigText(insuranceInfo.contractExposure, color = HedvigTheme.colorScheme.textSecondary) + } + } + } + } +} + +@HedvigPreview +@Composable +private fun PreviewTerminationConfirmationScreen( + @PreviewParameter(AddChipIdScreenStateProvider ::class) state: AddChipIdUiState, +) { + HedvigTheme { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { + AddChipIdScreen( + state, + globalSnackBarState = GlobalSnackBarState(), + submitChipId = { }, + reload = { }, + navigateUp = { }, + showedSnackBar = {}, + ) + } + } +} + + +private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< AddChipIdUiState>( + listOf( + AddChipIdUiState.Error, + AddChipIdUiState.Loading, + Content( + chipIdState = TextFieldState(), + contract = PetContractForChipId( + id = "sdf", + displayName = "Display name", + contractExposure = "Kitty", + contractGroup = ContractGroup.CAT + ), + showSuccessSnackBar = false, + submittingData = false, + ), + Content( + chipIdState = TextFieldState(initialText = "123456789012345"), + contract = PetContractForChipId( + id = "sdf", + displayName = "Display name", + contractExposure = "Kitty", + contractGroup = ContractGroup.CAT + ), + showSuccessSnackBar = false, + submittingData = false, + ), + Content( + chipIdState = TextFieldState(), + contract = PetContractForChipId( + id = "sdf", + displayName = "Display name", + contractExposure = "Kitty", + contractGroup = ContractGroup.CAT + ), + showSuccessSnackBar = false, + submittingData = false, + errorType = ChipIdErrorType.WrongInput + ), + Content( + chipIdState = TextFieldState(), + contract = PetContractForChipId( + id = "sdf", + displayName = "Display name", + contractExposure = "Kitty", + contractGroup = ContractGroup.CAT + ), + showSuccessSnackBar = false, + submittingData = false, + errorType = ChipIdErrorType.GeneralError + ), + ), +) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 14f095525f..e6457db489 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -11,24 +11,29 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.Snapshot import androidx.compose.ui.text.TextRange +import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase +import com.hedvig.android.feature.chip.id.data.PetContractForChipId import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase import com.hedvig.android.molecule.public.MoleculePresenter import com.hedvig.android.molecule.public.MoleculePresenterScope import com.hedvig.android.molecule.public.MoleculeViewModel internal class AddChipIdViewModel( - private val updateChipIdUseCase: UpdateChipIdUseCase, + updateChipIdUseCase: UpdateChipIdUseCase, + getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, contractId: String, ) : MoleculeViewModel( - initialState = AddChipIdUiState.Loading, - presenter = AddChipIdPresenter( - updateChipIdUseCase = updateChipIdUseCase, - contractId = contractId, - ), - ) + initialState = AddChipIdUiState.Loading, + presenter = AddChipIdPresenter( + updateChipIdUseCase = updateChipIdUseCase, + contractId = contractId, + getPetContractsForChipIdUseCase = getPetContractsForChipIdUseCase, + ), +) internal class AddChipIdPresenter( private val updateChipIdUseCase: UpdateChipIdUseCase, + private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, private val contractId: String, ) : MoleculePresenter { @Composable @@ -37,11 +42,32 @@ internal class AddChipIdPresenter( val lastChipIdState = lastState.content?.chipIdState TextFieldState(lastChipIdState?.text?.toString() ?: "", lastChipIdState?.selection ?: TextRange(0)) } + var currentState by remember { mutableStateOf(lastState) } var submittingData by remember { mutableStateOf(false) } var showSuccessSnackBar by remember { mutableStateOf(false) } var errorType by remember { mutableStateOf(null) } var submitIteration by remember { mutableIntStateOf(0) } + var loadIteration by remember { mutableIntStateOf(0) } + + LaunchedEffect(loadIteration) { + getPetContractsForChipIdUseCase.invoke().fold( + ifLeft = { + currentState = AddChipIdUiState.Error + }, + ifRight = { + val contract = it.firstOrNull { it.id == contractId } + if (contract == null) { + currentState = AddChipIdUiState.Error + return@LaunchedEffect + } + currentState = AddChipIdUiState.Content( + chipIdState = chipIdState, + contract = contract, + ) + }, + ) + } LaunchedEffect(submitIteration) { if (submitIteration == 0) return@LaunchedEffect @@ -68,7 +94,7 @@ internal class AddChipIdPresenter( CollectEvents { event -> when (event) { AddChipIdEvent.RetryLoadData -> { - // Retry by resetting state + loadIteration++ chipIdState.setTextAndPlaceCursorAtEnd("") } @@ -91,12 +117,15 @@ internal class AddChipIdPresenter( } } - return AddChipIdUiState.Content( - chipIdState = chipIdState, - showSuccessSnackBar = showSuccessSnackBar, - submittingData = submittingData, - errorType = errorType, - ) + return when (val state = currentState) { + is AddChipIdUiState.Content -> state.copy( + chipIdState = chipIdState, + showSuccessSnackBar = showSuccessSnackBar, + submittingData = submittingData, + errorType = errorType, + ) + AddChipIdUiState.Error, AddChipIdUiState.Loading -> state + } } } @@ -110,6 +139,7 @@ internal sealed interface AddChipIdUiState { data class Content( val chipIdState: TextFieldState, + val contract: PetContractForChipId, val showSuccessSnackBar: Boolean = false, val submittingData: Boolean = false, val errorType: ChipIdErrorType? = null, diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt index c0b8c3b691..086770c4f1 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt @@ -1,28 +1,46 @@ package com.hedvig.android.feature.chip.id.ui.selectinsurance +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.hedvig.android.compose.ui.dropUnlessResumed +import com.hedvig.android.data.contract.ContractGroup.HOMEOWNER +import com.hedvig.android.data.contract.pillowResource import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigCard import com.hedvig.android.design.system.hedvig.HedvigErrorSection import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress +import com.hedvig.android.design.system.hedvig.HedvigPreview import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.HorizontalDivider +import com.hedvig.android.design.system.hedvig.HorizontalItemsWithMaximumSpaceTaken import com.hedvig.android.design.system.hedvig.Icon import com.hedvig.android.design.system.hedvig.IconButton +import com.hedvig.android.design.system.hedvig.LocalTextStyle +import com.hedvig.android.design.system.hedvig.ProvideTextStyle import com.hedvig.android.design.system.hedvig.RadioGroup import com.hedvig.android.design.system.hedvig.RadioOption import com.hedvig.android.design.system.hedvig.RadioOptionId +import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.design.system.hedvig.a11y.FlowHeading import com.hedvig.android.design.system.hedvig.icon.Close import com.hedvig.android.design.system.hedvig.icon.HedvigIcons @@ -31,9 +49,12 @@ import hedvig.resources.ADDON_FLOW_SELECT_INSURANCE_SUBTITLE import hedvig.resources.ADDON_FLOW_SELECT_INSURANCE_TITLE import hedvig.resources.Res import hedvig.resources.SELECT_INSURANCE_TO_REMOVE_ADDON_TITLE +import hedvig.resources.TERMINATION_ADDON_COVERAGE_TITLE import hedvig.resources.TIER_FLOW_SELECT_INSURANCE_SUBTITLE import hedvig.resources.general_close_button import hedvig.resources.general_continue_button +import kotlinx.datetime.LocalDate +import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @Composable From bec5781451b9e280949ef2b87fbaecf423373ca1 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 30 Mar 2026 17:21:02 +0200 Subject: [PATCH 18/42] save selection state --- .../ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt index 0072dba41b..e310f1efb6 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt @@ -33,7 +33,9 @@ internal class SelectInsuranceForChipIdPresenter( var currentState by remember { mutableStateOf(lastState) } var loadIteration by remember { mutableIntStateOf(0) } - var selectedContract: PetContractForChipId? by remember { mutableStateOf(null) } + var selectedContract: PetContractForChipId? by remember { mutableStateOf( + if (lastState is SelectInsuranceForChipIdState.Success) lastState.selectedContract else + null) } var contractIdToContinue: String? by remember { mutableStateOf(null) } LaunchedEffect(loadIteration) { From 988c2db4c4021e66e080854d34a14fa08c51eef4 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 09:39:56 +0200 Subject: [PATCH 19/42] fix test, change GetMissingChipIdReminderUseCase return type to either --- .../presentation/InsurancePresenterTest.kt | 5 ++++ .../ContractDetailPresenterTest.kt | 3 ++ .../TerminatedContractsPresenterTest.kt | 6 ++++ .../GetMemberRemindersUseCase.kt | 15 +++++----- .../GetMissingChipIdReminderUseCase.kt | 30 ++++++++++--------- .../GetMemberRemindersUseCaseTest.kt | 15 ++++++++++ 6 files changed, 53 insertions(+), 21 deletions(-) diff --git a/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurance/presentation/InsurancePresenterTest.kt b/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurance/presentation/InsurancePresenterTest.kt index 7e389e6487..03ca1900cc 100644 --- a/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurance/presentation/InsurancePresenterTest.kt +++ b/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurance/presentation/InsurancePresenterTest.kt @@ -22,6 +22,7 @@ import com.hedvig.android.data.addons.data.AddonBannerInfo import com.hedvig.android.data.addons.data.AddonBannerSource import com.hedvig.android.data.addons.data.FlowType import com.hedvig.android.data.addons.data.GetAddonBannerInfoUseCase +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractType import com.hedvig.android.data.contract.CrossSell @@ -97,6 +98,7 @@ internal class InsurancePresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing, ), EstablishedInsuranceContract( id = "contractId#2", @@ -144,6 +146,7 @@ internal class InsurancePresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), ) private val terminatedContracts: List = listOf( @@ -193,6 +196,7 @@ internal class InsurancePresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), EstablishedInsuranceContract( id = "contractId#4", @@ -240,6 +244,7 @@ internal class InsurancePresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), ) private val validCrossSells: CrossSellResult = CrossSellResult( diff --git a/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailPresenterTest.kt b/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailPresenterTest.kt index 9f3a61e2c4..575209deda 100644 --- a/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailPresenterTest.kt +++ b/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/insurancedetail/ContractDetailPresenterTest.kt @@ -10,6 +10,7 @@ import assertk.assertions.isInstanceOf import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractType import com.hedvig.android.data.productvariant.ProductVariant @@ -290,6 +291,7 @@ class ContractDetailPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ) private val insuranceWithTerminationDate = EstablishedInsuranceContract( @@ -338,6 +340,7 @@ class ContractDetailPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ) private val responseTurbine = Turbine>() diff --git a/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsPresenterTest.kt b/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsPresenterTest.kt index 2057be26bf..14bd019207 100644 --- a/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsPresenterTest.kt +++ b/app/feature/feature-insurances/src/test/kotlin/com/hedvig/android/feature/insurances/terminatedcontracts/TerminatedContractsPresenterTest.kt @@ -10,6 +10,7 @@ import assertk.assertions.isInstanceOf import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.data.contract.ChipIdState import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.ContractType import com.hedvig.android.data.productvariant.ProductVariant @@ -233,6 +234,7 @@ class TerminatedContractsPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), EstablishedInsuranceContract( "contractId2", @@ -280,6 +282,7 @@ class TerminatedContractsPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), ) @@ -329,6 +332,7 @@ class TerminatedContractsPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ) private val activeInsurances = listOf( @@ -378,6 +382,7 @@ class TerminatedContractsPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), EstablishedInsuranceContract( "contractId4", @@ -425,6 +430,7 @@ class TerminatedContractsPresenterTest { tierName = "STANDARD", existingAddons = emptyList(), availableAddons = emptyList(), + chipId = ChipIdState.Missing ), ) } diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt index 87b7bee003..85ecdb618b 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt @@ -3,6 +3,7 @@ package com.hedvig.android.memberreminders import arrow.core.Either import arrow.core.NonEmptyList import arrow.core.merge +import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.memberreminders.MemberReminder.ContactInfoUpdateNeeded import java.util.UUID @@ -57,18 +58,18 @@ internal class GetMemberRemindersUseCaseImpl( ) { values -> val enableNotifications = values[0] as MemberReminder.EnableNotifications? val connectPayment = values[1] as MemberReminder.PaymentReminder? - val upcomingRenewalReminders = values[2] as NonEmptyList? - val coInsuredInfoResult = values[3] as Either> - val contactInfoReminder = values[4] as Either - val missingChipId = values[5] as MemberReminder.MissingChipId? + val upcomingRenewalReminders = values[2] as? NonEmptyList? + val coInsuredInfoResult = values[3] as? Either> + val contactInfoReminder = values[4] as? Either + val missingChipIdReminder = values[5] as? Either MemberReminders( connectPayment = connectPayment, upcomingRenewals = upcomingRenewalReminders, enableNotifications = enableNotifications, - coInsuredInfo = coInsuredInfoResult.getOrNull(), - updateContactInfo = contactInfoReminder.getOrNull(), - missingChipId = missingChipId, + coInsuredInfo = coInsuredInfoResult?.getOrNull(), + updateContactInfo = contactInfoReminder?.getOrNull(), + missingChipId = missingChipIdReminder?.getOrNull(), ) } } diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt index ea0e55bbd7..57476d6ee5 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt @@ -1,35 +1,37 @@ package com.hedvig.android.memberreminders +import arrow.core.Either +import arrow.core.raise.either import com.apollographql.apollo.ApolloClient import com.apollographql.apollo.cache.normalized.FetchPolicy import com.apollographql.apollo.cache.normalized.fetchPolicy +import com.hedvig.android.apollo.ErrorMessage import com.hedvig.android.apollo.safeFlow -import com.hedvig.android.data.contract.ContractGroup -import com.hedvig.android.data.contract.toContractGroup +import com.hedvig.android.core.common.ErrorMessage import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapLatest import octopus.MissingChipIdReminderQuery internal interface GetMissingChipIdReminderUseCase { - fun invoke(): Flow + fun invoke(): Flow> } internal class GetMissingChipIdReminderUseCaseImpl( private val apolloClient: ApolloClient, ) : GetMissingChipIdReminderUseCase { - override fun invoke(): Flow { + override fun invoke(): Flow> { return apolloClient.query(MissingChipIdReminderQuery()) .fetchPolicy(FetchPolicy.CacheAndNetwork) - .safeFlow() - .mapLatest { result -> - result.fold( - ifRight = { data -> - data.currentMember.activeContracts - .firstOrNull { it.missingPetId } - ?.let { MemberReminder.MissingChipId() } - }, - ifLeft = { null }, - ) + .safeFlow(::ErrorMessage) + .mapLatest { result: Either -> + either { + result + .bind() + .currentMember + .activeContracts + .firstOrNull { it.missingPetId } + ?.let { MemberReminder.MissingChipId() } + } } } } diff --git a/app/member-reminders/member-reminders-public/src/test/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCaseTest.kt b/app/member-reminders/member-reminders-public/src/test/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCaseTest.kt index 37924c30c1..59401d599f 100644 --- a/app/member-reminders/member-reminders-public/src/test/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCaseTest.kt +++ b/app/member-reminders/member-reminders-public/src/test/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCaseTest.kt @@ -34,12 +34,14 @@ class GetMemberRemindersUseCaseTest { val getUpcomingRenewalRemindersUseCase = TestGetUpcomingRenewalRemindersUseCase() val getNeedsCoInsuredInfoRemindersUseCase = TestGetNeedsCoInsuredInfoRemindersUseCase() val getContactInfoUpdateIsNeededUseCase = TestGetContactInfoUpdateIsNeededUseCase() + val getMissingChipIdReminderUseCase = TestGetMissingChipIdReminderUseCase() val getMemberRemindersUseCase = GetMemberRemindersUseCaseImpl( enableNotificationsReminderSnoozeManager = enableNotificationsReminderManager, getConnectPaymentReminderUseCase = getConnectPaymentReminderUseCase, getUpcomingRenewalRemindersUseCase = getUpcomingRenewalRemindersUseCase, getNeedsCoInsuredInfoRemindersUseCase = getNeedsCoInsuredInfoRemindersUseCase, getContactInfoUpdateIsNeededUseCase = getContactInfoUpdateIsNeededUseCase, + getMissingChipIdReminderUseCase = getMissingChipIdReminderUseCase ) getMemberRemindersUseCase.invoke().test { @@ -66,12 +68,14 @@ class GetMemberRemindersUseCaseTest { val getUpcomingRenewalRemindersUseCase = TestGetUpcomingRenewalRemindersUseCase() val getNeedsCoInsuredInfoRemindersUseCase = TestGetNeedsCoInsuredInfoRemindersUseCase() val getContactInfoUpdateIsNeededUseCase = TestGetContactInfoUpdateIsNeededUseCase() + val getMissingChipIdReminderUseCase = TestGetMissingChipIdReminderUseCase() val getMemberRemindersUseCase = GetMemberRemindersUseCaseImpl( enableNotificationsReminderSnoozeManager = enableNotificationsReminderManager, getConnectPaymentReminderUseCase = getConnectPaymentReminderUseCase, getUpcomingRenewalRemindersUseCase = getUpcomingRenewalRemindersUseCase, getNeedsCoInsuredInfoRemindersUseCase = getNeedsCoInsuredInfoRemindersUseCase, getContactInfoUpdateIsNeededUseCase = getContactInfoUpdateIsNeededUseCase, + getMissingChipIdReminderUseCase = getMissingChipIdReminderUseCase ) val testId = "test" @@ -133,4 +137,15 @@ class GetMemberRemindersUseCaseTest { ) } } + + class TestGetMissingChipIdReminderUseCase : GetMissingChipIdReminderUseCase { + override fun invoke(): Flow> { + return flowOf( + either { + null + }, + ) + } + } + } From 33d3c0b1f3a652e80ab32a016f599eea64ae7814 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 13:48:32 +0200 Subject: [PATCH 20/42] clear error in input change --- .../hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index e6457db489..2039f93aa8 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -50,6 +50,10 @@ internal class AddChipIdPresenter( var submitIteration by remember { mutableIntStateOf(0) } var loadIteration by remember { mutableIntStateOf(0) } + LaunchedEffect(chipIdState.text) { + errorType = null + } + LaunchedEffect(loadIteration) { getPetContractsForChipIdUseCase.invoke().fold( ifLeft = { From 1cf9ad6ff3f57e574791b266ebd2c3201ac900b8 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 14:50:16 +0200 Subject: [PATCH 21/42] add "000-000-000-000-000" mask --- .../feature/chip/id/ui/AddChipIdScreen.kt | 104 ++++++++++++++---- .../feature/chip/id/ui/AddChipIdViewModel.kt | 32 +++--- 2 files changed, 99 insertions(+), 37 deletions(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 82ea6fb56e..9fd2184351 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -22,25 +22,31 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.input.InputTransformation -import androidx.compose.foundation.text.input.KeyboardActionHandler import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.byValue import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.focus.FocusManager +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.hedvig.android.compose.ui.preview.DoubleBooleanCollectionPreviewParameterProvider -import com.hedvig.android.compose.ui.preview.TripleBooleanCollectionPreviewParameterProvider import com.hedvig.android.data.contract.ContractGroup import com.hedvig.android.data.contract.pillowResource import com.hedvig.android.design.system.hedvig.GlobalSnackBarState @@ -94,6 +100,9 @@ internal fun AddChipIdDestination( viewModel.emit(AddChipIdEvent.ShowedMessage) popFlowOnSuccess() }, + updateText = { + viewModel.emit(AddChipIdEvent.UpdateText(it)) + } ) } @@ -105,6 +114,7 @@ private fun AddChipIdScreen( reload: () -> Unit, navigateUp: () -> Unit, showedSnackBar: () -> Unit, + updateText: (String) -> Unit ) { val focusManager = LocalFocusManager.current HedvigScaffold( @@ -139,6 +149,7 @@ private fun AddChipIdScreen( submitChipId = submitChipId, focusManager = focusManager, showedSnackBar = showedSnackBar, + updateText = updateText ) } } @@ -152,6 +163,7 @@ private fun ColumnScope.AddChipIdContent( submitChipId: () -> Unit, focusManager: FocusManager, showedSnackBar: () -> Unit, + updateText: (String) -> Unit ) { val successMessage = stringResource(Res.string.CONTACT_INFO_CHANGES_SAVED) LaunchedEffect(uiState.showSuccessSnackBar) { @@ -167,12 +179,10 @@ private fun ColumnScope.AddChipIdContent( modifier = Modifier.padding(horizontal = 16.dp)) Spacer(Modifier.height(16.dp)) ChipIdTextField( - textFieldState = uiState.chipIdState, + text = uiState.chipIdText, labelText = stringResource(Res.string.CHIP_ID_LABEL), - keyboardActionHandler = KeyboardActionHandler { - submitChipId() - focusManager.clearFocus() - }, + updateText = updateText + ) AnimatedContent( @@ -213,24 +223,30 @@ private fun ColumnScope.AddChipIdContent( @Composable private fun ChipIdTextField( - textFieldState: TextFieldState, + text: String, labelText: String, - keyboardActionHandler: KeyboardActionHandler?, + updateText: (String) -> Unit ) { val interactionSource = remember { MutableInteractionSource() } - val digitsOnlyTransformation = InputTransformation.byValue { _, proposed -> - proposed.filter { it.isDigit() } - } + var input by remember { mutableStateOf(text ?: "") } + val mask = "000-000-000-000-000" + val maskColor = HedvigTheme.colorScheme.textTertiary + val visualTransformation = ChipIdVisualTransformation(mask, maskColor) HedvigTextField( - state = textFieldState, + text = input, labelText = labelText, errorState = HedvigTextFieldDefaults.ErrorState.NoError, + onValueChange = { + if(it.length<=15) { + updateText(it) + input = it + } + }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, imeAction = ImeAction.Done, ), - inputTransformation = digitsOnlyTransformation, - keyboardActions = keyboardActionHandler, + visualTransformation = visualTransformation, textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, interactionSource = interactionSource, modifier = Modifier @@ -239,6 +255,51 @@ private fun ChipIdTextField( ) } +private class ChipIdVisualTransformation( + private val mask: String, + private val maskColor: Color, +) : VisualTransformation { + override fun filter(text: AnnotatedString): TransformedText { + val trimmed = if (text.text.length >= 15) text.text.substring(0..14) else text.text + + val annotatedString = buildAnnotatedString { + for (i in trimmed.indices) { + append(trimmed[i]) + if (i in listOf(2,5,8,11)) { + append("-") + } + } + withStyle(SpanStyle(color = maskColor)) { + append(mask.takeLast(mask.length - length)) + } + } + + val personalNumberOffsetTranslator = object : OffsetMapping { + override fun originalToTransformed(offset: Int): Int { + return when { + offset <= 2 -> offset + offset <= 5 -> offset + 1 + offset <= 8 -> offset + 2 + offset <= 11 -> offset + 3 + offset <= 15 -> offset + 4 + else -> 19 + } + } + + override fun transformedToOriginal(offset: Int): Int { + return when { + offset <= 3 -> offset + offset <= 7 -> offset - 1 + offset <= 11 -> offset - 2 + offset <= 15 -> offset - 3 + else -> offset - 4 + }.coerceAtMost(text.length) + } + } + return TransformedText(annotatedString, personalNumberOffsetTranslator) + } +} + @Composable private fun InsuranceInfoCard( @@ -283,6 +344,7 @@ private fun PreviewTerminationConfirmationScreen( reload = { }, navigateUp = { }, showedSnackBar = {}, + {} ) } } @@ -294,7 +356,7 @@ private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< AddChipIdUiState.Error, AddChipIdUiState.Loading, Content( - chipIdState = TextFieldState(), + chipIdText = "", contract = PetContractForChipId( id = "sdf", displayName = "Display name", @@ -305,7 +367,7 @@ private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< submittingData = false, ), Content( - chipIdState = TextFieldState(initialText = "123456789012345"), + chipIdText = "123456789012345", contract = PetContractForChipId( id = "sdf", displayName = "Display name", @@ -316,7 +378,7 @@ private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< submittingData = false, ), Content( - chipIdState = TextFieldState(), + chipIdText = "", contract = PetContractForChipId( id = "sdf", displayName = "Display name", @@ -328,7 +390,7 @@ private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< errorType = ChipIdErrorType.WrongInput ), Content( - chipIdState = TextFieldState(), + chipIdText = "", contract = PetContractForChipId( id = "sdf", displayName = "Display name", diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 2039f93aa8..7d71c6a727 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -1,6 +1,5 @@ package com.hedvig.android.feature.chip.id.ui -import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -10,7 +9,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.Snapshot -import androidx.compose.ui.text.TextRange import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase import com.hedvig.android.feature.chip.id.data.PetContractForChipId import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase @@ -38,9 +36,9 @@ internal class AddChipIdPresenter( ) : MoleculePresenter { @Composable override fun MoleculePresenterScope.present(lastState: AddChipIdUiState): AddChipIdUiState { - val chipIdState = remember { - val lastChipIdState = lastState.content?.chipIdState - TextFieldState(lastChipIdState?.text?.toString() ?: "", lastChipIdState?.selection ?: TextRange(0)) + var chipIdText by remember { + val lastChipIdState = lastState.content?.chipIdText + mutableStateOf(lastChipIdState ?: "") } var currentState by remember { mutableStateOf(lastState) } var submittingData by remember { mutableStateOf(false) } @@ -50,7 +48,7 @@ internal class AddChipIdPresenter( var submitIteration by remember { mutableIntStateOf(0) } var loadIteration by remember { mutableIntStateOf(0) } - LaunchedEffect(chipIdState.text) { + LaunchedEffect(chipIdText) { errorType = null } @@ -66,7 +64,7 @@ internal class AddChipIdPresenter( return@LaunchedEffect } currentState = AddChipIdUiState.Content( - chipIdState = chipIdState, + chipIdText = chipIdText, contract = contract, ) }, @@ -79,7 +77,7 @@ internal class AddChipIdPresenter( submittingData = true errorType = null - updateChipIdUseCase.invoke(insuranceId = contractId, petId = chipIdState.text.toString()).fold( + updateChipIdUseCase.invoke(insuranceId = contractId, petId = chipIdText).fold( ifLeft = { error -> Snapshot.withMutableSnapshot { submittingData = false @@ -99,11 +97,10 @@ internal class AddChipIdPresenter( when (event) { AddChipIdEvent.RetryLoadData -> { loadIteration++ - chipIdState.setTextAndPlaceCursorAtEnd("") } AddChipIdEvent.SubmitData -> { - if (!chipIdState.text.toString().all { it.isDigit() } || chipIdState.text.toString().length != 15) { + if (!chipIdText.all { it.isDigit() } || chipIdText.length != 15) { Snapshot.withMutableSnapshot { errorType = ChipIdErrorType.WrongInput } @@ -118,12 +115,16 @@ internal class AddChipIdPresenter( errorType = null } } + + is AddChipIdEvent.UpdateText -> { + chipIdText = event.newText + } } } return when (val state = currentState) { is AddChipIdUiState.Content -> state.copy( - chipIdState = chipIdState, + chipIdText = chipIdText, showSuccessSnackBar = showSuccessSnackBar, submittingData = submittingData, errorType = errorType, @@ -142,15 +143,12 @@ internal sealed interface AddChipIdUiState { data object Error : AddChipIdUiState data class Content( - val chipIdState: TextFieldState, + val chipIdText: String, val contract: PetContractForChipId, val showSuccessSnackBar: Boolean = false, val submittingData: Boolean = false, val errorType: ChipIdErrorType? = null, - ) : AddChipIdUiState { - val isChipIdValid: Boolean - get() = chipIdState.text.toString().length == 15 && chipIdState.text.toString().all { it.isDigit() } - } + ) : AddChipIdUiState } internal sealed interface ChipIdErrorType { @@ -165,4 +163,6 @@ internal sealed interface AddChipIdEvent { data object SubmitData : AddChipIdEvent data object ShowedMessage : AddChipIdEvent + + data class UpdateText(val newText: String): AddChipIdEvent } From 970a2990c99d1d137698e4add63ee6b2853cb397 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 14:50:56 +0200 Subject: [PATCH 22/42] ktlint --- .../feature/chip/id/ui/AddChipIdScreen.kt | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index 9fd2184351..b1056f609f 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -21,9 +21,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.foundation.text.input.InputTransformation -import androidx.compose.foundation.text.input.TextFieldState -import androidx.compose.foundation.text.input.byValue import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -102,7 +99,7 @@ internal fun AddChipIdDestination( }, updateText = { viewModel.emit(AddChipIdEvent.UpdateText(it)) - } + }, ) } @@ -114,7 +111,7 @@ private fun AddChipIdScreen( reload: () -> Unit, navigateUp: () -> Unit, showedSnackBar: () -> Unit, - updateText: (String) -> Unit + updateText: (String) -> Unit, ) { val focusManager = LocalFocusManager.current HedvigScaffold( @@ -149,7 +146,7 @@ private fun AddChipIdScreen( submitChipId = submitChipId, focusManager = focusManager, showedSnackBar = showedSnackBar, - updateText = updateText + updateText = updateText, ) } } @@ -163,7 +160,7 @@ private fun ColumnScope.AddChipIdContent( submitChipId: () -> Unit, focusManager: FocusManager, showedSnackBar: () -> Unit, - updateText: (String) -> Unit + updateText: (String) -> Unit, ) { val successMessage = stringResource(Res.string.CONTACT_INFO_CHANGES_SAVED) LaunchedEffect(uiState.showSuccessSnackBar) { @@ -175,15 +172,17 @@ private fun ColumnScope.AddChipIdContent( Spacer(Modifier.weight(1f)) Spacer(Modifier.height(16.dp)) - InsuranceInfoCard(uiState.contract, - modifier = Modifier.padding(horizontal = 16.dp)) + InsuranceInfoCard( + uiState.contract, + modifier = Modifier.padding(horizontal = 16.dp), + ) Spacer(Modifier.height(16.dp)) ChipIdTextField( text = uiState.chipIdText, labelText = stringResource(Res.string.CHIP_ID_LABEL), - updateText = updateText + updateText = updateText, - ) + ) AnimatedContent( targetState = uiState.errorType, @@ -225,10 +224,10 @@ private fun ColumnScope.AddChipIdContent( private fun ChipIdTextField( text: String, labelText: String, - updateText: (String) -> Unit + updateText: (String) -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } - var input by remember { mutableStateOf(text ?: "") } + var input by remember { mutableStateOf(text) } val mask = "000-000-000-000-000" val maskColor = HedvigTheme.colorScheme.textTertiary val visualTransformation = ChipIdVisualTransformation(mask, maskColor) @@ -237,7 +236,7 @@ private fun ChipIdTextField( labelText = labelText, errorState = HedvigTextFieldDefaults.ErrorState.NoError, onValueChange = { - if(it.length<=15) { + if (it.length <= 15) { updateText(it) input = it } @@ -265,7 +264,7 @@ private class ChipIdVisualTransformation( val annotatedString = buildAnnotatedString { for (i in trimmed.indices) { append(trimmed[i]) - if (i in listOf(2,5,8,11)) { + if (i in listOf(2, 5, 8, 11)) { append("-") } } @@ -277,9 +276,9 @@ private class ChipIdVisualTransformation( val personalNumberOffsetTranslator = object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { return when { - offset <= 2 -> offset - offset <= 5 -> offset + 1 - offset <= 8 -> offset + 2 + offset <= 2 -> offset + offset <= 5 -> offset + 1 + offset <= 8 -> offset + 2 offset <= 11 -> offset + 3 offset <= 15 -> offset + 4 else -> 19 @@ -288,8 +287,8 @@ private class ChipIdVisualTransformation( override fun transformedToOriginal(offset: Int): Int { return when { - offset <= 3 -> offset - offset <= 7 -> offset - 1 + offset <= 3 -> offset + offset <= 7 -> offset - 1 offset <= 11 -> offset - 2 offset <= 15 -> offset - 3 else -> offset - 4 @@ -306,13 +305,15 @@ private fun InsuranceInfoCard( insuranceInfo: PetContractForChipId, modifier: Modifier = Modifier, ) { - HedvigCard(modifier - .border( - width = 1.dp, - color = HedvigTheme.colorScheme.borderPrimary, - shape = HedvigTheme.shapes.cornerXLarge, - ), - color = HedvigTheme.colorScheme.backgroundPrimary) { + HedvigCard( + modifier + .border( + width = 1.dp, + color = HedvigTheme.colorScheme.borderPrimary, + shape = HedvigTheme.shapes.cornerXLarge, + ), + color = HedvigTheme.colorScheme.backgroundPrimary, + ) { Column(Modifier.padding(16.dp)) { Row { Image( @@ -333,25 +334,25 @@ private fun InsuranceInfoCard( @HedvigPreview @Composable private fun PreviewTerminationConfirmationScreen( - @PreviewParameter(AddChipIdScreenStateProvider ::class) state: AddChipIdUiState, + @PreviewParameter(AddChipIdScreenStateProvider::class) state: AddChipIdUiState, ) { HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { AddChipIdScreen( state, globalSnackBarState = GlobalSnackBarState(), - submitChipId = { }, - reload = { }, - navigateUp = { }, + submitChipId = { }, + reload = { }, + navigateUp = { }, showedSnackBar = {}, - {} + {}, ) } } } -private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< AddChipIdUiState>( +private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider( listOf( AddChipIdUiState.Error, AddChipIdUiState.Loading, @@ -361,45 +362,45 @@ private class AddChipIdScreenStateProvider : CollectionPreviewParameterProvider< id = "sdf", displayName = "Display name", contractExposure = "Kitty", - contractGroup = ContractGroup.CAT + contractGroup = ContractGroup.CAT, ), showSuccessSnackBar = false, submittingData = false, ), Content( - chipIdText = "123456789012345", + chipIdText = "123456789012345", contract = PetContractForChipId( id = "sdf", displayName = "Display name", contractExposure = "Kitty", - contractGroup = ContractGroup.CAT + contractGroup = ContractGroup.CAT, ), showSuccessSnackBar = false, submittingData = false, ), Content( - chipIdText = "", + chipIdText = "", contract = PetContractForChipId( id = "sdf", displayName = "Display name", contractExposure = "Kitty", - contractGroup = ContractGroup.CAT + contractGroup = ContractGroup.CAT, ), showSuccessSnackBar = false, submittingData = false, - errorType = ChipIdErrorType.WrongInput + errorType = ChipIdErrorType.WrongInput, ), Content( - chipIdText = "", + chipIdText = "", contract = PetContractForChipId( id = "sdf", displayName = "Display name", contractExposure = "Kitty", - contractGroup = ContractGroup.CAT + contractGroup = ContractGroup.CAT, ), showSuccessSnackBar = false, submittingData = false, - errorType = ChipIdErrorType.GeneralError + errorType = ChipIdErrorType.GeneralError, ), ), ) From 6debaada2e224f180f1c05943c969c53d92351ed Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 14:51:24 +0200 Subject: [PATCH 23/42] ktlint --- .../com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 7d71c6a727..b6c1a46671 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -1,6 +1,5 @@ package com.hedvig.android.feature.chip.id.ui -import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue From 785f783cc7fe8fc3649584c841befcba3fe91f14 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 14:54:41 +0200 Subject: [PATCH 24/42] rename to GetContractsWithMissingChipIdUseCase --- ...e.kt => GetContractsWithMissingChipIdUseCase.kt} | 6 +++--- .../android/feature/chip/id/di/ChipIdModule.kt | 12 ++++++------ .../feature/chip/id/ui/AddChipIdViewModel.kt | 10 +++++----- .../SelectInsuranceForChipIdViewModel.kt | 13 ++++++------- 4 files changed, 20 insertions(+), 21 deletions(-) rename app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/{GetPetContractsForChipIdUseCase.kt => GetContractsWithMissingChipIdUseCase.kt} (90%) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt similarity index 90% rename from app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt rename to app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt index 5c09c1863f..1713cfaf5d 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetPetContractsForChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt @@ -10,13 +10,13 @@ import com.hedvig.android.data.contract.toContractGroup import com.hedvig.android.logger.logcat import octopus.GetPetContractsForChipIdQuery -internal interface GetPetContractsForChipIdUseCase { +internal interface GetContractsWithMissingChipIdUseCase { suspend fun invoke(): Either> } -internal class GetPetContractsForChipIdUseCaseImpl( +internal class GetContractsWithMissingChipIdUseCaseImpl( private val apolloClient: ApolloClient, -) : GetPetContractsForChipIdUseCase { +) : GetContractsWithMissingChipIdUseCase { override suspend fun invoke(): Either> { return apolloClient .query(GetPetContractsForChipIdQuery()) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt index c6a3c2c346..0e05ad40f4 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/di/ChipIdModule.kt @@ -1,8 +1,8 @@ package com.hedvig.android.feature.chip.id.di import com.apollographql.apollo.ApolloClient -import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase -import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCaseImpl +import com.hedvig.android.feature.chip.id.data.GetContractsWithMissingChipIdUseCase +import com.hedvig.android.feature.chip.id.data.GetContractsWithMissingChipIdUseCaseImpl import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCaseImpl import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel @@ -17,8 +17,8 @@ val chipIdModule = module { ) } - single { - GetPetContractsForChipIdUseCaseImpl( + single { + GetContractsWithMissingChipIdUseCaseImpl( apolloClient = get(), ) } @@ -26,7 +26,7 @@ val chipIdModule = module { viewModel { params -> SelectInsuranceForChipIdViewModel( preselectedContractId = params.getOrNull(), - getPetContractsForChipIdUseCase = get(), + getContractsWithMissingChipIdUseCase = get(), ) } @@ -34,7 +34,7 @@ val chipIdModule = module { AddChipIdViewModel( updateChipIdUseCase = get(), contractId = params.get(), - getPetContractsForChipIdUseCase = get(), + getContractsWithMissingChipIdUseCase = get(), ) } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index b6c1a46671..6279b7a3fa 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -8,7 +8,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.Snapshot -import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase +import com.hedvig.android.feature.chip.id.data.GetContractsWithMissingChipIdUseCase import com.hedvig.android.feature.chip.id.data.PetContractForChipId import com.hedvig.android.feature.chip.id.data.UpdateChipIdUseCase import com.hedvig.android.molecule.public.MoleculePresenter @@ -17,20 +17,20 @@ import com.hedvig.android.molecule.public.MoleculeViewModel internal class AddChipIdViewModel( updateChipIdUseCase: UpdateChipIdUseCase, - getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, + getContractsWithMissingChipIdUseCase: GetContractsWithMissingChipIdUseCase, contractId: String, ) : MoleculeViewModel( initialState = AddChipIdUiState.Loading, presenter = AddChipIdPresenter( updateChipIdUseCase = updateChipIdUseCase, contractId = contractId, - getPetContractsForChipIdUseCase = getPetContractsForChipIdUseCase, + getContractsWithMissingChipIdUseCase = getContractsWithMissingChipIdUseCase, ), ) internal class AddChipIdPresenter( private val updateChipIdUseCase: UpdateChipIdUseCase, - private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, + private val getContractsWithMissingChipIdUseCase: GetContractsWithMissingChipIdUseCase, private val contractId: String, ) : MoleculePresenter { @Composable @@ -52,7 +52,7 @@ internal class AddChipIdPresenter( } LaunchedEffect(loadIteration) { - getPetContractsForChipIdUseCase.invoke().fold( + getContractsWithMissingChipIdUseCase.invoke().fold( ifLeft = { currentState = AddChipIdUiState.Error }, diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt index e310f1efb6..0877a05ffc 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdViewModel.kt @@ -7,24 +7,23 @@ import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshots.Snapshot -import com.hedvig.android.feature.chip.id.data.GetPetContractsForChipIdUseCase +import com.hedvig.android.feature.chip.id.data.GetContractsWithMissingChipIdUseCase import com.hedvig.android.feature.chip.id.data.PetContractForChipId import com.hedvig.android.molecule.public.MoleculePresenter import com.hedvig.android.molecule.public.MoleculePresenterScope import com.hedvig.android.molecule.public.MoleculeViewModel internal class SelectInsuranceForChipIdViewModel( - private val preselectedContractId: String?, - private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, + preselectedContractId: String?, + getContractsWithMissingChipIdUseCase: GetContractsWithMissingChipIdUseCase, ) : MoleculeViewModel( initialState = SelectInsuranceForChipIdState.Loading, - presenter = SelectInsuranceForChipIdPresenter(preselectedContractId, getPetContractsForChipIdUseCase), + presenter = SelectInsuranceForChipIdPresenter(preselectedContractId, getContractsWithMissingChipIdUseCase), ) internal class SelectInsuranceForChipIdPresenter( private val preselectedContractId: String?, - private val getPetContractsForChipIdUseCase: GetPetContractsForChipIdUseCase, + private val getContractsWithMissingChipIdUseCase: GetContractsWithMissingChipIdUseCase, ) : MoleculePresenter { @Composable override fun MoleculePresenterScope.present( @@ -40,7 +39,7 @@ internal class SelectInsuranceForChipIdPresenter( LaunchedEffect(loadIteration) { currentState = SelectInsuranceForChipIdState.Loading - val result = getPetContractsForChipIdUseCase.invoke() + val result = getContractsWithMissingChipIdUseCase.invoke() currentState = result.fold( ifLeft = { SelectInsuranceForChipIdState.Failure }, ifRight = { contracts -> From c3216733ea1b1582e7ffc88e996287ef44c5b6e3 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 31 Mar 2026 15:00:02 +0200 Subject: [PATCH 25/42] error with message --- .../hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt | 1 + .../hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt index b1056f609f..a23ddeb4c5 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdScreen.kt @@ -193,6 +193,7 @@ private fun ColumnScope.AddChipIdContent( val errorMessage = when (errorType) { ChipIdErrorType.WrongInput -> stringResource(Res.string.CHIP_ID_WRONG_INPUT) ChipIdErrorType.GeneralError -> stringResource(Res.string.something_went_wrong) + is ChipIdErrorType.ErrorWithMessage -> errorType.message } HedvigNotificationCard( message = errorMessage, diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt index 6279b7a3fa..c1b7351d85 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/AddChipIdViewModel.kt @@ -79,8 +79,10 @@ internal class AddChipIdPresenter( updateChipIdUseCase.invoke(insuranceId = contractId, petId = chipIdText).fold( ifLeft = { error -> Snapshot.withMutableSnapshot { + val errorMessage = error.message submittingData = false - errorType = ChipIdErrorType.GeneralError + errorType = if (errorMessage==null) ChipIdErrorType.GeneralError + else ChipIdErrorType.ErrorWithMessage(errorMessage) } }, ifRight = { @@ -154,6 +156,8 @@ internal sealed interface ChipIdErrorType { data object WrongInput : ChipIdErrorType data object GeneralError : ChipIdErrorType + + data class ErrorWithMessage(val message: String) : ChipIdErrorType } internal sealed interface AddChipIdEvent { From 20da46b3b6c8f9d6f64e27f5fac9d7dd919df89c Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Thu, 2 Apr 2026 10:16:00 +0200 Subject: [PATCH 26/42] update renamed schema --- .../android/apollo/octopus/schema.graphqls | 29 +++++-------------- .../GetPetContractsForChipIdQuery.graphql | 2 +- .../GetContractsWithMissingChipIdUseCase.kt | 2 +- .../graphql/QueryInsuranceContracts.graphql | 2 +- .../data/GetInsuranceContractsUseCase.kt | 2 +- .../QueryMissingChipIdReminder.graphql | 2 +- .../GetMissingChipIdReminderUseCase.kt | 2 +- 7 files changed, 14 insertions(+), 27 deletions(-) diff --git a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls index 8f16d8b8c4..fbf7f09b1a 100644 --- a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls +++ b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls @@ -1310,7 +1310,7 @@ type Contract { """ Checks if petId is missing on the current or upcoming agreement. """ - missingPetId: Boolean! + isMissingPetId: Boolean! """ User messages to show due to self change is blocked. """ @@ -2435,7 +2435,7 @@ type Member { """ Get contract info during termination flow. Null if no message to display. """ - terminationFlowNotification(input: TerminationFlowNotificationInput!): FlowTerminationNotification + terminationFlowNotification(input: TerminationFlowNotificationInput!): FlowTerminationNotification @deprecated(reason: "Use Query.Member.terminationNotification instead") """ Current bundle discount information for this member's non terminated contracts (active, future or pending). Returns null for members that have a contract configuration that don't enable bundle discount. @@ -3380,11 +3380,11 @@ type Mutation { flowClaimSingleItemNext(input: FlowClaimSingleItemInput!, context: FlowContext!): Flow! flowClaimSummaryNext(input: FlowClaimSummaryInput!, context: FlowContext!): Flow! flowClaimSingleItemCheckoutNext(input: FlowClaimSingleItemCheckoutInput!, context: FlowContext!): Flow! - flowTerminationStart(input: FlowTerminationStartInput!, context: FlowContext): Flow! - flowTerminationDateNext(input: FlowTerminationDateInput!, context: FlowContext!): Flow! - flowTerminationDeletionNext(input: FlowTerminationDeletionInput, context: FlowContext!): Flow! - flowTerminationSurveyNext(input: FlowTerminationSurveyInput!, context: FlowContext!): Flow! - flowTerminationCarAutoDecomNext(input: FlowTerminationCarAutoDecomInput!, context: FlowContext!): Flow! + flowTerminationStart(input: FlowTerminationStartInput!, context: FlowContext): Flow! @deprecated(reason: "Use Query.terminationSurvey instead") + flowTerminationDateNext(input: FlowTerminationDateInput!, context: FlowContext!): Flow! @deprecated(reason: "Use Query.terminationSurvey instead") + flowTerminationDeletionNext(input: FlowTerminationDeletionInput, context: FlowContext!): Flow! @deprecated(reason: "Use Query.terminationSurvey instead") + flowTerminationSurveyNext(input: FlowTerminationSurveyInput!, context: FlowContext!): Flow! @deprecated(reason: "Use Query.terminationSurvey instead") + flowTerminationCarAutoDecomNext(input: FlowTerminationCarAutoDecomInput!, context: FlowContext!): Flow! @deprecated(reason: "Use Query.terminationSurvey instead") travelCertificateCreate(input: TravelCertificateCreateInput!): TravelCertificate! """ The document includes details of the member’s home insurance, @@ -3438,11 +3438,6 @@ type Mutation { """ priceIntentConfirm(priceIntentId: UUID!): PriceIntentMutationOutput! """ - Apply the customer's registered address (from SPAR lookup) directly into the price intent data - server-side, so the real address value never needs to be sent to the client. - """ - priceIntentApplySuggestedAddress(priceIntentId: UUID!): PriceIntentMutationOutput! - """ Change the start date of the given `ProductOffer`s by their ID. This is used because it's common to want to change the start date AFTER getting the offer. """ @@ -3653,10 +3648,6 @@ type PriceIntent { """ suggestedData: PricingFormData! """ - Masked display values of the customer's registered address. Null when no suggested address is available. - """ - suggestedAddressDisplay: SuggestedAddressDisplay - """ The resulting product offers generated by inputting data and confirming the intent. """ offers: [ProductOffer!]! @@ -4128,7 +4119,7 @@ type Query { Cost for selected configuration of removed addon offer """ addonRemoveOfferCost(contractId: ID!, addonIds: [ID!]!): ItemCost! - terminationSurvey(contractId: ID!): TerminationFlowSurvey! + terminationSurvey(contractId: UUID!): TerminationFlowSurvey! """ Call this to get the cost of an addon offer for selected addon(s). """ @@ -4479,10 +4470,6 @@ type StoryblokImageAsset { src: String! alt: String } -type SuggestedAddressDisplay { - maskedStreet: String - maskedZipCode: String -} """ Represents a case of switching, pointing towards a soon-to-be insurance Contract on our platform. If it is not completed, it can be by calling `Mutation.switcherCaseComplete`. diff --git a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql index 1c192bb7e5..b5a11ac9e6 100644 --- a/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql +++ b/app/feature/feature-chip-id/src/main/graphql/GetPetContractsForChipIdQuery.graphql @@ -3,7 +3,7 @@ query GetPetContractsForChipId { activeContracts { id exposureDisplayNameShort - missingPetId + isMissingPetId currentAgreement { productVariant { typeOfContract diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt index 1713cfaf5d..d92e35de04 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/GetContractsWithMissingChipIdUseCase.kt @@ -25,7 +25,7 @@ internal class GetContractsWithMissingChipIdUseCaseImpl( .map { data -> data.currentMember.activeContracts .mapNotNull { contract -> - if (contract.missingPetId) { + if (contract.isMissingPetId) { PetContractForChipId( id = contract.id, displayName = contract.currentAgreement.productVariant.displayName, diff --git a/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql b/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql index 27af10ec61..0c78b2ce17 100644 --- a/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql +++ b/app/feature/feature-insurances/src/main/graphql/QueryInsuranceContracts.graphql @@ -82,7 +82,7 @@ fragment ContractFragment on Contract { displayName description } - missingPetId + isMissingPetId } fragment AgreementFragment on Agreement { diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt index d2da3de07c..132e1d3a08 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/data/GetInsuranceContractsUseCase.kt @@ -230,7 +230,7 @@ private fun ContractFragment.toContract( description = it.description, ) }.orEmpty(), - chipId = when (missingPetId) { + chipId = when (isMissingPetId) { true -> ChipIdState.Missing false -> ChipIdState.NotRequired }, diff --git a/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql b/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql index 2b3807d7d2..0364a2a9f8 100644 --- a/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql +++ b/app/member-reminders/member-reminders-public/src/main/graphql/QueryMissingChipIdReminder.graphql @@ -1,7 +1,7 @@ query MissingChipIdReminder { currentMember { activeContracts { - missingPetId + isMissingPetId } } } diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt index 57476d6ee5..0e037df7c5 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMissingChipIdReminderUseCase.kt @@ -29,7 +29,7 @@ internal class GetMissingChipIdReminderUseCaseImpl( .bind() .currentMember .activeContracts - .firstOrNull { it.missingPetId } + .firstOrNull { it.isMissingPetId } ?.let { MemberReminder.MissingChipId() } } } From f38d317ea7e87d4da08f88761ce9fcc365ff1ea1 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Thu, 2 Apr 2026 15:43:50 +0200 Subject: [PATCH 27/42] adjust to schema changes --- .../android/apollo/octopus/schema.graphqls | 244 +++++++++++++++++- .../main/graphql/UpdateChipIdMutation.graphql | 10 +- .../chip/id/data/UpdateChipIdUseCase.kt | 10 +- 3 files changed, 254 insertions(+), 10 deletions(-) diff --git a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls index fbf7f09b1a..3d9b04ddd8 100644 --- a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls +++ b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls @@ -2409,6 +2409,7 @@ type Member { Payment information for this member. """ paymentInformation: MemberPaymentInformation! + paymentMethods: MemberPaymentMethods! conversations: [Conversation!]! legacyConversation: Conversation """ @@ -2710,6 +2711,20 @@ type MemberMutationOutput { member: Member userError: UserError } +type MemberPaymentAvailablePaymentMethod { + """ + Payment provider, eg Trustly, Swish, Nordea, Kivra etc. + """ + provider: MemberPaymentProvider! + """ + True if the member can set up this payment method for payin. + """ + supportsPayin: Boolean! + """ + True if the member can set up this payment method for payout. + """ + supportsPayout: Boolean! +} type MemberPaymentChargeMethodInfo { """ An abstract display name of the connection - usually like the name of the bank you are connected to. @@ -2779,6 +2794,73 @@ type MemberPaymentInformation { """ chargeMethod: MemberPaymentChargeMethodInfo } +type MemberPaymentMethod { + """ + The unique id of the payment method. This id is used for switching default and revoking payment methods. + """ + id: ID! + """ + Payment provider, eg Trustly, Swish, Nordea, Kivra etc. + """ + provider: MemberPaymentProvider! + """ + The payment method status - ACTIVE, PENDING, or PENDING_DEFAULT. + PENDING_DEFAULT means the payment method is awaiting activation and will become default once activated. + """ + status: MemberPaymentMethodStatus! + """ + True if this is the default payment method. Only one ACTIVE payment method can be default at a time. + If status is PENDING then payment method will become the default once activated. + """ + isDefault: Boolean! + """ + Specific details of the actual connection - e.g. a bank account reference, phone number for swish, + or email/kivra for invoice. + """ + details: PaymentMethodDetails! +} +type MemberPaymentMethods { + """ + List of active and pending payment payin methods for this member. + """ + payinMethods: [MemberPaymentMethod!]! + """ + List of active and pending payment payout methods for this member. + """ + payoutMethods: [MemberPaymentMethod!]! + """ + The default payment method for payin if any. + """ + defaultPayinMethod: MemberPaymentMethod + """ + The default payment method for payout if any. + """ + defaultPayoutMethod: MemberPaymentMethod + """ + The available payment methods that the member can choose from when setting up a new payment method. + """ + availableMethods: [MemberPaymentAvailablePaymentMethod!]! + """ + The date of the month when member's premium will be charged (or due if invoice) + """ + chargingDay: Int +} +enum MemberPaymentMethodStatus { + """ + The payment connection is active and can be used for payins or payouts. + """ + ACTIVE + """ + The payment connection has been partially set up but is awaiting activation. + """ + PENDING +} +enum MemberPaymentProvider { + TRUSTLY + SWISH + NORDEA + INVOICE +} type MemberReferral { """ The name of this referral. This reflects the name of the member created through the referral. @@ -2895,10 +2977,13 @@ enum MidtermChangeIntentState { INITIATED COMPLETED } -type MidtermChangePetIdOutput { - activationDate: Date - userError: UserError +type MidtermChangePetIdActivationDate { + """ + Activation date of the MTA agreement. + """ + activationDate: Date! } +union MidtermChangePetIdOutput = MidtermChangePetIdActivationDate|UserError type MidtermChangePriceDetailItem { displayName: String! displayValue: String! @@ -3299,6 +3384,34 @@ input MoveToHouseInput { } type Mutation { registerDirectDebit2(clientContext: RegisterDirectDebitClientContext2): DirectDebitResponse2! + """ + Setup invoice payment method for the member. Kivra will be used as the provider if supported, else mail. + """ + paymentMethodSetupInvoicePayin(input: PaymentMethodSetupInvoicePayinInput!): PaymentMethodSetupOutput! + """ + Setup Trustly payment payin and payout method for the member. + """ + paymentMethodSetupTrustly(input: PaymentMethodSetupTrustlyInput!): PaymentMethodSetupOutput! + """ + Setup direct bank payout method for the member. + """ + paymentMethodSetupNordeaPayout(input: PaymentMethodSetupNordeaPayoutInput!): PaymentMethodSetupOutput! + """ + Setup Swish payout method for the member. + """ + paymentMethodSetupSwishPayout(input: PaymentMethodSetupSwishInput!): PaymentMethodSetupOutput! + """ + Setup Swish payin method for the member. + """ + paymentMethodSetupSwishPayin(input: PaymentMethodSetupSwishInput!): PaymentMethodSetupOutput! + """ + Revoke an active payment method. The member will be required to set up a new payment method if they revoke their default one. + """ + paymentMethodRevoke(id: ID!): UserError + """ + Set an active payment method as default. + """ + paymentMethodSetDefault(id: ID!): UserError """ Start a conversation. This is effectively creating one, but with two slight differences from a regular "create something"-mutation: @@ -3450,6 +3563,14 @@ type Mutation { """ productOfferAddonsSelect(productOfferId: UUID!, addonIds: [UUID!]!): ProductOffersMutationOutput! """ + Reprice an existing product offer with updated data. Merges the provided data with the offer's + existing `priceIntentData`, creates a new underwriter quote matching the original variant, + and replaces the offer. + Useful for recommendation offers that don't have a `priceIntentId` and therefore can't use the + normal `priceIntentDataUpdate` + `priceIntentConfirm` flow. + """ + productOfferReprice(offerId: UUID!, data: PricingFormData!): ProductOffersMutationOutput! + """ Update the customer of the shop session. Only non-null fields will be changed. Can trigger automatic lookup of other information. The session can be placed in a "point of no return" state where it is no longer legal to update the customer, @@ -3524,7 +3645,7 @@ type Mutation { """ Called to change the Pet-Id of a cat/dog contract. Creates a midterm change without price change and commits it. """ - midtermChangePetId(contractId: ID!, petId: String!): MidtermChangePetIdOutput + midtermChangePetId(contractId: ID!, petId: String!): MidtermChangePetIdOutput! """ Call this to confirm removal of selected addon(s). """ @@ -3556,6 +3677,113 @@ type PartnerData { type PartnerWidgetTrial { trialContract: TrialContract! } +type PaymentMethodBankAccountDetails { + """ + The bank account reference - e.g. clearing number and account number. + """ + account: String! + """ + The name of the bank - e.g. Nordea, SEB, Handelsbanken. + """ + bank: String! +} +union PaymentMethodDetails = PaymentMethodInvoiceDetails|PaymentMethodSwishDetails|PaymentMethodBankAccountDetails +enum PaymentMethodInvoiceDelivery { + KIVRA + MAIL +} +type PaymentMethodInvoiceDetails { + """ + How email is delivered - e.g. Kivra or mail. + """ + delivery: PaymentMethodInvoiceDelivery! + """ + The email address where the invoice is sent in case delivery is set to MAIL. + """ + email: String +} +input PaymentMethodSetupInvoicePayinInput { + """ + Set up invoice payment method as default. + """ + setAsDefaultPayout: Boolean! +} +input PaymentMethodSetupNordeaPayoutInput { + """ + Set up Nordea payout method as default. + """ + setAsDefault: Boolean! + """ + The clearing number for member's bank account. + """ + clearingNumber: String! + """ + The account number for member's bank account. + """ + accountNumber: String! +} +type PaymentMethodSetupOutput { + """ + The status of the setup process. If FAILED the reason for failure can be found in the `error` field. + """ + status: PaymentMethodSetupStatus! + """ + Url to redirect the member to if any. + """ + url: String + """ + An error message. Only sat if the setup process failed. + """ + error: UserError +} +enum PaymentMethodSetupStatus { + """ + The payment method setup process is completed and the payment method is ready to use. + """ + ACTIVE + """ + The payment method setup process is still ongoing. + """ + PENDING + """ + The payment method setup process has failed. + """ + FAILED +} +input PaymentMethodSetupSwishInput { + """ + Set up Swish payment method as default. + """ + setAsDefault: Boolean! + """ + The Swish mobile number to use for payout or payin. + """ + phoneNumber: String! +} +input PaymentMethodSetupTrustlyInput { + """ + Set up Trustly payment method as default for payin. + """ + setAsDefaultPayin: Boolean! + """ + Set up Trustly payment method as default for payout. + """ + setAsDefaultPayout: Boolean! + """ + The URL to redirect the member back to after a successful setup after Trustly onboarding. + """ + successUrl: String! + """ + The URL to redirect the member back to after a failed setup after Trustly onboarding. + """ + failureUrl: String! +} +type PaymentMethodSwishDetails { + """ + The Swish phone number. + """ + phoneNumber: String! +} """ A pending contract is a proto-contract that has yet to become a fully fledged insurance. It usually means it is meant to be activated when an existing external insurance has been cancelled (switching). @@ -3979,6 +4207,14 @@ type ProductOfferPriceMatch { externalPrice: Money! externalInsurer: ExternalInsurer! priceReduction: Money! + """ + Renewal date of the external insurer's policy. Null when not provided by the external insurer. + """ + renewalDate: Date + """ + External insurer's product name/coverage label. + """ + externalInsuranceName: String } type ProductOffersMutationOutput { productOffers: [ProductOffer!]! diff --git a/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql b/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql index e00b92f6de..c6fc4fa901 100644 --- a/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql +++ b/app/feature/feature-chip-id/src/main/graphql/UpdateChipIdMutation.graphql @@ -1,8 +1,12 @@ mutation UpdateChipIdNumber($petId: String!, $contractId: ID!) { midtermChangePetId(petId: $petId, contractId: $contractId) { - userError { - message + ...on MidtermChangePetIdOutput { + ... on MidtermChangePetIdActivationDate { + activationDate + } + ... on UserError { + message + } } - activationDate } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt index 462a6e05bc..f826e30f3c 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt @@ -10,6 +10,8 @@ import com.hedvig.android.apollo.safeExecute import com.hedvig.android.core.common.ErrorMessage import com.hedvig.android.logger.logcat import octopus.UpdateChipIdNumberMutation +import octopus.UpdateChipIdNumberMutation.Data.MidtermChangePetId.Companion.asMidtermChangePetIdActivationDate +import octopus.UpdateChipIdNumberMutation.Data.MidtermChangePetId.Companion.asUserError internal interface UpdateChipIdUseCase { suspend fun invoke(petId: String, insuranceId: String): Either @@ -29,15 +31,17 @@ internal class UpdateChipIdUseCaseImpl( ) .safeExecute { logcat { "UpdateChipIdNumberMutation error: $it" } - ErrorMessage() + raise(ErrorMessage()) } .bind() - val userError = result.midtermChangePetId?.userError + val userError = result.midtermChangePetId.asUserError() if (userError != null) { raise(ErrorMessage(userError.message)) } - if (result.midtermChangePetId?.activationDate != null) { + val date = result.midtermChangePetId.asMidtermChangePetIdActivationDate()?.activationDate + if (date != null) { + logcat { "UpdateChipIdNumberMutation success with activationDate: $date" } Unit } else { raise(ErrorMessage()) From 1f893c7c56f61e080d1b51ae97927a46252e5c09 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Thu, 2 Apr 2026 15:53:39 +0200 Subject: [PATCH 28/42] don't need raise --- .../hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt index f826e30f3c..5fd2dbbe1e 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/data/UpdateChipIdUseCase.kt @@ -31,7 +31,7 @@ internal class UpdateChipIdUseCaseImpl( ) .safeExecute { logcat { "UpdateChipIdNumberMutation error: $it" } - raise(ErrorMessage()) + ErrorMessage() } .bind() From e3a3b95088f7b682b0d3bbe398c2ea8b106c8fa9 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Tue, 7 Apr 2026 11:24:06 +0200 Subject: [PATCH 29/42] strings --- .../androidMain/res/values-sv-rSE/strings.xml | 19 +++++++++++-------- .../src/androidMain/res/values/strings.xml | 19 +++++++++++-------- .../values-sv-rSE/strings.xml | 19 +++++++++++-------- .../composeResources/values/strings.xml | 19 +++++++++++-------- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml index 2c59853791..6363f601ee 100644 --- a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml @@ -168,11 +168,11 @@ Meddelanden Skicka Checkout - Chip-ID - Lägg till Chip-ID - Chip-ID för ditt husdjur saknas - Uppdatera husdjurets chip-ID - Måste vara 15 siffror + Djur-ID (15 siffror) + Lägg till djur-ID + Lägg till ditt husdjurs ID för bättre hjälp + Lägg till djur-ID + Ange ett djur-ID med 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. Aktivera Ärende @@ -848,9 +848,11 @@ Säg upp försäkring Välj slutdatum Vi skickar en bekräftelse på uppsägningen inom några dagar. Hör gärna av dig om du inte fått den efter 5 dagar. - Eftersom din bil har avställts kommer din försäkring att sägas upp automatiskt. + Om du har ställt av din bil säger vi upp din försäkring automatiskt. Vi får informationen direkt från Transportstyrelsen. + När du har ställt på bilen hos Transportstyrelsen uppdateras din försäkring automatiskt till ditt tidigare skydd. + Om du har skrotat din bil säger vi upp din försäkring automatiskt. Vi får informationen direkt från Transportstyrelsen. Eftersom din bil har skrotats kommer din försäkring att sägas upp automatiskt. - Eftersom du har sålt din bil kommer din försäkring att sägas upp automatiskt. + Om du har sålt din bil säger vi upp din försäkring automatiskt. Vi får informationen direkt från Transportstyrelsen. Vi avslutar din försäkring automatiskt Du kommer att få ett bekräftelsemail på din avställningsförsäkring inom några dagar, där du kommer att se ditt nya pris. Vad kostar det @@ -859,11 +861,11 @@ Om du har ställt av din bil via Transportstyrelsen kommer din försäkring automatiskt övergå till en avställningsförsäkring. Vill du inte behålla din avställningsförsäkring kan du enkelt säga upp den nedan. Din försäkring kommer övergå till en avställningsförsäkring + Vi uppdaterar din försäkring automatiskt Säg upp försäkring Du kan närsomhelst avsluta din försäkring. Avslutar du din försäkring kommer du endast att debiteras för den tid du varit aktiv medlem hos Hedvig. När du avslutat din försäkring kan du se din sista betalning under fliken \"Betalningar\" här i appen. Avsluta din försäkring Avsluta försäkring - Eftersom din bil är påställd igen kommer din försäkring automatiskt att ändras tillbaka till ditt ordinarie skydd. Din bil är tillbaka på vägen Observera att du bara kan säga upp en försäkring åt gången Välj den försäkring du vill säga upp @@ -878,6 +880,7 @@ Om det blir ett uppehåll i din försäkring, kan det innebära att du inte får den hjälp eller ersättning du behöver i framtiden. Se därför till att alltid ha en aktiv försäkring. Viktig information Jag förstår + Läs mer Nästa betalning Skicka ett meddelande här i appen så hjälper vi dig. Skicka meddelande diff --git a/app/core/core-resources/src/androidMain/res/values/strings.xml b/app/core/core-resources/src/androidMain/res/values/strings.xml index 7428a9b828..a858e2afd9 100644 --- a/app/core/core-resources/src/androidMain/res/values/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values/strings.xml @@ -168,11 +168,11 @@ Messages Send Checkout - Chip-ID - Add Chip-ID - Chip ID for your pet is missing - Update pet Chip-ID - Must be 15 digits + Pet ID (15 digits) + Add pet ID + Add your pet’s ID for better support + Add pet ID + Enter a 15-digit pet ID Don’t miss out on important information for your claim Enable notifications Case @@ -848,9 +848,11 @@ Cancel insurance Select termination date We’ll send a cancellation confirmation within a few days. If you don’t get it after 5 days, feel free to contact us. - Since your car has been decommissioned, your insurance will be automatically cancelled. + If you’ve decommissioned your car, we’ll cancel your insurance automatically. We get this information directly from Transportstyrelsen. + Once your car is registered as active with Transportstyrelsen, your insurance will be updated automatically to your previous coverage. + If you’ve scrapped your car, we’ll cancel your insurance automatically. We get this information directly from Transportstyrelsen. Since your car has been scrapped, your insurance will be automatically cancelled. - Since you\'ve sold your car, your insurance will be automatically cancelled. + If you’ve sold your car, we’ll cancel your insurance automatically. We receive this information directly from Transportstyrelsen. We’ll cancel your insurance automatically You’ll receive a confirmation email within a few days, where you can see your new price. What it costs @@ -859,11 +861,11 @@ If you’ve decommissioned your car through Transportstyrelsen, your insurance will automatically switch to decommission insurance. If you don’t want to keep your decommission insurance, you can cancel it below. Your insurance will switch to decommission insurance + We’ll update your insurance automatically Cancel insurance You can cancel your insurance at any time. You will only be charged for the time you have been an active member. When the insurance is cancelled you can see your last payment under the tab \"Payments\" here in the app. Cancelling your insurance Cancel insurance - Since your car is registered again, your insurance will automatically switch back to your regular coverage. Your car is back on the road Please note that you can only cancel one insurance at a time Select the insurance you want to cancel @@ -878,6 +880,7 @@ If there is a gap in your insurance, you may not receive future help or compensation. Make sure that you always have an active insurance. Important information I understand + Learn more Next payment You need our help to cancel your insurance. Send us a message to get further help. Send message diff --git a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml index ce0d6791fa..6eee33cf55 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml @@ -168,11 +168,11 @@ Meddelanden Skicka Checkout - Chip-ID - Lägg till Chip-ID - Chip-ID för ditt husdjur saknas - Uppdatera husdjurets chip-ID - Måste vara 15 siffror + Djur-ID (15 siffror) + Lägg till djur-ID + Lägg till ditt husdjurs ID för bättre hjälp + Lägg till djur-ID + Ange ett djur-ID med 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. Aktivera Ärende @@ -848,9 +848,11 @@ Säg upp försäkring Välj slutdatum Vi skickar en bekräftelse på uppsägningen inom några dagar. Hör gärna av dig om du inte fått den efter 5 dagar. - Eftersom din bil har avställts kommer din försäkring att sägas upp automatiskt. + Om du har ställt av din bil säger vi upp din försäkring automatiskt. Vi får informationen direkt från Transportstyrelsen. + När du har ställt på bilen hos Transportstyrelsen uppdateras din försäkring automatiskt till ditt tidigare skydd. + Om du har skrotat din bil säger vi upp din försäkring automatiskt. Vi får informationen direkt från Transportstyrelsen. Eftersom din bil har skrotats kommer din försäkring att sägas upp automatiskt. - Eftersom du har sålt din bil kommer din försäkring att sägas upp automatiskt. + Om du har sålt din bil säger vi upp din försäkring automatiskt. Vi får informationen direkt från Transportstyrelsen. Vi avslutar din försäkring automatiskt Du kommer att få ett bekräftelsemail på din avställningsförsäkring inom några dagar, där du kommer att se ditt nya pris. Vad kostar det @@ -859,11 +861,11 @@ Om du har ställt av din bil via Transportstyrelsen kommer din försäkring automatiskt övergå till en avställningsförsäkring. Vill du inte behålla din avställningsförsäkring kan du enkelt säga upp den nedan. Din försäkring kommer övergå till en avställningsförsäkring + Vi uppdaterar din försäkring automatiskt Säg upp försäkring Du kan närsomhelst avsluta din försäkring. Avslutar du din försäkring kommer du endast att debiteras för den tid du varit aktiv medlem hos Hedvig. När du avslutat din försäkring kan du se din sista betalning under fliken "Betalningar" här i appen. Avsluta din försäkring Avsluta försäkring - Eftersom din bil är påställd igen kommer din försäkring automatiskt att ändras tillbaka till ditt ordinarie skydd. Din bil är tillbaka på vägen Observera att du bara kan säga upp en försäkring åt gången Välj den försäkring du vill säga upp @@ -878,6 +880,7 @@ Om det blir ett uppehåll i din försäkring, kan det innebära att du inte får den hjälp eller ersättning du behöver i framtiden. Se därför till att alltid ha en aktiv försäkring. Viktig information Jag förstår + Läs mer Nästa betalning Skicka ett meddelande här i appen så hjälper vi dig. Skicka meddelande diff --git a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml index 5b11704e52..02b90898ee 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml @@ -168,11 +168,11 @@ Messages Send Checkout - Chip-ID - Add Chip-ID - Chip ID for your pet is missing - Update pet Chip-ID - Must be 15 digits + Pet ID (15 digits) + Add pet ID + Add your pet’s ID for better support + Add pet ID + Enter a 15-digit pet ID Don’t miss out on important information for your claim Enable notifications Case @@ -848,9 +848,11 @@ Cancel insurance Select termination date We’ll send a cancellation confirmation within a few days. If you don’t get it after 5 days, feel free to contact us. - Since your car has been decommissioned, your insurance will be automatically cancelled. + If you’ve decommissioned your car, we’ll cancel your insurance automatically. We get this information directly from Transportstyrelsen. + Once your car is registered as active with Transportstyrelsen, your insurance will be updated automatically to your previous coverage. + If you’ve scrapped your car, we’ll cancel your insurance automatically. We get this information directly from Transportstyrelsen. Since your car has been scrapped, your insurance will be automatically cancelled. - Since you've sold your car, your insurance will be automatically cancelled. + If you’ve sold your car, we’ll cancel your insurance automatically. We receive this information directly from Transportstyrelsen. We’ll cancel your insurance automatically You’ll receive a confirmation email within a few days, where you can see your new price. What it costs @@ -859,11 +861,11 @@ If you’ve decommissioned your car through Transportstyrelsen, your insurance will automatically switch to decommission insurance. If you don’t want to keep your decommission insurance, you can cancel it below. Your insurance will switch to decommission insurance + We’ll update your insurance automatically Cancel insurance You can cancel your insurance at any time. You will only be charged for the time you have been an active member. When the insurance is cancelled you can see your last payment under the tab "Payments" here in the app. Cancelling your insurance Cancel insurance - Since your car is registered again, your insurance will automatically switch back to your regular coverage. Your car is back on the road Please note that you can only cancel one insurance at a time Select the insurance you want to cancel @@ -878,6 +880,7 @@ If there is a gap in your insurance, you may not receive future help or compensation. Make sure that you always have an active insurance. Important information I understand + Learn more Next payment You need our help to cancel your insurance. Send us a message to get further help. Send message From 6940bbcb6aa49ec0389df96d52531a53d7a86764 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 8 Apr 2026 08:55:53 +0200 Subject: [PATCH 30/42] publish to staging --- .github/workflows/staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 4bfa42c651..316c4105eb 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -3,7 +3,7 @@ on: push: branches: - develop - - feature/cio-backed-deep-links + - feat/pet-chip-id workflow_dispatch: concurrency: From 75fee9dcd6ca700431f0f13c12e9e71efbf6d595 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 8 Apr 2026 15:40:53 +0200 Subject: [PATCH 31/42] add pet-id deeplink --- .../android/app/navigation/HedvigNavHost.kt | 1 + app/feature/feature-chip-id/build.gradle.kts | 1 + .../feature/chip/id/navigation/ChipIdGraph.kt | 24 +++++++++++++++++++ .../id/navigation/ChipIdNavDestination.kt | 15 +++++++++++- .../core/HedvigDeepLinkContainer.kt | 19 ++++++++++++++- 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index f5b19af251..0261a057b1 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -416,6 +416,7 @@ internal fun HedvigNavHost( navController = navController, globalSnackBarState = globalSnackBarState, navigateUp = navController::navigateUp, + hedvigDeepLinkContainer = hedvigDeepLinkContainer, ) movingFlowGraph( navController = navController, diff --git a/app/feature/feature-chip-id/build.gradle.kts b/app/feature/feature-chip-id/build.gradle.kts index d4bbd6d821..6cf9c98e32 100644 --- a/app/feature/feature-chip-id/build.gradle.kts +++ b/app/feature/feature-chip-id/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { implementation(projects.dataContract) implementation(projects.designSystemHedvig) implementation(projects.moleculePublic) + implementation(projects.navigationCore) implementation(projects.navigationCommon) implementation(projects.navigationCompose) implementation(projects.navigationComposeTyped) diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index 3412b1e0f5..5ee7735af0 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -1,5 +1,6 @@ package com.hedvig.android.feature.chip.id.navigation +import androidx.compose.runtime.LaunchedEffect import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import com.hedvig.android.design.system.hedvig.GlobalSnackBarState @@ -7,10 +8,12 @@ import com.hedvig.android.feature.chip.id.ui.AddChipIdDestination import com.hedvig.android.feature.chip.id.ui.AddChipIdViewModel import com.hedvig.android.feature.chip.id.ui.selectinsurance.SelectInsuranceForChipIdDestination import com.hedvig.android.feature.chip.id.ui.selectinsurance.SelectInsuranceForChipIdViewModel +import com.hedvig.android.navigation.compose.navDeepLinks import com.hedvig.android.navigation.compose.navdestination import com.hedvig.android.navigation.compose.navgraph import com.hedvig.android.navigation.compose.typed.getRouteFromBackStack import com.hedvig.android.navigation.compose.typedPopUpTo +import com.hedvig.android.navigation.core.HedvigDeepLinkContainer import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -18,7 +21,26 @@ fun NavGraphBuilder.chipIdGraph( navController: NavController, globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, + hedvigDeepLinkContainer: HedvigDeepLinkContainer, ) { + navdestination( + deepLinks = navDeepLinks( + hedvigDeepLinkContainer.petIdWithoutContractId, + hedvigDeepLinkContainer.petIdWithContractId, + ), + ) { + val contractId = this.contractId + LaunchedEffect(Unit) { + navController.navigate( + ChipIdGraphDestination( + contractId = contractId, + ), + ) { + typedPopUpTo({ inclusive = true }) + } + } + } + navgraph( startDestination = ChipIdDestination.SelectInsuranceForChipId::class, destinationNavTypeAware = ChipIdGraphDestination, @@ -65,3 +87,5 @@ fun NavGraphBuilder.chipIdGraph( } } } + + diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt index f29684d867..891de2fad8 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdNavDestination.kt @@ -4,6 +4,7 @@ import com.hedvig.android.navigation.common.Destination import com.hedvig.android.navigation.common.DestinationNavTypeAware import kotlin.reflect.KType import kotlin.reflect.typeOf +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable @@ -14,9 +15,21 @@ data class ChipIdGraphDestination(val contractId: String? = null) : Destination } internal sealed interface ChipIdDestination { + @androidx.annotation.Keep @Serializable - data class AddChipId(val contractId: String) : ChipIdDestination, Destination + data class AddChipId( + val contractId: String + ) : ChipIdDestination, Destination + @androidx.annotation.Keep @Serializable data object SelectInsuranceForChipId : ChipIdDestination, Destination + @androidx.annotation.Keep + @Serializable + data class AddChipIdTriage( + /** Must match the name of the param inside [com.hedvig.android.navigation.core.HedvigDeepLinkContainer.petIdWithContractId] */ + @SerialName("contractId") + val contractId: String? = null + ) : ChipIdDestination, Destination } + diff --git a/app/navigation/navigation-core/src/commonMain/kotlin/com/hedvig/android/navigation/core/HedvigDeepLinkContainer.kt b/app/navigation/navigation-core/src/commonMain/kotlin/com/hedvig/android/navigation/core/HedvigDeepLinkContainer.kt index ece00c6729..650003a628 100644 --- a/app/navigation/navigation-core/src/commonMain/kotlin/com/hedvig/android/navigation/core/HedvigDeepLinkContainer.kt +++ b/app/navigation/navigation-core/src/commonMain/kotlin/com/hedvig/android/navigation/core/HedvigDeepLinkContainer.kt @@ -75,6 +75,10 @@ interface HedvigDeepLinkContainer { * that comes after `/` which follows the base deeplink domain */ fun buildDeepLink(suffix: String): String + + val petIdWithoutContractId: List + + val petIdWithContractId: List } internal class HedvigDeepLinkContainerImpl( @@ -185,6 +189,13 @@ internal class HedvigDeepLinkContainerImpl( override fun buildDeepLink(suffix: String): String { return "${baseDeepLinkDomains.first()}/$suffix" } + + override val petIdWithoutContractId: List = baseDeepLinkDomains.map { baseDeepLinkDomain -> + "$baseDeepLinkDomain/pet-id" + } + override val petIdWithContractId: List = baseDeepLinkDomains.map { baseDeepLinkDomain -> + "$baseDeepLinkDomain/pet-id?contractId={contractId}" + } } val HedvigDeepLinkContainer.allDeepLinkUriPatterns: List @@ -218,4 +229,10 @@ val HedvigDeepLinkContainer.allDeepLinkUriPatterns: List insuranceEvidence.first(), claimFlow.first(), moveContract.first(), - ) + editCoOwners.first(), + carAddon.first(), + carAddonWithContractId.first(), + travelAddonWithContractId.first(), + petIdWithoutContractId.first(), + petIdWithContractId.first(), + ) From 18e82f3663b4378914cea71aca1cabafc3506e86 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 8 Apr 2026 16:42:59 +0200 Subject: [PATCH 32/42] add empty error state --- .../androidMain/res/values-sv-rSE/strings.xml | 1 + .../src/androidMain/res/values/strings.xml | 1 + .../values-sv-rSE/strings.xml | 1 + .../composeResources/values/strings.xml | 1 + .../feature/chip/id/navigation/ChipIdGraph.kt | 2 +- .../SelectInsuranceForChipIdDestination.kt | 96 ++++++++++++------- 6 files changed, 67 insertions(+), 35 deletions(-) diff --git a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml index 6363f601ee..5462194d3d 100644 --- a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml @@ -171,6 +171,7 @@ Djur-ID (15 siffror) Lägg till djur-ID Lägg till ditt husdjurs ID för bättre hjälp + Inga djurförsäkringar med saknat chip-ID. Lägg till djur-ID Ange ett djur-ID med 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. diff --git a/app/core/core-resources/src/androidMain/res/values/strings.xml b/app/core/core-resources/src/androidMain/res/values/strings.xml index a858e2afd9..e73b851ac0 100644 --- a/app/core/core-resources/src/androidMain/res/values/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values/strings.xml @@ -171,6 +171,7 @@ Pet ID (15 digits) Add pet ID Add your pet’s ID for better support + No pet insurances with missing chip ID. Add pet ID Enter a 15-digit pet ID Don’t miss out on important information for your claim diff --git a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml index 6eee33cf55..cd4390f676 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml @@ -171,6 +171,7 @@ Djur-ID (15 siffror) Lägg till djur-ID Lägg till ditt husdjurs ID för bättre hjälp + Inga djurförsäkringar med saknat chip-ID. Lägg till djur-ID Ange ett djur-ID med 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. diff --git a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml index 02b90898ee..823587717f 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml @@ -171,6 +171,7 @@ Pet ID (15 digits) Add pet ID Add your pet’s ID for better support + No pet insurances with missing chip ID. Add pet ID Enter a 15-digit pet ID Don’t miss out on important information for your claim diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index 5ee7735af0..a536290bd5 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -62,7 +62,7 @@ fun NavGraphBuilder.chipIdGraph( navigateToAddChipId = { contractId: String, popSelectInsurance: Boolean -> navController.navigate(ChipIdDestination.AddChipId(contractId)) { if (popSelectInsurance) { - typedPopUpTo { + typedPopUpTo { inclusive = true } } diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt index 086770c4f1..9dea55c037 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/ui/selectinsurance/SelectInsuranceForChipIdDestination.kt @@ -1,15 +1,20 @@ package com.hedvig.android.feature.chip.id.ui.selectinsurance import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row 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.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -23,6 +28,9 @@ import androidx.lifecycle.compose.dropUnlessResumed import com.hedvig.android.compose.ui.dropUnlessResumed import com.hedvig.android.data.contract.ContractGroup.HOMEOWNER import com.hedvig.android.data.contract.pillowResource +import com.hedvig.android.design.system.hedvig.EmptyState +import com.hedvig.android.design.system.hedvig.EmptyStateDefaults +import com.hedvig.android.design.system.hedvig.EmptyStateDefaults.EmptyStateIconStyle.ERROR import com.hedvig.android.design.system.hedvig.HedvigButton import com.hedvig.android.design.system.hedvig.HedvigCard import com.hedvig.android.design.system.hedvig.HedvigErrorSection @@ -47,6 +55,7 @@ import com.hedvig.android.design.system.hedvig.icon.HedvigIcons import com.hedvig.android.feature.chip.id.data.PetContractForChipId import hedvig.resources.ADDON_FLOW_SELECT_INSURANCE_SUBTITLE import hedvig.resources.ADDON_FLOW_SELECT_INSURANCE_TITLE +import hedvig.resources.CHIP_ID_NO_INSURANCES import hedvig.resources.Res import hedvig.resources.SELECT_INSURANCE_TO_REMOVE_ADDON_TITLE import hedvig.resources.TERMINATION_ADDON_COVERAGE_TITLE @@ -157,40 +166,59 @@ private fun SelectInsuranceForChipIdContentScreen( null, Modifier.padding(horizontal = 16.dp), ) - Spacer(Modifier.weight(1f)) - Spacer(Modifier.height(16.dp)) - RadioGroup( - options = uiState.contracts.map { insuranceForAddon -> - RadioOption( - id = RadioOptionId(insuranceForAddon.id), - text = insuranceForAddon.displayName, - label = insuranceForAddon.contractExposure, + if (uiState.contracts.isEmpty()) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(horizontal = 16.dp), + ) { + EmptyState( + text = stringResource(Res.string.CHIP_ID_NO_INSURANCES), + description = null, + iconStyle = ERROR, + buttonStyle = EmptyStateDefaults.EmptyStateButtonStyle.NoButton, ) - }, - selectedOption = uiState.selectedContract?.id?.let { RadioOptionId(it) }, - onRadioOptionSelected = { optionId -> - uiState.contracts.firstOrNull { it.id == optionId.id }?.let { - selectInsurance(it) - } - }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) - Spacer(Modifier.height(12.dp)) - HedvigButton( - stringResource(Res.string.general_continue_button), - enabled = uiState.selectedContract != null, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - onClick = { - uiState.selectedContract?.let { - navigateToAddChipId(it.id, uiState.contracts.size == 1) - } - }, - isLoading = false, - ) - Spacer(Modifier.height(16.dp)) + } + } else { + Spacer(Modifier.weight(1f)) + Spacer(Modifier.height(16.dp)) + RadioGroup( + options = uiState.contracts.map { insuranceForAddon -> + RadioOption( + id = RadioOptionId(insuranceForAddon.id), + text = insuranceForAddon.displayName, + label = insuranceForAddon.contractExposure, + ) + }, + selectedOption = uiState.selectedContract?.id?.let { RadioOptionId(it) }, + onRadioOptionSelected = { optionId -> + uiState.contracts.firstOrNull { it.id == optionId.id }?.let { + selectInsurance(it) + } + }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + Spacer(Modifier.height(12.dp)) + HedvigButton( + stringResource(Res.string.general_continue_button), + enabled = uiState.selectedContract != null, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + onClick = { + uiState.selectedContract?.let { + navigateToAddChipId(it.id, uiState.contracts.size == 1) + } + }, + isLoading = false, + ) + Spacer(Modifier.height(16.dp)) + } + } } From f65050a2b7fecba8f141211d44a0c66b32c9b4bd Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Wed, 8 Apr 2026 16:54:54 +0200 Subject: [PATCH 33/42] remove nav freezing --- .../com/hedvig/android/app/navigation/HedvigNavHost.kt | 1 + .../hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index 0261a057b1..dd97678359 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -417,6 +417,7 @@ internal fun HedvigNavHost( globalSnackBarState = globalSnackBarState, navigateUp = navController::navigateUp, hedvigDeepLinkContainer = hedvigDeepLinkContainer, + popBackStack = popBackStackOrFinish, ) movingFlowGraph( navController = navController, diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index a536290bd5..11d2169244 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -22,6 +22,7 @@ fun NavGraphBuilder.chipIdGraph( globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, hedvigDeepLinkContainer: HedvigDeepLinkContainer, + popBackStack: () -> Unit ) { navdestination( deepLinks = navDeepLinks( @@ -56,9 +57,7 @@ fun NavGraphBuilder.chipIdGraph( SelectInsuranceForChipIdDestination( viewModel = viewModel, navigateUp = navigateUp, - popBackStack = { - navController.popBackStack() - }, + popBackStack = popBackStack, navigateToAddChipId = { contractId: String, popSelectInsurance: Boolean -> navController.navigate(ChipIdDestination.AddChipId(contractId)) { if (popSelectInsurance) { From 729000ba645b4779a7505c767dc4a820744124fa Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 10:06:10 +0200 Subject: [PATCH 34/42] switch order and set minLines to 2 --- .../android/design/system/hedvig/Notification.kt | 2 +- .../memberreminders/GetMemberRemindersUseCase.kt | 6 +++--- .../memberreminders/ui/MemberReminderCards.kt | 12 ++++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt b/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt index 7d864ff86d..8378e6394b 100644 --- a/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt +++ b/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt @@ -87,7 +87,7 @@ fun HedvigNotificationCard( ) { HedvigNotificationCard( content = { - HedvigText(text = message) + HedvigText(text = message, minLines = 2) }, priority = priority, modifier = modifier, diff --git a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt index 85ecdb618b..f0de036c79 100644 --- a/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt +++ b/app/member-reminders/member-reminders-public/src/main/kotlin/com/hedvig/android/memberreminders/GetMemberRemindersUseCase.kt @@ -96,6 +96,9 @@ data class MemberReminders( coInsuredInfo?.let { addAll(coInsuredInfo) } + missingChipId?.let { + add(it) + } if (!alreadyHasNotificationPermission) { enableNotifications?.let { add(enableNotifications) @@ -107,9 +110,6 @@ data class MemberReminders( updateContactInfo?.let { add(it) } - missingChipId?.let { - add(it) - } } } } diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 092d195a8d..eccc7a352d 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -409,3 +409,15 @@ private fun PreviewReminderCardUpdateContactInfo() { } } } + +@Preview +@Composable +private fun PreviewReminderMissingChipId() { + HedvigTheme { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { + ReminderMissingChipId( + {}, + ) + } + } +} From 7200e35dbc848bbe1bdf3ed031ed73c9815b9bab Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 10:08:19 +0200 Subject: [PATCH 35/42] minLines as arg --- .../com/hedvig/android/design/system/hedvig/Notification.kt | 3 ++- .../hedvig/android/memberreminders/ui/MemberReminderCards.kt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt b/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt index 8378e6394b..3366acd6cb 100644 --- a/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt +++ b/app/design-system/design-system-hedvig/src/commonMain/kotlin/com/hedvig/android/design/system/hedvig/Notification.kt @@ -84,10 +84,11 @@ fun HedvigNotificationCard( withIcon: Boolean = NotificationDefaults.withIconDefault, style: InfoCardStyle = defaultStyle, buttonLoading: Boolean = false, + minLines: Int = 1 ) { HedvigNotificationCard( content = { - HedvigText(text = message, minLines = 2) + HedvigText(text = message, minLines = minLines) }, priority = priority, modifier = modifier, diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index eccc7a352d..1e770dff3f 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -279,6 +279,7 @@ internal fun ReminderMissingChipId(navigateToChipId: () -> Unit, modifier: Modif buttonText = stringResource(Res.string.CHIP_ID_MISSING_BUTTON), onButtonClick = navigateToChipId, ), + minLines = 2 ) } From a5a26dfdab670df080fa389322494ab4232b8c53 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 10:10:41 +0200 Subject: [PATCH 36/42] strings update --- .../src/androidMain/res/values-sv-rSE/strings.xml | 12 ++++++------ .../src/androidMain/res/values/strings.xml | 12 ++++++------ .../composeResources/values-sv-rSE/strings.xml | 12 ++++++------ .../commonMain/composeResources/values/strings.xml | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml index 5462194d3d..f58b1218a2 100644 --- a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml @@ -168,12 +168,12 @@ Meddelanden Skicka Checkout - Djur-ID (15 siffror) - Lägg till djur-ID - Lägg till ditt husdjurs ID för bättre hjälp - Inga djurförsäkringar med saknat chip-ID. - Lägg till djur-ID - Ange ett djur-ID med 15 siffror + ID-nummer + Lägg till ID + Vi saknar ditt djurs ID-nummer + Du har redan lagt till ID-nummer för samtliga djur + Uppdatera ID-nummer + ID-numret måste vara exakt 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. Aktivera Ärende diff --git a/app/core/core-resources/src/androidMain/res/values/strings.xml b/app/core/core-resources/src/androidMain/res/values/strings.xml index e73b851ac0..5b9c7e8bc7 100644 --- a/app/core/core-resources/src/androidMain/res/values/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values/strings.xml @@ -168,12 +168,12 @@ Messages Send Checkout - Pet ID (15 digits) - Add pet ID - Add your pet’s ID for better support - No pet insurances with missing chip ID. - Add pet ID - Enter a 15-digit pet ID + ID-number + Add ID + We are missing your pet’s ID-number + You’ve already added the ID-number for all your pets + Update ID-number + ID-number needs to be exactly 15 numbers Don’t miss out on important information for your claim Enable notifications Case diff --git a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml index cd4390f676..35d531ddea 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml @@ -168,12 +168,12 @@ Meddelanden Skicka Checkout - Djur-ID (15 siffror) - Lägg till djur-ID - Lägg till ditt husdjurs ID för bättre hjälp - Inga djurförsäkringar med saknat chip-ID. - Lägg till djur-ID - Ange ett djur-ID med 15 siffror + ID-nummer + Lägg till ID + Vi saknar ditt djurs ID-nummer + Du har redan lagt till ID-nummer för samtliga djur + Uppdatera ID-nummer + ID-numret måste vara exakt 15 siffror Aktivera pushnotiser så vi kan hålla dig uppdaterad om ditt ärende. Aktivera Ärende diff --git a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml index 823587717f..e600c27561 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml @@ -168,12 +168,12 @@ Messages Send Checkout - Pet ID (15 digits) - Add pet ID - Add your pet’s ID for better support - No pet insurances with missing chip ID. - Add pet ID - Enter a 15-digit pet ID + ID-number + Add ID + We are missing your pet’s ID-number + You’ve already added the ID-number for all your pets + Update ID-number + ID-number needs to be exactly 15 numbers Don’t miss out on important information for your claim Enable notifications Case From 2f581ee140deb274afafd2a54cf86add0f294007 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 10:11:25 +0200 Subject: [PATCH 37/42] schema update --- .../com/hedvig/android/apollo/octopus/schema.graphqls | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls index 3d9b04ddd8..288983627b 100644 --- a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls +++ b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls @@ -2512,10 +2512,15 @@ type Member { type MemberActions { memberId: ID! """ + Returns a deflection to emergency partners if the member has an active contract that includes travel insurance coverage. + Reuses the ClaimIntentStepContentDeflection type for convenience. + """ + sickAbroadDeflect: ClaimIntentStepContentDeflection + """ Indicates that the member should review their phone number or add if it is missing. """ isContactInfoUpdateNeeded: Boolean! - sickAbroadAction: SickAbroadAction + sickAbroadAction: SickAbroadAction @deprecated(reason: "Use sickAbroadDeflect instead") """ Indicate whether the travel certificate option should be displayed. """ From d45ac09abf645d8de7b128930e3c9e8799f05cba Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 11:25:23 +0200 Subject: [PATCH 38/42] measure lines dynamically --- .../memberreminders/ui/MemberReminderCards.kt | 235 ++++++++++++++---- 1 file changed, 183 insertions(+), 52 deletions(-) diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 1e770dff3f..8ddbd4096d 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues @@ -19,13 +20,17 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.dp import com.hedvig.android.compose.pager.indicator.HorizontalPagerIndicator import com.hedvig.android.core.common.daysUntil import com.hedvig.android.data.coinsured.CoInsuredFlowType import com.hedvig.android.design.system.hedvig.HedvigNotificationCard import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.LocalTextStyle import com.hedvig.android.design.system.hedvig.NotificationDefaults.InfoCardStyle import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority import com.hedvig.android.design.system.hedvig.Surface @@ -53,6 +58,64 @@ import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone import org.jetbrains.compose.resources.stringResource +@Composable +fun getMemberReminderMessage(reminder: MemberReminder): String { + return when (reminder) { + is MemberReminder.CoInsuredInfo -> stringResource( + when (reminder.coInsuredType) { + CoInsuredFlowType.CoInsured -> Res.string.CONTRACT_COINSURED_MISSING_INFO_TEXT + CoInsuredFlowType.CoOwners -> Res.string.CONTRACT_COOWNERS_MISSING_INFO_TEXT + } + ) + + is MemberReminder.PaymentReminder.ConnectPayment -> + stringResource(Res.string.info_card_missing_payment_body) + + is MemberReminder.PaymentReminder.TerminationDueToMissedPayments -> + stringResource(Res.string.info_card_missing_payment_missing_payments_body, reminder.terminationDate) + + is UpcomingRenewal -> + { + val daysUntilRenewal = remember(TimeZone.currentSystemDefault(), reminder.renewalDate) { + daysUntil(reminder.renewalDate) + } + stringResource(Res.string.DASHBOARD_RENEWAL_PROMPTER_BODY, daysUntilRenewal) + } + + + is MemberReminder.EnableNotifications -> + stringResource(Res.string.PROFILE_ALLOW_NOTIFICATIONS_INFO_LABEL) + + is MemberReminder.ContactInfoUpdateNeeded -> + stringResource(Res.string.MISSING_CONTACT_INFO_CARD_TEXT) + + is MemberReminder.MissingChipId -> + stringResource(Res.string.CHIP_ID_MISSING_MESSAGE) + } +} + +@Composable +fun rememberMaxLineCountForReminders( + memberReminders: List, + maxWidthPx: Int, +): Int { + val textMeasurer = rememberTextMeasurer() + + val messages = memberReminders.map { reminder -> getMemberReminderMessage(reminder) } + val textStyle = LocalTextStyle.current + + return remember(messages, textMeasurer, maxWidthPx, textStyle) { + messages.maxOfOrNull { message -> + val textLayout = textMeasurer.measure( + text = AnnotatedString(message), + style = textStyle, + constraints = Constraints(maxWidth = maxWidthPx) + ) + textLayout.lineCount + } ?: 1 + } +} + @Composable fun MemberReminderCardsWithoutNotification( memberReminders: List, @@ -107,31 +170,41 @@ fun MemberReminderCards( navigateToContactInfo = navigateToContactInfo, navigateToChipId = navigateToChipId, modifier = modifier.padding(contentPadding), + minLines = 1 ) } else if (memberReminders.isNotEmpty()) { val pagerState = rememberPagerState(pageCount = { memberReminders.size }) - HorizontalPager( - state = pagerState, - contentPadding = contentPadding, - beyondViewportPageCount = 1, - pageSpacing = 8.dp, - key = { index -> memberReminders[index].id }, - modifier = Modifier - .fillMaxWidth() - .systemGestureExclusion(), - ) { page -> - MemberReminderCard( - memberReminder = memberReminders[page], - navigateToAddMissingInfo = navigateToAddMissingInfo, - navigateToConnectPayment = navigateToConnectPayment, - openUrl = openUrl, - onNavigateToNewConversation = onNavigateToNewConversation, - snoozeNotificationPermissionReminder = snoozeNotificationPermissionReminder, - notificationPermissionState = notificationPermissionState, - navigateToContactInfo = navigateToContactInfo, - navigateToChipId = navigateToChipId, - modifier = modifier.fillMaxWidth(), + BoxWithConstraints(Modifier.fillMaxWidth()) { + val minLineCount = rememberMaxLineCountForReminders( + memberReminders = memberReminders, + maxWidthPx = constraints.maxWidth ) + Column { + HorizontalPager( + state = pagerState, + contentPadding = contentPadding, + beyondViewportPageCount = 1, + pageSpacing = 8.dp, + key = { index -> memberReminders[index].id }, + modifier = Modifier + .fillMaxWidth() + .systemGestureExclusion(), + ) { page -> + MemberReminderCard( + memberReminder = memberReminders[page], + navigateToAddMissingInfo = navigateToAddMissingInfo, + navigateToConnectPayment = navigateToConnectPayment, + openUrl = openUrl, + onNavigateToNewConversation = onNavigateToNewConversation, + snoozeNotificationPermissionReminder = snoozeNotificationPermissionReminder, + notificationPermissionState = notificationPermissionState, + navigateToContactInfo = navigateToContactInfo, + navigateToChipId = navigateToChipId, + modifier = modifier.fillMaxWidth(), + minLines = minLineCount + ) + } + } } Spacer(Modifier.height(16.dp)) @@ -159,16 +232,18 @@ private fun ColumnScope.MemberReminderCard( snoozeNotificationPermissionReminder: () -> Unit, onNavigateToNewConversation: () -> Unit, notificationPermissionState: NotificationPermissionState?, + minLines: Int, modifier: Modifier = Modifier, ) { when (memberReminder) { is MemberReminder.CoInsuredInfo -> { ReminderCoInsuredInfo( - coInsuredType = memberReminder.coInsuredType, + memberReminder = memberReminder, navigateToAddMissingInfo = { navigateToAddMissingInfo(memberReminder.contractId, memberReminder.coInsuredType) }, modifier = modifier, + minLines = minLines, ) } @@ -176,22 +251,26 @@ private fun ColumnScope.MemberReminderCard( ReminderCardConnectPayment( navigateToConnectPayment = navigateToConnectPayment, modifier = modifier, + minLines = minLines, + memberReminder = memberReminder, ) } is MemberReminder.PaymentReminder.TerminationDueToMissedPayments -> { ReminderCardMissingPayment( - terminationDate = memberReminder.terminationDate, + memberReminder = memberReminder, onNavigateToNewConversation = onNavigateToNewConversation, modifier = modifier, + minLines = minLines, ) } is UpcomingRenewal -> { ReminderCardUpcomingRenewals( - upcomingRenewal = memberReminder, openUrl = openUrl, + memberReminder = memberReminder, modifier = modifier, + minLines = minLines, ) } @@ -207,6 +286,7 @@ private fun ColumnScope.MemberReminderCard( ReminderCardEnableNotifications( snoozeNotificationPermissionReminder = snoozeNotificationPermissionReminder, requestNotificationPermission = notificationPermissionState::launchPermissionRequest, + minLines = minLines, ) } } @@ -216,12 +296,14 @@ private fun ColumnScope.MemberReminderCard( ReminderCardUpdateContactInfo( navigateToContactInfo = navigateToContactInfo, modifier = modifier, + minLines = minLines, ) } is MemberReminder.MissingChipId -> { ReminderMissingChipId( navigateToChipId = navigateToChipId, + minLines = minLines, modifier = modifier, ) } @@ -241,10 +323,12 @@ private val cardReminderExitTransition = fadeOut() + shrinkVertically( fun ReminderCardEnableNotifications( snoozeNotificationPermissionReminder: () -> Unit, requestNotificationPermission: () -> Unit, + minLines: Int = 1, modifier: Modifier = Modifier, ) { + val message = getMemberReminderMessage(MemberReminder.EnableNotifications()) HedvigNotificationCard( - message = stringResource(Res.string.PROFILE_ALLOW_NOTIFICATIONS_INFO_LABEL), + message = message, modifier = modifier, priority = NotificationPriority.Info, style = InfoCardStyle.Buttons( @@ -253,106 +337,128 @@ fun ReminderCardEnableNotifications( rightButtonText = stringResource(Res.string.PUSH_NOTIFICATIONS_ALERT_ACTION_OK), onRightButtonClick = requestNotificationPermission, ), + minLines = minLines, ) } @Composable -fun ReminderCardUpdateContactInfo(navigateToContactInfo: () -> Unit, modifier: Modifier = Modifier) { +fun ReminderCardUpdateContactInfo( + navigateToContactInfo: () -> Unit, + modifier: Modifier = Modifier, + minLines: Int = 1, +) { + val message = getMemberReminderMessage(MemberReminder.ContactInfoUpdateNeeded) HedvigNotificationCard( - message = stringResource(Res.string.MISSING_CONTACT_INFO_CARD_TEXT), + message = message, modifier = modifier, priority = NotificationPriority.Info, style = InfoCardStyle.Button( buttonText = stringResource(Res.string.MISSING_CONTACT_INFO_CARD_BUTTON), onButtonClick = navigateToContactInfo, ), + minLines = minLines, ) } @Composable -internal fun ReminderMissingChipId(navigateToChipId: () -> Unit, modifier: Modifier = Modifier) { +internal fun ReminderMissingChipId( + navigateToChipId: () -> Unit, + minLines: Int, + modifier: Modifier = Modifier, +) { + val message = getMemberReminderMessage(MemberReminder.MissingChipId()) HedvigNotificationCard( - message = stringResource(Res.string.CHIP_ID_MISSING_MESSAGE), + message = message, modifier = modifier, priority = NotificationPriority.Attention, style = InfoCardStyle.Button( buttonText = stringResource(Res.string.CHIP_ID_MISSING_BUTTON), onButtonClick = navigateToChipId, ), - minLines = 2 + minLines = minLines ) } @Composable -private fun ReminderCardConnectPayment(navigateToConnectPayment: () -> Unit, modifier: Modifier = Modifier) { +private fun ReminderCardConnectPayment( + memberReminder: MemberReminder, + navigateToConnectPayment: () -> Unit, + modifier: Modifier = Modifier, + minLines: Int = 1, +) { + val message = getMemberReminderMessage(memberReminder) HedvigNotificationCard( - message = stringResource(Res.string.info_card_missing_payment_body), + message = message, modifier = modifier, priority = NotificationPriority.Attention, style = InfoCardStyle.Button( buttonText = stringResource(Res.string.PROFILE_PAYMENT_CONNECT_DIRECT_DEBIT_BUTTON), onButtonClick = navigateToConnectPayment, ), + minLines = minLines, ) } @Composable private fun ReminderCardMissingPayment( - terminationDate: LocalDate, + memberReminder: MemberReminder, onNavigateToNewConversation: () -> Unit, modifier: Modifier = Modifier, + minLines: Int = 1, ) { + val message = getMemberReminderMessage(memberReminder) HedvigNotificationCard( - message = stringResource(Res.string.info_card_missing_payment_missing_payments_body, terminationDate), + message = message, modifier = modifier, priority = NotificationPriority.Attention, style = InfoCardStyle.Button( buttonText = stringResource(Res.string.open_chat), onButtonClick = onNavigateToNewConversation, ), + minLines = minLines, ) } @Composable private fun ReminderCardUpcomingRenewals( - upcomingRenewal: UpcomingRenewal, + memberReminder: MemberReminder.UpcomingRenewal, openUrl: (String) -> Unit, modifier: Modifier = Modifier, + minLines: Int = 1, ) { - val daysUntilRenewal = remember(TimeZone.currentSystemDefault(), upcomingRenewal.renewalDate) { - daysUntil(upcomingRenewal.renewalDate) - } - val style = upcomingRenewal.draftCertificateUrl?.let { + val message = getMemberReminderMessage(memberReminder) + val style = memberReminder.draftCertificateUrl?.let { InfoCardStyle.Button( onButtonClick = { openUrl(it) }, buttonText = stringResource(Res.string.CONTRACT_VIEW_CERTIFICATE_BUTTON), ) } ?: InfoCardStyle.Default HedvigNotificationCard( - message = stringResource(Res.string.DASHBOARD_RENEWAL_PROMPTER_BODY, daysUntilRenewal), + message = message, modifier = modifier, priority = NotificationPriority.Info, style = style, + minLines = minLines, ) } @Composable private fun ReminderCoInsuredInfo( - coInsuredType: CoInsuredFlowType, + memberReminder: MemberReminder, navigateToAddMissingInfo: () -> Unit, modifier: Modifier = Modifier, + minLines: Int = 1, ) { + val message = getMemberReminderMessage(memberReminder) HedvigNotificationCard( - message = when (coInsuredType) { - CoInsuredFlowType.CoInsured -> stringResource(Res.string.CONTRACT_COINSURED_MISSING_INFO_TEXT) - CoInsuredFlowType.CoOwners -> stringResource(Res.string.CONTRACT_COOWNERS_MISSING_INFO_TEXT) - }, + message = message, modifier = modifier, priority = NotificationPriority.Attention, style = InfoCardStyle.Button( buttonText = stringResource(Res.string.CONTRACT_COINSURED_MISSING_ADD_INFO), onButtonClick = navigateToAddMissingInfo, ), + minLines = minLines, ) } @@ -361,7 +467,10 @@ private fun ReminderCoInsuredInfo( private fun PreviewReminderCardEnableNotifications() { HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { - ReminderCardEnableNotifications({}, {}) + ReminderCardEnableNotifications( + snoozeNotificationPermissionReminder = {}, + requestNotificationPermission = {}, + ) } } } @@ -371,7 +480,24 @@ private fun PreviewReminderCardEnableNotifications() { private fun PreviewReminderCardConnectPayment() { HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { - ReminderCardConnectPayment({}) + ReminderCardConnectPayment( + navigateToConnectPayment = {}, + memberReminder = MemberReminder.PaymentReminder.ConnectPayment() + ) + } + } +} + +@Preview +@Composable +private fun PreviewReminderCardMissingPayment() { + HedvigTheme { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { + ReminderCardConnectPayment( + navigateToConnectPayment = {}, + memberReminder = MemberReminder.PaymentReminder.TerminationDueToMissedPayments( + terminationDate = LocalDate(2029,1,1)) + ) } } } @@ -379,11 +505,12 @@ private fun PreviewReminderCardConnectPayment() { @Preview @Composable private fun PreviewReminderCardUpcomingRenewals() { + val upcomingRenewal = UpcomingRenewal("contract name", LocalDate.parse("2024-03-05"), "") HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { ReminderCardUpcomingRenewals( - UpcomingRenewal("contract name", LocalDate.parse("2024-03-05"), ""), - {}, + openUrl = {}, + memberReminder = upcomingRenewal ) } } @@ -394,7 +521,10 @@ private fun PreviewReminderCardUpcomingRenewals() { private fun PreviewReminderCardCoInsuredInfo() { HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { - ReminderCoInsuredInfo(CoInsuredFlowType.CoInsured, {}) + ReminderCoInsuredInfo( + memberReminder = MemberReminder.CoInsuredInfo("", CoInsuredFlowType.CoInsured), + navigateToAddMissingInfo = {}, + ) } } } @@ -405,7 +535,7 @@ private fun PreviewReminderCardUpdateContactInfo() { HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { ReminderCardUpdateContactInfo( - {}, + navigateToContactInfo = {}, ) } } @@ -417,7 +547,8 @@ private fun PreviewReminderMissingChipId() { HedvigTheme { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { ReminderMissingChipId( - {}, + navigateToChipId = {}, + minLines = 1 ) } } From 8156758a7e29ea924833d6a04b9b3bcfeebf86e8 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 13:04:08 +0200 Subject: [PATCH 39/42] add keys to remember --- .../android/memberreminders/ui/MemberReminderCards.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 8ddbd4096d..2018cc8ebe 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -20,6 +20,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFontFamilyResolver import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.tooling.preview.Preview @@ -100,16 +102,20 @@ fun rememberMaxLineCountForReminders( maxWidthPx: Int, ): Int { val textMeasurer = rememberTextMeasurer() + val density = LocalDensity.current + val fontFamilyResolver = LocalFontFamilyResolver.current val messages = memberReminders.map { reminder -> getMemberReminderMessage(reminder) } val textStyle = LocalTextStyle.current - return remember(messages, textMeasurer, maxWidthPx, textStyle) { + return remember(messages, textMeasurer, maxWidthPx, textStyle, density, fontFamilyResolver) { messages.maxOfOrNull { message -> val textLayout = textMeasurer.measure( text = AnnotatedString(message), style = textStyle, - constraints = Constraints(maxWidth = maxWidthPx) + constraints = Constraints(maxWidth = maxWidthPx), + density = density, + fontFamilyResolver = fontFamilyResolver, ) textLayout.lineCount } ?: 1 From 80110e72b466ca26d078b5c5b28be55bd65358fe Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 13:42:22 +0200 Subject: [PATCH 40/42] fix pop on success --- .../com/hedvig/android/app/navigation/HedvigNavHost.kt | 7 +++++++ .../android/feature/chip/id/navigation/ChipIdGraph.kt | 9 ++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index f8a0209475..755ba996b2 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -421,6 +421,13 @@ internal fun HedvigNavHost( navigateUp = navController::navigateUp, hedvigDeepLinkContainer = hedvigDeepLinkContainer, popBackStack = popBackStackOrFinish, + popFlowOnSuccess = { + if (!navController.popBackStack(ChipIdGraphDestination::class, inclusive = true)) { + navController.navigate(HomeDestination.Graph) { + popUpTo(ChipIdGraphDestination::class) { inclusive = true } + } + } + } ) movingFlowGraph( navController = navController, diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index 11d2169244..0b72fa6130 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -22,7 +22,8 @@ fun NavGraphBuilder.chipIdGraph( globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, hedvigDeepLinkContainer: HedvigDeepLinkContainer, - popBackStack: () -> Unit + popBackStack: () -> Unit, + popFlowOnSuccess: () -> Unit ) { navdestination( deepLinks = navDeepLinks( @@ -61,7 +62,7 @@ fun NavGraphBuilder.chipIdGraph( navigateToAddChipId = { contractId: String, popSelectInsurance: Boolean -> navController.navigate(ChipIdDestination.AddChipId(contractId)) { if (popSelectInsurance) { - typedPopUpTo { + typedPopUpTo { inclusive = true } } @@ -79,9 +80,7 @@ fun NavGraphBuilder.chipIdGraph( viewModel = viewModel, globalSnackBarState = globalSnackBarState, navigateUp = navigateUp, - popFlowOnSuccess = { - navController.popBackStack(ChipIdGraphDestination::class, inclusive = true) - }, + popFlowOnSuccess = popFlowOnSuccess, ) } } From 57ee81f9459b9980144fe0792e6738e2db9eb011 Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 14:12:02 +0200 Subject: [PATCH 41/42] fix navigateUp in AddChipIdDestination --- .../android/app/navigation/HedvigNavHost.kt | 6 ++---- .../feature/chip/id/navigation/ChipIdGraph.kt | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index 755ba996b2..43fdab75f4 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -420,13 +420,11 @@ internal fun HedvigNavHost( globalSnackBarState = globalSnackBarState, navigateUp = navController::navigateUp, hedvigDeepLinkContainer = hedvigDeepLinkContainer, - popBackStack = popBackStackOrFinish, - popFlowOnSuccess = { - if (!navController.popBackStack(ChipIdGraphDestination::class, inclusive = true)) { + popBackStackOrFinish = popBackStackOrFinish, + goHome = { navController.navigate(HomeDestination.Graph) { popUpTo(ChipIdGraphDestination::class) { inclusive = true } } - } } ) movingFlowGraph( diff --git a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt index 0b72fa6130..d1b22df1dd 100644 --- a/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt +++ b/app/feature/feature-chip-id/src/main/kotlin/com/hedvig/android/feature/chip/id/navigation/ChipIdGraph.kt @@ -22,8 +22,8 @@ fun NavGraphBuilder.chipIdGraph( globalSnackBarState: GlobalSnackBarState, navigateUp: () -> Unit, hedvigDeepLinkContainer: HedvigDeepLinkContainer, - popBackStack: () -> Unit, - popFlowOnSuccess: () -> Unit + popBackStackOrFinish: () -> Unit, + goHome: () -> Unit ) { navdestination( deepLinks = navDeepLinks( @@ -58,11 +58,11 @@ fun NavGraphBuilder.chipIdGraph( SelectInsuranceForChipIdDestination( viewModel = viewModel, navigateUp = navigateUp, - popBackStack = popBackStack, + popBackStack = popBackStackOrFinish, navigateToAddChipId = { contractId: String, popSelectInsurance: Boolean -> navController.navigate(ChipIdDestination.AddChipId(contractId)) { if (popSelectInsurance) { - typedPopUpTo { + typedPopUpTo { inclusive = true } } @@ -79,8 +79,16 @@ fun NavGraphBuilder.chipIdGraph( AddChipIdDestination( viewModel = viewModel, globalSnackBarState = globalSnackBarState, - navigateUp = navigateUp, - popFlowOnSuccess = popFlowOnSuccess, + navigateUp = { + if (!navController.popBackStack(ChipIdDestination.AddChipId::class, inclusive = true)) { + goHome() + } + }, + popFlowOnSuccess = { + if (!navController.popBackStack(ChipIdGraphDestination::class, inclusive = true)) { + goHome() + } + } ) } } From 8cacbdb2f263e6f320cae28dcfc23f7dccaa9ccc Mon Sep 17 00:00:00 2001 From: mariiapanasetskaia Date: Mon, 13 Apr 2026 14:24:45 +0200 Subject: [PATCH 42/42] strings --- app/core/core-resources/src/androidMain/res/values/strings.xml | 2 +- .../src/commonMain/composeResources/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/core/core-resources/src/androidMain/res/values/strings.xml b/app/core/core-resources/src/androidMain/res/values/strings.xml index 5b9c7e8bc7..f2db8a113b 100644 --- a/app/core/core-resources/src/androidMain/res/values/strings.xml +++ b/app/core/core-resources/src/androidMain/res/values/strings.xml @@ -173,7 +173,7 @@ We are missing your pet’s ID-number You’ve already added the ID-number for all your pets Update ID-number - ID-number needs to be exactly 15 numbers + ID-number needs to be exactly 15 digits Don’t miss out on important information for your claim Enable notifications Case diff --git a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml index e600c27561..7edb7fd368 100644 --- a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml +++ b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml @@ -173,7 +173,7 @@ We are missing your pet’s ID-number You’ve already added the ID-number for all your pets Update ID-number - ID-number needs to be exactly 15 numbers + ID-number needs to be exactly 15 digits Don’t miss out on important information for your claim Enable notifications Case