Skip to content
Merged
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 @@ -14,17 +14,20 @@ package cmp.navigation.authenticated
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.navOptions
import androidx.navigation.navigation
import cmp.navigation.authenticatednavbar.AuthenticatedNavbarRoute
import cmp.navigation.authenticatednavbar.authenticatedNavbarGraph
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.model.entity.TransferSuccessDestination
import org.mifos.mobile.core.model.EventType
import org.mifos.mobile.core.model.StatusNavigationDestination
import org.mifos.mobile.core.model.enums.TransferType
import org.mifos.mobile.feature.accounts.accountTransactions.accountTransactionsDestination
import org.mifos.mobile.feature.accounts.accountTransactions.navigateToAccountTransactionsScreen
import org.mifos.mobile.feature.accounts.accounts.AccountNavRoute
import org.mifos.mobile.feature.accounts.accounts.accountsDestination
import org.mifos.mobile.feature.accounts.accounts.navigateToAccountsScreen
import org.mifos.mobile.feature.auth.login.navigateToLoginScreen
Expand All @@ -36,6 +39,7 @@ import org.mifos.mobile.feature.charge.charges.navigateToClientChargeScreen
import org.mifos.mobile.feature.charge.navigation.clientChargeNavGraph
import org.mifos.mobile.feature.charge.navigation.navigateToChargeGraph
import org.mifos.mobile.feature.home.navigation.HomeNavigationDestination
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.loan.application.navigation.loanApplicationNavGraph
import org.mifos.mobile.feature.loan.application.navigation.navigateToLoanApplicationGraph
import org.mifos.mobile.feature.loanaccount.loanAccountDetails.navigateToLoanAccountDetailsScreen
Expand Down Expand Up @@ -63,6 +67,7 @@ import org.mifos.mobile.feature.status.navigation.statusDestination
import org.mifos.mobile.feature.third.party.transfer.navigation.TptNavigationDestination
import org.mifos.mobile.feature.transfer.process.makeTransfer.makeTransferDestination
import org.mifos.mobile.feature.transfer.process.makeTransfer.navigateToMakeTransferScreen
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.navigateToTransferProcessScreen
import org.mifos.mobile.feature.transfer.process.transferProcess.transferProcessDestination

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

@Suppress("CyclomaticComplexMethod")
@Suppress("CyclomaticComplexMethod", "LongMethod")
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
internal fun NavGraphBuilder.authenticatedGraph(
navController: NavController,
Expand Down Expand Up @@ -132,7 +137,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
navController.navigateToTransferProcessScreen(
destination.payload,
TransferType.TPT,
TransferSuccessDestination.TRANSFER_TAB.name,
StatusNavigationDestination.THIRD_PARTY_TRANSFER.name,
)
}
else -> {
Expand Down Expand Up @@ -171,6 +176,41 @@ internal fun NavGraphBuilder.authenticatedGraph(
Constants.LOGIN -> {
navController.navigateToLoginScreen()
}

StatusNavigationDestination.SAVINGS_APPLICATION.name -> {
navController.navigateToAccountFromStatus(Constants.SAVINGS_ACCOUNT)
}

StatusNavigationDestination.LOAN_APPLICATION.name -> {
navController.navigateToAccountFromStatus(Constants.LOAN_ACCOUNT)
}

StatusNavigationDestination.SHARE_APPLICATION.name -> {
navController.navigateToAccountFromStatus(Constants.SHARE_ACCOUNTS)
}

StatusNavigationDestination.PREVIOUS_SCREEN.name -> {
navController.popScreens()
}

StatusNavigationDestination.THIRD_PARTY_TRANSFER.name -> {
navController.navigateToHomeAfterStatus()
}

StatusNavigationDestination.SAVINGS_ACCOUNT.name -> {
repeat(3) { navController.popBackStack() }
}

StatusNavigationDestination.LOAN_ACCOUNT.name -> {
repeat(3) { navController.popBackStack() }
}

StatusNavigationDestination.SAVINGS_UPDATE.name,
StatusNavigationDestination.SAVINGS_WITHDRAW.name,
-> {
repeat(2) { navController.popBackStack() }
}

else -> {
navController.navigateToHomeAfterStatus()
}
Expand All @@ -181,7 +221,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
savingsNavGraph(
navController = navController,
navigateToClientChargeScreen = navController::navigateToClientChargeScreen,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
navigateToStatusScreen = navController::navigateToStatusScreenWithoutPopUpTo,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
navigateToTransferScreen = {
navController.navigateToMakeTransferScreen(it)
Expand All @@ -207,18 +247,18 @@ internal fun NavGraphBuilder.authenticatedGraph(
loanApplicationNavGraph(
navController = navController,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
navigateToStatusScreen = navController::navigateToStatusScreen,
)

savingsApplicationNavGraph(
navController = navController,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
navigateToStatusScreen = navController::navigateToStatusScreen,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
)

shareApplicationNavGraph(
navController = navController,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
navigateToStatusScreen = navController::navigateToStatusScreen,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
)

Expand All @@ -235,7 +275,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
beneficiaryNavGraph(
navController = navController,
navigateToQR = navController::navigateToQrReaderScreen,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
navigateToStatusScreen = navController::navigateToStatusScreen,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
)

Expand All @@ -259,20 +299,15 @@ internal fun NavGraphBuilder.authenticatedGraph(
navController.navigateToTransferProcessScreen(
transferPayload = transferPayload,
transferType = transferType,
transferSuccessDestination = when (transferDestination) {
TransferSuccessDestination.SAVINGS_ACCOUNT -> Constants.NAVIGATE_BACK_TO_SAVINGS
TransferSuccessDestination.LOAN_ACCOUNT -> Constants.NAVIGATE_BACK_TO_LOAN
TransferSuccessDestination.HOME -> ""
TransferSuccessDestination.TRANSFER_TAB -> Constants.TRANSFER_TAB
},
transferSuccessDestination = transferDestination,
)
},
)

transferProcessDestination(
navigateBack = navController::popBackStack,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
navigateToStatusScreen = navController::navigateToStatusScreenWithoutPopUpTo,
)

faqDestination(onBackClick = navController::popBackStack, contact = {})
Expand Down Expand Up @@ -328,7 +363,7 @@ fun NavController.navigateToStatusScreenPasscodeFlow(
}
}

fun NavController.navigateToStatusAfterUpdate(
fun NavController.navigateToStatusScreen(
eventType: String,
eventDestination: String,
title: String,
Expand All @@ -344,18 +379,91 @@ fun NavController.navigateToStatusAfterUpdate(
buttonText = buttonText,
),
) {
popUpTo(AuthenticatedGraphRoute) {
if (eventType == EventType.SUCCESS.name) {
popUpTo(AuthenticatedGraphRoute) {
inclusive = true
}
launchSingleTop = true
}
}
}

fun NavController.navigateToStatusScreenWithoutPopUpTo(
eventType: String,
eventDestination: String,
title: String,
subtitle: String,
buttonText: String,
) {
if (eventDestination == StatusNavigationDestination.THIRD_PARTY_TRANSFER.name) {
this.navigate(
StatusNavigationRoute(
eventType = eventType,
eventDestination = eventDestination,
title = title,
subtitle = subtitle,
buttonText = buttonText,
),
) {
if (eventType == EventType.SUCCESS.name) {
popUpTo(AuthenticatedGraphRoute) {
inclusive = true
}
launchSingleTop = true
}
}
} else {
this.navigate(
StatusNavigationRoute(
eventType = eventType,
eventDestination = eventDestination,
title = title,
subtitle = subtitle,
buttonText = buttonText,
),
) {
launchSingleTop = true
}
}
}

fun NavController.navigateToHomeAfterStatus() {
this.navigate(AuthenticatedNavbarRoute) {
popUpTo(StatusNavigationRoute::class) {
inclusive = true
}
launchSingleTop = true
}
}

fun NavController.navigateToHomeAfterStatus() {
fun NavController.navigateToAccountFromStatus(
accountType: String,
) {
this.navigate(AuthenticatedNavbarRoute) {
popUpTo(StatusNavigationRoute::class) {
inclusive = true
}
launchSingleTop = true
}

this.navigate(AccountNavRoute(accountType)) {
launchSingleTop = true
}
}

fun NavController.popScreens(
popRules: Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
),
) {
val lastEntry = previousBackStackEntry?.destination?.route

val pops = popRules.entries
.firstOrNull { (route, _) ->
lastEntry?.startsWith(route) == true
}
?.value ?: 1

repeat(pops) { popBackStack() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package org.mifos.mobile.core.model

import kotlinx.serialization.Serializable

@Serializable
enum class StatusNavigationDestination {
HOME,
SAVINGS_APPLICATION,
LOAN_APPLICATION,
SHARE_APPLICATION,
PREVIOUS_SCREEN,
LOGIN,

LOAN_ACCOUNT,
SAVINGS_ACCOUNT,
THIRD_PARTY_TRANSFER,

SAVINGS_UPDATE,
SAVINGS_WITHDRAW,
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ data class AccountDetails(
val outstandingBalance: Double? = null,
val transferType: String,
val transferTarget: TransferType,
val transferSuccessDestination: TransferSuccessDestination,
val transferSuccessDestination: String,
)

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ import org.mifos.mobile.core.designsystem.theme.AppColors
import org.mifos.mobile.core.designsystem.theme.DesignToken
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.designsystem.theme.MifosTypography
import org.mifos.mobile.core.model.StatusNavigationDestination
import org.mifos.mobile.core.model.entity.AccountDetails
import org.mifos.mobile.core.model.entity.TransferSuccessDestination
import org.mifos.mobile.core.model.enums.ChargeType
import org.mifos.mobile.core.model.enums.TransferType
import org.mifos.mobile.core.ui.component.MifosActionCard
Expand Down Expand Up @@ -90,7 +90,7 @@ internal fun LoanAccountDetailsScreen(
outstandingBalance = uiState.totalOutStandingBalance ?: 1.00,
transferType = TRANSFER_PAY_TO,
transferTarget = TransferType.SELF,
transferSuccessDestination = TransferSuccessDestination.LOAN_ACCOUNT,
transferSuccessDestination = StatusNavigationDestination.LOAN_ACCOUNT.name,
)
navigateToMakePaymentScreen(transferArgs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ internal class RepaymentScheduleViewModel(
action.outStandingBalance,
action.transferTyp,
action.transferTarget,
action.transferSuccessDestination,
action.transferSuccessDestination.name,
),
)
}
Expand Down Expand Up @@ -190,7 +190,7 @@ sealed interface RepaymentScheduleEvent {
val outStandingBalance: Double?,
val transferTyp: String,
val transferTarget: TransferType,
val transferSuccessDestination: TransferSuccessDestination,
val transferSuccessDestination: String,
) : RepaymentScheduleEvent
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.toRoute
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.serializer
import mifos_mobile.feature.loan_application.generated.resources.Res
import mifos_mobile.feature.loan_application.generated.resources.feature_apply_loan_error_server
import mifos_mobile.feature.loan_application.generated.resources.feature_apply_loan_label_applicant_name
Expand All @@ -37,14 +34,14 @@ import org.mifos.mobile.core.data.repository.LoanRepository
import org.mifos.mobile.core.data.repository.ReviewLoanApplicationRepository
import org.mifos.mobile.core.datastore.UserPreferencesRepository
import org.mifos.mobile.core.model.EventType
import org.mifos.mobile.core.model.StatusNavigationDestination
import org.mifos.mobile.core.model.entity.payload.LoansPayload
import org.mifos.mobile.core.model.entity.templates.loans.LoanTemplate
import org.mifos.mobile.core.model.enums.LoanState
import org.mifos.mobile.core.ui.utils.AuthResult
import org.mifos.mobile.core.ui.utils.BaseViewModel
import org.mifos.mobile.core.ui.utils.ResultNavigator
import org.mifos.mobile.core.ui.utils.observe
import org.mifos.mobile.feature.loan.application.navigation.LoanApplicationNavGraph

/**
* `ViewModel` for the confirm details screen of the loan application process.
Expand Down Expand Up @@ -256,6 +253,7 @@ internal class ConfirmDetailsViewModel(
getLoanPayload(),
loanId = -1,
)
dismissDialog()
sendAction(ConfirmDetailsAction.Internal.ReceiveLoanApplyStatus(response))
}
}
Expand All @@ -267,14 +265,13 @@ internal class ConfirmDetailsViewModel(
*
* @param status The [DataState] containing the status of the loan submission.
*/
@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)
private suspend fun handleLoanApplyStatus(status: DataState<String>) {
when (status) {
is DataState.Error -> {
sendEvent(
ConfirmDetailsEvent.NavigateToStatus(
eventType = EventType.FAILURE.name,
eventDestination = LoanApplicationNavGraph::class.serializer().descriptor.serialName,
eventDestination = StatusNavigationDestination.PREVIOUS_SCREEN.name,
title = getString(Res.string.feature_apply_loan_status_failure),
subtitle = getString(Res.string.feature_apply_loan_status_failure_tip),
buttonText = getString(Res.string.feature_apply_loan_status_failure_action),
Expand All @@ -286,7 +283,7 @@ internal class ConfirmDetailsViewModel(
sendEvent(
ConfirmDetailsEvent.NavigateToStatus(
eventType = EventType.SUCCESS.name,
eventDestination = LoanApplicationNavGraph::class.serializer().descriptor.serialName,
eventDestination = StatusNavigationDestination.LOAN_APPLICATION.name,
title = getString(Res.string.feature_apply_loan_status_success),
subtitle = getString(Res.string.feature_apply_loan_status_success_tip),
buttonText = getString(Res.string.feature_apply_loan_status_success_action),
Expand Down
Loading
Loading