diff --git a/core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosListingComponent.kt b/core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosListingComponent.kt index 97f595de630..4ae4e27133b 100644 --- a/core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosListingComponent.kt +++ b/core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosListingComponent.kt @@ -105,8 +105,20 @@ fun MifosListingRowItem( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - keyContent() - valueContent() + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + Box( + modifier = Modifier.weight(1f), + contentAlignment = Alignment.CenterStart, + ) { keyContent() } + + Box( + modifier = Modifier.weight(1f), + contentAlignment = Alignment.CenterEnd, + ) { valueContent() } + } } } diff --git a/feature/loan/src/commonMain/composeResources/values/strings.xml b/feature/loan/src/commonMain/composeResources/values/strings.xml index f48f13c71dc..1e204ebc21d 100644 --- a/feature/loan/src/commonMain/composeResources/values/strings.xml +++ b/feature/loan/src/commonMain/composeResources/values/strings.xml @@ -220,4 +220,45 @@ Amount Type Collected On + + + On principal payment + On interest payment + On Arrears Aging + Enable installment level Delinquency + Recalculate Interest + Days in month + Principal + Loan Term + Number of Repayments + First Repayment Date + Interest Charged From + Repaid Every + Nominal Interest Rate + Is Equal Amortization + Amortization + Interest Calculation Period + Calculate interest for exact days in partial + Arrears tolerance + Interest free period + Repayment strategy + Installment Amount + Balloon Repayment Amount + Product Name + Loan Officer + External ID + Submitted Date + Expected Disbursement + Loan Purpose + Is Savings Linked + Yes + No + Terms + Moratorium + Details + Charges + View + Active Charges + + \ No newline at end of file diff --git a/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt index 52d879e137f..79781d436cd 100644 --- a/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt +++ b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt @@ -136,9 +136,10 @@ private fun NewLoanAccountScaffold( } }, Step(stringResource(Res.string.step_preview)) { - PreviewPage { - onAction(NewLoanAccountAction.NextStep) - } + PreviewPage( + state = state, + onAction = onAction, + ) }, ) diff --git a/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt index d7b6a0cc143..a22cbfd31e7 100644 --- a/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt +++ b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountViewModel.kt @@ -12,14 +12,17 @@ package com.mifos.feature.loan.newLoanAccount import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute +import co.touchlab.kermit.Logger import com.mifos.core.common.utils.DataState import com.mifos.core.common.utils.DateHelper import com.mifos.core.data.repository.ClientDetailsRepository import com.mifos.core.data.util.NetworkMonitor +import com.mifos.core.domain.useCases.CreateLoanAccountUseCase import com.mifos.core.domain.useCases.GetAllLoanUseCase import com.mifos.core.domain.useCases.GetLoansAccountTemplateUseCase import com.mifos.core.model.objects.organisations.LoanProducts import com.mifos.core.network.model.CollateralItem +import com.mifos.core.network.model.LoansPayload import com.mifos.core.ui.util.BaseViewModel import com.mifos.core.ui.util.TextFieldsValidator import com.mifos.feature.loan.newLoanAccount.NewLoanAccountState.DialogState @@ -35,6 +38,7 @@ internal class NewLoanAccountViewModel( private val repo: ClientDetailsRepository, private val getLoansAccountTemplateUseCase: GetLoansAccountTemplateUseCase, private val networkMonitor: NetworkMonitor, + private val loanUseCase: CreateLoanAccountUseCase, val savedStateHandle: SavedStateHandle, ) : BaseViewModel( @@ -71,9 +75,13 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.OnLoanPurposeChange -> handleLoanPurposeChange(action) - is NewLoanAccountAction.OnExpectedDisbursementDateChange -> handleExpectedDisbursementDateChange(action) + is NewLoanAccountAction.OnExpectedDisbursementDateChange -> handleExpectedDisbursementDateChange( + action, + ) - is NewLoanAccountAction.OnExpectedDisbursementDatePick -> handleExpectedDisbursementDatePick(action) + is NewLoanAccountAction.OnExpectedDisbursementDatePick -> handleExpectedDisbursementDatePick( + action, + ) is NewLoanAccountAction.OnSubmissionDateChange -> handleSubmissionDateChange(action) @@ -81,27 +89,41 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.OnLinkSavingsChange -> handleLinkSavingsChange(action) - is NewLoanAccountAction.OnStandingInstructionsChange -> handleStandingInstructionsChange(action) + is NewLoanAccountAction.OnStandingInstructionsChange -> handleStandingInstructionsChange( + action, + ) is NewLoanAccountAction.OnDetailsSubmit -> handleOnDetailsSubmit() - is NewLoanAccountAction.Internal.OnReceivingLoanAccounts -> handleAllLoansResponse(action.loans) + is NewLoanAccountAction.Internal.OnReceivingLoanAccounts -> handleAllLoansResponse( + action.loans, + ) - is NewLoanAccountAction.Internal.OnReceivingLoanTemplate -> handleLoanTemplateResponse(action.template) + is NewLoanAccountAction.Internal.OnReceivingLoanTemplate -> handleLoanTemplateResponse( + action.template, + ) - is NewLoanAccountAction.OnFirstRepaymentDateChange -> handleFirstRepaymentDateChange(action) + is NewLoanAccountAction.OnFirstRepaymentDateChange -> handleFirstRepaymentDateChange( + action, + ) is NewLoanAccountAction.OnFirstRepaymentDatePick -> handleFirstRepaymentDatePick(action) - is NewLoanAccountAction.OnInterestChargedFromChange -> handleInterestChargedFromChange(action) + is NewLoanAccountAction.OnInterestChargedFromChange -> handleInterestChargedFromChange( + action, + ) - is NewLoanAccountAction.OnInterestChargedFromDatePick -> handleInterestChargedFromDatePick(action) + is NewLoanAccountAction.OnInterestChargedFromDatePick -> handleInterestChargedFromDatePick( + action, + ) is NewLoanAccountAction.OnNoOfRepaymentsChange -> handleNoOfRepaymentsChange(action) is NewLoanAccountAction.OnPrincipalAmountChange -> handlePrincipalAmountChange(action) - is NewLoanAccountAction.OnTermFrequencyIndexChange -> handleTermFrequencyIndexChange(action) + is NewLoanAccountAction.OnTermFrequencyIndexChange -> handleTermFrequencyIndexChange( + action, + ) is NewLoanAccountAction.OnRepaidEveryChange -> handleRepaidEveryChange(action) @@ -109,33 +131,59 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.OnSelectedOnIndexChange -> handleSelectedOnIndexChange(action) - is NewLoanAccountAction.OnNominalInterestRateChange -> handleNominalInterestRateChange(action) + is NewLoanAccountAction.OnNominalInterestRateChange -> handleNominalInterestRateChange( + action, + ) - is NewLoanAccountAction.OnNominalFrequencyIndexChange -> handleNominalFrequencyIndexChange(action) + is NewLoanAccountAction.OnNominalFrequencyIndexChange -> handleNominalFrequencyIndexChange( + action, + ) - is NewLoanAccountAction.OnNominalMethodIndexChange -> handleNominalMethodIndexChange(action) + is NewLoanAccountAction.OnNominalMethodIndexChange -> handleNominalMethodIndexChange( + action, + ) - is NewLoanAccountAction.OnNominalAmortizationIndexChange -> handleNominalAmortizationIndexChange(action) + is NewLoanAccountAction.OnNominalAmortizationIndexChange -> handleNominalAmortizationIndexChange( + action, + ) - is NewLoanAccountAction.OnEqualAmortizationCheckChange -> handleEqualAmortizationCheckChange(action) + is NewLoanAccountAction.OnEqualAmortizationCheckChange -> handleEqualAmortizationCheckChange( + action, + ) - is NewLoanAccountAction.OnRepaymentStrategyIndexChange -> handleRepaymentStrategyIndexChange(action) + is NewLoanAccountAction.OnRepaymentStrategyIndexChange -> handleRepaymentStrategyIndexChange( + action, + ) - is NewLoanAccountAction.OnBalloonRepaymentAmountChange -> handleBalloonRepaymentAmountChange(action) + is NewLoanAccountAction.OnBalloonRepaymentAmountChange -> handleBalloonRepaymentAmountChange( + action, + ) - is NewLoanAccountAction.OnInterestCalculationPeriodIndexChange -> handleInterestCalculationPeriodIndexChange(action) + is NewLoanAccountAction.OnInterestCalculationPeriodIndexChange -> handleInterestCalculationPeriodIndexChange( + action, + ) - is NewLoanAccountAction.OnInterestPartialPeriodCheckChange -> handleInterestPartialPeriodCheckChange(action) + is NewLoanAccountAction.OnInterestPartialPeriodCheckChange -> handleInterestPartialPeriodCheckChange( + action, + ) is NewLoanAccountAction.OnArrearsToleranceChange -> handleArrearsToleranceChange(action) - is NewLoanAccountAction.OnInterestFreePeriodChange -> handleInterestFreePeriodChange(action) + is NewLoanAccountAction.OnInterestFreePeriodChange -> handleInterestFreePeriodChange( + action, + ) - is NewLoanAccountAction.OnMoratoriumGraceOnInterestPaymentChange -> handleMoratoriumGraceOnInterestPaymentChange(action) + is NewLoanAccountAction.OnMoratoriumGraceOnInterestPaymentChange -> handleMoratoriumGraceOnInterestPaymentChange( + action, + ) - is NewLoanAccountAction.OnMoratoriumGraceOnPrincipalPaymentChange -> handleMoratoriumGraceOnPrincipalPaymentChange(action) + is NewLoanAccountAction.OnMoratoriumGraceOnPrincipalPaymentChange -> handleMoratoriumGraceOnPrincipalPaymentChange( + action, + ) - is NewLoanAccountAction.OnMoratoriumOnArrearsAgeingChange -> handleMoratoriumOnArrearsAgeingChange(action) + is NewLoanAccountAction.OnMoratoriumOnArrearsAgeingChange -> handleMoratoriumOnArrearsAgeingChange( + action, + ) is NewLoanAccountAction.DismissDialog -> handleDismissAddCollateralDialog() @@ -143,9 +191,13 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.AddCollateralToList -> handleAddCollateralToList() - is NewLoanAccountAction.OnCollateralQuantityChanged -> handleCollateralQuantityChanged(action) + is NewLoanAccountAction.OnCollateralQuantityChanged -> handleCollateralQuantityChanged( + action, + ) - is NewLoanAccountAction.SelectedCollateralIndexChange -> handleSelectedCollateralIndexChange(action) + is NewLoanAccountAction.SelectedCollateralIndexChange -> handleSelectedCollateralIndexChange( + action, + ) is NewLoanAccountAction.HideCollaterals -> handleHideCollaterals() @@ -153,7 +205,9 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.AddChargeToList -> handleAddChargeToList() - is NewLoanAccountAction.OnChooseChargeIndexChange -> handleChooseChargeIndexChange(action) + is NewLoanAccountAction.OnChooseChargeIndexChange -> handleChooseChargeIndexChange( + action, + ) is NewLoanAccountAction.ShowAddChargeDialog -> handleShowAddChargeDialog() @@ -172,6 +226,67 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.EditChargeDialog -> handleEditChargeDialog(action.index) is NewLoanAccountAction.EditCharge -> handleEditCharge(action.index) + + NewLoanAccountAction.GotoPreviousStep -> {} + + NewLoanAccountAction.SubmitLoanApplication -> submitLoanApplication() + } + } + + private fun submitLoanApplication() { + viewModelScope.launch { + val payload = LoansPayload( + loanOfficerId = state.loanOfficerIndex, + principal = state.principalAmount, + clientId = state.clientId, + allowPartialPeriodInterestCalcualtion = state.isCheckedInterestPartialPeriod, + amortizationType = state.nominalAmortizationIndex, + dateFormat = DateHelper.SHORT_MONTH, + interestCalculationPeriodType = state.interestCalculationPeriodIndex, + interestRatePerPeriod = state.nominalInterestRate, + interestType = state.nominalInterestMethodIndex, + loanTermFrequency = state.termFrequencyIndex, + loanTermFrequencyType = state.termFrequencyIndex, + loanType = "individual", + locale = "en", + numberOfRepayments = state.noOfRepayments, + productId = state.loanProductSelected, + repaymentEvery = state.repaidEvery, + repaymentFrequencyDayOfWeekType = state.selectedDayIndex, + repaymentFrequencyNthDayType = state.selectedOnIndex, + repaymentFrequencyType = state.repaymentStrategyIndex, + expectedDisbursementDate = state.expectedDisbursementDate, + submittedOnDate = state.submissionDate, + loanPurposeId = state.loanPurposeIndex, + fundId = state.fundIndex, + linkAccountId = state.linkSavingsIndex, + ) + + loanUseCase(payload).collect { dataState -> + when (dataState) { + is DataState.Error -> { + mutableStateFlow.update { + it.copy( + dialogState = NewLoanAccountState.DialogState.Error(dataState.message), + isLoading = false, + ) + } + } + + DataState.Loading -> { + mutableStateFlow.update { + it.copy( + isLoading = true, + ) + } + } + + is DataState.Success -> { + Logger.d("DebugTtt success") + sendEvent(NewLoanAccountEvent.Finish) + } + } + } } } @@ -623,6 +738,7 @@ internal class NewLoanAccountViewModel( ) } } + else -> Unit } } @@ -698,6 +814,7 @@ internal class NewLoanAccountViewModel( data class NewLoanAccountState @OptIn(ExperimentalTime::class) constructor( + val isLoading: Boolean = false, val networkConnection: Boolean = false, val clientId: Int, val productLoans: List = emptyList(), @@ -713,9 +830,13 @@ constructor( val loanOfficerIndex: Int = -1, val loanPurposeIndex: Int = -1, val fundIndex: Int = -1, - val submissionDate: String = DateHelper.getDateAsStringFromLong(Clock.System.now().toEpochMilliseconds()), + val submissionDate: String = DateHelper.getDateAsStringFromLong( + Clock.System.now().toEpochMilliseconds(), + ), val showSubmissionDatePick: Boolean = false, - val expectedDisbursementDate: String = DateHelper.getDateAsStringFromLong(Clock.System.now().toEpochMilliseconds()), + val expectedDisbursementDate: String = DateHelper.getDateAsStringFromLong( + Clock.System.now().toEpochMilliseconds(), + ), val showExpectedDisbursementDatePick: Boolean = false, val linkSavingsIndex: Int = -1, val isCheckedStandingInstructions: Boolean = false, @@ -724,8 +845,12 @@ constructor( val principalAmountText: String = "", val noOfRepayments: Int = 0, val termFrequencyIndex: Int = -1, - val firstRepaymentDate: String = DateHelper.getDateAsStringFromLong(Clock.System.now().toEpochMilliseconds()), - val interestChargedFromDate: String = DateHelper.getDateAsStringFromLong(Clock.System.now().toEpochMilliseconds()), + val firstRepaymentDate: String = DateHelper.getDateAsStringFromLong( + Clock.System.now().toEpochMilliseconds(), + ), + val interestChargedFromDate: String = DateHelper.getDateAsStringFromLong( + Clock.System.now().toEpochMilliseconds(), + ), val showFirstRepaymentDatePick: Boolean = false, val showInterestChargedFromDatePick: Boolean = false, val repaidEvery: Int = 1, @@ -756,7 +881,9 @@ constructor( val chooseChargeIndex: Int = -1, val addedCharges: List = emptyList(), - val chargeDate: String = DateHelper.getDateAsStringFromLong(Clock.System.now().toEpochMilliseconds()), + val chargeDate: String = DateHelper.getDateAsStringFromLong( + Clock.System.now().toEpochMilliseconds(), + ), val showChargesDatePick: Boolean = false, val chargeAmount: String = "", @@ -769,12 +896,15 @@ constructor( data object ShowCharges : DialogState data object ShowOverDueCharges : DialogState } + sealed interface ScreenState { data object Loading : ScreenState data object Success : ScreenState data object NetworkError : ScreenState } - val isDetailsNextEnabled = loanProductSelected != -1 && externalId.isNotEmpty() && submissionDate.isNotEmpty() && expectedDisbursementDate.isNotEmpty() + + val isDetailsNextEnabled = + loanProductSelected != -1 && externalId.isNotEmpty() && submissionDate.isNotEmpty() && expectedDisbursementDate.isNotEmpty() val isCollateralBtnEnabled = collateralQuantity != 0 && collateralSelectedIndex != -1 } @@ -818,7 +948,9 @@ sealed interface NewLoanAccountAction { data class OnRepaidEveryChange(val number: Int) : NewLoanAccountAction data class OnSelectedOnIndexChange(val index: Int) : NewLoanAccountAction data class OnSelectedDayIndexChange(val index: Int) : NewLoanAccountAction - data class OnNominalInterestRateChange(val rate: Double, val text: String) : NewLoanAccountAction + data class OnNominalInterestRateChange(val rate: Double, val text: String) : + NewLoanAccountAction + data class OnNominalFrequencyIndexChange(val index: Int) : NewLoanAccountAction data class OnNominalMethodIndexChange(val index: Int) : NewLoanAccountAction data class OnNominalAmortizationIndexChange(val index: Int) : NewLoanAccountAction @@ -851,6 +983,8 @@ sealed interface NewLoanAccountAction { data class DeleteChargeFromSelectedCharges(val index: Int) : NewLoanAccountAction data class EditChargeDialog(val index: Int) : NewLoanAccountAction data class EditCharge(val index: Int) : NewLoanAccountAction + data object SubmitLoanApplication : NewLoanAccountAction + data object GotoPreviousStep : NewLoanAccountAction } data class CreatedCollateral( diff --git a/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt index 9c3cf9f0e8a..b24d6e8be41 100644 --- a/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt +++ b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt @@ -10,26 +10,294 @@ package com.mifos.feature.loan.newLoanAccount.pages import androidclient.feature.loan.generated.resources.Res -import androidclient.feature.loan.generated.resources.next -import androidclient.feature.loan.generated.resources.step_preview +import androidclient.feature.loan.generated.resources.back +import androidclient.feature.loan.generated.resources.expected_disbursement +import androidclient.feature.loan.generated.resources.external_id +import androidclient.feature.loan.generated.resources.feature_loan_charge_submit +import androidclient.feature.loan.generated.resources.first_repayment_date +import androidclient.feature.loan.generated.resources.interest_calculation_period +import androidclient.feature.loan.generated.resources.interest_charged_from +import androidclient.feature.loan.generated.resources.loan_new_loan_active_charges +import androidclient.feature.loan.generated.resources.loan_new_loan_amortization +import androidclient.feature.loan.generated.resources.loan_new_loan_arrears_tolerance +import androidclient.feature.loan.generated.resources.loan_new_loan_ballon_repayment_amount +import androidclient.feature.loan.generated.resources.loan_new_loan_calculate_interest_for_exact_days_in_pertial +import androidclient.feature.loan.generated.resources.loan_new_loan_charges +import androidclient.feature.loan.generated.resources.loan_new_loan_days_in_month +import androidclient.feature.loan.generated.resources.loan_new_loan_enable_installment_level +import androidclient.feature.loan.generated.resources.loan_new_loan_installment_amount +import androidclient.feature.loan.generated.resources.loan_new_loan_interest_free_period +import androidclient.feature.loan.generated.resources.loan_new_loan_is_equal_amortization +import androidclient.feature.loan.generated.resources.loan_new_loan_is_savings_linked +import androidclient.feature.loan.generated.resources.loan_new_loan_loan_officer +import androidclient.feature.loan.generated.resources.loan_new_loan_loan_purpose +import androidclient.feature.loan.generated.resources.loan_new_loan_loan_term +import androidclient.feature.loan.generated.resources.loan_new_loan_moratorium +import androidclient.feature.loan.generated.resources.loan_new_loan_nominal_interest_rate +import androidclient.feature.loan.generated.resources.loan_new_loan_on_arrears_aging +import androidclient.feature.loan.generated.resources.loan_new_loan_on_interest_payment +import androidclient.feature.loan.generated.resources.loan_new_loan_on_principal_payment +import androidclient.feature.loan.generated.resources.loan_new_loan_recalculate_interest +import androidclient.feature.loan.generated.resources.loan_new_loan_repaid_every +import androidclient.feature.loan.generated.resources.loan_new_loan_view +import androidclient.feature.loan.generated.resources.no +import androidclient.feature.loan.generated.resources.number_of_repayments +import androidclient.feature.loan.generated.resources.principal +import androidclient.feature.loan.generated.resources.product_name +import androidclient.feature.loan.generated.resources.repayment_strategy +import androidclient.feature.loan.generated.resources.step_details +import androidclient.feature.loan.generated.resources.submission_date +import androidclient.feature.loan.generated.resources.terms +import androidclient.feature.loan.generated.resources.yes +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text 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.CurrencyFormatter +import com.mifos.core.designsystem.theme.DesignToken +import com.mifos.core.designsystem.theme.MifosTypography +import com.mifos.core.ui.components.MifosDefaultListingComponentFromStringResources +import com.mifos.core.ui.components.MifosProgressIndicator +import com.mifos.core.ui.components.MifosProgressIndicatorOverlay +import com.mifos.core.ui.components.MifosRowWithTextAndButton +import com.mifos.core.ui.components.MifosTwoButtonRow +import com.mifos.feature.loan.newLoanAccount.NewLoanAccountAction +import com.mifos.feature.loan.newLoanAccount.NewLoanAccountState import org.jetbrains.compose.resources.stringResource @Composable -fun PreviewPage(onNext: () -> Unit) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text(stringResource(Res.string.step_preview)) - Spacer(Modifier.height(8.dp)) - Button(onClick = onNext) { - Text(stringResource(Res.string.next)) +fun PreviewPage( + state: NewLoanAccountState, + onAction: (NewLoanAccountAction) -> Unit, +) { + if (state.isLoading) { + MifosProgressIndicatorOverlay() + } else { + PreviewPageContent( + state, + onAction = onAction, + ) + } +} + +@Composable +fun PreviewPageContent( + state: NewLoanAccountState, + onAction: (NewLoanAccountAction) -> Unit, +) { + Column( + Modifier.fillMaxSize().padding(bottom = DesignToken.padding.large), + ) { + Column( + modifier = Modifier.weight(1f) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(20.dp), + ) { + Text( + text = stringResource(Res.string.step_details), + style = MifosTypography.labelLarge, + ) + DetailsCard( + productName = state.productLoans[state.loanProductSelected].name.toString(), + loanOfficer = if (state.loanOfficerIndex == -1) { + "" + } else { + state.loanTemplate?.loanOfficerOptions[state.loanOfficerIndex]?.displayName.toString() + }, + externalId = state.externalId, + submittedDate = state.submissionDate, + expectedDisbursement = state.expectedDisbursementDate, + loadPurpose = if (state.loanPurposeIndex == -1) { + "" + } else { + state.loanTemplate?.loanPurposeOptions[state.loanPurposeIndex]?.name.toString() + }, + isSavingsLinked = if (state.linkSavingsIndex == -1) { + stringResource(Res.string.no) + } else { + stringResource(Res.string.yes) + }, + ) + + Text( + text = stringResource(Res.string.terms), + style = MifosTypography.labelLarge, + ) + TermsCard( + principal = CurrencyFormatter.format( + balance = state.principalAmount, + currencyCode = state.loanTemplate?.currency?.code, + maximumFractionDigits = 2, + ), + loanTerm = if (state.termFrequencyIndex == -1) { + "" + } else { + state.loanTemplate?.termFrequencyTypeOptions[state.termFrequencyIndex]?.value + ?: "" + }, + numberOfRepayments = state.noOfRepayments.toString(), + firstRepaymentDate = state.firstRepaymentDate, + interestChargedForm = state.interestChargedFromDate, + repaidEvery = "", + nominalInterestRate = state.nominalInterestRate.toString(), + isEqualAmortization = state.isCheckedEqualAmortization.toString(), + amortization = if (state.nominalAmortizationIndex == -1) { + "" + } else { + state.loanTemplate?.amortizationTypeOptions[state.nominalAmortizationIndex]?.value + ?: "" + }, + interestCalculationPeriod = if (state.interestCalculationPeriodIndex == -1) { + "" + } else { + state.loanTemplate?.interestCalculationPeriodTypeOptions[state.interestCalculationPeriodIndex]?.value + ?: "" + }, + calculateInterestForExactDaysInPartial = "", + arrearsTolerance = state.arrearsTolerance.toString(), + interestFreePeriod = state.interestFreePeriod.toString(), + repaymentStrategy = if (state.repaymentStrategyIndex == -1) { + "" + } else { + state.loanTemplate?.transactionProcessingStrategyOptions[state.repaymentStrategyIndex]?.name + ?: "" + }, + // todo + installmentAmount = "", + ballonRepayment = state.balloonRepaymentAmount.toString(), + ) + + Text( + text = stringResource(Res.string.loan_new_loan_moratorium), + style = MifosTypography.labelLarge, + ) + MoratoriumCard( + onPrincipalPayment = state.moratoriumGraceOnPrincipalPayment.toString(), + onInternestPayment = state.moratoriumGraceOnInterestPayment.toString(), + onAreasAging = state.moratoriumOnArrearsAgeing.toString(), + // todo + enableInstallmentLevelDelinquency = "", + recalculateInterest = if (state.loanTemplate?.isInterestRecalculationEnabled + ?: false + ) { + stringResource(Res.string.yes) + } else { + stringResource(Res.string.no) + }, + // todo + daysInMonth = "", + ) + + Text( + text = stringResource(Res.string.loan_new_loan_charges), + style = MifosTypography.labelLarge, + ) + + MifosRowWithTextAndButton( + onBtnClick = { onAction(NewLoanAccountAction.ShowCharges) }, + text = state.addedCharges.size.toString() + " " + stringResource(Res.string.loan_new_loan_active_charges), + btnText = stringResource(Res.string.loan_new_loan_view), + modifier = Modifier.fillMaxWidth(), + ) } + MifosTwoButtonRow( + modifier = Modifier.padding(top = DesignToken.padding.small), + firstBtnText = stringResource(Res.string.back), + secondBtnText = stringResource(Res.string.feature_loan_charge_submit), + onFirstBtnClick = { onAction(NewLoanAccountAction.GotoPreviousStep) }, + onSecondBtnClick = { onAction(NewLoanAccountAction.SubmitLoanApplication) }, + ) } } + +@Composable +private fun MoratoriumCard( + onPrincipalPayment: String, + onInternestPayment: String, + onAreasAging: String, + enableInstallmentLevelDelinquency: String, + recalculateInterest: String, + daysInMonth: String, +) { + MifosDefaultListingComponentFromStringResources( + data = mapOf( + Res.string.loan_new_loan_on_principal_payment to onPrincipalPayment, + Res.string.loan_new_loan_on_interest_payment to onInternestPayment, + Res.string.loan_new_loan_on_arrears_aging to onAreasAging, + Res.string.loan_new_loan_enable_installment_level to enableInstallmentLevelDelinquency, + Res.string.loan_new_loan_recalculate_interest to recalculateInterest, + Res.string.loan_new_loan_days_in_month to daysInMonth, + ), + ) +} + +@Composable +private fun TermsCard( + principal: String, + loanTerm: String, + numberOfRepayments: String, + firstRepaymentDate: String, + interestChargedForm: String, + repaidEvery: String, + nominalInterestRate: String, + isEqualAmortization: String, + amortization: String, + interestCalculationPeriod: String, + calculateInterestForExactDaysInPartial: String, + arrearsTolerance: String, + interestFreePeriod: String, + repaymentStrategy: String, + installmentAmount: String, + ballonRepayment: String, +) { + MifosDefaultListingComponentFromStringResources( + data = mapOf( + Res.string.principal to principal, + Res.string.loan_new_loan_loan_term to loanTerm, + Res.string.number_of_repayments to numberOfRepayments, + Res.string.first_repayment_date to firstRepaymentDate, + Res.string.interest_charged_from to interestChargedForm, + Res.string.loan_new_loan_repaid_every to repaidEvery, + Res.string.loan_new_loan_nominal_interest_rate to nominalInterestRate, + Res.string.loan_new_loan_is_equal_amortization to isEqualAmortization, + Res.string.loan_new_loan_amortization to amortization, + Res.string.interest_calculation_period to interestCalculationPeriod, + Res.string.loan_new_loan_calculate_interest_for_exact_days_in_pertial to calculateInterestForExactDaysInPartial, + Res.string.loan_new_loan_arrears_tolerance to arrearsTolerance, + Res.string.loan_new_loan_interest_free_period to interestFreePeriod, + Res.string.repayment_strategy to repaymentStrategy, + Res.string.loan_new_loan_installment_amount to installmentAmount, + Res.string.loan_new_loan_ballon_repayment_amount to ballonRepayment, + ), + ) +} + +@Composable +private fun DetailsCard( + productName: String, + loanOfficer: String, + externalId: String, + submittedDate: String, + expectedDisbursement: String, + loadPurpose: String, + isSavingsLinked: String, +) { + MifosDefaultListingComponentFromStringResources( + data = mapOf( + Res.string.product_name to productName, + Res.string.loan_new_loan_loan_officer to loanOfficer, + Res.string.external_id to externalId, + Res.string.submission_date to submittedDate, + Res.string.expected_disbursement to expectedDisbursement, + Res.string.loan_new_loan_loan_purpose to loadPurpose, + Res.string.loan_new_loan_is_savings_linked to isSavingsLinked, + ), + ) +}