Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,11 @@ type Agreement {
"""
The cost details of this agreement on today's date or the date it starts
"""
cost: ItemCost!
cost: ItemCost! @deprecated(reason: "Use itemCost instead")
"""
The cost details of this agreement on today's date or the date it starts
"""
itemCost: ItemCost
"""
The date this agreement took effect.
"""
Expand Down Expand Up @@ -999,7 +1003,7 @@ type ClaimIntentStep {
"""
A union of all the different kinds of "step content".
"""
union ClaimIntentStepContent = ClaimIntentStepContentForm|ClaimIntentStepContentSelect|ClaimIntentStepContentTask|ClaimIntentStepContentAudioRecording|ClaimIntentStepContentFileUpload|ClaimIntentStepContentSummary|ClaimIntentStepContentDeflection
union ClaimIntentStepContent = ClaimIntentStepContentForm|ClaimIntentStepContentSelect|ClaimIntentStepContentTask|ClaimIntentStepContentAudioRecording|ClaimIntentStepContentFileUpload|ClaimIntentStepContentSummary|ClaimIntentStepContentDeflection|ClaimIntentStepContentDeflectionMessage
"""
An audio recording step is one where the user is meant to record some audio.
Submitted using `Mutation.claimIntentSubmitAudio`.
Expand Down Expand Up @@ -1041,6 +1045,13 @@ type ClaimIntentStepContentDeflectionInfoBlock {
title: String!
description: String!
}
"""
A minimal variant of a deflection step which only carries a text message - no button.
This is a terminal step - and cannot be submitted.
"""
type ClaimIntentStepContentDeflectionMessage {
message: String!
}
type ClaimIntentStepContentDeflectionPartner {
id: ID!
imageUrl: Url
Expand Down Expand Up @@ -2894,7 +2905,7 @@ type MemberPaymentChargeMethodInfo {
"""
dueDate: Int
"""
Payment provider used for charging the member, eg Trustly or Kivra.
Payment provider used for charging the member, eg Trustly or Invoice.
This is used to determine the charge schedule and mandate provider.
"""
paymentProvider: String!
Expand Down Expand Up @@ -2939,7 +2950,7 @@ type MemberPaymentInformation {
}
type MemberPaymentMethod {
"""
Payment provider, eg Trustly, Swish, Nordea, Kivra etc.
Payment provider, eg Trustly, Swish, Nordea, Invoice etc.
This is used as the "identifier" of the payment method since there can only be one ACTIVE or PENDING payment method
per provider.
"""
Expand Down Expand Up @@ -3015,6 +3026,15 @@ type MemberPaymentMethods {
The date of the month when member's premium will be charged (or due if invoice)
"""
chargingDay: Int
"""
Indicates which payment connection the member is missing, if any. The rule is:
- If member has only QASA-paid agreements, the payin connection is irrelevant and only payout is checked.
Returns PAYOUT if no default payout method exists, else null.
- Otherwise (any non-QASA agreement, e.g. member-paid), payin takes priority:
Returns PAYIN if no default payin method exists, else PAYOUT if no default payout method exists, else null.
- If member has no ongoing (active or future) agreements, returns null.
"""
missingConnection: MissingPaymentConnection
}
enum MemberPaymentMethodStatus {
"""
Expand Down Expand Up @@ -3159,6 +3179,10 @@ type MidtermChangePriceDetailItem {
displayName: String!
displayValue: String!
}
enum MissingPaymentConnection {
PAYIN
PAYOUT
}
"""
A monetary value with currency.
"""
Expand Down Expand Up @@ -3725,7 +3749,7 @@ type Mutation {
Optional `attribution` is merged field-by-field over `ShopSession.attribution` for this confirm only (quotes and
`PriceIntentConfirmed` events use the merged result).
"""
priceIntentConfirm(priceIntentId: UUID!, attribution: PriceIntentConfirmAttributionInput): PriceIntentMutationOutput!
priceIntentConfirm(priceIntentId: UUID!, attribution: PriceIntentConfirmAttributionInput, generateRecommendations: Boolean): 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.
Expand Down Expand Up @@ -3968,7 +3992,11 @@ type PendingContract {
"""
Calculated based on the pending agreement
"""
cost: ItemCost!
cost: ItemCost! @deprecated(reason: "Use itemCost instead")
"""
Calculated based on the pending agreement
"""
itemCost: ItemCost
discountsDetails: ContractDiscountDetails!
"""
Same as `Contract.exposureDisplayName`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import com.hedvig.android.core.buildconstants.HedvigBuildConstants
import com.hedvig.android.core.demomode.DemoManager
import com.hedvig.android.core.demomode.Provider
import com.hedvig.android.core.rive.RiveInitializer
import com.hedvig.android.data.paying.member.GetOnlyHasNonPayingContractsUseCase
import com.hedvig.android.data.settings.datastore.SettingsDataStore
import com.hedvig.android.featureflags.FeatureManager
import com.hedvig.android.language.LanguageLaunchCheckUseCase
Expand Down Expand Up @@ -70,9 +69,6 @@ class MainActivity : AppCompatActivity() {
@Inject
private lateinit var featureManager: FeatureManager

@Inject
private lateinit var getOnlyHasNonPayingContractsUseCase: Provider<GetOnlyHasNonPayingContractsUseCase>

@Inject
private lateinit var hedvigBuildConstants: HedvigBuildConstants

Expand Down Expand Up @@ -206,7 +202,6 @@ class MainActivity : AppCompatActivity() {
deepLinkChannel = deepLinkChannel,
windowSizeClass = windowSizeClass,
settingsDataStore = settingsDataStore,
getOnlyHasNonPayingContractsUseCase = getOnlyHasNonPayingContractsUseCase,
featureManager = featureManager,
splashIsRemovedSignal = splashIsRemovedSignal,
authTokenService = authTokenService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ import com.hedvig.android.core.appreview.WaitUntilAppReviewDialogShouldBeOpenedU
import com.hedvig.android.core.buildconstants.HedvigBuildConstants
import com.hedvig.android.core.demomode.DemoManager
import com.hedvig.android.core.demomode.Provider
import com.hedvig.android.data.paying.member.GetOnlyHasNonPayingContractsUseCase
import com.hedvig.android.data.settings.datastore.SettingsDataStore
import com.hedvig.android.design.system.hedvig.DemoModeLabel
import com.hedvig.android.design.system.hedvig.Surface
Expand Down Expand Up @@ -95,7 +94,6 @@ internal fun HedvigApp(
deepLinkChannel: Channel<String>,
windowSizeClass: WindowSizeClass,
settingsDataStore: SettingsDataStore,
getOnlyHasNonPayingContractsUseCase: Provider<GetOnlyHasNonPayingContractsUseCase>,
featureManager: FeatureManager,
splashIsRemovedSignal: Channel<Unit>,
authTokenService: AuthTokenService,
Expand All @@ -118,7 +116,6 @@ internal fun HedvigApp(
backstackController = backstackController,
windowSizeClass = windowSizeClass,
settingsDataStore = settingsDataStore,
getOnlyHasNonPayingContractsUseCase = getOnlyHasNonPayingContractsUseCase,
featureManager = featureManager,
missedPaymentNotificationServiceProvider = missedPaymentNotificationServiceProvider,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import com.hedvig.android.app.navigation.BackstackController
import com.hedvig.android.core.demomode.Provider
import com.hedvig.android.data.paying.member.GetOnlyHasNonPayingContractsUseCase
import com.hedvig.android.data.settings.datastore.SettingsDataStore
import com.hedvig.android.featureflags.FeatureManager
import com.hedvig.android.featureflags.flags.Feature
Expand All @@ -22,6 +21,7 @@ import com.hedvig.android.navigation.compose.NavigationSuiteType
import com.hedvig.android.notification.badge.data.payment.MissedPaymentNotificationService
import com.hedvig.android.theme.Theme
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.emitAll
Expand All @@ -33,7 +33,6 @@ internal fun rememberHedvigAppState(
backstackController: BackstackController,
windowSizeClass: WindowSizeClass,
settingsDataStore: SettingsDataStore,
getOnlyHasNonPayingContractsUseCase: Provider<GetOnlyHasNonPayingContractsUseCase>,
featureManager: FeatureManager,
missedPaymentNotificationServiceProvider: Provider<MissedPaymentNotificationService>,
coroutineScope: CoroutineScope = rememberCoroutineScope(),
Expand All @@ -43,7 +42,6 @@ internal fun rememberHedvigAppState(
windowSizeClass,
coroutineScope,
settingsDataStore,
getOnlyHasNonPayingContractsUseCase,
featureManager,
missedPaymentNotificationServiceProvider,
) {
Expand All @@ -52,7 +50,6 @@ internal fun rememberHedvigAppState(
windowSizeClass = windowSizeClass,
coroutineScope = coroutineScope,
settingsDataStore = settingsDataStore,
getOnlyHasNonPayingContractsUseCase = getOnlyHasNonPayingContractsUseCase,
featureManager = featureManager,
missedPaymentNotificationServiceProvider = missedPaymentNotificationServiceProvider,
)
Expand All @@ -66,7 +63,6 @@ internal class HedvigAppState(
val windowSizeClass: WindowSizeClass,
coroutineScope: CoroutineScope,
private val settingsDataStore: SettingsDataStore,
getOnlyHasNonPayingContractsUseCase: Provider<GetOnlyHasNonPayingContractsUseCase>,
featureManager: FeatureManager,
missedPaymentNotificationServiceProvider: Provider<MissedPaymentNotificationService>,
) {
Expand Down Expand Up @@ -94,25 +90,11 @@ internal class HedvigAppState(
val isInScreenEligibleForCrossSells: Boolean
get() = backstackController.currentDestination is CrossSellEligibleDestination

val topLevelTabs: StateFlow<Set<TopLevelTab>> = flow {
val onlyHasNonPayingContracts = getOnlyHasNonPayingContractsUseCase.provide().invoke().getOrNull()
emit(
buildList {
add(TopLevelTab.Home)
add(TopLevelTab.Insurances)
if (onlyHasNonPayingContracts != true) {
add(TopLevelTab.Forever)
}
add(TopLevelTab.Payments)
add(TopLevelTab.Profile)
}.toSet(),
)
}.stateIn(
coroutineScope,
SharingStarted.Eagerly,
val topLevelTabs: StateFlow<Set<TopLevelTab>> = MutableStateFlow(
setOf(
TopLevelTab.Home,
TopLevelTab.Insurances,
TopLevelTab.Forever,
TopLevelTab.Payments,
TopLevelTab.Profile,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ enum class ContractType {
SE_GROUP_APARTMENT_RENT,
SE_QASA_LONG_TERM_RENTAL,
SE_QASA_SHORT_TERM_RENTAL,

SE_QASA_LANDLORD,
NO_HOME_CONTENT_YOUTH_RENT,
NO_HOME_CONTENT_YOUTH_OWN,
DK_HOME_CONTENT_STUDENT_OWN,
Expand Down Expand Up @@ -132,6 +134,7 @@ fun ContractType.isTrialContract() = when (this) {
SE_DOG_PREMIUM,
SE_DOG_STANDARD,
UNKNOWN,
ContractType.SE_QASA_LANDLORD
-> false

SE_CAR_TRIAL_FULL,
Expand Down Expand Up @@ -162,6 +165,7 @@ fun String.toContractType(): ContractType = when (this) {
"SE_GROUP_APARTMENT_RENT" -> SE_GROUP_APARTMENT_RENT
"SE_QASA_LONG_TERM_RENTAL" -> SE_QASA_LONG_TERM_RENTAL
"SE_QASA_SHORT_TERM_RENTAL" -> SE_QASA_SHORT_TERM_RENTAL
"SE_QASA_LANDLORD" -> ContractType.SE_QASA_LANDLORD
"NO_HOME_CONTENT_YOUTH_RENT" -> NO_HOME_CONTENT_YOUTH_RENT
"NO_HOME_CONTENT_YOUTH_OWN" -> NO_HOME_CONTENT_YOUTH_OWN
"DK_HOME_CONTENT_STUDENT_OWN" -> DK_HOME_CONTENT_STUDENT_OWN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,12 @@ query ActiveInsuranceContractTypes {
}
}
}
terminatedContracts {
currentAgreement {
productVariant {
typeOfContract
}
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.hedvig.android.data.paying.member

import arrow.core.Either
import arrow.core.raise.either
import arrow.core.right
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.core.common.di.AppScope
import com.hedvig.android.core.demomode.DemoManager
import com.hedvig.android.core.demomode.ProdOrDemoProvider
import com.hedvig.android.core.demomode.Provider
import com.hedvig.android.data.contract.ContractType
import com.hedvig.android.data.contract.toContractType
import com.hedvig.android.logger.logcat
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import dev.zacsweers.metro.binding
import octopus.ActiveInsuranceContractTypesQuery

interface GetMemberTypeUseCase {
suspend fun invoke(): Either<ErrorMessage, MemberType>
}

enum class MemberType {
QASA_ONLY_MEMBER,

// in Payments: hide discounts, payment history, member payment details,
// in Payments: always show payout account;
// in Payments: show connect payout reminder if missing
// HelpCenter: hide Payments section
STANDARD_MEMBER,

// current logic
STANDARD_TO_QASA_MEMBER
// in Payments: if no upcoming payments: hide discounts and member payment details
// in Payments: if upcoming payment and missing payin: show connect payin reminder,
// else show connect payout reminder if missing
// in Payments: always show payout account;
}

@Inject
@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class, binding<Provider<GetMemberTypeUseCase>>())
internal class GetMemberTypeUseCaseProvider(
override val demoManager: DemoManager,
override val demoImpl: GetMemberTypeUseCaseDemo,
override val prodImpl: GetMemberTypeUseCaseImpl,
) : ProdOrDemoProvider<GetMemberTypeUseCase>

@SingleIn(AppScope::class)
@Inject
internal class GetMemberTypeUseCaseImpl(
private val apolloClient: ApolloClient,
) : GetMemberTypeUseCase {
override suspend fun invoke(): Either<ErrorMessage, MemberType> {
return either {
val result = apolloClient.query(ActiveInsuranceContractTypesQuery())
.safeExecute(::ErrorMessage)
.bind()
val activeContractsTypes = result.currentMember
.activeContracts
.map { it.currentAgreement.productVariant.typeOfContract.toContractType() }
val terminatedContractsTypes = result.currentMember
.terminatedContracts
.map { it.currentAgreement.productVariant.typeOfContract.toContractType() }

val onlyQasaContracts = (activeContractsTypes.isNotEmpty()
|| terminatedContractsTypes.isNotEmpty()) &&
activeContractsTypes.all { it == ContractType.SE_QASA_LANDLORD } &&
terminatedContractsTypes.all { it == ContractType.SE_QASA_LANDLORD }
if (onlyQasaContracts) return@either MemberType.QASA_ONLY_MEMBER

val standardToQasa = activeContractsTypes.isNotEmpty() &&
activeContractsTypes.all { it == ContractType.SE_QASA_LANDLORD } &&
terminatedContractsTypes.any { it != ContractType.SE_QASA_LANDLORD }
if (standardToQasa) return@either MemberType.STANDARD_TO_QASA_MEMBER

MemberType.STANDARD_MEMBER
}
}
}

@SingleIn(AppScope::class)
@Inject
internal class GetMemberTypeUseCaseDemo : GetMemberTypeUseCase {
override suspend fun invoke(): Either<ErrorMessage, MemberType> {
return MemberType.STANDARD_MEMBER.right()
}
}

This file was deleted.

Loading
Loading