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
1 change: 1 addition & 0 deletions cmp-navigation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ kotlin {
implementation(projects.feature.passcode)
implementation(projects.feature.status)
implementation(projects.feature.loanApplication)
implementation(projects.feature.savingsApplication)
// Core Modules
implementation(projects.core.data)
implementation(projects.core.common)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import org.mifos.mobile.feature.beneficiary.navigation.navigateToBeneficiaryNavG
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.navigation.loanApplicationNavGraph
import org.mifos.mobile.feature.loan.application.navigation.navigateToLoanApplicationGraph
import org.mifos.mobile.feature.loanaccount.loanAccountDetails.navigateToLoanAccountDetailsScreen
Expand All @@ -48,8 +49,12 @@ import org.mifos.mobile.feature.qr.navigation.qrNavGraph
import org.mifos.mobile.feature.qr.qr.navigateToQrReaderScreen
import org.mifos.mobile.feature.qr.qrCodeDisplay.navigateToQrDisplayScreen
import org.mifos.mobile.feature.recent.transaction.navigation.recentTransactionNavGraph
import org.mifos.mobile.feature.savings.application.navigation.navigateToSavingsApplicationGraph
import org.mifos.mobile.feature.savings.application.navigation.savingsApplicationNavGraph
import org.mifos.mobile.feature.savingsaccount.navigation.savingsNavGraph
import org.mifos.mobile.feature.savingsaccount.savingsAccountDetails.navigateToSavingsAccountDetailsScreen
import org.mifos.mobile.feature.settings.faq.faqDestination
import org.mifos.mobile.feature.settings.faq.navigateToFaq
import org.mifos.mobile.feature.status.navigation.StatusNavigationRoute
import org.mifos.mobile.feature.status.navigation.statusDestination
import org.mifos.mobile.feature.third.party.transfer.navigation.thirdPartyTransferNavGraph
Expand All @@ -72,22 +77,44 @@ internal fun NavGraphBuilder.authenticatedGraph(
navigation<AuthenticatedGraphRoute>(
startDestination = AuthenticatedNavbarRoute,
) {
authenticatedNavbarGraph(
navigateToNotificationScreen = navController::navigateToNotificationScreen,
navigateToAccountsScreen = {
when (it) {
Constants.SAVINGS_ACCOUNT, Constants.LOAN_ACCOUNT, Constants.SHARE_ACCOUNTS ->
navController.navigateToAccountsScreen(it)
else -> Unit
authenticatedNavbarGraph { destination ->
when (destination) {
is HomeNavigationDestination.AccountsWithType -> {
if (destination.type in listOf(
Constants.SAVINGS_ACCOUNT,
Constants.LOAN_ACCOUNT,
Constants.SHARE_ACCOUNTS,
)
) {
navController.navigateToAccountsScreen(destination.type)
}
}
},
navigateToChargeScreen = navController::navigateToChargeGraph,
navigateToBeneficiaryScreen = navController::navigateToBeneficiaryNavGraph,
navigateToTransactionScreen = {
navController.navigateToAccountTransactionsScreen(Constants.RECENT_TRANSACTIONS, -1L)
},
navigateToApplyLoanScreen = navController::navigateToLoanApplicationGraph,
)

is HomeNavigationDestination.Notification ->
navController.navigateToNotificationScreen()

is HomeNavigationDestination.Charge ->
navController.navigateToChargeGraph()

is HomeNavigationDestination.Faq ->
navController.navigateToFaq()

is HomeNavigationDestination.Beneficiary ->
navController.navigateToBeneficiaryNavGraph()

is HomeNavigationDestination.Transaction ->
navController.navigateToAccountTransactionsScreen(
Constants.RECENT_TRANSACTIONS,
-1L,
)

is HomeNavigationDestination.ApplyLoan ->
navController.navigateToLoanApplicationGraph()

is HomeNavigationDestination.ApplySavings ->
navController.navigateToSavingsApplicationGraph()
}
}

notificationDestination(
navigateBack = navController::popBackStack,
Expand Down Expand Up @@ -157,6 +184,10 @@ internal fun NavGraphBuilder.authenticatedGraph(
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
)

savingsApplicationNavGraph(
navController = navController,
)

passcodeDestination(
onPasscodeConfirm = navController::popBackStack,
)
Expand Down Expand Up @@ -220,6 +251,8 @@ internal fun NavGraphBuilder.authenticatedGraph(
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
navigateToStatusScreen = navController::navigateToStatusAfterUpdate,
)

faqDestination(onBackClick = navController::popBackStack, contact = {})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.ui.composableWithStayTransitions
import org.mifos.mobile.feature.home.navigation.HomeNavigator

@Serializable
data object AuthenticatedNavbarRoute
Expand All @@ -25,21 +26,11 @@ internal fun NavController.navigateToAuthenticatedNavBar(navOptions: NavOptions?
}

internal fun NavGraphBuilder.authenticatedNavbarGraph(
navigateToNotificationScreen: () -> Unit,
navigateToAccountsScreen: (String) -> Unit,
navigateToChargeScreen: () -> Unit,
navigateToBeneficiaryScreen: () -> Unit,
navigateToTransactionScreen: () -> Unit,
navigateToApplyLoanScreen: () -> Unit,
homeNavigator: HomeNavigator,
) {
composableWithStayTransitions<AuthenticatedNavbarRoute> {
AuthenticatedNavbarNavigationScreen(
navigateToNotificationScreen = navigateToNotificationScreen,
navigateToAccountsScreen = { navigateToAccountsScreen(it) },
navigateToChargeScreen = navigateToChargeScreen,
navigateToBeneficiaryScreen = navigateToBeneficiaryScreen,
navigateToTransactionScreen = navigateToTransactionScreen,
navigateToApplyLoanScreen = navigateToApplyLoanScreen,
homeNavigator = homeNavigator,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,18 @@ import org.koin.compose.viewmodel.koinViewModel
import org.mifos.mobile.core.ui.RootTransitionProviders
import org.mifos.mobile.core.ui.navigation.NavigationItem
import org.mifos.mobile.core.ui.utils.EventsEffect
import org.mifos.mobile.feature.home.navigation.HomeNavigator
import org.mifos.mobile.feature.home.navigation.HomeRoute
import org.mifos.mobile.feature.home.navigation.homeDestination
import org.mifos.mobile.feature.home.navigation.navigateToHomeScreen
import org.mifos.mobile.feature.settings.faq.navigateToFaq
import org.mifos.mobile.feature.settings.navigation.navigateToSettingsGraph
import org.mifos.mobile.feature.settings.navigation.settingsGraph
import org.mifos.mobile.navigation.generated.resources.Res
import org.mifos.mobile.navigation.generated.resources.not_connected

@Composable
internal fun AuthenticatedNavbarNavigationScreen(
navigateToNotificationScreen: () -> Unit,
navigateToAccountsScreen: (String) -> Unit,
navigateToChargeScreen: () -> Unit,
navigateToBeneficiaryScreen: () -> Unit,
navigateToTransactionScreen: () -> Unit,
navigateToApplyLoanScreen: () -> Unit,
homeNavigator: HomeNavigator,
modifier: Modifier = Modifier,
navController: NavHostController = rememberMifosNavController(
name = "AuthenticatedNavbarScreen",
Expand Down Expand Up @@ -107,24 +102,14 @@ internal fun AuthenticatedNavbarNavigationScreen(
onAction = remember(viewModel) {
{ viewModel.trySendAction(it) }
},
navigateToNotificationScreen = navigateToNotificationScreen,
navigateToAccountsScreen = { navigateToAccountsScreen(it) },
navigateToChargeScreen = navigateToChargeScreen,
navigateToBeneficiaryScreen = navigateToBeneficiaryScreen,
navigateToTransactionScreen = navigateToTransactionScreen,
navigateToApplyLoanScreen = navigateToApplyLoanScreen,
homeNavigator = homeNavigator,
)
}

@Composable
internal fun AuthenticatedNavbarNavigationScreenContent(
navController: NavHostController,
navigateToNotificationScreen: () -> Unit,
navigateToAccountsScreen: (String) -> Unit,
navigateToChargeScreen: () -> Unit,
navigateToBeneficiaryScreen: () -> Unit,
navigateToTransactionScreen: () -> Unit,
navigateToApplyLoanScreen: () -> Unit,
homeNavigator: HomeNavigator,
modifier: Modifier = Modifier,
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
onAction: (AuthenticatedNavBarAction) -> Unit,
Expand Down Expand Up @@ -175,21 +160,7 @@ internal fun AuthenticatedNavbarNavigationScreenContent(
popExitTransition = RootTransitionProviders.Exit.fadeOut,
) {
// TODO Add top level destination screens

homeDestination(
// navigateToDestinationScreen = {
// navController.navigate(
// it
// )
// },
navigateToAccountsScreen = { navigateToAccountsScreen(it) },
navigateToChargeScreen = navigateToChargeScreen,
navigateToNotificationScreen = navigateToNotificationScreen,
navigateToFaqScreen = navController::navigateToFaq,
navigateToBeneficiaryScreen = navigateToBeneficiaryScreen,
navigateToTransactionScreen = navigateToTransactionScreen,
navigateToApplyLoanScreen = navigateToApplyLoanScreen,
)
homeDestination(onNavigate = homeNavigator)

settingsGraph(
navController = navController,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.mifos.mobile.feature.onboarding.language.di.SetOnboardingLanguageModu
import org.mifos.mobile.feature.passcode.di.PasscodeModule
import org.mifos.mobile.feature.qr.di.QrModule
import org.mifos.mobile.feature.recent.transaction.di.recentTransactionModule
import org.mifos.mobile.feature.savings.application.di.savingsApplicationModule
import org.mifos.mobile.feature.savingsaccount.di.savingsAccountModule
import org.mifos.mobile.feature.settings.di.SettingsModule
import org.mifos.mobile.feature.shareaccount.di.shareAccountModule
Expand Down Expand Up @@ -79,6 +80,7 @@ object KoinModules {
PasscodeModule,
StatusModule,
loanApplicationModule,
savingsApplicationModule,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,6 @@ object Constants {
const val APPLY_LOAN = "apply_loan"
const val NAVIGATE_BACK_TO_SAVINGS = "navigate_back_to_savings"
const val NAVIGATE_BACK_TO_LOAN = "navigate_back_to_loan"

const val APPLY_SAVINGS = "apply_savings"
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ interface SavingsAccountRepository {

fun getSavingAccountApplicationTemplate(clientId: Long?): Flow<DataState<SavingsAccountTemplate>>

fun getSavingAccountApplicationTemplateByProduct(
clientId: Long?,
productId: Long?,
): Flow<DataState<SavingsAccountTemplate>>

suspend fun submitSavingAccountApplication(payload: SavingsAccountApplicationPayload?): DataState<String>

suspend fun updateSavingsAccount(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ class SavingsAccountRepositoryImp(
.asDataStateFlow().flowOn(ioDispatcher)
}

override fun getSavingAccountApplicationTemplateByProduct(
clientId: Long?,
productId: Long?,
): Flow<DataState<SavingsAccountTemplate>> {
return dataManager.savingAccountsListApi.getSavingsAccountApplicationTemplateByProduct(
clientId,
productId,
).asDataStateFlow().flowOn(ioDispatcher)
}

override suspend fun submitSavingAccountApplication(
payload: SavingsAccountApplicationPayload?,
): DataState<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import fluent.ui.system.icons.filled.QrCode
import fluent.ui.system.icons.filled.QuestionCircle
import fluent.ui.system.icons.filled.Receipt
import fluent.ui.system.icons.filled.ReceiptMoney
import fluent.ui.system.icons.filled.Savings
import fluent.ui.system.icons.filled.SignOut
import fluent.ui.system.icons.filled.TableCellEdit
import fluent.ui.system.icons.filled.Wallet
Expand Down Expand Up @@ -191,6 +192,7 @@ object MifosIcons {
val LoanAccount = FluentIcons.Filled.CoinMultiple
val ShareAccount = FluentIcons.Filled.DataWhisker
val ApplyForLoan = FluentIcons.Filled.Receipt
val ApplyForSavings = FluentIcons.Filled.Savings
val TransactionHistory = FluentIcons.Filled.ChatHistory
val Charges = FluentIcons.Filled.Feed
val Beneficiary = FluentIcons.Filled.ContactCardRibbon
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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.entity.templates.savings

import kotlinx.serialization.Serializable
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize

@Serializable
@Parcelize
data class FieldOfficerOptions(
val id: Int,
val firstname: String? = null,
val lastname: String? = null,
val displayName: String? = null,
val officeId: Int? = null,
val officeName: String? = null,
val isLoanOfficer: Boolean? = null,
val isActive: Boolean? = null,
) : Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,36 @@ package org.mifos.mobile.core.model.entity.templates.savings
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
import org.mifos.mobile.core.model.entity.accounts.savings.Currency

@Serializable
@Parcelize
data class SavingsAccountTemplate(
val clientId: Int = 0,
val clientName: String? = null,
val savingsProductId: Int? = null,
val savingsProductName: String? = null,
val timeline: Timeline? = null,
val currency: Currency? = null,
val nominalAnnualInterestRate: Double? = null,
val interestCompoundingPeriodType: ProductOptions? = null,
val interestPostingPeriodType: ProductOptions? = null,
val interestCalculationType: ProductOptions? = null,
val interestCalculationDaysInYearType: ProductOptions? = null,
val minRequiredOpeningBalance: Double? = null,
val withdrawalFeeForTransfers: Boolean? = null,
val allowOverdraft: Boolean? = null,
val enforceMinRequiredBalance: Boolean? = null,
val withHoldTax: Boolean? = null,
val isDormancyTrackingActive: Boolean? = null,
val charges: List<ChargeOptions>? = null,
val productOptions: ArrayList<ProductOptions> = arrayListOf(),
val fieldOfficerOptions: List<FieldOfficerOptions> = emptyList(),
val interestCompoundingPeriodTypeOptions: List<SavingsOptions> = emptyList(),
val interestPostingPeriodTypeOptions: List<SavingsOptions> = emptyList(),
val interestCalculationTypeOptions: List<SavingsOptions> = emptyList(),
val interestCalculationDaysInYearTypeOptions: List<SavingsOptions> = emptyList(),
val lockinPeriodFrequencyTypeOptions: List<SavingsOptions> = emptyList(),
val withdrawalFeeTypeOptions: List<SavingsOptions> = emptyList(),
val chargeOptions: ArrayList<ChargeOptions> = arrayListOf(),
) : Parcelable
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.entity.templates.savings

import kotlinx.serialization.Serializable
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize

@Serializable
@Parcelize
data class SavingsOptions(
val id: Int,
val code: String,
val value: String,
) : Parcelable
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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.entity.templates.savings

import kotlinx.serialization.Serializable
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize

@Serializable
@Parcelize
data class Timeline(
val expectedDisbursementDate: List<Int> = emptyList(),
) : Parcelable
Loading
Loading