diff --git a/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/FixedDepositRepository.kt b/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/FixedDepositRepository.kt new file mode 100644 index 00000000000..495116ef1bc --- /dev/null +++ b/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/FixedDepositRepository.kt @@ -0,0 +1,11 @@ +package com.mifos.core.data.repository + +import com.mifos.core.common.utils.DataState +import com.mifos.core.network.model.FixedDepositTemplate +import kotlinx.coroutines.flow.Flow + +interface FixedDepositRepository { + fun getFixedDepositTemplate(clientId: Int): Flow> + + +} \ No newline at end of file diff --git a/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/FixedDepositRepositoryImpl.kt b/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/FixedDepositRepositoryImpl.kt new file mode 100644 index 00000000000..cf4277feff0 --- /dev/null +++ b/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/FixedDepositRepositoryImpl.kt @@ -0,0 +1,20 @@ +package com.mifos.core.data.repositoryImp + + +import com.mifos.core.common.utils.DataState +import com.mifos.core.common.utils.asDataStateFlow +import com.mifos.core.data.repository.FixedDepositRepository +import com.mifos.core.network.datamanager.DataManagerFixedDeposit +import com.mifos.core.network.model.FixedDepositTemplate +import kotlinx.coroutines.flow.Flow + +class FixedDepositRepositoryImpl (private val dataManagerFixedDeposit: DataManagerFixedDeposit): FixedDepositRepository{ + + override fun getFixedDepositTemplate(clientId: Int): Flow> { + return dataManagerFixedDeposit.getFixedDepositTemplate(clientId).asDataStateFlow() + } + + + + +} diff --git a/core/database/src/commonMain/kotlin/com/mifos/room/basemodel/APIEndPoint.kt b/core/database/src/commonMain/kotlin/com/mifos/room/basemodel/APIEndPoint.kt index 4936e62aac3..4ad734e31a9 100644 --- a/core/database/src/commonMain/kotlin/com/mifos/room/basemodel/APIEndPoint.kt +++ b/core/database/src/commonMain/kotlin/com/mifos/room/basemodel/APIEndPoint.kt @@ -40,4 +40,6 @@ object APIEndPoint { const val DISBURSE = "disburse" const val NOTES = "notes" const val MAKER_CHECKER = "makercheckers" + + const val FIXED_DEPOSIT ="fixeddepositaccounts" } diff --git a/core/database/src/commonMain/kotlin/com/mifos/room/entities/accounts/savings/SavingAccountDepositTypeEntity.kt b/core/database/src/commonMain/kotlin/com/mifos/room/entities/accounts/savings/SavingAccountDepositTypeEntity.kt index e2d5de3f468..5ce7d5cdd6d 100644 --- a/core/database/src/commonMain/kotlin/com/mifos/room/entities/accounts/savings/SavingAccountDepositTypeEntity.kt +++ b/core/database/src/commonMain/kotlin/com/mifos/room/entities/accounts/savings/SavingAccountDepositTypeEntity.kt @@ -44,7 +44,7 @@ data class SavingAccountDepositTypeEntity( enum class ServerTypes(val id: Int, val code: String, val endpoint: String) { SAVINGS(100, "depositAccountType.savingsDeposit", APIEndPoint.SAVINGS_ACCOUNTS), - FIXED(200, "depositAccountType.fixedDeposit", APIEndPoint.SAVINGS_ACCOUNTS), + FIXED(200, "depositAccountType.fixedDeposit", APIEndPoint.FIXED_DEPOSIT), RECURRING(300, "depositAccountType.recurringDeposit", APIEndPoint.RECURRING_ACCOUNTS), ; diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/BaseApiManager.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/BaseApiManager.kt index 241e17b6866..9c511a824eb 100644 --- a/core/network/src/commonMain/kotlin/com/mifos/core/network/BaseApiManager.kt +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/BaseApiManager.kt @@ -43,6 +43,7 @@ import com.mifos.core.network.services.SavingsAccountService import com.mifos.core.network.services.SearchService import com.mifos.core.network.services.StaffService import com.mifos.core.network.services.SurveyService +import com.mifos.core.network.services.FixedDepositService import com.mifos.core.network.services.createCenterService import com.mifos.core.network.services.createChargeService import com.mifos.core.network.services.createCheckerInboxService @@ -58,6 +59,7 @@ import com.mifos.core.network.services.createOfficeService import com.mifos.core.network.services.createRecurringAccountService import com.mifos.core.network.services.createRunReportsService import com.mifos.core.network.services.createSavingsAccountService +import com.mifos.core.network.services.createFixedDepositService import com.mifos.core.network.services.createSearchService import com.mifos.core.network.services.createStaffService import com.mifos.core.network.services.createSurveyService @@ -74,6 +76,7 @@ class BaseApiManager( val dataTableService: DataTableService = ktorfit.createDataTableService() val loanService: LoanService = ktorfit.createLoanService() val savingsService: SavingsAccountService = ktorfit.createSavingsAccountService() + val fixedDepositService: FixedDepositService = ktorfit.createFixedDepositService() val recurringSavingsAccountService: RecurringAccountService = ktorfit.createRecurringAccountService() val searchService: SearchService = ktorfit.createSearchService() diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerFixedDeposit.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerFixedDeposit.kt new file mode 100644 index 00000000000..e10f45e3814 --- /dev/null +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerFixedDeposit.kt @@ -0,0 +1,12 @@ +package com.mifos.core.network.datamanager + +import com.mifos.core.network.BaseApiManager +import com.mifos.core.network.model.FixedDepositTemplate +import kotlinx.coroutines.flow.Flow + +class DataManagerFixedDeposit (private val baseApiManager: BaseApiManager){ + + fun getFixedDepositTemplate(clientId:Int): Flow = + baseApiManager.fixedDepositService.fixedDepositProductTemplate(clientId) + +} \ No newline at end of file diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/di/DataMangerModule.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/di/DataMangerModule.kt index b3c48a79dfa..fd0432ecfda 100644 --- a/core/network/src/commonMain/kotlin/com/mifos/core/network/di/DataMangerModule.kt +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/di/DataMangerModule.kt @@ -21,6 +21,7 @@ import com.mifos.core.network.datamanager.DataManagerDataTable import com.mifos.core.network.datamanager.DataManagerDocument import com.mifos.core.network.datamanager.DataManagerGroups import com.mifos.core.network.datamanager.DataManagerIdentifiers +import com.mifos.core.network.datamanager.DataManagerFixedDeposit import com.mifos.core.network.datamanager.DataManagerLoan import com.mifos.core.network.datamanager.DataManagerNote import com.mifos.core.network.datamanager.DataManagerOffices @@ -51,4 +52,5 @@ val DataManagerModule = module { single { DataManagerStaff(get(), get(), get()) } single { DataManagerSurveys(get(), get(), get()) } single { DataManagerIdentifiers(get()) } + single { DataManagerFixedDeposit(get()) } } diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositProductOption.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositProductOption.kt new file mode 100644 index 00000000000..992a83fe979 --- /dev/null +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositProductOption.kt @@ -0,0 +1,20 @@ +package com.mifos.core.network.model + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class FixedDepositProductOption( + @SerialName("id") + val id: Int, + + @SerialName("name") + val name: String, + + @SerialName("shortName") + val shortName: String, + + @SerialName("totalShares") + val totalShares: Int, +) \ No newline at end of file diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositTemplate.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositTemplate.kt new file mode 100644 index 00000000000..88c0f9b860d --- /dev/null +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/model/FixedDepositTemplate.kt @@ -0,0 +1,18 @@ +package com.mifos.core.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + + +@Serializable +data class FixedDepositTemplate( + @SerialName("clientId") + val clientId: Int, + + @SerialName(value = "clientName") + val clientName: String, + + @SerialName("productOptions") + val productOptions: List = emptyList(), +) \ No newline at end of file diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/services/FixedDepositService.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/services/FixedDepositService.kt new file mode 100644 index 00000000000..42407c799bb --- /dev/null +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/services/FixedDepositService.kt @@ -0,0 +1,25 @@ +package com.mifos.core.network.services + +import com.mifos.core.network.model.FixedDepositTemplate +import com.mifos.room.basemodel.APIEndPoint +import de.jensklingenberg.ktorfit.http.Query +import de.jensklingenberg.ktorfit.http.GET +import kotlinx.coroutines.flow.Flow + + + + + + +interface FixedDepositService { + + @GET( APIEndPoint.FIXED_DEPOSIT + "/template") + fun fixedDepositProductTemplate( + @Query("clientId") clientId: Int, + ): Flow +} + + + + + diff --git a/feature/client/src/commonMain/composeResources/values/strings.xml b/feature/client/src/commonMain/composeResources/values/strings.xml index 0c715494a8a..8939d93e4c0 100644 --- a/feature/client/src/commonMain/composeResources/values/strings.xml +++ b/feature/client/src/commonMain/composeResources/values/strings.xml @@ -530,6 +530,12 @@ Update Document New Fixed Deposit Account + New Recurring Deposit Account + + 1 Year Fixed Deposit + Submission On + Field Officer + \ No newline at end of file diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationRoute.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationRoute.kt index 38d69d23b80..cbc13565efa 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationRoute.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationRoute.kt @@ -25,7 +25,7 @@ fun NavGraphBuilder.clientApplyNewApplicationRoute( onNavigateApplySavingsAccount: (Int) -> Unit, onNavigateApplyShareAccount: () -> Unit, onNavigateApplyRecurringAccount: () -> Unit, - onNavigateApplyFixedAccount: () -> Unit, + onNavigateApplyFixedAccount: (Int) -> Unit, navController: NavController, ) { composable { diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationsScreen.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationsScreen.kt index 1af152e0c0d..1be75216dd4 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationsScreen.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientApplyNewApplications/ClientApplyNewApplicationsScreen.kt @@ -60,7 +60,7 @@ internal fun ClientApplyNewApplicationsScreen( onNavigateApplySavingsAccount: (Int) -> Unit, onNavigateApplyShareAccount: () -> Unit, onNavigateApplyRecurringAccount: () -> Unit, - onNavigateApplyFixedAccount: () -> Unit, + onNavigateApplyFixedAccount: (Int) -> Unit, navController: NavController, viewModel: ClientApplyNewApplicationsViewModel = koinViewModel(), ) { @@ -71,7 +71,7 @@ internal fun ClientApplyNewApplicationsScreen( ClientApplyNewApplicationsEvent.NavigateBack -> onNavigateBack() is ClientApplyNewApplicationsEvent.OnActionClick -> { when (event.action) { - ClientApplyNewApplicationsItem.NewFixedAccount -> onNavigateApplyFixedAccount() + ClientApplyNewApplicationsItem.NewFixedAccount -> onNavigateApplyFixedAccount(state.clientId) ClientApplyNewApplicationsItem.NewLoanAccount -> onNavigateApplyLoanAccount(state.clientId) ClientApplyNewApplicationsItem.NewRecurringAccount -> onNavigateApplyRecurringAccount() ClientApplyNewApplicationsItem.NewSavingsAccount -> onNavigateApplySavingsAccount(state.clientId) diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/di/ClientModule.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/di/ClientModule.kt index 4a2928b9355..bd7d090815d 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/di/ClientModule.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/di/ClientModule.kt @@ -39,6 +39,7 @@ import com.mifos.feature.client.clientsList.ClientListViewModel import com.mifos.feature.client.createNewClient.CreateNewClientViewModel import com.mifos.feature.client.documentPreviewScreen.DocumentPreviewScreenViewModel import com.mifos.feature.client.fixedDepositAccount.FixedDepositAccountViewModel +import com.mifos.feature.client.newFixedDepositAccount.CreateFixedDepositAccountViewmodel import com.mifos.feature.client.recurringDepositAccount.RecurringDepositAccountViewModel import com.mifos.feature.client.savingsAccounts.SavingsAccountsViewModel import com.mifos.feature.client.shareAccounts.ShareAccountsViewModel @@ -81,6 +82,7 @@ val ClientModule = module { viewModelOf(::ShareAccountsViewModel) viewModelOf(::ClientIdentifiersListViewModel) viewModelOf(::ClientIdentifiersAddUpdateViewModel) + viewModelOf(::CreateFixedDepositAccountViewmodel) singleOf(::DocumentSelectAndUploadRepositoryImpl) { bind() diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt index 8e04acf5fdf..dcef52a1497 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/navigation/ClientNavigation.kt @@ -75,8 +75,9 @@ import com.mifos.feature.client.documentPreviewScreen.createDocumentPreviewRoute import com.mifos.feature.client.documentPreviewScreen.navigateToDocumentPreviewRoute import com.mifos.feature.client.fixedDepositAccount.clientFixedDepositAccountDestination import com.mifos.feature.client.fixedDepositAccount.navigateToFixedDepositAccountRoute -import com.mifos.feature.client.newFixedDepositAccount.fixedAccountDestination -import com.mifos.feature.client.newFixedDepositAccount.navigateToNewFixedDepositRoute +import com.mifos.feature.client.newFixedDepositAccount.createFixedDepositAccountRoute +import com.mifos.feature.client.newFixedDepositAccount.createFixedDepositAccountDestination +import com.mifos.feature.client.newFixedDepositAccount.navigateToCreateFixedDepositRoute import com.mifos.feature.client.recurringDepositAccount.clientRecurringDepositAccountDestination import com.mifos.feature.client.recurringDepositAccount.navigateToRecurringDepositAccountRoute import com.mifos.feature.client.savingsAccounts.navigateToClientSavingsAccountsRoute @@ -312,7 +313,7 @@ fun NavGraphBuilder.clientNavGraph( onNavigateApplyLoanAccount = navController::navigateToNewLoanAccountRoute, onNavigateApplySavingsAccount = navController::navigateToSavingsAccountRoute, onNavigateApplyRecurringAccount = navController::navigateToRecurringAccountRoute, - onNavigateApplyFixedAccount = navController::navigateToNewFixedDepositRoute, + onNavigateApplyFixedAccount = navController::navigateToCreateFixedDepositRoute, navController = navController, ) clientUpcomingChargesDestination( @@ -343,7 +344,7 @@ fun NavGraphBuilder.clientNavGraph( shareAccountDestination() recurringAccountDestination() - fixedAccountDestination() + createFixedDepositAccountDestination(navController = navController) } } diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountViewmodel.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountViewmodel.kt deleted file mode 100644 index 3c047f1a0d4..00000000000 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountViewmodel.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.feature.client.newFixedDepositAccount - -import com.mifos.core.ui.util.BaseViewModel -import kotlinx.coroutines.flow.update - -class NewFixedDepositAccountViewmodel : - BaseViewModel< - NewFixedDepositAccountState, - NewFixedDepositAccountEvent, - NewFixedDepositAccountAction, - >(NewFixedDepositAccountState()) { - override fun handleAction(action: NewFixedDepositAccountAction) { - when (action) { - NewFixedDepositAccountAction.NextStep -> - mutableStateFlow.update { state -> - val maxIndex = 4 - state.copy(currentStep = (state.currentStep + 1).coerceAtMost(maxIndex)) - } - is NewFixedDepositAccountAction.OnStepChange -> { - mutableStateFlow.update { it.copy(currentStep = action.index) } - } - is NewFixedDepositAccountAction.NavigateBack -> { - sendEvent(NewFixedDepositAccountEvent.NavigateBack) - } - NewFixedDepositAccountAction.Finish -> { - sendEvent(NewFixedDepositAccountEvent.Finish) - } - } - } -} - -data class NewFixedDepositAccountState( - val currentStep: Int = 0, - val dialogState: Any? = null, -) -sealed class NewFixedDepositAccountAction() { - object NextStep : NewFixedDepositAccountAction() - data class OnStepChange(val index: Int) : NewFixedDepositAccountAction() - object NavigateBack : NewFixedDepositAccountAction() - object Finish : NewFixedDepositAccountAction() -} -sealed class NewFixedDepositAccountEvent() { - object NavigateBack : NewFixedDepositAccountEvent() - object Finish : NewFixedDepositAccountEvent() -} diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountNavigation.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountRoute.kt similarity index 57% rename from feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountNavigation.kt rename to feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountRoute.kt index 423e28e82df..7656af5fbf6 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountNavigation.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountRoute.kt @@ -15,18 +15,24 @@ import androidx.navigation.compose.composable import kotlinx.serialization.Serializable @Serializable -data object FixedDepositRoute -fun NavGraphBuilder.fixedAccountDestination() { - composable { - FixedDepositAccountScreen( - onNavigateBack = {}, +data class createFixedDepositAccountRoute( + val clientId: Int, +) + + + +fun NavGraphBuilder.createFixedDepositAccountDestination(navController: NavController) { + composable { + CreateFixedDepositAccountScreen( + onNavigateBack = navController::popBackStack, onFinish = {}, + navController = navController, ) } } -fun NavController.navigateToNewFixedDepositRoute() { +fun NavController.navigateToCreateFixedDepositRoute(clientId: Int) { this.navigate( - FixedDepositRoute, + createFixedDepositAccountRoute(clientId=clientId) ) } diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountScreen.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountScreen.kt similarity index 94% rename from feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountScreen.kt rename to feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountScreen.kt index 6b07e2d29a8..07c62a60b1d 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/FixedDepositAccountScreen.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController import com.mifos.core.designsystem.component.MifosScaffold import com.mifos.core.ui.components.MifosStepper import com.mifos.core.ui.components.Step @@ -34,11 +35,12 @@ import com.mifos.feature.client.newFixedDepositAccount.pages.TermsPage import org.jetbrains.compose.resources.stringResource @Composable -internal fun FixedDepositAccountScreen( +internal fun CreateFixedDepositAccountScreen( onNavigateBack: () -> Unit, + navController: NavController, onFinish: () -> Unit, modifier: Modifier = Modifier, - viewModel: NewFixedDepositAccountViewmodel = viewModel(), + viewModel: CreateFixedDepositAccountViewmodel = viewModel(), ) { val state by viewModel.stateFlow.collectAsStateWithLifecycle() EventsEffect(viewModel.eventFlow) { event -> @@ -64,7 +66,8 @@ private fun FixedDepositAccountScaffold( listOf( Step(stringResource(Res.string.step_details)) { DetailsPage( - onNext = { onAction(NewFixedDepositAccountAction.NextStep) }, + state = state, + onAction = onAction, ) }, Step(name = stringResource(Res.string.step_terms)) { diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountViewmodel.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountViewmodel.kt new file mode 100644 index 00000000000..03c3b3dd7d4 --- /dev/null +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/createFixedDepositAccountViewmodel.kt @@ -0,0 +1,119 @@ +/* + * 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.feature.client.newFixedDepositAccount + +import com.mifos.core.common.utils.DateHelper +import com.mifos.core.ui.util.BaseViewModel +import com.mifos.room.entities.templates.clients.SavingProductOptionsEntity +import com.mifos.room.entities.templates.clients.StaffOptionsEntity +import kotlinx.coroutines.flow.update +import org.jetbrains.compose.resources.StringResource +import kotlin.time.Clock +import kotlin.time.ExperimentalTime + +class CreateFixedDepositAccountViewmodel : + BaseViewModel< + NewFixedDepositAccountState, + NewFixedDepositAccountEvent, + NewFixedDepositAccountAction, + >(NewFixedDepositAccountState()) { + override fun handleAction(action: NewFixedDepositAccountAction) { + when (action) { + is NewFixedDepositAccountAction.NextStep -> moveToNextStep() + is NewFixedDepositAccountAction.OnStepChange -> handleStepChange(action) + is NewFixedDepositAccountAction.NavigateBack -> sendEvent(NewFixedDepositAccountEvent.NavigateBack) + is NewFixedDepositAccountAction.Finish -> sendEvent(NewFixedDepositAccountEvent.Finish) + is NewFixedDepositAccountAction.OnSubmissionDatePick -> handleSubmissionDatePick(action) + is NewFixedDepositAccountAction.OnSubmissionDateChange -> handleSubmissionDateChange(action) + is NewFixedDepositAccountAction.OnProductNameChange -> handleOnProductNameChange(action) + is NewFixedDepositAccountAction.OnFieldOfficerChange -> handleFieldOfficerChange(action) + is NewFixedDepositAccountAction.OnExternalIdChange -> handleExternalIdChange(action) + NewFixedDepositAccountAction.OnDetailsSubmit -> handleOnDetailsSubmit() + } + } + private fun handleSubmissionDateChange(action: NewFixedDepositAccountAction.OnSubmissionDateChange) { + mutableStateFlow.update { it.copy(submissionDate = action.date) } + } + private fun handleStepChange(action: NewFixedDepositAccountAction.OnStepChange) { + mutableStateFlow.update { it.copy(currentStep = action.newIndex) } + } + + private fun handleSubmissionDatePick(action: NewFixedDepositAccountAction.OnSubmissionDatePick) { + mutableStateFlow.update { it.copy(showSubmissionDatePick = action.state) } + } + private fun handleOnProductNameChange(action: NewFixedDepositAccountAction.OnProductNameChange) { + mutableStateFlow.update { it.copy(fixedDepositProductSelected = action.index) } + } + private fun handleFieldOfficerChange(action: NewFixedDepositAccountAction.OnFieldOfficerChange) { + mutableStateFlow.update { it.copy(fieldOfficerIndex = action.index) } + } + private fun handleExternalIdChange(action: NewFixedDepositAccountAction.OnExternalIdChange) { + mutableStateFlow.update { it.copy(externalId = action.value) } + } + private fun handleOnDetailsSubmit() { + mutableStateFlow.update { + it.copy( + externalIdError = null, + ) + } + } + private fun moveToNextStep() { + val current = state.currentStep + if (current < state.totalSteps) { + mutableStateFlow.update { + it.copy( + currentStep = current + 1, + ) + } + } else { + sendEvent(NewFixedDepositAccountEvent.Finish) + } + } + + +} + +data class NewFixedDepositAccountState @OptIn(ExperimentalTime::class) constructor( + val currentStep: Int = 0, + val dialogState: Any? = null, + val showSubmissionDatePick: Boolean = false, + val fixedDepositProductSelected: Int = -1, + val fixedDepositProductOptions: List = emptyList(), + val submissionDate: String = DateHelper.getDateAsStringFromLong(Clock.System.now().toEpochMilliseconds()), + val fieldOfficerIndex: Int = -1, + val fieldOfficerOptions: List = emptyList(), + val externalId: String = "", + val externalIdError: StringResource? = null, + val totalSteps: Int = 4, + + +){ + val isDetailsNextEnabled = submissionDate.isNotEmpty() && + fixedDepositProductSelected != -1 && + fieldOfficerIndex != -1 +} +sealed class NewFixedDepositAccountAction() { + object NextStep : NewFixedDepositAccountAction() + data class OnStepChange(val newIndex: Int) : NewFixedDepositAccountAction() + object NavigateBack : NewFixedDepositAccountAction() + data class OnSubmissionDatePick(val state: Boolean) : NewFixedDepositAccountAction() + data class OnSubmissionDateChange(val date: String) : NewFixedDepositAccountAction() + data class OnProductNameChange(val index: Int) : NewFixedDepositAccountAction() + object Finish : NewFixedDepositAccountAction() + data class OnFieldOfficerChange(val index: Int) : NewFixedDepositAccountAction() + data class OnExternalIdChange(val value: String) : NewFixedDepositAccountAction() + data object OnDetailsSubmit : NewFixedDepositAccountAction() + + +} +sealed class NewFixedDepositAccountEvent() { + object NavigateBack : NewFixedDepositAccountEvent() + object Finish : NewFixedDepositAccountEvent() +} diff --git a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt index 99017367eec..be6fbadfb23 100644 --- a/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt +++ b/feature/client/src/commonMain/kotlin/com/mifos/feature/client/newFixedDepositAccount/pages/DetailsPage.kt @@ -9,26 +9,164 @@ */ package com.mifos.feature.client.newFixedDepositAccount.pages +import androidclient.feature.client.generated.resources.Field_officer import androidclient.feature.client.generated.resources.Res +import androidclient.feature.client.generated.resources.btn_back + +import androidclient.feature.client.generated.resources.feature_client_next +import androidclient.feature.client.generated.resources.step_charges import androidclient.feature.client.generated.resources.step_details +import androidclient.feature.client.generated.resources.step_interest +import androidclient.feature.client.generated.resources.one_year_fixed_deposit +import androidclient.feature.client.generated.resources.submission_on + + import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.material3.Button +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.DatePicker +import androidx.compose.material3.DatePickerDialog +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SelectableDates import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import com.mifos.core.common.utils.DateHelper +import com.mifos.core.designsystem.component.MifosDatePickerTextField +import com.mifos.core.designsystem.component.MifosOutlinedTextField +import com.mifos.core.designsystem.component.MifosTextFieldConfig +import com.mifos.core.designsystem.component.MifosTextFieldDropdown +import com.mifos.core.designsystem.theme.DesignToken +import com.mifos.core.ui.components.MifosTwoButtonRow +import com.mifos.feature.client.newFixedDepositAccount.NewFixedDepositAccountAction +import com.mifos.feature.client.newFixedDepositAccount.NewFixedDepositAccountState import org.jetbrains.compose.resources.stringResource +import kotlin.time.Clock +import kotlin.time.ExperimentalTime +@OptIn(ExperimentalMaterial3Api::class, ExperimentalTime::class) @Composable -fun DetailsPage(onNext: () -> Unit) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text(stringResource(Res.string.step_details)) - Spacer(Modifier.height(8.dp)) - Button(onClick = onNext) { - Text("Next Button") +fun DetailsPage( + state : NewFixedDepositAccountState, + onAction: (NewFixedDepositAccountAction) -> Unit, + modifier: Modifier = Modifier, + + ) { + val submissionDatePickerState = rememberDatePickerState( + initialSelectedDateMillis = Clock.System.now().toEpochMilliseconds(), + selectableDates = object : SelectableDates { + override fun isSelectableDate(utcTimeMillis: Long): Boolean { + return utcTimeMillis >= Clock.System.now().toEpochMilliseconds().minus(86_400_000L) + } + } + + ) + if (state.showSubmissionDatePick) { + DatePickerDialog( + onDismissRequest = { + onAction(NewFixedDepositAccountAction.OnSubmissionDatePick(state = false)) + }, + confirmButton = { + TextButton( + onClick = { + onAction(NewFixedDepositAccountAction.OnSubmissionDatePick(state = false)) + submissionDatePickerState.selectedDateMillis?.let { + onAction( + NewFixedDepositAccountAction.OnSubmissionDateChange( + DateHelper.getDateAsStringFromLong(it), + ), + ) + } + }, + ) { Text("Hello World") } + }, + dismissButton = { + TextButton( + onClick = { + onAction(NewFixedDepositAccountAction.OnSubmissionDatePick(state = false)) + }, + ) { Text("jljks") } + }, + ) { + DatePicker(state = submissionDatePickerState) + } + + } + Column (modifier = modifier.fillMaxSize()){ + Column( + modifier = modifier.weight(1f).verticalScroll(rememberScrollState()), + ) { + + MifosTextFieldDropdown( + value = if (state.fixedDepositProductSelected == -1) { + "" + } else { + state.fixedDepositProductOptions[state.fixedDepositProductSelected].name + }, + label = stringResource(Res.string.one_year_fixed_deposit), + onValueChanged = {}, + onOptionSelected = { index, value -> + onAction(NewFixedDepositAccountAction.OnProductNameChange(index)) + }, + options = state.fixedDepositProductOptions.map { + it.name + }, + + + + ) + MifosDatePickerTextField( + value = state.submissionDate, + label = stringResource(Res.string.submission_on), + openDatePicker = { + onAction(NewFixedDepositAccountAction.OnSubmissionDatePick(true)) + }, + ) + Spacer(Modifier.height(DesignToken.padding.large)) + MifosTextFieldDropdown( + value = if (state.fieldOfficerIndex == -1) { + "" + } else { + state.fieldOfficerOptions[state.fieldOfficerIndex].displayName + }, + label = stringResource(Res.string.Field_officer), + onValueChanged = {}, + onOptionSelected = { index, value -> + onAction(NewFixedDepositAccountAction.OnFieldOfficerChange(index)) + }, + options = state.fieldOfficerOptions.map { + it.displayName + } + + ) + MifosOutlinedTextField( + value = state.externalId, + onValueChange = { + onAction(NewFixedDepositAccountAction.OnExternalIdChange(it)) + }, + label = stringResource(Res.string.step_details), + config = MifosTextFieldConfig( + isError = state.externalIdError != null, + errorText = if (state.externalIdError != null) stringResource(state.externalIdError) else null, + ), + ) + Spacer(Modifier.height(DesignToken.padding.large)) } + MifosTwoButtonRow( + firstBtnText = stringResource(Res.string.btn_back), + secondBtnText = stringResource(Res.string.feature_client_next), + onFirstBtnClick = { onAction(NewFixedDepositAccountAction.NavigateBack) }, + onSecondBtnClick = { onAction(NewFixedDepositAccountAction.OnDetailsSubmit) }, + isSecondButtonEnabled = state.isDetailsNextEnabled, + modifier = Modifier.padding(top = DesignToken.padding.small), + ) + } + }