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 @@ -118,6 +118,7 @@ internal fun AuthenticatedNavbarNavigationScreen(
name = "AuthenticatedNavbarScreen",
),
navigateToNewLoanAccountScreen: (Int) -> Unit,
navigateToNewSavingsAccountScreen: (Int) -> Unit,
viewModel: AuthenticatedNavbarNavigationViewModel = koinViewModel(),
) {
val scope = rememberCoroutineScope()
Expand Down Expand Up @@ -179,6 +180,7 @@ internal fun AuthenticatedNavbarNavigationScreen(
navigateToDocumentScreen = navigateToDocumentScreen,
navigateToNoteScreen = navigateToNoteScreen,
navigateToNewLoanAccountScreen = navigateToNewLoanAccountScreen,
navigateToNewSavingsAccountScreen = navigateToNewSavingsAccountScreen,
)
}

Expand All @@ -190,6 +192,7 @@ internal fun AuthenticatedNavbarNavigationScreenContent(
navigateToDocumentScreen: (Int, String) -> Unit,
navigateToNoteScreen: (Int, String) -> Unit,
navigateToNewLoanAccountScreen: (Int) -> Unit,
navigateToNewSavingsAccountScreen: (Int) -> Unit,
modifier: Modifier = Modifier,
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
onAction: (AuthenticatedNavBarAction) -> Unit,
Expand Down Expand Up @@ -433,6 +436,7 @@ internal fun AuthenticatedNavbarNavigationScreenContent(
hasDatatables = navController::navigateDataTableList,
onDocumentClicked = navigateToDocumentScreen,
navigateToNewLoanAccount = navigateToNewLoanAccountScreen,
navigateToNewSavingsAccount = navigateToNewSavingsAccountScreen,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ internal fun NavGraphBuilder.authenticatedNavbarGraph(
navigateToDocumentScreen: (Int, String) -> Unit,
navigateToNoteScreen: (Int, String) -> Unit,
navigateToNewLoanAccountScreen: (Int) -> Unit,
navigateToNewSavingsAccountScreen: (Int) -> Unit,
) {
composable<AuthenticatedNavbar> {
AuthenticatedNavbarNavigationScreen(
onDrawerItemClick = onDrawerItemClick,
navigateToDocumentScreen = navigateToDocumentScreen,
navigateToNoteScreen = navigateToNoteScreen,
navigateToNewLoanAccountScreen = navigateToNewLoanAccountScreen,
navigateToNewSavingsAccountScreen = navigateToNewSavingsAccountScreen,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.mifos.feature.offline.navigation.offlineNavGraph
import com.mifos.feature.path.tracking.navigation.pathTrackingRoute
import com.mifos.feature.report.navigation.reportNavGraph
import com.mifos.feature.savings.navigation.savingsNavGraph
import com.mifos.feature.savings.savingsAccountv2.navigateToSavingsAccountRoute
import com.mifos.feature.settings.navigation.settingsScreen
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
Expand Down Expand Up @@ -61,6 +62,7 @@ internal fun NavGraphBuilder.authenticatedGraph(
navigateToDocumentScreen = navController::navigateToDocumentListScreen,
navigateToNoteScreen = navController::navigateToNoteScreen,
navigateToNewLoanAccountScreen = navController::navigateToNewLoanAccountRoute,
navigateToNewSavingsAccountScreen = navController::navigateToSavingsAccountRoute,
)

checkerInboxTaskNavGraph(navController)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import com.mifos.core.domain.useCases.GetClientDetailsUseCase
import com.mifos.core.domain.useCases.GetClientIdentifierTemplateUseCase
import com.mifos.core.domain.useCases.GetClientPinpointLocationsUseCase
import com.mifos.core.domain.useCases.GetClientSavingsAccountTemplateByProductUseCase
import com.mifos.core.domain.useCases.GetClientTemplateUseCase
import com.mifos.core.domain.useCases.GetDataTableInfoUseCase
import com.mifos.core.domain.useCases.GetDocumentsListUseCase
import com.mifos.core.domain.useCases.GetGroupDetailsUseCase
Expand Down Expand Up @@ -104,6 +105,7 @@ val UseCaseModule = module {
factoryOf(::CreateLoanAccountUseCase)
factoryOf(::CreateLoanChargesUseCase)
factoryOf(::CreateSavingsAccountUseCase)
factoryOf(::GetClientTemplateUseCase)
factoryOf(::DeleteCheckerUseCase)
factoryOf(::DeleteClientAddressPinpointUseCase)
factoryOf(::DeleteDataTableEntryUseCase)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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/android-client/blob/master/LICENSE.md
*/
package com.mifos.core.domain.useCases

import com.mifos.core.common.utils.DataState
import com.mifos.core.data.repository.CreateNewClientRepository
import com.mifos.room.entities.templates.clients.ClientsTemplateEntity
import kotlinx.coroutines.flow.Flow

class GetClientTemplateUseCase(
private val newClientRepository: CreateNewClientRepository,
) {
operator fun invoke(): Flow<DataState<ClientsTemplateEntity>> {
return newClientRepository.clientTemplate()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ object TextFieldsValidator {
}
}

fun optionalStringValidator(input: String): StringResource? {
return when {
input.any { !it.isLetterOrDigit() && !it.isWhitespace() } -> Res.string.error_invalid_characters
else -> null // valid
}
}

fun numberValidator(input: String): StringResource? {
return when {
input.isBlank() -> Res.string.error_field_empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ data class ClientApplyNewApplicationRoute(
fun NavGraphBuilder.clientApplyNewApplicationRoute(
onNavigateBack: () -> Unit,
onNavigateApplyLoanAccount: (Int) -> Unit,
onNavigateApplySavingsAccount: () -> Unit,
onNavigateApplySavingsAccount: (Int) -> Unit,
onNavigateApplyShareAccount: () -> Unit,
onNavigateApplyRecurringAccount: () -> Unit,
onNavigateApplyFixedAccount: () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import org.koin.compose.viewmodel.koinViewModel
internal fun ClientApplyNewApplicationsScreen(
onNavigateBack: () -> Unit,
onNavigateApplyLoanAccount: (Int) -> Unit,
onNavigateApplySavingsAccount: () -> Unit,
onNavigateApplySavingsAccount: (Int) -> Unit,
onNavigateApplyShareAccount: () -> Unit,
onNavigateApplyRecurringAccount: () -> Unit,
onNavigateApplyFixedAccount: () -> Unit,
Expand All @@ -74,7 +74,7 @@ internal fun ClientApplyNewApplicationsScreen(
ClientApplyNewApplicationsItem.NewFixedAccount -> onNavigateApplyFixedAccount()
ClientApplyNewApplicationsItem.NewLoanAccount -> onNavigateApplyLoanAccount(state.clientId)
ClientApplyNewApplicationsItem.NewRecurringAccount -> onNavigateApplyRecurringAccount()
ClientApplyNewApplicationsItem.NewSavingsAccount -> onNavigateApplySavingsAccount()
ClientApplyNewApplicationsItem.NewSavingsAccount -> onNavigateApplySavingsAccount(state.clientId)
ClientApplyNewApplicationsItem.NewShareAccount -> onNavigateApplyShareAccount()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ fun NavGraphBuilder.clientNavGraph(
hasDatatables: KFunction4<List<DataTableEntity>, Any?, Int, MutableList<List<FormWidgetDTO>>, Unit>,
onDocumentClicked: (Int, String) -> Unit,
navigateToNewLoanAccount: (Int) -> Unit,
navigateToNewSavingsAccount: (Int) -> Unit,
) {
navigation<ClientNavGraph>(
startDestination = ClientListScreenRoute,
Expand Down Expand Up @@ -252,7 +253,7 @@ fun NavGraphBuilder.clientNavGraph(
clientApplyNewApplicationRoute(
onNavigateBack = navController::popBackStack,
onNavigateApplyLoanAccount = navigateToNewLoanAccount,
onNavigateApplySavingsAccount = { },
onNavigateApplySavingsAccount = navigateToNewSavingsAccount,
onNavigateApplyShareAccount = { },
onNavigateApplyRecurringAccount = { },
onNavigateApplyFixedAccount = { },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
<string name="feature_savings_go_back">Go Back</string>
<string name="feature_savings_product">Savings Products</string>
<string name="feature_savings_submit">Submit</string>
<string name="feature_savings_select">Select</string>
<string name="feature_savings_external_id_not_unique">ExternalId must be unique</string>
<string name="feature_savings_submission_date">Submission Date</string>
<string name="feature_savings_next">Next</string>
<string name="feature_savings_back">Back</string>
<string name="feature_savings_create_savings_account">Add Savings Account</string>
<string name="feature_savings_savings_account_submitted_for_approval">The Savings Account has been submitted forApproval</string>
<string name="feature_savings_field_officer">Field Officer</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import com.mifos.feature.savings.savingsAccountApproval.SavingsAccountApprovalVi
import com.mifos.feature.savings.savingsAccountSummary.SavingsAccountSummaryViewModel
import com.mifos.feature.savings.savingsAccountTransaction.SavingsAccountTransactionViewModel
import com.mifos.feature.savings.savingsAccountTransactionReceipt.SavingsAccountTransactionReceiptViewModel
import com.mifos.feature.savings.savingsAccountv2.SavingsAccountViewModel
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module

val SavingsModule = module {
viewModelOf(::SavingAccountViewModel)
viewModelOf(::SavingsAccountViewModel)
viewModelOf(::SavingsAccountActivateViewModel)
viewModelOf(::SavingsAccountApprovalViewModel)
viewModelOf(::SavingsAccountSummaryViewModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ fun NavGraphBuilder.savingsNavGraph(
onBackPressed()
}

savingsAccountDestination()
savingsAccountDestination(
navController = navController,
onNavigateBack = onBackPressed,
onFinish = onBackPressed,
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,26 @@ import androidx.navigation.compose.composable
import kotlinx.serialization.Serializable

@Serializable
data object SavingsAccountRoute
data class SavingsAccountRoute(
val clientId: Int = -1,
)

fun NavGraphBuilder.savingsAccountDestination() {
fun NavGraphBuilder.savingsAccountDestination(
navController: NavController,
onNavigateBack: () -> Unit,
onFinish: () -> Unit,
) {
composable<SavingsAccountRoute> {
SavingsAccountScreen(
onNavigateBack = {},
onFinish = {},
onNavigateBack = onNavigateBack,
onFinish = onFinish,
navController = navController,
)
}
}

fun NavController.navigateToSavingsAccountRoute() {
fun NavController.navigateToSavingsAccountRoute(clientId: Int) {
this.navigate(
SavingsAccountRoute,
SavingsAccountRoute(clientId = clientId),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,25 @@ package com.mifos.feature.savings.savingsAccountv2

import androidclient.feature.savings.generated.resources.Res
import androidclient.feature.savings.generated.resources.feature_savings_create_savings_account
import androidclient.feature.savings.generated.resources.feature_savings_error_not_connected_internet
import androidclient.feature.savings.generated.resources.step_charges
import androidclient.feature.savings.generated.resources.step_details
import androidclient.feature.savings.generated.resources.step_preview
import androidclient.feature.savings.generated.resources.step_terms
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.mifos.core.designsystem.component.MifosScaffold
import com.mifos.core.designsystem.component.MifosSweetError
import com.mifos.core.ui.components.MifosBreadcrumbNavBar
import com.mifos.core.ui.components.MifosProgressIndicator
import com.mifos.core.ui.components.MifosProgressIndicatorOverlay
import com.mifos.core.ui.components.MifosStepper
import com.mifos.core.ui.components.Step
import com.mifos.core.ui.util.EventsEffect
Expand All @@ -30,13 +38,15 @@ import com.mifos.feature.savings.savingsAccountv2.pages.DetailsPage
import com.mifos.feature.savings.savingsAccountv2.pages.PreviewPage
import com.mifos.feature.savings.savingsAccountv2.pages.TermsPage
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel

@Composable
internal fun SavingsAccountScreen(
navController: NavController,
onNavigateBack: () -> Unit,
onFinish: () -> Unit,
modifier: Modifier = Modifier,
viewModel: SavingsAccountViewModel = androidx.lifecycle.viewmodel.compose.viewModel(),
viewModel: SavingsAccountViewModel = koinViewModel(),
) {
val state by viewModel.stateFlow.collectAsStateWithLifecycle()

Expand All @@ -47,24 +57,32 @@ internal fun SavingsAccountScreen(
}
}

NewSavingsAccountDialog(
state = state,
onAction = { viewModel.trySendAction(it) },
)

SavingsAccountScaffold(
modifier = modifier,
state = state,
onAction = { viewModel.trySendAction(it) },
navController = navController,
)
}

@Composable
private fun SavingsAccountScaffold(
navController: NavController,
state: SavingsAccountState,
modifier: Modifier = Modifier,
onAction: (SavingsAccountAction) -> Unit,
) {
val steps = listOf(
Step(stringResource(Res.string.step_details)) {
DetailsPage {
onAction(SavingsAccountAction.NextStep)
}
DetailsPage(
state = state,
onAction = onAction,
)
},
Step(stringResource(Res.string.step_terms)) {
TermsPage {
Expand All @@ -88,17 +106,51 @@ private fun SavingsAccountScaffold(
onBackPressed = { onAction(SavingsAccountAction.NavigateBack) },
modifier = modifier,
) { paddingValues ->
if (state.dialogState == null) {
MifosStepper(
steps = steps,
currentIndex = state.currentStep,
onStepChange = { newIndex ->
onAction(SavingsAccountAction.OnStepChange(newIndex))
},
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues),
when (state.screenState) {
is SavingsAccountState.ScreenState.Loading -> MifosProgressIndicator()
is SavingsAccountState.ScreenState.Success -> {
Column(
Modifier.fillMaxSize().padding(paddingValues),
) {
MifosBreadcrumbNavBar(
navController,
)
MifosStepper(
steps = steps,
currentIndex = state.currentStep,
onStepChange = { newIndex ->
onAction(SavingsAccountAction.OnStepChange(newIndex))
},
modifier = Modifier
.fillMaxWidth(),
)
}
}
is SavingsAccountState.ScreenState.NetworkError -> {
MifosSweetError(
message = stringResource(Res.string.feature_savings_error_not_connected_internet),
onclick = { onAction(SavingsAccountAction.Retry) },
)
}
}
if (state.isOverLayLoadingActive) {
MifosProgressIndicatorOverlay()
}
}
}

@Composable
private fun NewSavingsAccountDialog(
state: SavingsAccountState,
onAction: (SavingsAccountAction) -> Unit,
) {
when (state.dialogState) {
is SavingsAccountState.DialogState.Error -> {
MifosSweetError(
message = state.dialogState.message,
onclick = { onAction(SavingsAccountAction.Retry) },
)
}
null -> Unit
}
}
Loading