Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/feature/feature-home/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies {
implementation(projects.coreDemoMode)
implementation(projects.coreMarkdown)
implementation(projects.coreResources)
implementation(projects.coreUiData)
implementation(projects.crossSells)
implementation(projects.dataAddons)
implementation(projects.dataClaimIntent)
Expand Down
15 changes: 15 additions & 0 deletions app/feature/feature-home/src/main/graphql/QueryHome.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@ query Home($claimsHistoryFlag: Boolean!, $resumeClaimEnabled: Boolean!) {
}
}
}
ongoingShopSessions {
id
display {
title
subtitle
monthlyNet {
amount
currencyCode
}
resumeUrl
pillowImage {
src
}
}
}
memberActions {
firstVetAction {
sections {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ 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.core.uidata.UiCurrencyCode
import com.hedvig.android.core.uidata.UiMoney
import com.hedvig.android.crosssells.BundleProgress
import com.hedvig.android.crosssells.CrossSellSheetData
import com.hedvig.android.crosssells.RecommendedAddon
Expand Down Expand Up @@ -67,8 +69,12 @@ internal class GetHomeDataUseCaseImpl(
) : GetHomeDataUseCase {
@OptIn(ExperimentalCoroutinesApi::class)
override fun invoke(forceNetworkFetch: Boolean): Flow<Either<ApolloOperationError, HomeData>> {
return featureManager.isFeatureEnabled(Feature.ENABLE_CLAIM_INTENT_RESUME)
.flatMapLatest { resumeClaimEnabled ->
return combine(
featureManager.isFeatureEnabled(Feature.ENABLE_CLAIM_INTENT_RESUME),
featureManager.isFeatureEnabled(Feature.DISABLE_RESUMING_ONGOING_SHOP_SESSIONS),
::Pair,
)
.flatMapLatest { (resumeClaimEnabled, disableShopSessions) ->
combine(
apolloClient.query(HomeQuery(true, resumeClaimEnabled))
.fetchPolicy(if (forceNetworkFetch) FetchPolicy.NetworkOnly else FetchPolicy.CacheAndNetwork)
Expand Down Expand Up @@ -148,6 +154,22 @@ internal class GetHomeDataUseCaseImpl(
val otherCrossSellsData = crossSellsData.otherCrossSells.map {
it.toCrossSell()
}
val ongoingShopSessions = if (disableShopSessions) {
emptyList()
} else {
homeQueryData.currentMember.ongoingShopSessions.map { session ->
OngoingShopSession(
id = session.id,
title = session.display.title,
subtitle = session.display.subtitle,
monthlyNet = session.display.monthlyNet?.let {
UiMoney(it.amount, UiCurrencyCode.fromCurrencyCode(it.currencyCode))
},
resumeUrl = session.display.resumeUrl,
pillowImageUrl = session.display.pillowImage?.src,
)
}
}
val recommendedAddon = crossSellsData.recommendedAddon?.let {
RecommendedAddon(
id = it.id,
Expand Down Expand Up @@ -202,6 +224,7 @@ internal class GetHomeDataUseCaseImpl(
showHelpCenter = true,
firstVetSections = firstVetActions,
crossSells = crossSells,
ongoingShopSessions = ongoingShopSessions,
addonBannerInfos = travelBannerInfo.orEmpty(),
showChatIcon = showChatIcon,
firstName = homeQueryData.currentMember.firstName,
Expand Down Expand Up @@ -310,6 +333,15 @@ private fun HomeQuery.Data.claimStatusCards(): HomeData.ClaimStatusCardsData? {
)
}

data class OngoingShopSession(
val id: String,
val title: String,
val subtitle: String?,
val monthlyNet: UiMoney?,
val resumeUrl: String,
val pillowImageUrl: String?,
)

data class HomeData(
val contractStatus: ContractStatus,
val claimStatusCardsData: ClaimStatusCardsData?,
Expand All @@ -321,6 +353,8 @@ data class HomeData(
val firstVetSections: List<FirstVetSection>,
val crossSells: CrossSellSheetData,
val addonBannerInfos: List<AddonBannerInfo>,
// Defaulted only so test/demo construction sites stay terse.
val ongoingShopSessions: List<OngoingShopSession> = emptyList(),
// Always populated from the backend; defaulted only so test/demo construction sites stay terse.
val firstName: String = "",
val draftClaim: DraftClaim?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.hedvig.android.feature.home.home.data
import arrow.core.Either
import arrow.core.right
import com.hedvig.android.apollo.ApolloOperationError
import com.hedvig.android.core.uidata.UiCurrencyCode
import com.hedvig.android.core.uidata.UiMoney
import com.hedvig.android.crosssells.CrossSellSheetData
import com.hedvig.android.crosssells.RecommendedCrossSell
import com.hedvig.android.data.contract.CrossSell
Expand Down Expand Up @@ -55,6 +57,16 @@ internal class GetHomeDataUseCaseDemo : GetHomeDataUseCase {
),
recommendedAddon = null,
),
ongoingShopSessions = listOf(
OngoingShopSession(
id = "demo-session-1",
title = "Home + Accident",
subtitle = "Studio apartment, Stockholm",
monthlyNet = UiMoney(199.0, UiCurrencyCode.SEK),
resumeUrl = "https://www.hedvig.com",
pillowImageUrl = null,
),
),
addonBannerInfos = emptyList(),
showChatIcon = false,
firstName = "Demo",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ import com.hedvig.android.feature.home.home.data.HomeData.ClaimStatusCardsData
import com.hedvig.android.feature.home.home.data.HomeData.DraftClaim
import com.hedvig.android.feature.home.home.data.HomeData.VeryImportantMessage
import com.hedvig.android.feature.home.home.data.HomeData.VeryImportantMessage.LinkInfo
import com.hedvig.android.feature.home.home.data.OngoingShopSession
import com.hedvig.android.feature.home.home.ui.HomeText.Active
import com.hedvig.android.feature.home.home.ui.HomeTopBarAction.ChatAction
import com.hedvig.android.feature.home.home.ui.HomeTopBarAction.CrossSellsAction
Expand Down Expand Up @@ -205,6 +206,7 @@ import hedvig.resources.Res
import hedvig.resources.TOAST_NEW_OFFER
import hedvig.resources.blur_background
import hedvig.resources.general_cancel_button
import hedvig.resources.general_continue_button
import hedvig.resources.home_tab_claim_button_text
import hedvig.resources.home_tab_get_help
import hedvig.resources.home_tab_welcome_title_without_name
Expand Down Expand Up @@ -660,8 +662,8 @@ private fun HomeScreenSuccess(
applicableReminders.homeActionRequiredReminders().isNotEmpty()
}

HomeSection.Offers -> {
uiState.crossSellsPartition.offersCrossSell != null
HomeSection.Quotes -> {
uiState.ongoingShopSessions.isNotEmpty()
}

HomeSection.DiscoverInsurances -> {
Expand Down Expand Up @@ -888,10 +890,10 @@ private fun HomeScreenSuccess(
horizontalInsets = horizontalInsets,
)

HomeSection.Offers -> uiState.crossSellsPartition.offersCrossSell?.let { recommended ->
OffersSection(
recommendedCrossSell = recommended,
onCrossSellClick = openCrossSellUrl,
HomeSection.Quotes -> uiState.ongoingShopSessions.takeIf { it.isNotEmpty() }?.let { sessions ->
QuotesSection(
sessions = sessions,
onResumeClick = openUrl,
imageLoader = imageLoader,
horizontalInsets = horizontalInsets,
)
Expand Down Expand Up @@ -971,7 +973,7 @@ private enum class HomeSection {
ClaimStatusCards,
VeryImportantMessages,
MemberReminders,
Offers,
Quotes,
DiscoverInsurances,
Addons,
QuickActionTiles,
Expand All @@ -984,7 +986,7 @@ private val homeSectionOrder: List<HomeSection> = listOf(
HomeSection.ClaimStatusCards,
HomeSection.VeryImportantMessages,
HomeSection.MemberReminders,
HomeSection.Offers,
HomeSection.Quotes,
HomeSection.QuickActionTiles,
HomeSection.DiscoverInsurances,
HomeSection.Addons,
Expand Down Expand Up @@ -1099,13 +1101,12 @@ private fun MemberRemindersSection(
}

@Composable
private fun OffersSection(
recommendedCrossSell: RecommendedCrossSell,
onCrossSellClick: (String) -> Unit,
private fun QuotesSection(
sessions: List<OngoingShopSession>,
onResumeClick: (String) -> Unit,
imageLoader: ImageLoader,
horizontalInsets: PaddingValues,
) {
val crossSell = recommendedCrossSell.crossSell
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
Expand All @@ -1118,52 +1119,50 @@ private fun OffersSection(
style = HedvigTheme.typography.headlineSmall,
modifier = Modifier.semantics { heading() },
)
HedvigCard(
onClick = { onCrossSellClick(crossSell.storeUrl) },
color = HedvigTheme.colorScheme.fillNegative,
borderColor = HedvigTheme.colorScheme.borderPrimary,
modifier = Modifier
.fillMaxWidth()
.hedvigDropShadow(HedvigTheme.shapes.cornerXLarge),
) {
Column(Modifier.padding(16.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(
model = crossSell.pillowImage.src,
contentDescription = null,
imageLoader = imageLoader,
contentScale = ContentScale.Fit,
modifier = Modifier.size(48.dp),
)
Spacer(Modifier.width(12.dp))
Column(Modifier.weight(1f)) {
HedvigText(text = crossSell.title, style = HedvigTheme.typography.bodySmall)
HedvigText(
text = recommendedCrossSell.bannerText,
style = HedvigTheme.typography.label,
color = HedvigTheme.colorScheme.textSecondary,
)
}
val discountText = recommendedCrossSell.discountText
if (discountText != null) {
Spacer(Modifier.width(8.dp))
HighlightLabel(
labelText = discountText,
size = HighlightLabelDefaults.HighLightSize.Small,
color = HighlightLabelDefaults.HighlightColor.Green(HighlightLabelDefaults.HighlightShade.LIGHT),
)
for (session in sessions) {
HedvigCard(
onClick = { onResumeClick(session.resumeUrl) },
color = HedvigTheme.colorScheme.fillNegative,
borderColor = HedvigTheme.colorScheme.borderPrimary,
modifier = Modifier
.fillMaxWidth()
.hedvigDropShadow(HedvigTheme.shapes.cornerXLarge),
) {
Column(Modifier.padding(16.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
if (session.pillowImageUrl != null) {
AsyncImage(
model = session.pillowImageUrl,
contentDescription = null,
imageLoader = imageLoader,
contentScale = ContentScale.Fit,
modifier = Modifier.size(48.dp),
)
Spacer(Modifier.width(12.dp))
}
Column(Modifier.weight(1f)) {
HedvigText(text = session.title, style = HedvigTheme.typography.bodySmall)
val secondary = session.subtitle ?: session.monthlyNet?.toString()
if (secondary != null) {
HedvigText(
text = secondary,
style = HedvigTheme.typography.label,
color = HedvigTheme.colorScheme.textSecondary,
)
}
}
}
Spacer(Modifier.height(12.dp))
HedvigButton(
text = stringResource(Res.string.general_continue_button),
onClick = { onResumeClick(session.resumeUrl) },
buttonStyle = Secondary,
buttonSize = ButtonSize.Medium,
enabled = true,
shape = HedvigTheme.shapes.cornerFull,
modifier = Modifier.fillMaxWidth(),
)
}
Spacer(Modifier.height(12.dp))
HedvigButton(
text = recommendedCrossSell.buttonText,
onClick = { onCrossSellClick(crossSell.storeUrl) },
buttonStyle = Secondary,
buttonSize = ButtonSize.Medium,
enabled = true,
shape = HedvigTheme.shapes.cornerFull,
modifier = Modifier.fillMaxWidth(),
)
}
}
}
Expand Down Expand Up @@ -1477,23 +1476,18 @@ private fun PreviewHomeScreen(
quickActions = previewQuickActions,
hasUnseenChatMessages = hasUnseenChatMessages,
crossSellsPartition = CrossSellsPartition(
offersCrossSell = RecommendedCrossSell(
crossSell = CrossSell(
id = "car",
title = "Car Insurance",
subtitle = "For you and your car",
storeUrl = "",
pillowImage = ImageAsset("", "", ""),
),
bannerText = "15% bundle discount",
buttonText = "See your price",
discountText = "-15%",
buttonDescription = "",
backgroundPillowImages = "" to "",
bundleProgress = null,
),
discoverCrossSells = emptyList(),
),
ongoingShopSessions = listOf(
OngoingShopSession(
id = "preview-1",
title = "Home + Accident",
subtitle = "Studio apartment, Stockholm",
monthlyNet = null,
resumeUrl = "",
pillowImageUrl = null,
),
),
crossSellsAction = CrossSellsAction(
CrossSellSheetData(
recommendedCrossSell = RecommendedCrossSell(
Expand Down
Loading
Loading