Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.hedvig.android.feature.insurances.insurance

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
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.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonStyle.Ghost
import com.hedvig.android.design.system.hedvig.HedvigButton
import com.hedvig.android.design.system.hedvig.HedvigDialog
import com.hedvig.android.design.system.hedvig.HedvigPreview
import com.hedvig.android.design.system.hedvig.HedvigText
import com.hedvig.android.design.system.hedvig.HedvigTheme
import com.hedvig.android.design.system.hedvig.Surface

@Composable
internal fun HomePickerDialog(
onDismiss: () -> Unit,
onSelectApartmentRent: () -> Unit,
onSelectApartmentBrf: () -> Unit,
onSelectVilla: () -> Unit,
) {
HedvigDialog(onDismissRequest = onDismiss) {
Column(modifier = Modifier.fillMaxWidth()) {
HedvigText(
// TODO: Add "Which type of home insurance?" / "Vilken typ av hemförsäkring?" to Lokalise
text = "Which type of home insurance?",
style = HedvigTheme.typography.headlineSmall,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp),
)
// TODO: Add "Rental apartment" / "Hyresrätt" to Lokalise
HomePickerRow(text = "Rental apartment (Hyresrätt)", onClick = onSelectApartmentRent)
// TODO: Add "Owned apartment" / "Bostadsrätt" to Lokalise
HomePickerRow(text = "Owned apartment (Bostadsrätt)", onClick = onSelectApartmentBrf)
// TODO: Add "House" / "Villa" to Lokalise
HomePickerRow(text = "House (Villa)", onClick = onSelectVilla)
Spacer(Modifier.height(8.dp))
HedvigButton(
// TODO: Add "Cancel" / "Avbryt" to Lokalise
text = "Cancel",
onClick = onDismiss,
enabled = true,
buttonStyle = Ghost,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
Spacer(Modifier.height(16.dp))
}
}
}

@Composable
private fun HomePickerRow(text: String, onClick: () -> Unit) {
HedvigText(
text = text,
style = HedvigTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
.clickable(role = Role.Button) { onClick() }
.padding(horizontal = 16.dp, vertical = 14.dp),
)
}

@HedvigPreview
@Composable
private fun PreviewHomePickerDialog() {
HedvigTheme {
Surface(color = HedvigTheme.colorScheme.backgroundPrimary) {
HomePickerDialog(
onDismiss = {},
onSelectApartmentRent = {},
onSelectApartmentBrf = {},
onSelectVilla = {},
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.hedvig.android.feature.insurances.navigation

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
Expand All @@ -10,6 +14,7 @@ import com.hedvig.android.data.productvariant.AddonVariant
import com.hedvig.android.design.system.hedvig.motion.MotionDefaults
import com.hedvig.android.feature.insurances.data.AvailableAddon
import com.hedvig.android.feature.insurances.data.CancelInsuranceData
import com.hedvig.android.feature.insurances.insurance.HomePickerDialog
import com.hedvig.android.feature.insurances.insurance.InsuranceDestination
import com.hedvig.android.feature.insurances.insurance.presentation.InsuranceViewModel
import com.hedvig.android.feature.insurances.insurancedetail.ContractDetailDestination
Expand Down Expand Up @@ -58,6 +63,7 @@ fun NavGraphBuilder.insuranceGraph(
enterTransition = { MotionDefaults.fadeThroughEnter },
exitTransition = { MotionDefaults.fadeThroughExit },
) {
var showHomePicker by rememberSaveable { mutableStateOf(false) }
val viewModel: InsuranceViewModel = koinViewModel()
InsuranceDestination(
viewModel = viewModel,
Expand All @@ -76,22 +82,30 @@ fun NavGraphBuilder.insuranceGraph(
onNavigateToHousePurchase("SE_VACATION_HOME")
}

"car-insurance" in lower || "bilforsakring" in lower -> {
onNavigateToCarPurchase("SE_CAR")
}

"pet-insurance" in lower || "djurforsakring" in lower -> {
onNavigateToPetPurchase()
"villaforsakring" in lower || "home-insurance/house" in lower -> {
onNavigateToHousePurchase("SE_HOUSE")
}

"bostadsratt" in lower || "home-insurance/homeowner" in lower -> {
onNavigateToApartmentPurchase("SE_APARTMENT_BRF")
}

"hyresratt" in lower || "home-insurance" in lower || "hemforsakring" in lower -> {
"hyresratt" in lower || "home-insurance/rental" in lower -> {
onNavigateToApartmentPurchase("SE_APARTMENT_RENT")
}

"hemforsakring" in lower || "home-insurance" in lower -> {
showHomePicker = true
}

"car-insurance" in lower || "bilforsakring" in lower -> {
onNavigateToCarPurchase("SE_CAR")
}

"pet-insurance" in lower || "djurforsakring" in lower -> {
onNavigateToPetPurchase()
}

else -> {
openUrl(url)
}
Expand All @@ -106,6 +120,23 @@ fun NavGraphBuilder.insuranceGraph(
onNavigateToAddonPurchaseFlow(ids, null)
},
)
if (showHomePicker) {
HomePickerDialog(
onDismiss = { showHomePicker = false },
onSelectApartmentRent = {
showHomePicker = false
onNavigateToApartmentPurchase("SE_APARTMENT_RENT")
},
onSelectApartmentBrf = {
showHomePicker = false
onNavigateToApartmentPurchase("SE_APARTMENT_BRF")
},
onSelectVilla = {
showHomePicker = false
onNavigateToHousePurchase("SE_HOUSE")
},
)
}
}
navdestination<InsurancesDestinations.InsuranceContractDetail>(
deepLinks = navDeepLinks(hedvigDeepLinkContainer.contract),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.hedvig.android.feature.purchase.house.data

import arrow.core.Either
import arrow.core.raise.either
import com.apollographql.apollo.ApolloClient
import com.hedvig.android.apollo.safeExecute
import com.hedvig.android.core.common.ErrorMessage
import com.hedvig.android.logger.LogPriority
import com.hedvig.android.logger.logcat
import octopus.HousePriceIntentConfirmMutation
import octopus.HousePriceIntentDataUpdateMutation

internal interface SubmitHouseFormAndGetOffersUseCase {
suspend fun invoke(
priceIntentId: String,
ssn: String,
email: String,
street: String,
zipCode: String,
livingSpace: Int,
ancillaryArea: Int,
numberCoInsured: Int,
yearOfConstruction: Int,
numberOfBathrooms: Int,
isSubleted: Boolean,
): Either<ErrorMessage, HouseOffers>
}

internal class SubmitHouseFormAndGetOffersUseCaseImpl(
private val apolloClient: ApolloClient,
) : SubmitHouseFormAndGetOffersUseCase {
override suspend fun invoke(
priceIntentId: String,
ssn: String,
email: String,
street: String,
zipCode: String,
livingSpace: Int,
ancillaryArea: Int,
numberCoInsured: Int,
yearOfConstruction: Int,
numberOfBathrooms: Int,
isSubleted: Boolean,
): Either<ErrorMessage, HouseOffers> {
return either {
val formData = buildMap<String, Any> {
put("ssn", ssn)
put("email", email)
put("street", street)
put("zipCode", zipCode)
put("livingSpace", livingSpace)
put("ancillaryArea", ancillaryArea)
put("numberCoInsured", numberCoInsured)
put("yearOfConstruction", yearOfConstruction)
put("numberOfBathrooms", numberOfBathrooms)
put("isSubleted", isSubleted)
put("extraBuildings", emptyList<Map<String, Any>>())
}

val updateResult = apolloClient
.mutation(HousePriceIntentDataUpdateMutation(priceIntentId = priceIntentId, data = formData))
.safeExecute()
.fold(
ifLeft = {
logcat(LogPriority.ERROR) { "Failed to update price intent data: $it" }
raise(ErrorMessage())
},
ifRight = { it.priceIntentDataUpdate },
)

if (updateResult.userError != null) {
raise(ErrorMessage(updateResult.userError?.message))
}

val confirmResult = apolloClient
.mutation(HousePriceIntentConfirmMutation(priceIntentId = priceIntentId))
.safeExecute()
.fold(
ifLeft = {
logcat(LogPriority.ERROR) { "Failed to confirm price intent: $it" }
raise(ErrorMessage())
},
ifRight = { it.priceIntentConfirm },
)

if (confirmResult.userError != null) {
raise(ErrorMessage(confirmResult.userError?.message))
}

val offers = confirmResult.priceIntent?.offers.orEmpty()
if (offers.isEmpty()) {
logcat(LogPriority.ERROR) { "No offers returned after confirming price intent" }
raise(ErrorMessage())
}

HouseOffers(
productDisplayName = offers.first().variant.displayName,
offers = offers.map { it.toHouseTierOffer() },
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package com.hedvig.android.feature.purchase.house.di

import com.hedvig.android.feature.purchase.house.data.CreateHouseSessionAndPriceIntentUseCase
import com.hedvig.android.feature.purchase.house.data.CreateHouseSessionAndPriceIntentUseCaseImpl
import com.hedvig.android.feature.purchase.house.data.SubmitHouseFormAndGetOffersUseCase
import com.hedvig.android.feature.purchase.house.data.SubmitHouseFormAndGetOffersUseCaseImpl
import com.hedvig.android.feature.purchase.house.data.SubmitVacationHomeFormAndGetOffersUseCase
import com.hedvig.android.feature.purchase.house.data.SubmitVacationHomeFormAndGetOffersUseCaseImpl
import com.hedvig.android.feature.purchase.house.ui.house.HouseFormViewModel
import com.hedvig.android.feature.purchase.house.ui.vacationhome.VacationHomeFormViewModel
import org.koin.core.module.dsl.viewModel
import org.koin.dsl.module
Expand All @@ -15,6 +18,9 @@ val housePurchaseModule = module {
single<SubmitVacationHomeFormAndGetOffersUseCase> {
SubmitVacationHomeFormAndGetOffersUseCaseImpl(apolloClient = get())
}
single<SubmitHouseFormAndGetOffersUseCase> {
SubmitHouseFormAndGetOffersUseCaseImpl(apolloClient = get())
}

viewModel<VacationHomeFormViewModel> { params ->
VacationHomeFormViewModel(
Expand All @@ -23,4 +29,12 @@ val housePurchaseModule = module {
submitVacationHomeFormAndGetOffersUseCase = get(),
)
}

viewModel<HouseFormViewModel> { params ->
HouseFormViewModel(
productName = params.get(),
createHouseSessionAndPriceIntentUseCase = get(),
submitHouseFormAndGetOffersUseCase = get(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import com.hedvig.android.feature.purchase.common.ui.sign.SigningDestination
import com.hedvig.android.feature.purchase.common.ui.sign.SigningViewModel
import com.hedvig.android.feature.purchase.common.ui.summary.PurchaseSummaryDestination
import com.hedvig.android.feature.purchase.common.ui.summary.PurchaseSummaryViewModel
import com.hedvig.android.feature.purchase.house.data.HouseOffers
import com.hedvig.android.feature.purchase.house.navigation.HousePurchaseDestination.Form
import com.hedvig.android.feature.purchase.house.ui.house.HouseFormDestination
import com.hedvig.android.feature.purchase.house.ui.house.HouseFormViewModel
import com.hedvig.android.feature.purchase.house.ui.vacationhome.VacationHomeFormDestination
import com.hedvig.android.feature.purchase.house.ui.vacationhome.VacationHomeFormViewModel
import com.hedvig.android.navigation.compose.navdestination
Expand All @@ -41,13 +44,8 @@ fun NavGraphBuilder.housePurchaseNavGraph(
navdestination<Form> { backStackEntry ->
val graphRoute = navController
.getRouteFromBackStack<HousePurchaseGraphDestination>(backStackEntry)
val viewModel: VacationHomeFormViewModel = koinViewModel {
parametersOf(graphRoute.productName)
}
VacationHomeFormDestination(
viewModel = viewModel,
navigateUp = dropUnlessResumed { popBackStack() },
onOffersReceived = { shopSessionId, offers ->
val onOffersReceivedToSelectTier: (shopSessionId: String, offers: HouseOffers) -> Unit =
{ shopSessionId, offers ->
navController.navigate(
SelectTier(
SelectTierParameters(
Expand All @@ -71,8 +69,30 @@ fun NavGraphBuilder.housePurchaseNavGraph(
),
),
)
},
)
}
when (graphRoute.productName) {
"SE_VACATION_HOME" -> {
val viewModel: VacationHomeFormViewModel = koinViewModel { parametersOf(graphRoute.productName) }
VacationHomeFormDestination(
viewModel = viewModel,
navigateUp = dropUnlessResumed { popBackStack() },
onOffersReceived = onOffersReceivedToSelectTier,
)
}

"SE_HOUSE" -> {
val viewModel: HouseFormViewModel = koinViewModel { parametersOf(graphRoute.productName) }
HouseFormDestination(
viewModel = viewModel,
navigateUp = dropUnlessResumed { popBackStack() },
onOffersReceived = onOffersReceivedToSelectTier,
)
}

else -> {
error("Unknown productName for HousePurchaseGraph: ${graphRoute.productName}")
}
}
}

navdestination<SelectTier>(SelectTier) { backStackEntry ->
Expand Down
Loading
Loading