From 484f972a3eb89a533b5fd4bdfed3039b218ceb94 Mon Sep 17 00:00:00 2001 From: itsPronay Date: Tue, 16 Sep 2025 14:18:42 +0600 Subject: [PATCH 1/5] Merge Conflict # Conflicts: # core/ui/src/commonMain/kotlin/com/mifos/core/ui/components/MifosRowWithTextAndButton.kt --- .../newLoanAccount/NewLoanAccountScreen.kt | 5 +- .../loan/newLoanAccount/pages/PreviewPage.kt | 361 +++++++++++++++++- 2 files changed, 353 insertions(+), 13 deletions(-) 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..c6a716de1ca 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,7 +136,9 @@ private fun NewLoanAccountScaffold( } }, Step(stringResource(Res.string.step_preview)) { - PreviewPage { + PreviewPage( + state = state + ) { onAction(NewLoanAccountAction.NextStep) } }, @@ -483,3 +485,4 @@ private fun ShowChargesDialog( }, ) } + 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..283ca4f88b0 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,363 @@ 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 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.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.OutlinedCard 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.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.mifos.core.designsystem.theme.MifosTypography +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, +) { + val notAvailable = "Not Available" + Column( + modifier = Modifier.fillMaxSize() + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(20.dp), + ) { + Text( + "Details", + style = MifosTypography.labelLarge, + ) + DetailsCard( + productName = state.productLoans[state.loanProductSelected].name.toString(), + loanOfficer = if (state.loanOfficerIndex == -1) { + notAvailable + } else { + state.loanTemplate?.loanOfficerOptions[state.loanOfficerIndex]?.displayName.toString() + }, + externalId = state.externalId, + submittedDate = state.submissionDate, + expectedDisbursement = state.expectedDisbursementDate, + loadPurpose = if (state.loanPurposeIndex == -1) { + notAvailable + } else state.loanTemplate?.loanPurposeOptions[state.loanPurposeIndex]?.name.toString(), + isSavingsLinked = if (state.linkSavingsIndex == -1) { + "NO" + } else "YES", + ) + + Text( + "Terms", + style = MifosTypography.labelLarge, + ) + TermsCard( + //todo currency + principal = state.principalAmount.toString(), + loanTerm = if (state.termFrequencyIndex == -1) { + notAvailable + } 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) { + notAvailable + } else { + state.loanTemplate?.transactionProcessingStrategyOptions[state.repaymentStrategyIndex]?.name + ?: notAvailable + }, + installmentAmount = "", + ballonRepayment = state.balloonRepaymentAmount.toString(), + ) + + Text( + "Moratorium", + style = MifosTypography.labelLarge, + ) + MoratoriumCard( + onPrincipalPayment = state.moratoriumGraceOnPrincipalPayment.toString(), + onInternestPayment = state.moratoriumGraceOnInterestPayment.toString(), + onAreasAging = state.moratoriumOnArrearsAgeing.toString(), + enableInstallmentLevelDelinquency = "", + recalculateInterest = "", + daysInMonth = "", + ) + + Text( + "Moratorium", + style = MifosTypography.labelLarge, + ) + + MifosRowWithTextAndButton( + onBtnClick = {}, + text = "Add Charges", + btnText = "View", + modifier = Modifier.fillMaxWidth(), + ) + + MifosTwoButtonRow( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + firstBtnText = "Back", + secondBtnText = "Submit", + onFirstBtnClick = {}, + onSecondBtnClick = {}, + ) + } +} + +@Composable +private fun MoratoriumCard( + onPrincipalPayment: String, + onInternestPayment: String, + onAreasAging: String, + enableInstallmentLevelDelinquency: String, + recalculateInterest: String, + daysInMonth: String, +) { + OutlinedCard( + modifier = Modifier.fillMaxWidth(), + ) { + Column( + modifier = Modifier.fillMaxWidth().padding(16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + LoanPreviewItemRow( + title = "On principal payment", + description = onPrincipalPayment, + ) + + LoanPreviewItemRow( + title = "On interest payment", + description = onInternestPayment, + ) + + LoanPreviewItemRow( + title = "On Arrears Aging", + description = onAreasAging, + ) + + LoanPreviewItemRow( + title = "Enable installment level Delinquency", + description = enableInstallmentLevelDelinquency, + ) + + LoanPreviewItemRow( + title = "Recalculate Interest", + description = recalculateInterest, + ) + + LoanPreviewItemRow( + title = "Days in month", + description = 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, +) { + OutlinedCard( + modifier = Modifier.fillMaxWidth(), + ) { + Column( + modifier = Modifier.fillMaxWidth().padding(16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + LoanPreviewItemRow( + title = "Principal", + description = principal, + ) + + LoanPreviewItemRow( + title = "Loan Term", + description = loanTerm, + ) + + LoanPreviewItemRow( + title = "Number of Repayments", + description = numberOfRepayments, + ) + + LoanPreviewItemRow( + title = "First Repayment Date", + description = firstRepaymentDate, + ) + + LoanPreviewItemRow( + title = "Interest Charged From:", + description = interestChargedForm, + ) + + LoanPreviewItemRow( + title = "Repaid Every:", + description = repaidEvery, + ) + + LoanPreviewItemRow( + title = "Nominal Interest Rate:", + description = nominalInterestRate, + ) + + LoanPreviewItemRow( + title = "Is Equal Amortization:", + description = isEqualAmortization, + ) + + LoanPreviewItemRow( + title = "Amortization:", + description = amortization, + ) + LoanPreviewItemRow( + title = "Interest Calculation Period:", + description = interestCalculationPeriod, + ) + + LoanPreviewItemRow( + title = "Calculate interest for exact days in partial :", + description = calculateInterestForExactDaysInPartial, + ) + LoanPreviewItemRow( + title = "Arrears tolerance:", + description = arrearsTolerance, + ) + + LoanPreviewItemRow( + title = "Interest free period:", + description = interestFreePeriod, + ) + LoanPreviewItemRow( + title = "Repayment strategy:", + description = repaymentStrategy, + ) + LoanPreviewItemRow( + title = "Installment Amount:", + description = installmentAmount, + ) + LoanPreviewItemRow( + title = "Balloon Repayment Amount", + description = ballonRepayment, + ) + } + } +} + +@Composable +private fun DetailsCard( + productName: String, + loanOfficer: String, + externalId: String, + submittedDate: String, + expectedDisbursement: String, + loadPurpose: String, + isSavingsLinked: String, +) { + OutlinedCard( + modifier = Modifier.fillMaxWidth(), + ) { + Column( + modifier = Modifier.fillMaxWidth().padding(16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + LoanPreviewItemRow(title = "Product Name", description = productName) + LoanPreviewItemRow(title = "Loan Officer", description = loanOfficer) + LoanPreviewItemRow(title = "External ID", description = externalId) + LoanPreviewItemRow( + title = "Submitted Date", + description = submittedDate, + ) + + LoanPreviewItemRow( + title = "Expected Disbursement", + description = expectedDisbursement, + ) + + LoanPreviewItemRow( + title = "Loan Purpose", + description = loadPurpose, + ) + + LoanPreviewItemRow( + title = "Is Savings Linked", + description = isSavingsLinked, + ) + } + + } +} + +@Composable +private fun LoanPreviewItemRow( + title: String, + description: String, +) { + Row( + modifier = Modifier.fillMaxWidth(), + ) { + Text( + text = "$title:", + style = MifosTypography.labelMediumEmphasized, + modifier = Modifier.weight(5f), + maxLines = 1, + ) + + Text( + text = description, + modifier = Modifier.weight(5f), + maxLines = 1, + textAlign = TextAlign.End, + style = MifosTypography.labelMedium, + ) } } From 78b381d5367bbecc9ca9335cfb25a467cdbc6d69 Mon Sep 17 00:00:00 2001 From: itsPronay Date: Tue, 16 Sep 2025 16:05:49 +0600 Subject: [PATCH 2/5] update --- .../composeResources/values/strings.xml | 41 +++++ .../loan/newLoanAccount/pages/PreviewPage.kt | 168 +++++++++++------- 2 files changed, 141 insertions(+), 68 deletions(-) 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/pages/PreviewPage.kt b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/pages/PreviewPage.kt index 283ca4f88b0..160bbdaedf0 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,6 +10,44 @@ package com.mifos.feature.loan.newLoanAccount.pages import androidclient.feature.loan.generated.resources.Res +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.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.Row @@ -18,6 +56,9 @@ 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.CardColors +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -39,20 +80,19 @@ fun PreviewPage( state: NewLoanAccountState, onAction: (NewLoanAccountAction) -> Unit, ) { - val notAvailable = "Not Available" Column( modifier = Modifier.fillMaxSize() .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(20.dp), ) { Text( - "Details", + text = stringResource(Res.string.terms), style = MifosTypography.labelLarge, ) DetailsCard( productName = state.productLoans[state.loanProductSelected].name.toString(), loanOfficer = if (state.loanOfficerIndex == -1) { - notAvailable + "" } else { state.loanTemplate?.loanOfficerOptions[state.loanOfficerIndex]?.displayName.toString() }, @@ -60,22 +100,22 @@ fun PreviewPage( submittedDate = state.submissionDate, expectedDisbursement = state.expectedDisbursementDate, loadPurpose = if (state.loanPurposeIndex == -1) { - notAvailable + "" } else state.loanTemplate?.loanPurposeOptions[state.loanPurposeIndex]?.name.toString(), isSavingsLinked = if (state.linkSavingsIndex == -1) { - "NO" - } else "YES", + stringResource(Res.string.no) + } else stringResource(Res.string.yes), ) Text( - "Terms", + text = stringResource(Res.string.terms), style = MifosTypography.labelLarge, ) TermsCard( //todo currency principal = state.principalAmount.toString(), loanTerm = if (state.termFrequencyIndex == -1) { - notAvailable + "" } else { state.loanTemplate?.termFrequencyTypeOptions[state.termFrequencyIndex]?.value ?: "" }, @@ -101,17 +141,17 @@ fun PreviewPage( arrearsTolerance = state.arrearsTolerance.toString(), interestFreePeriod = state.interestFreePeriod.toString(), repaymentStrategy = if (state.repaymentStrategyIndex == -1) { - notAvailable + "" } else { state.loanTemplate?.transactionProcessingStrategyOptions[state.repaymentStrategyIndex]?.name - ?: notAvailable + ?: "" }, installmentAmount = "", ballonRepayment = state.balloonRepaymentAmount.toString(), ) Text( - "Moratorium", + text = stringResource(Res.string.loan_new_loan_moratorium), style = MifosTypography.labelLarge, ) MoratoriumCard( @@ -124,21 +164,21 @@ fun PreviewPage( ) Text( - "Moratorium", + text = stringResource(Res.string.loan_new_loan_charges), style = MifosTypography.labelLarge, ) MifosRowWithTextAndButton( onBtnClick = {}, - text = "Add Charges", - btnText = "View", + 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.fillMaxWidth().padding(horizontal = 16.dp), - firstBtnText = "Back", - secondBtnText = "Submit", + firstBtnText = stringResource(Res.string.back), + secondBtnText = stringResource(Res.string.feature_loan_charge_submit), onFirstBtnClick = {}, onSecondBtnClick = {}, ) @@ -156,45 +196,39 @@ private fun MoratoriumCard( ) { OutlinedCard( modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.background, + ), ) { Column( modifier = Modifier.fillMaxWidth().padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { LoanPreviewItemRow( - title = "On principal payment", + title = stringResource(Res.string.loan_new_loan_on_principal_payment), description = onPrincipalPayment, ) - LoanPreviewItemRow( - title = "On interest payment", + title = stringResource(Res.string.loan_new_loan_on_interest_payment), description = onInternestPayment, ) - LoanPreviewItemRow( - title = "On Arrears Aging", + title = stringResource(Res.string.loan_new_loan_on_arrears_aging), description = onAreasAging, ) - LoanPreviewItemRow( - title = "Enable installment level Delinquency", + title = stringResource(Res.string.loan_new_loan_enable_installment_level), description = enableInstallmentLevelDelinquency, ) - LoanPreviewItemRow( - title = "Recalculate Interest", + title = stringResource(Res.string.loan_new_loan_recalculate_interest), description = recalculateInterest, ) - LoanPreviewItemRow( - title = "Days in month", + title = stringResource(Res.string.loan_new_loan_days_in_month), description = daysInMonth, ) - - } - - } } @@ -219,83 +253,76 @@ private fun TermsCard( ) { OutlinedCard( modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.background, + ), ) { Column( modifier = Modifier.fillMaxWidth().padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { LoanPreviewItemRow( - title = "Principal", + title = stringResource(Res.string.principal), description = principal, ) - LoanPreviewItemRow( - title = "Loan Term", + title = stringResource(Res.string.loan_new_loan_loan_term), description = loanTerm, ) - LoanPreviewItemRow( - title = "Number of Repayments", + title = stringResource(Res.string.number_of_repayments), description = numberOfRepayments, ) - LoanPreviewItemRow( - title = "First Repayment Date", + title = stringResource(Res.string.first_repayment_date), description = firstRepaymentDate, ) - LoanPreviewItemRow( - title = "Interest Charged From:", + title = stringResource(Res.string.interest_charged_from), description = interestChargedForm, ) - LoanPreviewItemRow( - title = "Repaid Every:", + title = stringResource(Res.string.loan_new_loan_repaid_every), description = repaidEvery, ) - LoanPreviewItemRow( - title = "Nominal Interest Rate:", + title = stringResource(Res.string.loan_new_loan_nominal_interest_rate), description = nominalInterestRate, ) - LoanPreviewItemRow( - title = "Is Equal Amortization:", + title = stringResource(Res.string.loan_new_loan_is_equal_amortization), description = isEqualAmortization, ) - LoanPreviewItemRow( - title = "Amortization:", + title = stringResource(Res.string.loan_new_loan_amortization), description = amortization, ) LoanPreviewItemRow( - title = "Interest Calculation Period:", + title = stringResource(Res.string.interest_calculation_period), description = interestCalculationPeriod, ) - LoanPreviewItemRow( - title = "Calculate interest for exact days in partial :", + title = stringResource(Res.string.loan_new_loan_calculate_interest_for_exact_days_in_pertial), description = calculateInterestForExactDaysInPartial, ) LoanPreviewItemRow( - title = "Arrears tolerance:", + title = stringResource(Res.string.loan_new_loan_arrears_tolerance), description = arrearsTolerance, ) - LoanPreviewItemRow( - title = "Interest free period:", + title = stringResource(Res.string.loan_new_loan_interest_free_period), description = interestFreePeriod, ) LoanPreviewItemRow( - title = "Repayment strategy:", + title = stringResource(Res.string.repayment_strategy), description = repaymentStrategy, ) LoanPreviewItemRow( - title = "Installment Amount:", + title = stringResource(Res.string.loan_new_loan_installment_amount), description = installmentAmount, ) LoanPreviewItemRow( - title = "Balloon Repayment Amount", + title = stringResource(Res.string.loan_new_loan_ballon_repayment_amount), description = ballonRepayment, ) } @@ -319,30 +346,35 @@ private fun DetailsCard( modifier = Modifier.fillMaxWidth().padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { - LoanPreviewItemRow(title = "Product Name", description = productName) - LoanPreviewItemRow(title = "Loan Officer", description = loanOfficer) - LoanPreviewItemRow(title = "External ID", description = externalId) LoanPreviewItemRow( - title = "Submitted Date", + title = stringResource(Res.string.product_name), + description = productName, + ) + LoanPreviewItemRow( + title = stringResource(Res.string.loan_new_loan_loan_officer), + description = loanOfficer, + ) + LoanPreviewItemRow( + title = stringResource(Res.string.external_id), + description = externalId, + ) + LoanPreviewItemRow( + title = stringResource(Res.string.submission_date), description = submittedDate, ) - LoanPreviewItemRow( - title = "Expected Disbursement", + title = stringResource(Res.string.expected_disbursement), description = expectedDisbursement, ) - LoanPreviewItemRow( - title = "Loan Purpose", + title = stringResource(Res.string.loan_new_loan_loan_purpose), description = loadPurpose, ) - LoanPreviewItemRow( - title = "Is Savings Linked", + title = stringResource(Res.string.loan_new_loan_is_savings_linked), description = isSavingsLinked, ) } - } } From cc9ebdedafbd44820740013e4ad289df05ec552c Mon Sep 17 00:00:00 2001 From: itsPronay Date: Tue, 16 Sep 2025 21:06:19 +0600 Subject: [PATCH 3/5] update --- .../loan/newLoanAccount/NewLoanAccountViewModel.kt | 13 +++++++++++++ .../loan/newLoanAccount/pages/PreviewPage.kt | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) 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..44728a38746 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 @@ -23,6 +23,7 @@ import com.mifos.core.network.model.CollateralItem import com.mifos.core.ui.util.BaseViewModel import com.mifos.core.ui.util.TextFieldsValidator import com.mifos.feature.loan.newLoanAccount.NewLoanAccountState.DialogState +import com.mifos.room.entities.accounts.loans.LoanAccountEntity import com.mifos.room.entities.templates.loans.LoanTemplate import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -172,9 +173,19 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.EditChargeDialog -> handleEditChargeDialog(action.index) is NewLoanAccountAction.EditCharge -> handleEditCharge(action.index) + + NewLoanAccountAction.GotoPreviousStep -> {} + NewLoanAccountAction.SubmitLoanApplication -> { + + } } } + private fun submitLoanApplication() { + viewModelScope.launch { + LoanAccountEntity + } + } private fun handleChooseChargeIndexChange(action: NewLoanAccountAction.OnChooseChargeIndexChange) { mutableStateFlow.update { it.copy(chooseChargeIndex = action.index) @@ -851,6 +862,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 160bbdaedf0..d510dc0cdf2 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 @@ -146,6 +146,7 @@ fun PreviewPage( state.loanTemplate?.transactionProcessingStrategyOptions[state.repaymentStrategyIndex]?.name ?: "" }, + //todo installmentAmount = "", ballonRepayment = state.balloonRepaymentAmount.toString(), ) @@ -158,8 +159,14 @@ fun PreviewPage( onPrincipalPayment = state.moratoriumGraceOnPrincipalPayment.toString(), onInternestPayment = state.moratoriumGraceOnInterestPayment.toString(), onAreasAging = state.moratoriumOnArrearsAgeing.toString(), + //todo enableInstallmentLevelDelinquency = "", - recalculateInterest = "", + recalculateInterest = if (state.loanTemplate?.isInterestRecalculationEnabled ?: false) { + stringResource(Res.string.yes) + } else { + stringResource(Res.string.no) + }, + //todo daysInMonth = "", ) From 17fde8bfac3c225437899c0a1109102e079cc885 Mon Sep 17 00:00:00 2001 From: itsPronay Date: Wed, 17 Sep 2025 22:33:00 +0600 Subject: [PATCH 4/5] update --- .../newLoanAccount/NewLoanAccountScreen.kt | 3 +- .../newLoanAccount/NewLoanAccountViewModel.kt | 195 ++++++++++++++---- .../loan/newLoanAccount/pages/PreviewPage.kt | 44 ++-- 3 files changed, 189 insertions(+), 53 deletions(-) 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 c6a716de1ca..2990bbcd07c 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 @@ -137,7 +137,7 @@ private fun NewLoanAccountScaffold( }, Step(stringResource(Res.string.step_preview)) { PreviewPage( - state = state + state = state, ) { onAction(NewLoanAccountAction.NextStep) } @@ -485,4 +485,3 @@ private fun ShowChargesDialog( }, ) } - 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 44728a38746..7a5ccf4c7e8 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,18 +12,20 @@ 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 -import com.mifos.room.entities.accounts.loans.LoanAccountEntity import com.mifos.room.entities.templates.loans.LoanTemplate import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -36,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( @@ -72,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) @@ -82,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) @@ -110,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() @@ -144,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() @@ -154,7 +205,9 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.AddChargeToList -> handleAddChargeToList() - is NewLoanAccountAction.OnChooseChargeIndexChange -> handleChooseChargeIndexChange(action) + is NewLoanAccountAction.OnChooseChargeIndexChange -> handleChooseChargeIndexChange( + action, + ) is NewLoanAccountAction.ShowAddChargeDialog -> handleShowAddChargeDialog() @@ -175,17 +228,68 @@ internal class NewLoanAccountViewModel( is NewLoanAccountAction.EditCharge -> handleEditCharge(action.index) NewLoanAccountAction.GotoPreviousStep -> {} - NewLoanAccountAction.SubmitLoanApplication -> { - } + NewLoanAccountAction.SubmitLoanApplication -> submitLoanApplication() } } private fun submitLoanApplication() { viewModelScope.launch { - LoanAccountEntity + 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.invoke(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) + } + } + } } } + private fun handleChooseChargeIndexChange(action: NewLoanAccountAction.OnChooseChargeIndexChange) { mutableStateFlow.update { it.copy(chooseChargeIndex = action.index) @@ -634,6 +738,7 @@ internal class NewLoanAccountViewModel( ) } } + else -> Unit } } @@ -709,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(), @@ -724,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, @@ -735,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, @@ -767,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 = "", @@ -780,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 } @@ -829,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 @@ -862,7 +983,7 @@ 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 SubmitLoanApplication : NewLoanAccountAction data object GotoPreviousStep : NewLoanAccountAction } 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 d510dc0cdf2..5d6636137e9 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 @@ -56,19 +56,16 @@ 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.CardColors import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.mifos.core.designsystem.theme.MifosTypography +import com.mifos.core.ui.components.MifosProgressIndicator import com.mifos.core.ui.components.MifosRowWithTextAndButton import com.mifos.core.ui.components.MifosTwoButtonRow import com.mifos.feature.loan.newLoanAccount.NewLoanAccountAction @@ -79,6 +76,21 @@ import org.jetbrains.compose.resources.stringResource fun PreviewPage( state: NewLoanAccountState, onAction: (NewLoanAccountAction) -> Unit, +) { + if (state.isLoading) { + MifosProgressIndicator() + } else { + PreviewPageContent( + state, + onAction = onAction, + ) + } +} + +@Composable +fun PreviewPageContent( + state: NewLoanAccountState, + onAction: (NewLoanAccountAction) -> Unit, ) { Column( modifier = Modifier.fillMaxSize() @@ -101,10 +113,14 @@ fun PreviewPage( expectedDisbursement = state.expectedDisbursementDate, loadPurpose = if (state.loanPurposeIndex == -1) { "" - } else state.loanTemplate?.loanPurposeOptions[state.loanPurposeIndex]?.name.toString(), + } else { + state.loanTemplate?.loanPurposeOptions[state.loanPurposeIndex]?.name.toString() + }, isSavingsLinked = if (state.linkSavingsIndex == -1) { stringResource(Res.string.no) - } else stringResource(Res.string.yes), + } else { + stringResource(Res.string.yes) + }, ) Text( @@ -112,7 +128,7 @@ fun PreviewPage( style = MifosTypography.labelLarge, ) TermsCard( - //todo currency + // todo currency principal = state.principalAmount.toString(), loanTerm = if (state.termFrequencyIndex == -1) { "" @@ -146,7 +162,7 @@ fun PreviewPage( state.loanTemplate?.transactionProcessingStrategyOptions[state.repaymentStrategyIndex]?.name ?: "" }, - //todo + // todo installmentAmount = "", ballonRepayment = state.balloonRepaymentAmount.toString(), ) @@ -159,14 +175,14 @@ fun PreviewPage( onPrincipalPayment = state.moratoriumGraceOnPrincipalPayment.toString(), onInternestPayment = state.moratoriumGraceOnInterestPayment.toString(), onAreasAging = state.moratoriumOnArrearsAgeing.toString(), - //todo + // todo enableInstallmentLevelDelinquency = "", recalculateInterest = if (state.loanTemplate?.isInterestRecalculationEnabled ?: false) { stringResource(Res.string.yes) } else { stringResource(Res.string.no) }, - //todo + // todo daysInMonth = "", ) @@ -176,18 +192,18 @@ fun PreviewPage( ) MifosRowWithTextAndButton( - onBtnClick = {}, + 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.fillMaxWidth().padding(horizontal = 16.dp), + modifier = Modifier.fillMaxWidth(), firstBtnText = stringResource(Res.string.back), secondBtnText = stringResource(Res.string.feature_loan_charge_submit), - onFirstBtnClick = {}, - onSecondBtnClick = {}, + onFirstBtnClick = { onAction(NewLoanAccountAction.GotoPreviousStep) }, + onSecondBtnClick = { onAction(NewLoanAccountAction.SubmitLoanApplication) }, ) } } From de9fbd52860e60a5d9b79ac39849e0dd36de2dcb Mon Sep 17 00:00:00 2001 From: Arin Yadav Date: Fri, 3 Oct 2025 00:02:51 +0530 Subject: [PATCH 5/5] Enhance Preview Screen --- .../ui/components/MifosListingComponent.kt | 16 +- .../newLoanAccount/NewLoanAccountScreen.kt | 5 +- .../newLoanAccount/NewLoanAccountViewModel.kt | 2 +- .../loan/newLoanAccount/pages/PreviewPage.kt | 434 +++++++----------- 4 files changed, 172 insertions(+), 285 deletions(-) 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/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt b/feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/newLoanAccount/NewLoanAccountScreen.kt index 2990bbcd07c..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 @@ -138,9 +138,8 @@ private fun NewLoanAccountScaffold( Step(stringResource(Res.string.step_preview)) { PreviewPage( state = state, - ) { - onAction(NewLoanAccountAction.NextStep) - } + 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 7a5ccf4c7e8..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 @@ -262,7 +262,7 @@ internal class NewLoanAccountViewModel( linkAccountId = state.linkSavingsIndex, ) - loanUseCase.invoke(payload).collect { dataState -> + loanUseCase(payload).collect { dataState -> when (dataState) { is DataState.Error -> { mutableStateFlow.update { 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 5d6636137e9..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 @@ -45,27 +45,27 @@ 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.Row 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.CardDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign 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 @@ -78,7 +78,7 @@ fun PreviewPage( onAction: (NewLoanAccountAction) -> Unit, ) { if (state.isLoading) { - MifosProgressIndicator() + MifosProgressIndicatorOverlay() } else { PreviewPageContent( state, @@ -93,113 +93,122 @@ fun PreviewPageContent( onAction: (NewLoanAccountAction) -> Unit, ) { Column( - modifier = Modifier.fillMaxSize() - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(20.dp), + Modifier.fillMaxSize().padding(bottom = DesignToken.padding.large), ) { - Text( - text = stringResource(Res.string.terms), - 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( - // todo currency - principal = state.principalAmount.toString(), - 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(), - ) + 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.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.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_charges), - style = MifosTypography.labelLarge, - ) + 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 = "", + ) - 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(), - ) + 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.fillMaxWidth(), + modifier = Modifier.padding(top = DesignToken.padding.small), firstBtnText = stringResource(Res.string.back), secondBtnText = stringResource(Res.string.feature_loan_charge_submit), onFirstBtnClick = { onAction(NewLoanAccountAction.GotoPreviousStep) }, @@ -217,42 +226,16 @@ private fun MoratoriumCard( recalculateInterest: String, daysInMonth: String, ) { - OutlinedCard( - modifier = Modifier.fillMaxWidth(), - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.background, + 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, ), - ) { - Column( - modifier = Modifier.fillMaxWidth().padding(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_on_principal_payment), - description = onPrincipalPayment, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_on_interest_payment), - description = onInternestPayment, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_on_arrears_aging), - description = onAreasAging, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_enable_installment_level), - description = enableInstallmentLevelDelinquency, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_recalculate_interest), - description = recalculateInterest, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_days_in_month), - description = daysInMonth, - ) - } - } + ) } @Composable @@ -274,82 +257,26 @@ private fun TermsCard( installmentAmount: String, ballonRepayment: String, ) { - OutlinedCard( - modifier = Modifier.fillMaxWidth(), - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.background, + 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, ), - ) { - Column( - modifier = Modifier.fillMaxWidth().padding(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - LoanPreviewItemRow( - title = stringResource(Res.string.principal), - description = principal, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_loan_term), - description = loanTerm, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.number_of_repayments), - description = numberOfRepayments, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.first_repayment_date), - description = firstRepaymentDate, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.interest_charged_from), - description = interestChargedForm, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_repaid_every), - description = repaidEvery, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_nominal_interest_rate), - description = nominalInterestRate, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_is_equal_amortization), - description = isEqualAmortization, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_amortization), - description = amortization, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.interest_calculation_period), - description = interestCalculationPeriod, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_calculate_interest_for_exact_days_in_pertial), - description = calculateInterestForExactDaysInPartial, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_arrears_tolerance), - description = arrearsTolerance, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_interest_free_period), - description = interestFreePeriod, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.repayment_strategy), - description = repaymentStrategy, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_installment_amount), - description = installmentAmount, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_ballon_repayment_amount), - description = ballonRepayment, - ) - } - } + ) } @Composable @@ -362,66 +289,15 @@ private fun DetailsCard( loadPurpose: String, isSavingsLinked: String, ) { - OutlinedCard( - modifier = Modifier.fillMaxWidth(), - ) { - Column( - modifier = Modifier.fillMaxWidth().padding(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - LoanPreviewItemRow( - title = stringResource(Res.string.product_name), - description = productName, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_loan_officer), - description = loanOfficer, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.external_id), - description = externalId, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.submission_date), - description = submittedDate, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.expected_disbursement), - description = expectedDisbursement, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_loan_purpose), - description = loadPurpose, - ) - LoanPreviewItemRow( - title = stringResource(Res.string.loan_new_loan_is_savings_linked), - description = isSavingsLinked, - ) - } - } -} - -@Composable -private fun LoanPreviewItemRow( - title: String, - description: String, -) { - Row( - modifier = Modifier.fillMaxWidth(), - ) { - Text( - text = "$title:", - style = MifosTypography.labelMediumEmphasized, - modifier = Modifier.weight(5f), - maxLines = 1, - ) - - Text( - text = description, - modifier = Modifier.weight(5f), - maxLines = 1, - textAlign = TextAlign.End, - style = MifosTypography.labelMedium, - ) - } + 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, + ), + ) }