Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
97ee458
add manual charge button
panasetskaya Apr 16, 2026
ee6b114
add allowManualCharge
panasetskaya Apr 20, 2026
86e1119
add feature flag ENABLE_MANUAL_CHARGE
panasetskaya Apr 22, 2026
7e639b4
fix ui with new api
panasetskaya Apr 22, 2026
4f63c78
add box
panasetskaya Apr 23, 2026
226d3ff
fux box border and padding
panasetskaya Apr 23, 2026
a62c86f
ManualChargeScreen WIP
panasetskaya Apr 24, 2026
53a3339
ManualChargeScreen and string in PaymentsDestination
panasetskaya Apr 24, 2026
3f8a736
add GetManualChargeInfoUseCase and strings
panasetskaya Apr 24, 2026
a031271
adjust to new api
panasetskaya Apr 28, 2026
3d0e312
new schema
panasetskaya Apr 28, 2026
157ecf2
impl red dot wip
panasetskaya Apr 28, 2026
9c6c90b
impl red dot; change api; success
panasetskaya Apr 29, 2026
d0252c7
Merge branch 'develop' into feat/manual-charge
panasetskaya Apr 29, 2026
b2142ef
change api
panasetskaya Apr 29, 2026
25bab3b
Merge remote-tracking branch 'origin/feat/manual-charge' into feat/ma…
panasetskaya Apr 29, 2026
18bd31f
Merge branch 'develop' into feat/manual-charge
panasetskaya May 6, 2026
242d4c8
finish merging
panasetskaya May 6, 2026
164e905
finish merging
panasetskaya May 6, 2026
fdb56b5
add cancellation warning
panasetskaya May 6, 2026
e707598
fix previews
panasetskaya May 6, 2026
69394e3
fix no ongoing text
panasetskaya May 6, 2026
4d52c77
change userError message and button
panasetskaya May 6, 2026
904ab30
publ to staging
panasetskaya May 8, 2026
c04d288
change manual card display items
panasetskaya May 8, 2026
443a61d
Merge branch 'develop' into feat/manual-charge
panasetskaya May 8, 2026
b21d0a6
add feature flag back
panasetskaya May 8, 2026
733012a
missing imports and strings
panasetskaya May 8, 2026
0e5eb03
break from loop if first false
panasetskaya May 8, 2026
a02131b
remove todo
panasetskaya May 8, 2026
ed810c3
logs
panasetskaya May 8, 2026
b781255
rename MemberPaymentChargeMethod.Kivra to invoice
panasetskaya May 8, 2026
f75c1fd
add one more ff with include
panasetskaya May 8, 2026
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 .github/workflows/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- develop
- feat/manual-charge
workflow_dispatch:

concurrency:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,11 @@ type Member {
"""
crossSellV2(input: CrossSellInput!): CrossSellV2!
"""
Young Pet Guide stories for the member.
Returns a list of educational content stories for young pet owners.
"""
puppyGuideStories: [PuppyGuideStory!]!
"""
Fetch all the active contracts for this member. Active contracts include all insurances that are either
active today, or to-be-active in the future.
"""
Expand Down Expand Up @@ -3650,8 +3655,10 @@ type Mutation {
"""
Confirm this PriceIntent, which will use the current data (and likely `ShopSession.customer`) to generate
`ProductOffers` that can be added to the cart.
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!): PriceIntentMutationOutput!
priceIntentConfirm(priceIntentId: UUID!, attribution: PriceIntentConfirmAttributionInput): 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 All @@ -3673,6 +3680,10 @@ type Mutation {
"""
productOfferReprice(offerId: UUID!, data: PricingFormData!): ProductOffersMutationOutput!
"""
Mark a young pet guide story as read for a specific member.
"""
puppyGuideEngagement(engagement: PuppyEngagementInput!): PuppyGuideStoryMutationOutput!
"""
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,
Expand Down Expand Up @@ -4015,6 +4026,36 @@ type PriceIntentAnimalBreed {
displayName: String!
isMixedBreed: Boolean!
}
"""
Attribution values to apply when confirming a PriceIntent.
Provided fields override the ShopSession attribution for this confirmation only.
"""
input PriceIntentConfirmAttributionInput {
"""
Party credited for originating the flow, such as a partner, Hedvig, or marketing source.
"""
attributedTo: String
"""
Channel or surface where the flow was initiated.
"""
initiatedFrom: String
"""
High-level business flow used for attribution and analytics.
"""
userFlow: String
"""
More specific source within the user flow, when applicable.
"""
flowSource: String
"""
Experiment variants active when the price intent was confirmed.
"""
experiments: [ShopSessionExperimentInput!]
"""
Additional attribution metadata passed through for analytics integrations.
"""
trackingData: JSON
}
input PriceIntentCreateInput {
shopSessionId: UUID!
"""
Expand Down Expand Up @@ -4404,6 +4445,53 @@ type ProductVariantComparisonRow {
"""
covered: [String!]!
}
input PuppyEngagementInput {
name: String!
rating: Int
opened: Boolean
read: Boolean
closed: Boolean
}
type PuppyGuideStory {
"""
The unique name/identifier of the story.
"""
name: String!
"""
The display title of the story.
"""
title: String!
"""
The subtitle or description of the story.
"""
subtitle: String!
"""
The main content of the story.
"""
content: String!
"""
The image associated with this story.
"""
image: String!
"""
Categories this story belongs to.
"""
categories: [String!]!
"""
The date when the story was marked as read by the user.
"""
read: Boolean!
"""
The user's rating of the story.
"""
rating: Int
}
type PuppyGuideStoryMutationOutput {
"""
Indicates whether the mutation was successful.
"""
success: Boolean!
}
type Query {
"""
Return a conversation for a given ID.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import com.hedvig.android.logger.LogPriority
import com.hedvig.android.logger.logcat
import com.hedvig.android.navigation.core.HedvigDeepLinkContainer
import com.hedvig.android.navigation.core.allDeepLinkUriPatterns
import com.hedvig.android.notification.badge.data.payment.MissedPaymentNotificationServiceProvider
import com.hedvig.android.theme.Theme
import com.stylianosgakis.navigation.recents.url.sharing.provideAssistContent
import java.util.Locale
Expand Down Expand Up @@ -74,6 +75,7 @@ class MainActivity : AppCompatActivity() {

private val logoutUseCase: LogoutUseCase by inject()
private val getMemberAuthorizationCodeUseCase: GetMemberAuthorizationCodeUseCase by inject()
private val missedPaymentNotificationServiceProvider: MissedPaymentNotificationServiceProvider by inject()

private var navController: NavController? = null

Expand Down Expand Up @@ -164,6 +166,7 @@ class MainActivity : AppCompatActivity() {
externalNavigator = externalNavigator,
logoutUseCase = logoutUseCase,
getMemberAuthorizationCodeUseCase = getMemberAuthorizationCodeUseCase,
missedPaymentNotificationServiceProvider = missedPaymentNotificationServiceProvider,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ internal fun HedvigNavHost(
navigateToPayoutAccount = { navController.navigate(PayoutAccountDestination.Graph) },
languageService = languageService,
hedvigBuildConstants = hedvigBuildConstants,
openConversation = {
navigateToNewConversation()
}
)
payoutAccountGraph(
navController = navController,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ 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.feature.cross.sell.sheet.CrossSellSheet
import com.hedvig.android.notification.badge.data.payment.MissedPaymentNotificationServiceProvider
import com.hedvig.android.feature.login.navigation.LoginDestination
import com.hedvig.android.featureflags.FeatureManager
import com.hedvig.android.language.LanguageService
Expand Down Expand Up @@ -84,13 +85,15 @@ internal fun HedvigApp(
externalNavigator: ExternalNavigator,
logoutUseCase: LogoutUseCase,
getMemberAuthorizationCodeUseCase: GetMemberAuthorizationCodeUseCase,
missedPaymentNotificationServiceProvider: MissedPaymentNotificationServiceProvider,
) {
val hedvigAppState = rememberHedvigAppState(
windowSizeClass = windowSizeClass,
settingsDataStore = settingsDataStore,
getOnlyHasNonPayingContractsUseCase = getOnlyHasNonPayingContractsUseCase,
featureManager = featureManager,
navHostController = navHostController,
missedPaymentNotificationServiceProvider = missedPaymentNotificationServiceProvider,
)
val darkTheme = hedvigAppState.darkTheme
HedvigTheme(darkTheme = darkTheme) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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.feature.forever.navigation.ForeverDestination
import com.hedvig.android.notification.badge.data.payment.MissedPaymentNotificationServiceProvider
import com.hedvig.android.feature.help.center.navigation.helpCenterCrossSellBottomSheetPermittingDestinations
import com.hedvig.android.feature.home.home.navigation.HomeDestination
import com.hedvig.android.feature.home.home.navigation.homeCrossSellBottomSheetPermittingDestinations
Expand Down Expand Up @@ -62,6 +63,7 @@ internal fun rememberHedvigAppState(
getOnlyHasNonPayingContractsUseCase: Provider<GetOnlyHasNonPayingContractsUseCase>,
featureManager: FeatureManager,
navHostController: NavHostController,
missedPaymentNotificationServiceProvider: MissedPaymentNotificationServiceProvider,
coroutineScope: CoroutineScope = rememberCoroutineScope(),
): HedvigAppState {
NavigationViewTrackingEffect(navController = navHostController)
Expand All @@ -73,6 +75,7 @@ internal fun rememberHedvigAppState(
settingsDataStore,
getOnlyHasNonPayingContractsUseCase,
featureManager,
missedPaymentNotificationServiceProvider,
) {
HedvigAppState(
navController = navHostController,
Expand All @@ -81,6 +84,7 @@ internal fun rememberHedvigAppState(
settingsDataStore = settingsDataStore,
getOnlyHasNonPayingContractsUseCase = getOnlyHasNonPayingContractsUseCase,
featureManager = featureManager,
missedPaymentNotificationServiceProvider = missedPaymentNotificationServiceProvider,
)
}
}
Expand All @@ -93,6 +97,7 @@ internal class HedvigAppState(
private val settingsDataStore: SettingsDataStore,
getOnlyHasNonPayingContractsUseCase: Provider<GetOnlyHasNonPayingContractsUseCase>,
featureManager: FeatureManager,
missedPaymentNotificationServiceProvider: MissedPaymentNotificationServiceProvider,
) {
val currentDestination: NavDestination?
@Composable get() = navController.currentBackStackEntryAsState().value?.destination
Expand Down Expand Up @@ -162,6 +167,15 @@ internal class HedvigAppState(
),
)

val showPaymentsBadge: StateFlow<Boolean> = missedPaymentNotificationServiceProvider
.prodImpl
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we here just use provide to get the appropriate impl for if we're in demo mode or not?

.showRedDotNotification()
.stateIn(
coroutineScope,
SharingStarted.WhileSubscribed(5_000),
false,
)

/**
* UI logic for navigating to a top level destination in the app. Top level destinations have
* only one copy of the destination of the back stack, and save and restore state whenever you
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.hedvig.android.design.system.hedvig.tokens.MotionTokens
import com.hedvig.android.language.LanguageService
import com.hedvig.android.navigation.activity.ExternalNavigator
import com.hedvig.android.navigation.core.HedvigDeepLinkContainer
import com.hedvig.android.navigation.core.TopLevelGraph
import hedvig.resources.EXIT_DEMO_MODE_BUTTON
import hedvig.resources.Res
import org.jetbrains.compose.resources.stringResource
Expand All @@ -65,6 +66,7 @@ internal fun HedvigAppUi(
logoutUseCase: LogoutUseCase,
) {
val isDemoMode by demoManager.isDemoMode().collectAsState(false)
val showPaymentsBadge by hedvigAppState.showPaymentsBadge.collectAsState()
val globalSnackBarState = rememberGlobalSnackBarState()
Box(Modifier.fillMaxSize()) {
Surface(
Expand All @@ -76,6 +78,9 @@ internal fun HedvigAppUi(
topLevelGraphs = hedvigAppState.topLevelGraphs.collectAsState().value,
currentDestination = hedvigAppState.currentDestination,
onNavigateToTopLevelGraph = hedvigAppState::navigateToTopLevelGraph,
getShowNotificationBadge = { graph ->
if (graph == TopLevelGraph.Payments) showPaymentsBadge else false
},
) {
Box(
propagateMinConstraints = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal fun NavigationSuite(
currentDestination: NavDestination?,
onNavigateToTopLevelGraph: (TopLevelGraph) -> Unit,
modifier: Modifier = Modifier,
getShowNotificationBadge: (TopLevelGraph) -> Boolean = { false },
content: @Composable RowScope.() -> Unit,
) {
Column(modifier) {
Expand All @@ -49,6 +50,7 @@ internal fun NavigationSuite(
onNavigateToDestination = onNavigateToTopLevelGraph,
getIsCurrentlySelected = currentDestination::isTopLevelGraphInHierarchy,
isExtraTall = navigationSuiteType == NavigationSuiteType.NavigationRailXLarge,
getShowNotificationBadge = getShowNotificationBadge,
)
}
content()
Expand All @@ -62,6 +64,7 @@ internal fun NavigationSuite(
destinations = topLevelGraphs,
onNavigateToDestination = onNavigateToTopLevelGraph,
getIsCurrentlySelected = currentDestination::isTopLevelGraphInHierarchy,
getShowNotificationBadge = getShowNotificationBadge,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@
<string name="LETTER_TO_EIR_SUBJECT">Fråga angående skadeanmälan - Fordon reg. %1$s</string>
<string name="LOGIN_MARKET_PICKER_PREFERENCES">Välj land och språk</string>
<string name="LOGOUT_BUTTON">Logga ut</string>
<string name="MANUAL_CHARGE_CANCELLATION_WARNING">Aktivera ditt försäkringsskydd igen genom att kontakta oss när din betalning har registrerats</string>
<string name="MARKETING_GET_HEDVIG">Få ett prisförslag</string>
<string name="MISSING_CONTACT_INFO_CARD_BUTTON">Se över kontaktuppgifter</string>
<string name="MISSING_CONTACT_INFO_CARD_TEXT">Se till att vi har rätt kontaktuppgifter ifall vi behöver nå dig.</string>
Expand Down Expand Up @@ -609,7 +610,7 @@
<string name="PAYMENTS_PAYMENT_FAILED">Denna betalning misslyckades och lades till i din betalning den %1$s .</string>
<string name="PAYMENTS_PAYMENT_HISTORY_BUTTON_LABEL">Betalningshistorik</string>
<string name="PAYMENTS_PAYMENT_IN_PROGRESS">Betalning pågår</string>
<string name="PAYMENTS_PAYMENT_IN_PROGRESS_DESCRIPTION">Det kan ta upp till 5 bankdagar innan betalningen syns</string>
<string name="PAYMENTS_PAYMENT_IN_PROGRESS_DESCRIPTION">Det kan ta upp till 5 bankdagar innan betalningen registreras</string>
<string name="PAYMENTS_PAYMENT_METHOD">Betalningssätt</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_AMOUNT_DUE">Att betala: %1$s</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_BODY">Vi kunde inte dra betalningen från ditt bankkonto. Betala för att undvika avbrott i ditt skydd.</string>
Expand All @@ -620,6 +621,8 @@
<string name="PAYMENTS_PAYMENT_OVERDUE_DETAILS_PAY">Betala %1$s</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_DETAILS_SINCE">Försenad sedan %1$s</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_DETAILS_VIEW_DETAILS">Visa betalningsdetaljer</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_MISSING_SUBTITLE">Inga försenade betalningar</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_MISSING_TITLE">Allt är betalt</string>
<string name="PAYMENTS_PAYMENT_OVERDUE_TITLE">Försenad betalning</string>
<string name="PAYMENTS_PAYMENT_SUCCESSFUL">Betalning genomförd</string>
<string name="PAYMENTS_PERIOD_DAYS">%1$s dagar</string>
Expand Down Expand Up @@ -709,6 +712,7 @@
<string name="SEARCH_PLACEHOLDER">Sök</string>
<string name="SELECT_INSURANCE_TO_REMOVE_ADDON_DESCRIPTION">Välj den försäkring du vill uppdatera</string>
<string name="SELECT_INSURANCE_TO_REMOVE_ADDON_TITLE">Select insurance</string>
<string name="SELF_MANUAL_CHARGE_CHANGES_BEEN_MADE_TITLE">Betalningen kan inte genomföras</string>
<string name="SETTINGS_LANGUAGE_TITLE">Språk</string>
<string name="SETTINGS_LOGIN_ROW">Logga in</string>
<string name="SETTINGS_NOTIFICATIONS_TITLE">Notiser</string>
Expand Down Expand Up @@ -1025,9 +1029,9 @@
<string name="claim_status_being_handled_support_text">Din skadeanmälan granskas av en av våra försäkringsspecialister. Vi hör av oss snart med en uppdatering.</string>
<string name="claim_status_being_handled_reopened_support_text">Vi har återöppnat din skadeanmälan och en av våra försäkringsspecialister granskar den. Vi hör av oss snart med en uppdatering.</string>
<string name="claim_status_claim_details_button">Se detaljer</string>
<string name="claim_status_claim_details_exposure_display_name">Reg nr</string>
<string name="claim_status_claim_details_exposure_display_name">Registreringsnummer</string>
<string name="claim_status_claim_details_external_id">Ärendenummer</string>
<string name="claim_status_claim_details_handler_email">E-mail</string>
<string name="claim_status_claim_details_handler_email">Mail för ärende</string>
<string name="claim_status_claim_details_info_text">Saknas något? Skicka ett meddelande till oss här i appen.</string>
<string name="claim_status_claim_details_submitted">Inskickad</string>
<string name="claim_status_claim_details_title">Detaljer om skadeanmälan</string>
Expand All @@ -1037,7 +1041,7 @@
<string name="claim_status_not_compensated_support_text">Din skada täcks, men tyvärr är ersättningen lika stor eller mindre än självrisken. Se konversation för mer information.</string>
<string name="claim_status_not_covered_support_text">Tyvärr täcks inte din skada. Se konversation för mer information om beslutet.</string>
<string name="claim_status_paid_support_text_short">Din skada har täckts. Du borde ha fått ersättningen utbetald vid det här laget.</string>
<string name="claim_status_partner_support_text">Den här skadan hanteras av vår externa partner Eir via mail.\nRedan i kontakt med dem? Svara i din befintliga mailtråd så att all skadeinformation hålls samlad i en och samma konversation.</string>
<string name="claim_status_partner_support_text">Våra bilspecialister på Eir hanterar din skadeanmälan via mail.\n\nNär de har gått igenom ärendet får du en bekräftelse via mail. Behöver du komma i kontakt kring din anmälan, svara i samma e-posttråd.</string>
<string name="claim_status_submitted_support_text">Vi har tagit emot din skadeanmälan och kommer snart att börja granska den.</string>
<string name="claim_status_uploaded_files_upload_text">Ladda upp foton, kvitton eller andra dokument kopplade till din skadeanmälan</string>
<string name="claim_status_appeal_instruction_link_text">Besvärshänvisning</string>
Expand Down
Loading
Loading