refactor(loan): show consistent loan actions for all account statuses (#2952)

This commit is contained in:
Nagarjuna 2025-08-24 19:15:57 +05:30 committed by GitHub
parent d83c760eeb
commit bd78ecefc1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 97 additions and 35 deletions

View File

@ -14,6 +14,8 @@ enum class LoanStatus(val status: String) {
CLOSED("Closed"),
CLOSED_OBLIGATIONS_MET("Closed (obligations met)"),
MATURED("Matured"),
APPROVED("Approved"),
@ -25,4 +27,12 @@ enum class LoanStatus(val status: String) {
REJECTED("Rejected"),
WITHDRAWN("Withdrawn by applicant"),
OVERPAID("Overpaid"),
;
companion object {
fun fromStatus(value: String?): LoanStatus? =
entries.firstOrNull { it.status.equals(value, ignoreCase = true) }
}
}

View File

@ -10,6 +10,7 @@
package org.mifos.mobile.core.model.entity.accounts.loan
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.model.LoanStatus
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
@ -40,6 +41,9 @@ data class Status(
) : Parcelable {
val loanStatus: LoanStatus?
get() = LoanStatus.fromStatus(value)
fun isLoanTypeWithdrawn(): Boolean {
return !(
this.active == true || this.closed == true || this.pendingApproval == true ||

View File

@ -28,7 +28,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.collections.immutable.ImmutableList
import mifos_mobile.feature.loan_account.generated.resources.Res
import mifos_mobile.feature.loan_account.generated.resources.feature_account_details_action
import mifos_mobile.feature.loan_account.generated.resources.feature_account_details_top_bar_title
@ -163,14 +162,14 @@ internal fun LoanAccountDetailsContent(
)
}
if (state.isActive) {
SavingsAccountActions(
items = state.items,
onActionClick = {
onAction(LoanAccountDetailsAction.OnNavigateToAction(it))
},
)
}
val visibleActions = state.accountStatus?.allowedActions ?: emptySet()
SavingsAccountActions(
visibleActions = visibleActions,
onActionClick = {
onAction(LoanAccountDetailsAction.OnNavigateToAction(it))
},
)
}
}
}
@ -222,8 +221,7 @@ internal fun AccountDetailsGrid(
@Composable
internal fun SavingsAccountActions(
items: ImmutableList<LoanActionItems>,
// onAction: (LoanAccountDetailsAction) -> Unit,
visibleActions: Set<LoanActionItems>,
onActionClick: (String) -> Unit,
) {
Column(
@ -237,16 +235,15 @@ internal fun SavingsAccountActions(
FlowRow(
modifier = Modifier.fillMaxWidth(),
) {
items.forEach { item ->
MifosActionCard(
title = item.title,
subTitle = item.subTitle,
icon = item.icon,
onClick = {
onActionClick(item.route)
},
)
}
visibleActions
.forEach { item ->
MifosActionCard(
title = item.title,
subTitle = item.subTitle,
icon = item.icon,
onClick = { onActionClick(item.route) },
)
}
}
}
}

View File

@ -178,7 +178,7 @@ internal class LoanAccountDetailsViewModel(
mutableStateFlow.update {
it.copy(
accountId = loan?.id?.toLong() ?: -1L,
isActive = loan?.status?.value == LoanStatus.ACTIVE.status,
accountStatus = loan?.status?.loanStatus,
accountNumber = loan?.accountNo,
clientName = loan?.clientName,
product = loan?.loanProductName,
@ -198,7 +198,7 @@ internal class LoanAccountDetailsViewModel(
* @property accountId Unique ID for the loan account.
* @property displayItems List of account metadata to be displayed.
* @property transactionList List of most recent transaction details.
* @property isActive True if the loan is active.
* @property accountStatus True if the loan is active.
* @property items List of quick action items (e.g., Repay, Foreclose).
* @property isUpdatable Whether the loan is editable (e.g., in a pending state).
* @property dialogState State representing UI dialogs like loading or error.
@ -214,7 +214,7 @@ internal data class LoanAccountDetailsState(
val product: String? = "",
val displayItems: List<LabelValueItem> = emptyList(),
val transactionList: List<LabelValueItem>? = emptyList(),
val isActive: Boolean = false,
val accountStatus: LoanStatus? = LoanStatus.ACTIVE,
val items: ImmutableList<LoanActionItems>,
val isUpdatable: Boolean = false,
val dialogState: DialogState?,
@ -231,6 +231,57 @@ internal data class LoanAccountDetailsState(
}
}
val LoanStatus.allowedActions: Set<LoanActionItems>
get() = when (this) {
LoanStatus.SUBMIT_AND_PENDING_APPROVAL -> setOf(
LoanActionItems.LoanSummary,
)
LoanStatus.APPROVED -> setOf(
LoanActionItems.LoanSummary,
LoanActionItems.Charges,
)
LoanStatus.DISBURSED,
LoanStatus.ACTIVE,
-> setOf(
LoanActionItems.MakePayment,
LoanActionItems.LoanSummary,
LoanActionItems.RepaymentSchedule,
LoanActionItems.Transactions,
LoanActionItems.Charges,
LoanActionItems.QrCode,
)
LoanStatus.MATURED -> setOf(
LoanActionItems.LoanSummary,
LoanActionItems.RepaymentSchedule,
LoanActionItems.Transactions,
)
LoanStatus.CLOSED -> setOf(
LoanActionItems.LoanSummary,
LoanActionItems.Transactions,
)
LoanStatus.CLOSED_OBLIGATIONS_MET -> setOf(
LoanActionItems.LoanSummary,
LoanActionItems.Transactions,
)
LoanStatus.REJECTED,
LoanStatus.WITHDRAWN,
-> setOf(
LoanActionItems.LoanSummary,
)
LoanStatus.OVERPAID -> setOf(
LoanActionItems.LoanSummary,
LoanActionItems.Transactions,
)
}
/**
* One-time navigation or effect events for the Loan Account Details screen.
*/

View File

@ -149,7 +149,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_expected_payoff_label,
CurrencyFormatter.format(
loan?.summary?.totalExpectedRepayment,
loan?.summary?.totalExpectedRepayment ?: 0.0,
currencyCode,
maxDigits,
),
@ -157,7 +157,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_interest_payoff_label,
CurrencyFormatter.format(
loan?.summary?.interestCharged,
loan?.summary?.interestCharged ?: 0.0,
currencyCode,
maxDigits,
),
@ -165,7 +165,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_principal_label,
CurrencyFormatter.format(
loan?.summary?.principalDisbursed,
loan?.summary?.principalDisbursed ?: 0.0,
currencyCode,
maxDigits,
),
@ -184,7 +184,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_fees_label,
CurrencyFormatter.format(
loan?.summary?.feeChargesCharged,
loan?.summary?.feeChargesCharged ?: 0.0,
currencyCode,
maxDigits,
),
@ -192,7 +192,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_penalties_label,
CurrencyFormatter.format(
loan?.summary?.penaltyChargesCharged,
loan?.summary?.penaltyChargesCharged ?: 0.0,
currencyCode,
maxDigits,
),
@ -203,7 +203,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_interest_waived_label,
CurrencyFormatter.format(
loan?.summary?.interestWaived,
loan?.summary?.interestWaived ?: 0.0,
currencyCode,
maxDigits,
),
@ -211,7 +211,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_penalty_waived_label,
CurrencyFormatter.format(
loan?.summary?.penaltyChargesWaived,
loan?.summary?.penaltyChargesWaived ?: 0.0,
currencyCode,
maxDigits,
),
@ -219,7 +219,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_fees_waived_label,
CurrencyFormatter.format(
loan?.summary?.feeChargesWaived,
loan?.summary?.feeChargesWaived ?: 0.0,
currencyCode,
maxDigits,
),
@ -230,7 +230,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_interest_paid_off_label,
CurrencyFormatter.format(
loan?.summary?.interestPaid,
loan?.summary?.interestPaid ?: 0.0,
currencyCode,
maxDigits,
),
@ -238,7 +238,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_principal_paid_off_label,
CurrencyFormatter.format(
loan?.summary?.principalPaid,
loan?.summary?.principalPaid ?: 0.0,
currencyCode,
maxDigits,
),
@ -266,7 +266,7 @@ internal class LoanAccountSummaryViewModel(
LabelValueItem(
Res.string.feature_loan_total_outstanding_label,
CurrencyFormatter.format(
loan?.summary?.totalOutstanding,
loan?.summary?.totalOutstanding ?: 0.0,
currencyCode,
maxDigits,
),