diff --git a/cmp-navigation/src/commonMain/kotlin/cmp/navigation/di/KoinModules.kt b/cmp-navigation/src/commonMain/kotlin/cmp/navigation/di/KoinModules.kt index cce03ab981..4d14674e00 100644 --- a/cmp-navigation/src/commonMain/kotlin/cmp/navigation/di/KoinModules.kt +++ b/cmp-navigation/src/commonMain/kotlin/cmp/navigation/di/KoinModules.kt @@ -31,7 +31,7 @@ import com.mifos.feature.loan.di.LoanModule import com.mifos.feature.note.di.NoteModule import com.mifos.feature.offline.di.OfflineModule import com.mifos.feature.path.tracking.di.PathTrackingModule -import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.di.RecurringDepositModule +import com.mifos.feature.recurringDeposit.di.RecurringDepositModule import com.mifos.feature.report.di.ReportModule import com.mifos.feature.savings.di.SavingsModule import com.mifos.feature.search.di.SearchModule diff --git a/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt b/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt index b6da3df34a..cee9d8f11d 100644 --- a/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt +++ b/core/data/src/commonMain/kotlin/com/mifos/core/data/repository/RecurringAccountRepository.kt @@ -17,11 +17,9 @@ import kotlinx.coroutines.flow.Flow interface RecurringAccountRepository { - fun getRecuttingAccountRepository(): Flow> - - fun getRecuttingAccountRepositoryBtProduct( + fun getRecurringAccountTemplate( clientId: Int, - productId: Int, + productId: Int? = null, ): Flow> fun createRecurringDepositAccount( diff --git a/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt b/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt index 72ffcc43ca..35722fa534 100644 --- a/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt +++ b/core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/RecurringAccountRepositoryImp.kt @@ -21,16 +21,12 @@ import kotlinx.coroutines.flow.Flow class RecurringAccountRepositoryImp( val dataManagerRecurringAccount: DataManagerRecurringAccount, ) : RecurringAccountRepository { - override fun getRecuttingAccountRepository(): Flow> { - return dataManagerRecurringAccount.getRecurringDepositAccountTemplate - .asDataStateFlow() - } - override fun getRecuttingAccountRepositoryBtProduct( + override fun getRecurringAccountTemplate( clientId: Int, - productId: Int, + productId: Int?, ): Flow> { - return dataManagerRecurringAccount.getRecurringDepositAccountTemplateByProduct( + return dataManagerRecurringAccount.getRecurringDepositAccountTemplate( clientId, productId, ).asDataStateFlow() diff --git a/core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosOutlinedTextField.kt b/core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosOutlinedTextField.kt index 8c5da4d655..e4bcf207b4 100644 --- a/core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosOutlinedTextField.kt +++ b/core/designsystem/src/commonMain/kotlin/com/mifos/core/designsystem/component/MifosOutlinedTextField.kt @@ -436,7 +436,13 @@ fun MifosOutlinedTextField( shape = shape, colors = colors, value = value, - label = { Text(text = label) }, + label = { + Text( + text = label, + maxLines = 1, + softWrap = true, + ) + }, onValueChange = onValueChange, textStyle = textStyle, modifier = modifier.fillMaxWidth(), @@ -448,6 +454,7 @@ fun MifosOutlinedTextField( interactionSource = interactionSource, singleLine = config.singleLine, maxLines = config.maxLines, + prefix = config.prefix, minLines = config.minLines, leadingIcon = config.leadingIcon, isError = config.isError, @@ -494,6 +501,7 @@ data class MifosTextFieldConfig( val keyboardOptions: KeyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), val trailingIcon: @Composable (() -> Unit)? = null, val leadingIcon: @Composable (() -> Unit)? = null, + val prefix: @Composable (() -> Unit)? = null, ) @Preview diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt index fd3c1caa91..92201a86aa 100644 --- a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/payloads/RecurringDepositAccountPayload.kt @@ -13,9 +13,9 @@ import kotlinx.serialization.Serializable @Serializable data class RecurringDepositAccountPayload( + // val charges: List? = null, val adjustAdvanceTowardsFuturePayments: Boolean? = null, val allowWithdrawal: Boolean? = null, -// val charges: List? = null, val clientId: Int? = null, val dateFormat: String? = null, val depositPeriod: Int? = null, diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt index 2fa161c073..04b7e73c6e 100644 --- a/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/datamanager/DataManagerRecurringAccount.kt @@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.Flow class DataManagerRecurringAccount( val mBaseApiManager: BaseApiManager, ) { - fun createRecurringDepositAccount( recurringDepositAccountPayload: RecurringDepositAccountPayload?, ): Flow { @@ -27,14 +26,11 @@ class DataManagerRecurringAccount( ) } - val getRecurringDepositAccountTemplate: Flow - get() = mBaseApiManager.recurringSavingsAccountService.getRecurringDepositAccountTemplate() - - fun getRecurringDepositAccountTemplateByProduct( + fun getRecurringDepositAccountTemplate( clientId: Int, - productId: Int, + productId: Int?, ): Flow { - return mBaseApiManager.recurringSavingsAccountService.getRecurringDepositAccountTemplateByProduct( + return mBaseApiManager.recurringSavingsAccountService.getRecurringDepositAccountTemplate( clientId, productId, ) diff --git a/core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt b/core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt index 350c8b0a27..494f654b4f 100644 --- a/core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt +++ b/core/network/src/commonMain/kotlin/com/mifos/core/network/services/RecurringAccountService.kt @@ -27,11 +27,8 @@ interface RecurringAccountService { ): Flow @GET(APIEndPoint.CREATE_RECURRING_DEPOSIT_ACCOUNTS + "/template") - fun getRecurringDepositAccountTemplate(): Flow - - @GET(APIEndPoint.CREATE_RECURRING_DEPOSIT_ACCOUNTS + "/template") - fun getRecurringDepositAccountTemplateByProduct( + fun getRecurringDepositAccountTemplate( @Query("clientId") clientId: Int, - @Query("productId") productId: Int, + @Query("productId") productId: Int?, ): Flow } diff --git a/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml b/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml new file mode 100644 index 0000000000..b82f0de3f8 --- /dev/null +++ b/feature/recurringDeposit/src/commonMain/composeResources/values/feature_recurring_deposit_string.xml @@ -0,0 +1,52 @@ + + + + Details + Terms + Settings + Interest + Charges + Create Recurring Deposit Account + Is Mandatory Deposit? + Adjust advance payments toward future installments? + Allow Withdrawals? + Lock-in Period + Frequency + Type + Recurring Deposit Details + Recurring Deposit Amount + Deposit Period + Deposit Frequency Same as Group/Center meeting + Minimum Deposit Term + And thereafter, in Multiples of + Maximum Deposit Term + For Pre-mature closure + Apply Penal Interest (less) + Penal Interest (%) + Period + Minimum Balance For Interest Calculation + Back + Next + No Internet Connection + Select + Cancel + Product Name + Submitted On + Field Officer + External Id + Deposit amount is required + Lock-in period frequency is required + Recurring frequency is required + Terms Page + Next Button + Interest Page + Charges Page + \ No newline at end of file diff --git a/feature/recurringDeposit/src/commonMain/composeResources/values/string.xml b/feature/recurringDeposit/src/commonMain/composeResources/values/string.xml deleted file mode 100644 index 524d3433da..0000000000 --- a/feature/recurringDeposit/src/commonMain/composeResources/values/string.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - Details - Terms - Settings - Interest - Charges - Create Recurring Deposit Account - - - Select - Cancel - Product Name - Submitted On - Field Officer - External Id - Back - Next - \ No newline at end of file diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/di/RecurringDepositModule.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/di/RecurringDepositModule.kt new file mode 100644 index 0000000000..bf5e9f53fa --- /dev/null +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/di/RecurringDepositModule.kt @@ -0,0 +1,18 @@ +/* + * 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.recurringDeposit.di + +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountViewModel +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module + +val RecurringDepositModule = module { + viewModelOf(::RecurringAccountViewModel) +} diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt index 3704063f2b..da6bc13695 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountRoute.kt @@ -24,9 +24,9 @@ fun NavGraphBuilder.recurringAccountDestination( ) { composable { RecurringAccountScreen( + navController = navController, onNavigateBack = {}, onFinish = {}, - navController = navController, ) } } diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt index 595d1a5e7c..6d9f1a85c8 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountScreen.kt @@ -10,12 +10,12 @@ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount import androidclient.feature.recurringdeposit.generated.resources.Res -import androidclient.feature.recurringdeposit.generated.resources.create_recurring_deposit_account -import androidclient.feature.recurringdeposit.generated.resources.step_charges -import androidclient.feature.recurringdeposit.generated.resources.step_details -import androidclient.feature.recurringdeposit.generated.resources.step_interest -import androidclient.feature.recurringdeposit.generated.resources.step_settings -import androidclient.feature.recurringdeposit.generated.resources.step_terms +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_create_recurring_deposit_account +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_charges +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_details +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_interest +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_settings +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_terms import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -23,7 +23,6 @@ import androidx.compose.runtime.Composable 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.MifosBreadcrumbNavBar @@ -32,6 +31,7 @@ import com.mifos.core.ui.components.MifosProgressIndicator import com.mifos.core.ui.components.MifosStepper import com.mifos.core.ui.components.Step import com.mifos.core.ui.util.EventsEffect +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountAction.NavigateToStep import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.ChargesPage import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.DetailsPage import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages.InterestPage @@ -58,51 +58,52 @@ internal fun RecurringAccountScreen( } RecurringAccountScaffold( + navController = navController, modifier = modifier, state = state, onAction = { viewModel.trySendAction(it) }, - navController = navController, ) } @Composable private fun RecurringAccountScaffold( - state: RecurringAccountState, navController: NavController, + state: RecurringAccountState, modifier: Modifier = Modifier, onAction: (RecurringAccountAction) -> Unit, ) { val steps = listOf( - Step(name = stringResource(Res.string.step_details)) { + Step(name = stringResource(Res.string.feature_recurring_deposit_step_details)) { DetailsPage( state = state, onAction = onAction, ) }, - Step(name = stringResource(Res.string.step_terms)) { + Step(name = stringResource(Res.string.feature_recurring_deposit_step_terms)) { TermsPage( - onNext = { onAction(RecurringAccountAction.NextStep) }, + onNext = { onAction(RecurringAccountAction.OnNextPress) }, ) }, - Step(name = stringResource(Res.string.step_settings)) { + Step(name = stringResource(Res.string.feature_recurring_deposit_step_settings)) { SettingPage( - onNext = { onAction(RecurringAccountAction.NextStep) }, + state = state, + onAction = onAction, ) }, - Step(name = stringResource(Res.string.step_interest)) { + Step(name = stringResource(Res.string.feature_recurring_deposit_step_interest)) { InterestPage( - onNext = { onAction(RecurringAccountAction.NextStep) }, + onNext = { onAction(RecurringAccountAction.OnNextPress) }, ) }, - Step(name = stringResource(Res.string.step_charges)) { + Step(name = stringResource(Res.string.feature_recurring_deposit_step_charges)) { ChargesPage( - onNext = { onAction(RecurringAccountAction.NextStep) }, + onNext = { onAction(RecurringAccountAction.OnNextPress) }, ) }, ) MifosScaffold( - title = stringResource(Res.string.create_recurring_deposit_account), + title = stringResource(Res.string.feature_recurring_deposit_create_recurring_deposit_account), onBackPressed = { onAction(RecurringAccountAction.NavigateBack) }, modifier = modifier, ) { paddingValues -> @@ -112,26 +113,26 @@ private fun RecurringAccountScaffold( .padding(paddingValues), ) { MifosBreadcrumbNavBar(navController) - when (state.state) { - is RecurringAccountState.State.Error -> { + when (state.screenState) { + is RecurringAccountState.ScreenState.Error -> { MifosErrorComponent( - message = state.state.message, + message = state.screenState.message, isRetryEnabled = true, ) { onAction(RecurringAccountAction.Retry) } } - is RecurringAccountState.State.Loading -> { + is RecurringAccountState.ScreenState.Loading -> { MifosProgressIndicator() } - is RecurringAccountState.State.Success -> { + is RecurringAccountState.ScreenState.Success -> { MifosStepper( steps = steps, currentIndex = state.currentStep, onStepChange = { newIndex -> - onAction(RecurringAccountAction.OnStepChange(newIndex)) + onAction(NavigateToStep(newIndex)) }, modifier = Modifier .fillMaxWidth(), diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt index 5f14d81154..d477224f7f 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/RecurringAccountViewModel.kt @@ -9,21 +9,33 @@ */ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount +import androidclient.feature.recurringdeposit.generated.resources.Res +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_deposit_amount_is_required +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_lock_in_period_frequency_is_required +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_no_internet_connection +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_recurring_frequency_is_required import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute import com.mifos.core.common.utils.DataState import com.mifos.core.data.repository.RecurringAccountRepository +import com.mifos.core.data.util.NetworkMonitor +import com.mifos.core.model.objects.payloads.RecurringDepositAccountPayload import com.mifos.core.model.objects.template.recurring.FieldOfficerOption import com.mifos.core.ui.util.BaseViewModel +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountState.ScreenState import com.mifos.room.entities.templates.recurringDeposit.RecurringDepositAccountTemplate +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.getString + +const val TOTAL_STEPS = 4 class RecurringAccountViewModel( + savedStateHandle: SavedStateHandle, + private val networkMonitor: NetworkMonitor, private val recurringAccountRepo: RecurringAccountRepository, - private val savedStateHandle: SavedStateHandle, ) : BaseViewModel< RecurringAccountState, RecurringAccountEvent, @@ -39,108 +51,202 @@ class RecurringAccountViewModel( loadRecurringAccountTemplate() } - override fun handleAction(action: RecurringAccountAction) { - when (action) { - RecurringAccountAction.NextStep -> { - mutableStateFlow.update { state -> - val maxIndex = 4 - state.copy(currentStep = (state.currentStep + 1).coerceAtMost(maxIndex)) - } - } - - is RecurringAccountAction.OnStepChange -> { - mutableStateFlow.update { it.copy(currentStep = action.index) } - } + private fun setLoadingState() { + mutableStateFlow.update { + it.copy( + screenState = ScreenState.Loading, + ) + } + } + private fun setSuccessState() { + mutableStateFlow.update { + it.copy(screenState = ScreenState.Success) + } + } - RecurringAccountAction.NavigateBack -> { - sendEvent(RecurringAccountEvent.NavigateBack) - } + private fun setErrorState(message: String) { + mutableStateFlow.update { + it.copy( + screenState = ScreenState.Error(message), + ) + } + } - RecurringAccountAction.Finish -> { - sendEvent(RecurringAccountEvent.Finish) + private fun moveToNextStep() { + if (state.currentStep < state.totalSteps) { + mutableStateFlow.update { + it.copy( + currentStep = state.currentStep + 1, + ) } + } else { + sendEvent(RecurringAccountEvent.Finish) + } + } - is RecurringAccountAction.OnProductNameChange -> handleProductNameChange(action) + private fun createRecurringDepositAccount() { + viewModelScope.launch { + val s = state + val settings = s.recurringDepositAccountSettings - is RecurringAccountAction.OnSubmissionDateChange -> handleSubmissionDateChange(action) + val online = networkMonitor.isOnline.first() + if (!online) { + setErrorState(getString(Res.string.feature_recurring_deposit_no_internet_connection)) + return@launch + } + val lockInFreq = settings.lockInPeriod.frequency.toIntOrNull() + val depositAmountInt = settings.recurringDepositDetails.depositAmount + .filter(Char::isDigit) + .toIntOrNull() + val recurringFreq = settings.minimumDepositTerm.frequency.toIntOrNull() - is RecurringAccountAction.OnSubmissionDatePick -> handleSubmissionDatePick(action) + val payload = RecurringDepositAccountPayload( + adjustAdvanceTowardsFuturePayments = settings.adjustAdvancePayments, + allowWithdrawal = settings.allowWithdrawals, + clientId = state.clientId, + dateFormat = "dd MMMM yyyy", + depositPeriod = settings.depositPeriod.period.toIntOrNull(), + depositPeriodFrequencyId = settings.depositPeriod.periodType, + expectedFirstDepositOnDate = null, + externalId = s.recurringDepositAccountDetail.externalId, + fieldOfficerId = s.recurringDepositAccountDetail.fieldOfficer?.id, + interestCalculationDaysInYearType = null, + interestCalculationType = null, + interestCompoundingPeriodType = null, + interestPostingPeriodType = null, + isCalendarInherited = null, + isMandatoryDeposit = settings.isMandatory, + locale = "en", + lockinPeriodFrequency = lockInFreq, + lockinPeriodFrequencyType = settings.lockInPeriod.frequencyTypeIndex, + mandatoryRecommendedDepositAmount = depositAmountInt, + monthDayFormat = "dd MMMM", + productId = s.recurringDepositAccountDetail.productId, + recurringFrequency = recurringFreq, + recurringFrequencyType = settings.minimumDepositTerm.frequencyTypeIndex, + // date in dd MM yyyy format. + submittedOnDate = s.recurringDepositAccountDetail.submittedOnDate, + ) - is RecurringAccountAction.OnFieldOfficerChange -> handleFieldOfficerChange(action) + if (state.isOnline) { + recurringAccountRepo.createRecurringDepositAccount(payload).collect { dataState -> + when (dataState) { + is DataState.Error -> { + if (depositAmountInt == null) { + setErrorState(getString(Res.string.feature_recurring_deposit_deposit_amount_is_required)) + } else if (lockInFreq == null) { + setErrorState(getString(Res.string.feature_recurring_deposit_lock_in_period_frequency_is_required)) + } else if (recurringFreq == null) { + setErrorState(getString(Res.string.feature_recurring_deposit_recurring_frequency_is_required)) + } else { + setErrorState(dataState.message) + } + } - is RecurringAccountAction.OnExternalIdChange -> handleExternalIdChange(action) + is DataState.Loading -> { + setLoadingState() + } - RecurringAccountAction.Retry -> resetForRetry() + is DataState.Success -> { + setSuccessState() + } + } + } + } } } - private fun handleProductNameChange(action: RecurringAccountAction.OnProductNameChange) { + private fun handleProductNameChange(action: RecurringAccountAction.RecurringAccountDetailsAction.OnProductNameChange) { mutableStateFlow.update { it.copy( - loanProductSelected = action.index, + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + loanProductSelected = action.index, + ), ) } - loadRecurringAccountTemplateWithProduct(state.clientId, state.template?.productOptions?.get(state.loanProductSelected)?.id ?: -1) + loadRecurringAccountTemplateWithProduct( + state.clientId, + state.template.productOptions?.get(state.recurringDepositAccountDetail.loanProductSelected)?.id ?: -1, + ) } private fun resetForRetry() { mutableStateFlow.update { it.copy( + isOnline = false, + clientId = -1, currentStep = 0, - template = null, - state = RecurringAccountState.State.Loading, - fieldOfficerOptions = emptyList(), + screenState = ScreenState.Loading, + recurringDepositAccountDetail = RecurringAccountDetailsState(), + template = RecurringDepositAccountTemplate(), + recurringDepositAccountSettings = RecurringAccountSettingsState(), + currencyIndex = -1, + currencyError = null, ) } loadRecurringAccountTemplate() } - private fun handleFieldOfficerChange(action: RecurringAccountAction.OnFieldOfficerChange) { + private fun handleFieldOfficerChange(action: RecurringAccountAction.RecurringAccountDetailsAction.OnFieldOfficerChange) { mutableStateFlow.update { it.copy( - fieldOfficerIndex = action.index, - fieldOfficerError = null, + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + fieldOfficerIndex = action.index, + fieldOfficerError = null, + ), ) } } - private fun handleSubmissionDatePick(action: RecurringAccountAction.OnSubmissionDatePick) { - mutableStateFlow.update { it.copy(showSubmissionDatePick = action.state) } + private fun handleSubmissionDatePick(action: RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDatePick) { + mutableStateFlow.update { + it.copy( + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + showSubmissionDatePick = action.state, + ), + ) + } } - private fun handleSubmissionDateChange(action: RecurringAccountAction.OnSubmissionDateChange) { - mutableStateFlow.update { it.copy(submissionDate = action.date) } + private fun handleSubmissionDateChange(action: RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDateChange) { + mutableStateFlow.update { + it.copy( + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + submissionDate = action.date, + ), + ) + } } - private fun handleExternalIdChange(action: RecurringAccountAction.OnExternalIdChange) { - mutableStateFlow.update { it.copy(externalId = action.value) } + private fun handleExternalIdChange(action: RecurringAccountAction.RecurringAccountDetailsAction.OnExternalIdChange) { + mutableStateFlow.update { + it.copy( + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + externalId = action.value, + ), + ) + } } private fun loadRecurringAccountTemplate() = viewModelScope.launch { - recurringAccountRepo.getRecuttingAccountRepository().collect { state -> + recurringAccountRepo.getRecurringAccountTemplate(clientId = state.clientId).collect { state -> when (state) { is DataState.Success -> { + setSuccessState() mutableStateFlow.update { it.copy( - state = RecurringAccountState.State.Success, template = state.data, + isOnline = true, ) } } + is DataState.Error -> { - mutableStateFlow.update { - it.copy( - state = RecurringAccountState.State.Error(state.message), - ) - } + setErrorState(state.message) } DataState.Loading -> { - mutableStateFlow.update { - it.copy( - state = RecurringAccountState.State.Loading, - ) - } + setLoadingState() } } } @@ -150,66 +256,368 @@ class RecurringAccountViewModel( clientId: Int, productId: Int, ) = viewModelScope.launch { - recurringAccountRepo.getRecuttingAccountRepositoryBtProduct(clientId, productId).collect { state -> + recurringAccountRepo.getRecurringAccountTemplate(clientId, productId).collect { state -> when (state) { is DataState.Success -> { mutableStateFlow.update { it.copy( - state = RecurringAccountState.State.Success, + screenState = ScreenState.Success, template = state.data, - fieldOfficerOptions = state.data.fieldOfficerOptions, - isMiniLoaderActive = false, + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + isMiniLoaderActive = false, + ), ) } } + is DataState.Error -> { + setErrorState(state.message) mutableStateFlow.update { it.copy( - state = RecurringAccountState.State.Error(state.message), - isMiniLoaderActive = false, + recurringDepositAccountDetail = it.recurringDepositAccountDetail.copy( + isMiniLoaderActive = false, + ), ) } } DataState.Loading -> { + setLoadingState() + } + } + } + } + + override fun handleAction(action: RecurringAccountAction) { + when (action) { + RecurringAccountAction.Retry -> { + resetForRetry() + } + + is RecurringAccountAction.RecurringAccountSettingsAction -> { + when (action) { + is RecurringAccountAction.RecurringAccountSettingsAction.SetDepositPeriod -> { + mutableStateFlow.update { state -> + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + depositPeriod = state.recurringDepositAccountSettings.depositPeriod.copy( + period = action.period, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetDepositPeriodType -> { + mutableStateFlow.update { state -> + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + depositPeriod = state.recurringDepositAccountSettings.depositPeriod.copy( + periodType = state.template.periodFrequencyTypeOptions?.get( + action.periodType, + )?.id ?: -1, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetLockInPeriod -> { + mutableStateFlow.update { state -> + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + lockInPeriod = state.recurringDepositAccountSettings.lockInPeriod.copy( + frequency = action.frequency, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetLockInPeriodType -> { + mutableStateFlow.update { state -> + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + lockInPeriod = state.recurringDepositAccountSettings.lockInPeriod.copy( + frequencyTypeIndex = state.template.lockinPeriodFrequencyTypeOptions?.get( + action.frequencyTypeIndex, + )?.id ?: -1, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreq -> { + mutableStateFlow.update { state -> + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + minimumDepositTerm = state.recurringDepositAccountSettings.minimumDepositTerm.copy( + frequency = action.frequency, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreqType -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + minimumDepositTerm = state.recurringDepositAccountSettings.minimumDepositTerm.copy( + frequencyTypeIndex = state.template.periodFrequencyTypeOptions?.get( + action.frequencyTypeIndex, + )?.id ?: -1, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreqAfterInMultiOf -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + minimumDepositTerm = state.recurringDepositAccountSettings.minimumDepositTerm.copy( + frequencyAfterInMultiplesOf = action.frequencyAfterInMultiplesOf, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreqTypeAfterInMultiOf -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + minimumDepositTerm = state.recurringDepositAccountSettings.minimumDepositTerm.copy( + frequencyTypeIndexAfterInMultiplesOf = state.template.periodFrequencyTypeOptions?.get( + action.frequencyTypeIndexAfterInMultiplesOf, + )?.id ?: -1, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetMaxDepositTermFreq -> { + mutableStateFlow.update { state -> + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + maxDepositTerm = state.recurringDepositAccountSettings.maxDepositTerm.copy( + frequency = action.frequency, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetMaxDepositTermFreqType -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + maxDepositTerm = state.recurringDepositAccountSettings.maxDepositTerm.copy( + frequencyTypeIndex = state.template.periodFrequencyTypeOptions?.get( + action.frequencyTypeIndex, + )?.id ?: -1, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosureInterestPeriodIndex -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + preMatureClosure = state.recurringDepositAccountSettings.preMatureClosure.copy( + interestPeriodIndex = state.template.preClosurePenalInterestOnTypeOptions?.get( + action.interestPeriodIndex, + )?.id ?: -1, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosureMinimumBalanceForInterestCalculation -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + preMatureClosure = state.recurringDepositAccountSettings.preMatureClosure.copy( + minimumBalanceForInterestCalculation = action.minimumBalanceForInterestCalculation, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosurePenalInterest -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + preMatureClosure = state.recurringDepositAccountSettings.preMatureClosure.copy( + penalInterest = action.penalInterest, + ), + ), + ) + } + } + + is RecurringAccountAction.RecurringAccountSettingsAction.SetRecurringDepositAmount -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + recurringDepositDetails = state.recurringDepositAccountSettings + .recurringDepositDetails.copy( + depositAmount = action.depositAmount, + ), + ), + ) + } + } + + RecurringAccountAction.RecurringAccountSettingsAction.ToggleAdvancePaymentsTowardsFutureInstallments -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + adjustAdvancePayments = !state.recurringDepositAccountSettings.adjustAdvancePayments, + ), + ) + } + } + + RecurringAccountAction.RecurringAccountSettingsAction.ToggleAllowWithdrawals -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + allowWithdrawals = !state.recurringDepositAccountSettings.allowWithdrawals, + ), + ) + } + } + + RecurringAccountAction.RecurringAccountSettingsAction.ToggleDepositFrequencySameAsGroupCenterMeeting -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + depositPeriod = state.recurringDepositAccountSettings.depositPeriod.copy( + depositFrequencySameAsGroupCenterMeeting = !state.recurringDepositAccountSettings + .depositPeriod.depositFrequencySameAsGroupCenterMeeting, + ), + ), + ) + } + } + + RecurringAccountAction.RecurringAccountSettingsAction.ToggleMandatoryDeposit -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + isMandatory = !state.recurringDepositAccountSettings.isMandatory, + ), + ) + } + } + + RecurringAccountAction.RecurringAccountSettingsAction.TogglePreMatureClosureApplyPenalInterest -> { + mutableStateFlow.update { + state.copy( + recurringDepositAccountSettings = state.recurringDepositAccountSettings.copy( + preMatureClosure = state.recurringDepositAccountSettings.preMatureClosure.copy( + applyPenalInterest = !state.recurringDepositAccountSettings + .preMatureClosure.applyPenalInterest, + ), + ), + ) + } + } + } + } + + is RecurringAccountAction.RecurringAccountDetailsAction -> { + when (action) { + is RecurringAccountAction.RecurringAccountDetailsAction.OnProductNameChange -> { + handleProductNameChange(action) + } + is RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDateChange -> { + handleSubmissionDateChange(action) + } + is RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDatePick -> { + handleSubmissionDatePick(action) + } + is RecurringAccountAction.RecurringAccountDetailsAction.OnFieldOfficerChange -> { + handleFieldOfficerChange(action) + } + is RecurringAccountAction.RecurringAccountDetailsAction.OnExternalIdChange -> { + handleExternalIdChange(action) + } + } + } + + RecurringAccountAction.NavigateBack -> { + sendEvent(RecurringAccountEvent.NavigateBack) + } + + is RecurringAccountAction.NavigateToStep -> { + val newIndex = action.index + if (newIndex in 0..state.totalSteps) { mutableStateFlow.update { - it.copy( - isMiniLoaderActive = true, - ) + it.copy(currentStep = newIndex) } } } + + RecurringAccountAction.OnBackPress -> { + mutableStateFlow.update { + it.copy(currentStep = 3) + } + } + + RecurringAccountAction.OnNextPress -> { + moveToNextStep() + } } } } data class RecurringAccountState( - val clientId: Int, + val isOnline: Boolean = false, + val clientId: Int = -1, val currentStep: Int = 0, + val totalSteps: Int = TOTAL_STEPS, + val screenState: ScreenState = ScreenState.Loading, + val recurringDepositAccountDetail: RecurringAccountDetailsState = RecurringAccountDetailsState(), + val template: RecurringDepositAccountTemplate = RecurringDepositAccountTemplate(), + val recurringDepositAccountSettings: RecurringAccountSettingsState = RecurringAccountSettingsState(), val currencyIndex: Int = -1, val currencyError: String? = null, - val loanProductSelected: Int = -1, - val template: RecurringDepositAccountTemplate? = null, - val fieldOfficerOptions: List? = null, - val recurringDepositAccountSettings: RecurringAccountSettingsState = RecurringAccountSettingsState(), - val state: State = State.Loading, +) { + sealed interface ScreenState { + data class Error(val message: String) : ScreenState + data object Loading : ScreenState + data object Success : ScreenState + } +} + +data class RecurringAccountDetailsState( + val productId: Int = -1, + val submittedOnDate: String = "", + val fieldOfficer: FieldOfficerOption? = null, val showSubmissionDatePick: Boolean = false, + val loanProductSelected: Int = -1, val submissionDate: String = "", val fieldOfficerIndex: Int = -1, - val fieldOfficerError: StringResource? = null, + val fieldOfficerError: String? = null, val externalId: String = "", val isMiniLoaderActive: Boolean = false, + val fieldOfficerOptions: List? = null, ) { - sealed interface State { - data object Success : State - data class Error(val message: String) : State - object Loading : State - } - val isDetailButtonEnabled = fieldOfficerIndex != -1 && submissionDate.isNotEmpty() } data class RecurringAccountSettingsState( + val canDoNext: Boolean = false, val isMandatory: Boolean = false, val adjustAdvancePayments: Boolean = false, val allowWithdrawals: Boolean = false, @@ -217,8 +625,10 @@ data class RecurringAccountSettingsState( val recurringDepositDetails: RecurringDepositDetails = RecurringDepositDetails(), val depositPeriod: DepositPeriod = DepositPeriod(), val minimumDepositTerm: MinimumDepositTerm = MinimumDepositTerm(), + val maxDepositTerm: MaxDepositTerm = MaxDepositTerm(), val preMatureClosure: PreMatureClosure = PreMatureClosure(), ) { + data class LockInPeriod( val frequency: String = "", val frequencyTypeIndex: Int = -1, @@ -245,6 +655,12 @@ data class RecurringAccountSettingsState( val freqTypeAfterInMultiplesOfError: String? = null, ) + data class MaxDepositTerm( + val frequency: String = "", + val frequencyTypeIndex: Int = -1, + val frequencyTypeError: String? = null, + ) + data class PreMatureClosure( val applyPenalInterest: Boolean = false, val penalInterest: String = "", @@ -252,19 +668,55 @@ data class RecurringAccountSettingsState( val interestPeriodIndexError: String? = null, val minimumBalanceForInterestCalculation: String = "", ) + + val isSettingsNextEnabled = preMatureClosure.penalInterest.isNotBlank() && + preMatureClosure.minimumBalanceForInterestCalculation.isNotBlank() && + recurringDepositDetails.depositAmount.isNotBlank() && + depositPeriod.period.isNotBlank() && + lockInPeriod.frequency.isNotBlank() && + minimumDepositTerm.frequency.isNotBlank() && + minimumDepositTerm.frequencyAfterInMultiplesOf.isNotBlank() && + maxDepositTerm.frequency.isNotBlank() } -sealed interface RecurringAccountAction { - data object Retry : RecurringAccountAction - data object NextStep : RecurringAccountAction - data class OnStepChange(val index: Int) : RecurringAccountAction - data object NavigateBack : RecurringAccountAction - data object Finish : RecurringAccountAction - data class OnProductNameChange(val index: Int) : RecurringAccountAction - data class OnSubmissionDateChange(val date: String) : RecurringAccountAction - data class OnSubmissionDatePick(val state: Boolean) : RecurringAccountAction - data class OnFieldOfficerChange(val index: Int) : RecurringAccountAction - data class OnExternalIdChange(val value: String) : RecurringAccountAction +sealed class RecurringAccountAction { + data class NavigateToStep(val index: Int) : RecurringAccountAction() + object NavigateBack : RecurringAccountAction() + object OnBackPress : RecurringAccountAction() + object OnNextPress : RecurringAccountAction() + data object Retry : RecurringAccountAction() + + sealed class RecurringAccountDetailsAction : RecurringAccountAction() { + data class OnProductNameChange(val index: Int) : RecurringAccountDetailsAction() + data class OnSubmissionDateChange(val date: String) : RecurringAccountDetailsAction() + data class OnSubmissionDatePick(val state: Boolean) : RecurringAccountDetailsAction() + data class OnFieldOfficerChange(val index: Int) : RecurringAccountDetailsAction() + data class OnExternalIdChange(val value: String) : RecurringAccountDetailsAction() + } + + sealed class RecurringAccountSettingsAction : RecurringAccountAction() { + object ToggleMandatoryDeposit : RecurringAccountSettingsAction() + object ToggleAdvancePaymentsTowardsFutureInstallments : RecurringAccountSettingsAction() + object ToggleAllowWithdrawals : RecurringAccountSettingsAction() + data class SetLockInPeriod(val frequency: String) : RecurringAccountSettingsAction() + data class SetLockInPeriodType(val frequencyTypeIndex: Int) : RecurringAccountSettingsAction() + data class SetRecurringDepositAmount(val depositAmount: String) : RecurringAccountSettingsAction() + data class SetDepositPeriod(val period: String) : RecurringAccountSettingsAction() + data class SetDepositPeriodType(val periodType: Int) : RecurringAccountSettingsAction() + data object ToggleDepositFrequencySameAsGroupCenterMeeting : RecurringAccountSettingsAction() + + data class SetMinDepositTermFreq(val frequency: String) : RecurringAccountSettingsAction() + data class SetMinDepositTermFreqType(val frequencyTypeIndex: Int) : RecurringAccountSettingsAction() + data class SetMinDepositTermFreqAfterInMultiOf(val frequencyAfterInMultiplesOf: String) : RecurringAccountSettingsAction() + data class SetMinDepositTermFreqTypeAfterInMultiOf(val frequencyTypeIndexAfterInMultiplesOf: Int) : RecurringAccountSettingsAction() + + data class SetMaxDepositTermFreq(val frequency: String) : RecurringAccountSettingsAction() + data class SetMaxDepositTermFreqType(val frequencyTypeIndex: Int) : RecurringAccountSettingsAction() + data object TogglePreMatureClosureApplyPenalInterest : RecurringAccountSettingsAction() + data class SetPreMatureClosurePenalInterest(val penalInterest: String) : RecurringAccountSettingsAction() + data class SetPreMatureClosureInterestPeriodIndex(val interestPeriodIndex: Int) : RecurringAccountSettingsAction() + data class SetPreMatureClosureMinimumBalanceForInterestCalculation(val minimumBalanceForInterestCalculation: String) : RecurringAccountSettingsAction() + } } sealed class RecurringAccountEvent { diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt index a7d1069b32..cacdd0e124 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/ChargesPage.kt @@ -9,6 +9,9 @@ */ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages +import androidclient.feature.recurringdeposit.generated.resources.Res +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_charges_page +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next_button import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -18,14 +21,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import org.jetbrains.compose.resources.stringResource @Composable fun ChargesPage(onNext: () -> Unit) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text("Charges Page") + Text(stringResource(Res.string.feature_recurring_deposit_charges_page)) Spacer(Modifier.height(8.dp)) Button(onClick = onNext) { - Text("Next Button") + Text(stringResource(Res.string.feature_recurring_deposit_next_button)) } } } diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/DetailsPage.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/DetailsPage.kt index 718bf20332..0a7673bc10 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/DetailsPage.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/DetailsPage.kt @@ -10,14 +10,14 @@ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages import androidclient.feature.recurringdeposit.generated.resources.Res -import androidclient.feature.recurringdeposit.generated.resources.back -import androidclient.feature.recurringdeposit.generated.resources.cancel -import androidclient.feature.recurringdeposit.generated.resources.external_id -import androidclient.feature.recurringdeposit.generated.resources.field_officer -import androidclient.feature.recurringdeposit.generated.resources.next -import androidclient.feature.recurringdeposit.generated.resources.product_name -import androidclient.feature.recurringdeposit.generated.resources.select -import androidclient.feature.recurringdeposit.generated.resources.submitted_on +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_back +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_cancel +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_external_id +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_field_officer +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_product_name +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_select +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_submitted_on import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -63,31 +63,31 @@ fun DetailsPage( }, ) - if (state.showSubmissionDatePick) { + if (state.recurringDepositAccountDetail.showSubmissionDatePick) { DatePickerDialog( onDismissRequest = { - onAction(RecurringAccountAction.OnSubmissionDatePick(state = false)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDatePick(state = false)) }, confirmButton = { TextButton( onClick = { - onAction(RecurringAccountAction.OnSubmissionDatePick(state = false)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDatePick(state = false)) submissionDatePickerState.selectedDateMillis?.let { onAction( - RecurringAccountAction.OnSubmissionDateChange( + RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDateChange( DateHelper.getDateAsStringFromLong(it), ), ) } }, - ) { Text(stringResource(Res.string.select)) } + ) { Text(stringResource(Res.string.feature_recurring_deposit_select)) } }, dismissButton = { TextButton( onClick = { - onAction(RecurringAccountAction.OnSubmissionDatePick(state = false)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDatePick(state = false)) }, - ) { Text(stringResource(Res.string.cancel)) } + ) { Text(stringResource(Res.string.feature_recurring_deposit_cancel)) } }, ) { DatePicker(state = submissionDatePickerState) @@ -96,53 +96,54 @@ fun DetailsPage( Column(horizontalAlignment = Alignment.CenterHorizontally) { MifosTextFieldDropdown( - value = if (state.loanProductSelected == -1) { + value = if (state.recurringDepositAccountDetail.loanProductSelected == -1) { "" } else { - state.template?.productOptions?.get(state.loanProductSelected)?.name ?: "" + state.template.productOptions?.get(state.recurringDepositAccountDetail.loanProductSelected)?.name ?: "" }, onValueChanged = {}, onOptionSelected = { index, value -> - onAction(RecurringAccountAction.OnProductNameChange(index)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnProductNameChange(index)) }, - options = state.template?.productOptions?.map { + options = state.template.productOptions?.map { it.name ?: "" } ?: emptyList(), - label = stringResource(Res.string.product_name), + label = stringResource(Res.string.feature_recurring_deposit_product_name), ) - if (!state.template?.fieldOfficerOptions.isNullOrEmpty()) { + if (!state.template.fieldOfficerOptions.isNullOrEmpty()) { MifosDatePickerTextField( - value = state.submissionDate, - label = stringResource(Res.string.submitted_on), + value = state.recurringDepositAccountDetail.submissionDate, + label = stringResource(Res.string.feature_recurring_deposit_submitted_on), openDatePicker = { - onAction(RecurringAccountAction.OnSubmissionDatePick(true)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnSubmissionDatePick(true)) }, ) Spacer(Modifier.height(DesignToken.padding.large)) MifosTextFieldDropdown( - value = if (state.fieldOfficerIndex == -1) { + value = if (state.recurringDepositAccountDetail.fieldOfficerIndex == -1) { "" } else { - state.fieldOfficerOptions?.get(state.fieldOfficerIndex)?.displayName ?: "" + state.template.fieldOfficerOptions + ?.get(state.recurringDepositAccountDetail.fieldOfficerIndex)?.displayName ?: "" }, onValueChanged = {}, onOptionSelected = { index, value -> - onAction(RecurringAccountAction.OnFieldOfficerChange(index)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnFieldOfficerChange(index)) }, - options = state.fieldOfficerOptions?.mapNotNull { - it.displayName + options = state.template.fieldOfficerOptions?.map { + it.displayName ?: "" } ?: emptyList(), - label = stringResource(Res.string.field_officer), + label = stringResource(Res.string.feature_recurring_deposit_field_officer), ) MifosOutlinedTextField( - value = state.externalId, + value = state.recurringDepositAccountDetail.externalId, onValueChange = { - onAction(RecurringAccountAction.OnExternalIdChange(it)) + onAction(RecurringAccountAction.RecurringAccountDetailsAction.OnExternalIdChange(it)) }, - label = stringResource(Res.string.external_id), + label = stringResource(Res.string.feature_recurring_deposit_external_id), config = MifosTextFieldConfig( keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, @@ -152,16 +153,16 @@ fun DetailsPage( Spacer(Modifier.height(DesignToken.padding.large)) } - if (state.isMiniLoaderActive) { + if (state.recurringDepositAccountDetail.isMiniLoaderActive) { MifosProgressIndicatorMini() } MifosTwoButtonRow( - firstBtnText = stringResource(Res.string.back), - secondBtnText = stringResource(Res.string.next), + firstBtnText = stringResource(Res.string.feature_recurring_deposit_back), + secondBtnText = stringResource(Res.string.feature_recurring_deposit_next), onFirstBtnClick = { onAction(RecurringAccountAction.NavigateBack) }, - onSecondBtnClick = { onAction(RecurringAccountAction.NextStep) }, - isSecondButtonEnabled = state.isDetailButtonEnabled, + onSecondBtnClick = { onAction(RecurringAccountAction.OnNextPress) }, + isSecondButtonEnabled = state.recurringDepositAccountDetail.isDetailButtonEnabled, modifier = Modifier.padding(top = DesignToken.padding.small), ) } diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt index eda2c9dfc3..cb8ed3d409 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/InterestPage.kt @@ -9,6 +9,9 @@ */ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages +import androidclient.feature.recurringdeposit.generated.resources.Res +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_interest_page +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next_button import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -18,14 +21,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import org.jetbrains.compose.resources.stringResource @Composable fun InterestPage(onNext: () -> Unit) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text("Interest Page") + Text(stringResource(Res.string.feature_recurring_deposit_interest_page)) Spacer(Modifier.height(8.dp)) Button(onClick = onNext) { - Text("Next Button") + Text(stringResource(Res.string.feature_recurring_deposit_next_button)) } } } diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt index 365a938143..ac486f71ce 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/SettingsPage.kt @@ -9,23 +9,353 @@ */ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages +import androidclient.feature.recurringdeposit.generated.resources.Res +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_adjust_advance_payments +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_allow_withdrawals +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_apply_penal_interest +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_back +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_deposit_frequency_same_as_meeting +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_deposit_period +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_for_pre_mature_closure +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_frequency +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_in_multiples_of +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_is_mandatory_deposit +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_lock_in_period +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_maximum_deposit_term +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_minimum_balance_for_interest +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_minimum_deposit_term +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_penal_interest_percentage +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_period +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_recurring_deposit_amount +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_recurring_deposit_details +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_step_settings +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_type +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.material3.Button +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +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.ui.components.MifosCheckBox +import com.mifos.core.ui.components.MifosTwoButtonRow +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountAction +import com.mifos.feature.recurringDeposit.newRecurringDepositAccount.RecurringAccountState +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun SettingPage(onNext: () -> Unit) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text("Settings Page") - Spacer(Modifier.height(8.dp)) - Button(onClick = onNext) { - Text("Next Button") +fun SettingPage( + state: RecurringAccountState, + onAction: (RecurringAccountAction) -> Unit, +) { + val settingsState = state.recurringDepositAccountSettings + + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(scrollState), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(20.dp), + ) { + Text(stringResource(Res.string.feature_recurring_deposit_step_settings), fontWeight = FontWeight.Bold, fontSize = 18.sp) + + Column( + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(10.dp), + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox(settingsState.isMandatory, onCheckedChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.ToggleMandatoryDeposit) }) + Text(stringResource(Res.string.feature_recurring_deposit_is_mandatory_deposit)) + } + Row(verticalAlignment = Alignment.CenterVertically) { + MifosCheckBox( + text = stringResource(Res.string.feature_recurring_deposit_adjust_advance_payments), + checked = settingsState.adjustAdvancePayments, + onCheckChanged = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.ToggleAdvancePaymentsTowardsFutureInstallments) }, + ) + } + Row(verticalAlignment = Alignment.CenterVertically) { + MifosCheckBox( + text = stringResource(Res.string.feature_recurring_deposit_allow_withdrawals), + checked = settingsState.allowWithdrawals, + onCheckChanged = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.ToggleAllowWithdrawals) }, + ) + } + } + + Text(stringResource(Res.string.feature_recurring_deposit_lock_in_period), fontWeight = FontWeight.Bold) + MifosOutlinedTextField( + value = settingsState.lockInPeriod.frequency, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetLockInPeriod(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_frequency), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + ), + modifier = Modifier.fillMaxWidth(), + ) + MifosTextFieldDropdown( + value = if (settingsState.lockInPeriod.frequencyTypeIndex != -1) { + state.template.lockinPeriodFrequencyTypeOptions + ?.getOrNull(settingsState.lockInPeriod.frequencyTypeIndex)?.value.orEmpty() + } else { + "" + }, + options = state.template.lockinPeriodFrequencyTypeOptions?.map { + it.value.orEmpty() + } ?: emptyList(), + onValueChanged = {}, + onOptionSelected = { id, name -> + onAction( + RecurringAccountAction.RecurringAccountSettingsAction.SetLockInPeriodType(id), + ) + }, + label = stringResource(Res.string.feature_recurring_deposit_type), + ) + Text(stringResource(Res.string.feature_recurring_deposit_recurring_deposit_details), fontWeight = FontWeight.Bold) + MifosOutlinedTextField( + value = settingsState.recurringDepositDetails.depositAmount, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetRecurringDepositAmount(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_recurring_deposit_amount), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + prefix = { + Text(state.template.currency?.displaySymbol.orEmpty()) + }, + ), + modifier = Modifier.fillMaxWidth(), + ) + Text(stringResource(Res.string.feature_recurring_deposit_deposit_period), fontWeight = FontWeight.Bold) + MifosOutlinedTextField( + value = settingsState.depositPeriod.period, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetDepositPeriod(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_deposit_period), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + ), + modifier = Modifier.fillMaxWidth(), + ) + MifosTextFieldDropdown( + value = if (settingsState.depositPeriod.periodType != -1) { + state.template.periodFrequencyTypeOptions + ?.getOrNull(settingsState.depositPeriod.periodType)?.value.orEmpty() + } else { + "" + }, + options = state.template.periodFrequencyTypeOptions?.map { + it.value.orEmpty() + } ?: emptyList(), + onValueChanged = {}, + onOptionSelected = { id, name -> + onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetDepositPeriodType(id)) + }, + label = stringResource(Res.string.feature_recurring_deposit_type), + modifier = Modifier.fillMaxWidth(), + ) + Row(verticalAlignment = Alignment.CenterVertically) { + MifosCheckBox( + text = stringResource(Res.string.feature_recurring_deposit_deposit_frequency_same_as_meeting), + checked = settingsState.depositPeriod.depositFrequencySameAsGroupCenterMeeting, + onCheckChanged = { + onAction(RecurringAccountAction.RecurringAccountSettingsAction.ToggleDepositFrequencySameAsGroupCenterMeeting) + }, + ) + } + Text(stringResource(Res.string.feature_recurring_deposit_minimum_deposit_term), fontWeight = FontWeight.Bold) + MifosOutlinedTextField( + value = settingsState.minimumDepositTerm.frequency, + onValueChange = { + onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreq(it)) + }, + label = stringResource(Res.string.feature_recurring_deposit_frequency), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + ), + modifier = Modifier.fillMaxWidth(), + ) + MifosTextFieldDropdown( + value = if (settingsState.minimumDepositTerm.frequencyTypeIndex != -1) { + state.template.periodFrequencyTypeOptions?.getOrNull(settingsState.minimumDepositTerm.frequencyTypeIndex)?.value.orEmpty() + } else { + "" + }, + options = state.template.periodFrequencyTypeOptions?.map { + it.value.orEmpty() + } ?: emptyList(), + onValueChanged = {}, + onOptionSelected = { id, name -> + onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreqType(id)) + }, + label = stringResource(Res.string.feature_recurring_deposit_type), + modifier = Modifier.fillMaxWidth(), + ) + Text(stringResource(Res.string.feature_recurring_deposit_in_multiples_of), fontWeight = FontWeight.Bold) + MifosOutlinedTextField( + value = settingsState.minimumDepositTerm.frequencyAfterInMultiplesOf, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreqAfterInMultiOf(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_frequency), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + ), + modifier = Modifier.fillMaxWidth(), + ) + MifosTextFieldDropdown( + value = if (settingsState.minimumDepositTerm.frequencyTypeIndexAfterInMultiplesOf != -1) { + state.template.periodFrequencyTypeOptions?.getOrNull(settingsState.minimumDepositTerm.frequencyTypeIndexAfterInMultiplesOf)?.value.orEmpty() + } else { + "" + }, + options = state.template.periodFrequencyTypeOptions?.map { + it.value.orEmpty() + } ?: emptyList(), + onValueChanged = {}, + onOptionSelected = { id, name -> + onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetMinDepositTermFreqTypeAfterInMultiOf(id)) + }, + label = stringResource(Res.string.feature_recurring_deposit_type), + modifier = Modifier.fillMaxWidth(), + ) + Text(stringResource(Res.string.feature_recurring_deposit_maximum_deposit_term), fontWeight = FontWeight.Bold) + MifosOutlinedTextField( + value = settingsState.maxDepositTerm.frequency, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetMaxDepositTermFreq(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_frequency), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + ), + modifier = Modifier.fillMaxWidth(), + ) + MifosTextFieldDropdown( + value = if (settingsState.maxDepositTerm.frequencyTypeIndex != -1) { + state.template.periodFrequencyTypeOptions?.getOrNull(settingsState.maxDepositTerm.frequencyTypeIndex)?.value.orEmpty() + } else { + "" + }, + options = state.template.periodFrequencyTypeOptions?.map { + it.value.orEmpty() + } ?: emptyList(), + onValueChanged = {}, + onOptionSelected = { id, name -> + onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetMaxDepositTermFreqType(id)) + }, + label = stringResource(Res.string.feature_recurring_deposit_type), + modifier = Modifier.fillMaxWidth(), + ) + Text(stringResource(Res.string.feature_recurring_deposit_for_pre_mature_closure), fontWeight = FontWeight.Bold) + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + settingsState.preMatureClosure.applyPenalInterest, + onCheckedChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.TogglePreMatureClosureApplyPenalInterest) }, + ) + Text(stringResource(Res.string.feature_recurring_deposit_apply_penal_interest)) } + AnimatedVisibility( + visible = settingsState.preMatureClosure.applyPenalInterest, + ) { + Column( + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(20.dp), + ) { + MifosOutlinedTextField( + value = settingsState.preMatureClosure.penalInterest, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosurePenalInterest(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_penal_interest_percentage), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + ), + modifier = Modifier.fillMaxWidth(), + ) + MifosTextFieldDropdown( + value = if (settingsState.preMatureClosure.interestPeriodIndex != -1) { + state.template.preClosurePenalInterestOnTypeOptions + ?.getOrNull(settingsState.preMatureClosure.interestPeriodIndex)?.value.orEmpty() + } else { + "" + }, + options = state.template.preClosurePenalInterestOnTypeOptions?.map { + it.value.orEmpty() + } ?: emptyList(), + onValueChanged = {}, + onOptionSelected = { id, name -> + onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosureInterestPeriodIndex(id)) + }, + label = stringResource(Res.string.feature_recurring_deposit_period), + modifier = Modifier.fillMaxWidth(), + ) + MifosOutlinedTextField( + value = settingsState.preMatureClosure.minimumBalanceForInterestCalculation, + onValueChange = { onAction(RecurringAccountAction.RecurringAccountSettingsAction.SetPreMatureClosureMinimumBalanceForInterestCalculation(it)) }, + label = stringResource(Res.string.feature_recurring_deposit_minimum_balance_for_interest), + config = MifosTextFieldConfig( + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + prefix = { + Text(state.template.currency?.displaySymbol.orEmpty()) + }, + ), + modifier = Modifier.fillMaxWidth(), + ) + } + } + + MifosTwoButtonRow( + firstBtnText = stringResource(Res.string.feature_recurring_deposit_back), + secondBtnText = stringResource(Res.string.feature_recurring_deposit_next), + onFirstBtnClick = { onAction(RecurringAccountAction.OnBackPress) }, + onSecondBtnClick = { onAction(RecurringAccountAction.OnNextPress) }, + isButtonIconVisible = true, + isSecondButtonEnabled = settingsState.isSettingsNextEnabled, + ) } } + +@Preview +@Composable +private fun SettingPagePreview() { + SettingPage( + state = RecurringAccountState(), + onAction = {}, + ) +} diff --git a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/TermsPage.kt b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/TermsPage.kt index 09785bdd83..4be700953c 100644 --- a/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/TermsPage.kt +++ b/feature/recurringDeposit/src/commonMain/kotlin/com/mifos/feature/recurringDeposit/newRecurringDepositAccount/pages/TermsPage.kt @@ -9,6 +9,9 @@ */ package com.mifos.feature.recurringDeposit.newRecurringDepositAccount.pages +import androidclient.feature.recurringdeposit.generated.resources.Res +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_next_button +import androidclient.feature.recurringdeposit.generated.resources.feature_recurring_deposit_terms_page import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -18,14 +21,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import org.jetbrains.compose.resources.stringResource @Composable fun TermsPage(onNext: () -> Unit) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text("Terms Page") + Text(stringResource(Res.string.feature_recurring_deposit_terms_page)) Spacer(Modifier.height(8.dp)) Button(onClick = onNext) { - Text("Next Button") + Text(stringResource(Res.string.feature_recurring_deposit_next_button)) } } }