Skip to content

Commit 9e1c4ce

Browse files
refactor: navigation after transfers, update, withdraw, (#2954)
1 parent bd78ece commit 9e1c4ce

File tree

16 files changed

+198
-68
lines changed

16 files changed

+198
-68
lines changed

cmp-navigation/src/commonMain/kotlin/cmp/navigation/authenticated/AuthenticatedNavigation.kt

Lines changed: 126 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@ package cmp.navigation.authenticated
1414
import androidx.navigation.NavController
1515
import androidx.navigation.NavGraphBuilder
1616
import androidx.navigation.NavOptions
17+
import androidx.navigation.navOptions
1718
import androidx.navigation.navigation
1819
import cmp.navigation.authenticatednavbar.AuthenticatedNavbarRoute
1920
import cmp.navigation.authenticatednavbar.authenticatedNavbarGraph
2021
import kotlinx.serialization.ExperimentalSerializationApi
2122
import kotlinx.serialization.InternalSerializationApi
2223
import kotlinx.serialization.Serializable
2324
import org.mifos.mobile.core.common.Constants
24-
import org.mifos.mobile.core.model.entity.TransferSuccessDestination
25+
import org.mifos.mobile.core.model.EventType
26+
import org.mifos.mobile.core.model.StatusNavigationDestination
2527
import org.mifos.mobile.core.model.enums.TransferType
2628
import org.mifos.mobile.feature.accounts.accountTransactions.accountTransactionsDestination
2729
import org.mifos.mobile.feature.accounts.accountTransactions.navigateToAccountTransactionsScreen
30+
import org.mifos.mobile.feature.accounts.accounts.AccountNavRoute
2831
import org.mifos.mobile.feature.accounts.accounts.accountsDestination
2932
import org.mifos.mobile.feature.accounts.accounts.navigateToAccountsScreen
3033
import org.mifos.mobile.feature.auth.login.navigateToLoginScreen
@@ -36,6 +39,7 @@ import org.mifos.mobile.feature.charge.charges.navigateToClientChargeScreen
3639
import org.mifos.mobile.feature.charge.navigation.clientChargeNavGraph
3740
import org.mifos.mobile.feature.charge.navigation.navigateToChargeGraph
3841
import org.mifos.mobile.feature.home.navigation.HomeNavigationDestination
42+
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
3943
import org.mifos.mobile.feature.loan.application.navigation.loanApplicationNavGraph
4044
import org.mifos.mobile.feature.loan.application.navigation.navigateToLoanApplicationGraph
4145
import org.mifos.mobile.feature.loanaccount.loanAccountDetails.navigateToLoanAccountDetailsScreen
@@ -63,6 +67,7 @@ import org.mifos.mobile.feature.status.navigation.statusDestination
6367
import org.mifos.mobile.feature.third.party.transfer.navigation.TptNavigationDestination
6468
import org.mifos.mobile.feature.transfer.process.makeTransfer.makeTransferDestination
6569
import org.mifos.mobile.feature.transfer.process.makeTransfer.navigateToMakeTransferScreen
70+
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
6671
import org.mifos.mobile.feature.transfer.process.transferProcess.navigateToTransferProcessScreen
6772
import org.mifos.mobile.feature.transfer.process.transferProcess.transferProcessDestination
6873

@@ -73,7 +78,7 @@ internal fun NavController.navigateToAuthenticatedGraph(navOptions: NavOptions?
7378
navigate(route = AuthenticatedGraphRoute, navOptions = navOptions)
7479
}
7580

76-
@Suppress("CyclomaticComplexMethod")
81+
@Suppress("CyclomaticComplexMethod", "LongMethod")
7782
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
7883
internal fun NavGraphBuilder.authenticatedGraph(
7984
navController: NavController,
@@ -132,7 +137,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
132137
navController.navigateToTransferProcessScreen(
133138
destination.payload,
134139
TransferType.TPT,
135-
TransferSuccessDestination.TRANSFER_TAB.name,
140+
StatusNavigationDestination.THIRD_PARTY_TRANSFER.name,
136141
)
137142
}
138143
else -> {
@@ -171,6 +176,41 @@ internal fun NavGraphBuilder.authenticatedGraph(
171176
Constants.LOGIN -> {
172177
navController.navigateToLoginScreen()
173178
}
179+
180+
StatusNavigationDestination.SAVINGS_APPLICATION.name -> {
181+
navController.navigateToAccountFromStatus(Constants.SAVINGS_ACCOUNT)
182+
}
183+
184+
StatusNavigationDestination.LOAN_APPLICATION.name -> {
185+
navController.navigateToAccountFromStatus(Constants.LOAN_ACCOUNT)
186+
}
187+
188+
StatusNavigationDestination.SHARE_APPLICATION.name -> {
189+
navController.navigateToAccountFromStatus(Constants.SHARE_ACCOUNTS)
190+
}
191+
192+
StatusNavigationDestination.PREVIOUS_SCREEN.name -> {
193+
navController.popScreens()
194+
}
195+
196+
StatusNavigationDestination.THIRD_PARTY_TRANSFER.name -> {
197+
navController.navigateToHomeAfterStatus()
198+
}
199+
200+
StatusNavigationDestination.SAVINGS_ACCOUNT.name -> {
201+
repeat(3) { navController.popBackStack() }
202+
}
203+
204+
StatusNavigationDestination.LOAN_ACCOUNT.name -> {
205+
repeat(3) { navController.popBackStack() }
206+
}
207+
208+
StatusNavigationDestination.SAVINGS_UPDATE.name,
209+
StatusNavigationDestination.SAVINGS_WITHDRAW.name,
210+
-> {
211+
repeat(2) { navController.popBackStack() }
212+
}
213+
174214
else -> {
175215
navController.navigateToHomeAfterStatus()
176216
}
@@ -181,7 +221,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
181221
savingsNavGraph(
182222
navController = navController,
183223
navigateToClientChargeScreen = navController::navigateToClientChargeScreen,
184-
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
224+
navigateToStatusScreen = navController::navigateToStatusScreenWithoutPopUpTo,
185225
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
186226
navigateToTransferScreen = {
187227
navController.navigateToMakeTransferScreen(it)
@@ -207,18 +247,18 @@ internal fun NavGraphBuilder.authenticatedGraph(
207247
loanApplicationNavGraph(
208248
navController = navController,
209249
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
210-
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
250+
navigateToStatusScreen = navController::navigateToStatusScreen,
211251
)
212252

213253
savingsApplicationNavGraph(
214254
navController = navController,
215-
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
255+
navigateToStatusScreen = navController::navigateToStatusScreen,
216256
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
217257
)
218258

219259
shareApplicationNavGraph(
220260
navController = navController,
221-
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
261+
navigateToStatusScreen = navController::navigateToStatusScreen,
222262
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
223263
)
224264

@@ -235,7 +275,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
235275
beneficiaryNavGraph(
236276
navController = navController,
237277
navigateToQR = navController::navigateToQrReaderScreen,
238-
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
278+
navigateToStatusScreen = navController::navigateToStatusScreen,
239279
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
240280
)
241281

@@ -259,20 +299,15 @@ internal fun NavGraphBuilder.authenticatedGraph(
259299
navController.navigateToTransferProcessScreen(
260300
transferPayload = transferPayload,
261301
transferType = transferType,
262-
transferSuccessDestination = when (transferDestination) {
263-
TransferSuccessDestination.SAVINGS_ACCOUNT -> Constants.NAVIGATE_BACK_TO_SAVINGS
264-
TransferSuccessDestination.LOAN_ACCOUNT -> Constants.NAVIGATE_BACK_TO_LOAN
265-
TransferSuccessDestination.HOME -> ""
266-
TransferSuccessDestination.TRANSFER_TAB -> Constants.TRANSFER_TAB
267-
},
302+
transferSuccessDestination = transferDestination,
268303
)
269304
},
270305
)
271306

272307
transferProcessDestination(
273308
navigateBack = navController::popBackStack,
274309
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
275-
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
310+
navigateToStatusScreen = navController::navigateToStatusScreenWithoutPopUpTo,
276311
)
277312

278313
faqDestination(onBackClick = navController::popBackStack, contact = {})
@@ -328,7 +363,7 @@ fun NavController.navigateToStatusScreenPasscodeFlow(
328363
}
329364
}
330365

331-
fun NavController.navigateToStatusAfterUpdate(
366+
fun NavController.navigateToStatusScreen(
332367
eventType: String,
333368
eventDestination: String,
334369
title: String,
@@ -344,18 +379,91 @@ fun NavController.navigateToStatusAfterUpdate(
344379
buttonText = buttonText,
345380
),
346381
) {
347-
popUpTo(AuthenticatedGraphRoute) {
382+
if (eventType == EventType.SUCCESS.name) {
383+
popUpTo(AuthenticatedGraphRoute) {
384+
inclusive = true
385+
}
386+
launchSingleTop = true
387+
}
388+
}
389+
}
390+
391+
fun NavController.navigateToStatusScreenWithoutPopUpTo(
392+
eventType: String,
393+
eventDestination: String,
394+
title: String,
395+
subtitle: String,
396+
buttonText: String,
397+
) {
398+
if (eventDestination == StatusNavigationDestination.THIRD_PARTY_TRANSFER.name) {
399+
this.navigate(
400+
StatusNavigationRoute(
401+
eventType = eventType,
402+
eventDestination = eventDestination,
403+
title = title,
404+
subtitle = subtitle,
405+
buttonText = buttonText,
406+
),
407+
) {
408+
if (eventType == EventType.SUCCESS.name) {
409+
popUpTo(AuthenticatedGraphRoute) {
410+
inclusive = true
411+
}
412+
launchSingleTop = true
413+
}
414+
}
415+
} else {
416+
this.navigate(
417+
StatusNavigationRoute(
418+
eventType = eventType,
419+
eventDestination = eventDestination,
420+
title = title,
421+
subtitle = subtitle,
422+
buttonText = buttonText,
423+
),
424+
) {
425+
launchSingleTop = true
426+
}
427+
}
428+
}
429+
430+
fun NavController.navigateToHomeAfterStatus() {
431+
this.navigate(AuthenticatedNavbarRoute) {
432+
popUpTo(StatusNavigationRoute::class) {
348433
inclusive = true
349434
}
350435
launchSingleTop = true
351436
}
352437
}
353438

354-
fun NavController.navigateToHomeAfterStatus() {
439+
fun NavController.navigateToAccountFromStatus(
440+
accountType: String,
441+
) {
355442
this.navigate(AuthenticatedNavbarRoute) {
356443
popUpTo(StatusNavigationRoute::class) {
357444
inclusive = true
358445
}
359446
launchSingleTop = true
360447
}
448+
449+
this.navigate(AccountNavRoute(accountType)) {
450+
launchSingleTop = true
451+
}
452+
}
453+
454+
fun NavController.popScreens(
455+
popRules: Map<String, Int> = mapOf(
456+
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
457+
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
458+
),
459+
) {
460+
val lastEntry = previousBackStackEntry?.destination?.route
461+
462+
val pops = popRules.entries
463+
.firstOrNull { (route, _) ->
464+
lastEntry?.startsWith(route) == true
465+
}
466+
?.value ?: 1
467+
468+
repeat(pops) { popBackStack() }
361469
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
9+
*/
10+
package org.mifos.mobile.core.model
11+
12+
import kotlinx.serialization.Serializable
13+
14+
@Serializable
15+
enum class StatusNavigationDestination {
16+
HOME,
17+
SAVINGS_APPLICATION,
18+
LOAN_APPLICATION,
19+
SHARE_APPLICATION,
20+
PREVIOUS_SCREEN,
21+
LOGIN,
22+
23+
LOAN_ACCOUNT,
24+
SAVINGS_ACCOUNT,
25+
THIRD_PARTY_TRANSFER,
26+
27+
SAVINGS_UPDATE,
28+
SAVINGS_WITHDRAW,
29+
}

core/model/src/commonMain/kotlin/org/mifos/mobile/core/model/entity/AccountDetails.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ data class AccountDetails(
2121
val outstandingBalance: Double? = null,
2222
val transferType: String,
2323
val transferTarget: TransferType,
24-
val transferSuccessDestination: TransferSuccessDestination,
24+
val transferSuccessDestination: String,
2525
)
2626

2727
@Serializable

feature/loan-account/src/commonMain/kotlin/org/mifos/mobile/feature/loanaccount/loanAccountDetails/LoanAccountDetailsScreen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ import org.mifos.mobile.core.designsystem.theme.AppColors
4444
import org.mifos.mobile.core.designsystem.theme.DesignToken
4545
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
4646
import org.mifos.mobile.core.designsystem.theme.MifosTypography
47+
import org.mifos.mobile.core.model.StatusNavigationDestination
4748
import org.mifos.mobile.core.model.entity.AccountDetails
48-
import org.mifos.mobile.core.model.entity.TransferSuccessDestination
4949
import org.mifos.mobile.core.model.enums.ChargeType
5050
import org.mifos.mobile.core.model.enums.TransferType
5151
import org.mifos.mobile.core.ui.component.MifosActionCard
@@ -89,7 +89,7 @@ internal fun LoanAccountDetailsScreen(
8989
outstandingBalance = uiState.totalOutStandingBalance ?: 1.00,
9090
transferType = TRANSFER_PAY_TO,
9191
transferTarget = TransferType.SELF,
92-
transferSuccessDestination = TransferSuccessDestination.LOAN_ACCOUNT,
92+
transferSuccessDestination = StatusNavigationDestination.LOAN_ACCOUNT.name,
9393
)
9494
navigateToMakePaymentScreen(transferArgs)
9595
}

feature/loan-account/src/commonMain/kotlin/org/mifos/mobile/feature/loanaccount/loanAccountRepaymentSchedule/RepaymentScheduleViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ internal class RepaymentScheduleViewModel(
7575
action.outStandingBalance,
7676
action.transferTyp,
7777
action.transferTarget,
78-
action.transferSuccessDestination,
78+
action.transferSuccessDestination.name,
7979
),
8080
)
8181
}
@@ -190,7 +190,7 @@ sealed interface RepaymentScheduleEvent {
190190
val outStandingBalance: Double?,
191191
val transferTyp: String,
192192
val transferTarget: TransferType,
193-
val transferSuccessDestination: TransferSuccessDestination,
193+
val transferSuccessDestination: String,
194194
) : RepaymentScheduleEvent
195195
}
196196

feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/confirmDetails/ConfirmDetailsViewModel.kt

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ import androidx.lifecycle.viewModelScope
1414
import androidx.navigation.toRoute
1515
import kotlinx.coroutines.flow.update
1616
import kotlinx.coroutines.launch
17-
import kotlinx.serialization.ExperimentalSerializationApi
18-
import kotlinx.serialization.InternalSerializationApi
19-
import kotlinx.serialization.serializer
2017
import mifos_mobile.feature.loan_application.generated.resources.Res
2118
import mifos_mobile.feature.loan_application.generated.resources.feature_apply_loan_error_server
2219
import mifos_mobile.feature.loan_application.generated.resources.feature_apply_loan_label_applicant_name
@@ -37,14 +34,14 @@ import org.mifos.mobile.core.data.repository.LoanRepository
3734
import org.mifos.mobile.core.data.repository.ReviewLoanApplicationRepository
3835
import org.mifos.mobile.core.datastore.UserPreferencesRepository
3936
import org.mifos.mobile.core.model.EventType
37+
import org.mifos.mobile.core.model.StatusNavigationDestination
4038
import org.mifos.mobile.core.model.entity.payload.LoansPayload
4139
import org.mifos.mobile.core.model.entity.templates.loans.LoanTemplate
4240
import org.mifos.mobile.core.model.enums.LoanState
4341
import org.mifos.mobile.core.ui.utils.AuthResult
4442
import org.mifos.mobile.core.ui.utils.BaseViewModel
4543
import org.mifos.mobile.core.ui.utils.ResultNavigator
4644
import org.mifos.mobile.core.ui.utils.observe
47-
import org.mifos.mobile.feature.loan.application.navigation.LoanApplicationNavGraph
4845

4946
/**
5047
* `ViewModel` for the confirm details screen of the loan application process.
@@ -256,6 +253,7 @@ internal class ConfirmDetailsViewModel(
256253
getLoanPayload(),
257254
loanId = -1,
258255
)
256+
dismissDialog()
259257
sendAction(ConfirmDetailsAction.Internal.ReceiveLoanApplyStatus(response))
260258
}
261259
}
@@ -267,14 +265,13 @@ internal class ConfirmDetailsViewModel(
267265
*
268266
* @param status The [DataState] containing the status of the loan submission.
269267
*/
270-
@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)
271268
private suspend fun handleLoanApplyStatus(status: DataState<String>) {
272269
when (status) {
273270
is DataState.Error -> {
274271
sendEvent(
275272
ConfirmDetailsEvent.NavigateToStatus(
276273
eventType = EventType.FAILURE.name,
277-
eventDestination = LoanApplicationNavGraph::class.serializer().descriptor.serialName,
274+
eventDestination = StatusNavigationDestination.PREVIOUS_SCREEN.name,
278275
title = getString(Res.string.feature_apply_loan_status_failure),
279276
subtitle = getString(Res.string.feature_apply_loan_status_failure_tip),
280277
buttonText = getString(Res.string.feature_apply_loan_status_failure_action),
@@ -286,7 +283,7 @@ internal class ConfirmDetailsViewModel(
286283
sendEvent(
287284
ConfirmDetailsEvent.NavigateToStatus(
288285
eventType = EventType.SUCCESS.name,
289-
eventDestination = LoanApplicationNavGraph::class.serializer().descriptor.serialName,
286+
eventDestination = StatusNavigationDestination.LOAN_APPLICATION.name,
290287
title = getString(Res.string.feature_apply_loan_status_success),
291288
subtitle = getString(Res.string.feature_apply_loan_status_success_tip),
292289
buttonText = getString(Res.string.feature_apply_loan_status_success_action),

0 commit comments

Comments
 (0)